From 574db2e61b115450bbae8040439c0f0da5612114 Mon Sep 17 00:00:00 2001 From: cherylEnkidu Date: Thu, 27 Feb 2025 12:25:18 -0500 Subject: [PATCH 001/113] create main branch of ppl --- Firestore/CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Firestore/CHANGELOG.md b/Firestore/CHANGELOG.md index a006d39ab7b..a533789f01a 100644 --- a/Firestore/CHANGELOG.md +++ b/Firestore/CHANGELOG.md @@ -1,3 +1,6 @@ +# Unreleased +- [feature] Add `Pipeline` support. + # 11.9.0 - [fixed] Fixed memory leak in `Query.whereField()`. (#13978) From 7a4a98c901f4a89edcd32d33a0172ab04b87db22 Mon Sep 17 00:00:00 2001 From: wu-hui <53845758+wu-hui@users.noreply.github.com> Date: Tue, 4 Mar 2025 13:18:27 -0500 Subject: [PATCH 002/113] Add ppl protos (#14516) --- .../Firestore.xcodeproj/project.pbxproj | 48 + .../Firestore_IntegrationTests_macOS.xcscheme | 22 +- Firestore/Protos/CMakeLists.txt | 3 + Firestore/Protos/cpp/firestore/bundle.pb.cc | 2 +- Firestore/Protos/cpp/firestore/bundle.pb.h | 2 +- .../cpp/firestore/local/maybe_document.pb.cc | 2 +- .../cpp/firestore/local/maybe_document.pb.h | 2 +- .../Protos/cpp/firestore/local/mutation.pb.cc | 2 +- .../Protos/cpp/firestore/local/mutation.pb.h | 2 +- .../Protos/cpp/firestore/local/target.pb.cc | 2 +- .../Protos/cpp/firestore/local/target.pb.h | 2 +- .../Protos/cpp/google/api/annotations.pb.cc | 2 +- .../Protos/cpp/google/api/annotations.pb.h | 2 +- .../cpp/google/api/field_behavior.pb.cc | 125 + .../Protos/cpp/google/api/field_behavior.pb.h | 168 + Firestore/Protos/cpp/google/api/http.pb.cc | 2 +- Firestore/Protos/cpp/google/api/http.pb.h | 2 +- .../Protos/cpp/google/api/resource.pb.cc | 2 +- Firestore/Protos/cpp/google/api/resource.pb.h | 2 +- .../cpp/google/firestore/admin/index.pb.cc | 2 +- .../cpp/google/firestore/admin/index.pb.h | 2 +- .../firestore/v1/aggregation_result.pb.cc | 2 +- .../firestore/v1/aggregation_result.pb.h | 2 +- .../google/firestore/v1/bloom_filter.pb.cc | 2 +- .../cpp/google/firestore/v1/bloom_filter.pb.h | 2 +- .../cpp/google/firestore/v1/common.pb.cc | 2 +- .../cpp/google/firestore/v1/common.pb.h | 2 +- .../cpp/google/firestore/v1/document.pb.cc | 1119 ++- .../cpp/google/firestore/v1/document.pb.h | 1626 +++- .../google/firestore/v1/explain_stats.pb.cc | 366 + .../google/firestore/v1/explain_stats.pb.h | 398 + .../cpp/google/firestore/v1/firestore.pb.cc | 1716 +++- .../cpp/google/firestore/v1/firestore.pb.h | 7109 ++++++++++------- .../cpp/google/firestore/v1/pipeline.pb.cc | 466 ++ .../cpp/google/firestore/v1/pipeline.pb.h | 480 ++ .../cpp/google/firestore/v1/query.pb.cc | 2 +- .../Protos/cpp/google/firestore/v1/query.pb.h | 2 +- .../cpp/google/firestore/v1/write.pb.cc | 2 +- .../Protos/cpp/google/firestore/v1/write.pb.h | 2 +- Firestore/Protos/cpp/google/rpc/status.pb.cc | 2 +- Firestore/Protos/cpp/google/rpc/status.pb.h | 2 +- Firestore/Protos/cpp/google/type/latlng.pb.cc | 2 +- Firestore/Protos/cpp/google/type/latlng.pb.h | 2 +- .../Protos/nanopb/firestore/bundle.nanopb.cc | 2 +- .../Protos/nanopb/firestore/bundle.nanopb.h | 2 +- .../firestore/local/maybe_document.nanopb.cc | 2 +- .../firestore/local/maybe_document.nanopb.h | 2 +- .../nanopb/firestore/local/mutation.nanopb.cc | 2 +- .../nanopb/firestore/local/mutation.nanopb.h | 2 +- .../nanopb/firestore/local/target.nanopb.cc | 2 +- .../nanopb/firestore/local/target.nanopb.h | 2 +- .../nanopb/google/api/annotations.nanopb.cc | 2 +- .../nanopb/google/api/annotations.nanopb.h | 2 +- .../google/api/field_behavior.nanopb.cc | 77 + .../nanopb/google/api/field_behavior.nanopb.h | 61 + .../Protos/nanopb/google/api/http.nanopb.cc | 2 +- .../Protos/nanopb/google/api/http.nanopb.h | 2 +- .../nanopb/google/api/resource.nanopb.cc | 2 +- .../nanopb/google/api/resource.nanopb.h | 2 +- .../google/firestore/admin/index.nanopb.cc | 2 +- .../google/firestore/admin/index.nanopb.h | 2 +- .../firestore/v1/aggregation_result.nanopb.cc | 2 +- .../firestore/v1/aggregation_result.nanopb.h | 2 +- .../firestore/v1/bloom_filter.nanopb.cc | 2 +- .../google/firestore/v1/bloom_filter.nanopb.h | 2 +- .../google/firestore/v1/common.nanopb.cc | 2 +- .../google/firestore/v1/common.nanopb.h | 2 +- .../google/firestore/v1/document.nanopb.cc | 140 +- .../google/firestore/v1/document.nanopb.h | 89 +- .../firestore/v1/explain_stats.nanopb.cc | 83 + .../firestore/v1/explain_stats.nanopb.h | 73 + .../google/firestore/v1/firestore.nanopb.cc | 78 +- .../google/firestore/v1/firestore.nanopb.h | 53 +- .../google/firestore/v1/pipeline.nanopb.cc | 106 + .../google/firestore/v1/pipeline.nanopb.h | 92 + .../google/firestore/v1/query.nanopb.cc | 2 +- .../nanopb/google/firestore/v1/query.nanopb.h | 2 +- .../google/firestore/v1/write.nanopb.cc | 2 +- .../nanopb/google/firestore/v1/write.nanopb.h | 2 +- .../nanopb/google/protobuf/any.nanopb.cc | 2 +- .../nanopb/google/protobuf/any.nanopb.h | 2 +- .../nanopb/google/protobuf/empty.nanopb.cc | 2 +- .../nanopb/google/protobuf/empty.nanopb.h | 2 +- .../nanopb/google/protobuf/struct.nanopb.cc | 2 +- .../nanopb/google/protobuf/struct.nanopb.h | 2 +- .../google/protobuf/timestamp.nanopb.cc | 2 +- .../nanopb/google/protobuf/timestamp.nanopb.h | 2 +- .../nanopb/google/protobuf/wrappers.nanopb.cc | 2 +- .../nanopb/google/protobuf/wrappers.nanopb.h | 2 +- .../Protos/nanopb/google/rpc/status.nanopb.cc | 2 +- .../Protos/nanopb/google/rpc/status.nanopb.h | 2 +- .../nanopb/google/type/latlng.nanopb.cc | 2 +- .../Protos/nanopb/google/type/latlng.nanopb.h | 2 +- .../protos/google/api/field_behavior.proto | 104 + .../protos/google/firestore/v1/document.proto | 128 +- .../google/firestore/v1/explain_stats.proto | 38 + .../google/firestore/v1/firestore.proto | 87 + .../protos/google/firestore/v1/pipeline.proto | 43 + 98 files changed, 11363 insertions(+), 3675 deletions(-) create mode 100644 Firestore/Protos/cpp/google/api/field_behavior.pb.cc create mode 100644 Firestore/Protos/cpp/google/api/field_behavior.pb.h create mode 100644 Firestore/Protos/cpp/google/firestore/v1/explain_stats.pb.cc create mode 100644 Firestore/Protos/cpp/google/firestore/v1/explain_stats.pb.h create mode 100644 Firestore/Protos/cpp/google/firestore/v1/pipeline.pb.cc create mode 100644 Firestore/Protos/cpp/google/firestore/v1/pipeline.pb.h create mode 100644 Firestore/Protos/nanopb/google/api/field_behavior.nanopb.cc create mode 100644 Firestore/Protos/nanopb/google/api/field_behavior.nanopb.h create mode 100644 Firestore/Protos/nanopb/google/firestore/v1/explain_stats.nanopb.cc create mode 100644 Firestore/Protos/nanopb/google/firestore/v1/explain_stats.nanopb.h create mode 100644 Firestore/Protos/nanopb/google/firestore/v1/pipeline.nanopb.cc create mode 100644 Firestore/Protos/nanopb/google/firestore/v1/pipeline.nanopb.h create mode 100644 Firestore/Protos/protos/google/api/field_behavior.proto create mode 100644 Firestore/Protos/protos/google/firestore/v1/explain_stats.proto create mode 100644 Firestore/Protos/protos/google/firestore/v1/pipeline.proto diff --git a/Firestore/Example/Firestore.xcodeproj/project.pbxproj b/Firestore/Example/Firestore.xcodeproj/project.pbxproj index 8deefcabab8..5cf594fd314 100644 --- a/Firestore/Example/Firestore.xcodeproj/project.pbxproj +++ b/Firestore/Example/Firestore.xcodeproj/project.pbxproj @@ -104,6 +104,7 @@ 0E17927CE45F5E3FC6691E24 /* firebase_auth_credentials_provider_test.mm in Sources */ = {isa = PBXBuildFile; fileRef = F869D85E900E5AF6CD02E2FC /* firebase_auth_credentials_provider_test.mm */; }; 0E4C94369FFF7EC0C9229752 /* iterator_adaptors_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 54A0353420A3D8CB003E0143 /* iterator_adaptors_test.cc */; }; 0E4F266A9FDF55CD38BB6D0F /* leveldb_query_engine_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = DB1F1E1B1ED15E8D042144B1 /* leveldb_query_engine_test.cc */; }; + 0E7A39BD9C87CC33F91A672F /* explain_stats.pb.cc in Sources */ = {isa = PBXBuildFile; fileRef = 682582E5728F3F1C531990EA /* explain_stats.pb.cc */; }; 0EA40EDACC28F445F9A3F32F /* pretty_printing_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = AB323F9553050F4F6490F9FF /* pretty_printing_test.cc */; }; 0EC3921AE220410F7394729B /* aggregation_result.pb.cc in Sources */ = {isa = PBXBuildFile; fileRef = D872D754B8AD88E28AF28B28 /* aggregation_result.pb.cc */; }; 0EDFC8A6593477E1D17CDD8F /* leveldb_bundle_cache_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 8E9CD82E60893DDD7757B798 /* leveldb_bundle_cache_test.cc */; }; @@ -229,6 +230,7 @@ 1F4930A8366F74288121F627 /* create_noop_connectivity_monitor.cc in Sources */ = {isa = PBXBuildFile; fileRef = CF39535F2C41AB0006FA6C0E /* create_noop_connectivity_monitor.cc */; }; 1F56F51EB6DF0951B1F4F85B /* lru_garbage_collector_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 277EAACC4DD7C21332E8496A /* lru_garbage_collector_test.cc */; }; 1F998DDECB54A66222CC66AA /* string_format_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 54131E9620ADE678001DF3FF /* string_format_test.cc */; }; + 1F9FFAE375C88EFF88CBB6F8 /* field_behavior.pb.cc in Sources */ = {isa = PBXBuildFile; fileRef = FAAF1A69F4A315C38357BDC4 /* field_behavior.pb.cc */; }; 1FE23E911F0761AA896FAD67 /* Validation_BloomFilterTest_MD5_500_1_bloom_filter_proto.json in Resources */ = {isa = PBXBuildFile; fileRef = D8E530B27D5641B9C26A452C /* Validation_BloomFilterTest_MD5_500_1_bloom_filter_proto.json */; }; 2045517602D767BD01EA71D9 /* overlay_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E1459FA70B8FC18DE4B80D0D /* overlay_test.cc */; }; 205601D1C6A40A4DD3BBAA04 /* target_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 526D755F65AC676234F57125 /* target_test.cc */; }; @@ -295,6 +297,7 @@ 2A86AB04B38DBB770A1D8B13 /* Validation_BloomFilterTest_MD5_1_1_membership_test_result.json in Resources */ = {isa = PBXBuildFile; fileRef = 3369AC938F82A70685C5ED58 /* Validation_BloomFilterTest_MD5_1_1_membership_test_result.json */; }; 2AAEABFD550255271E3BAC91 /* to_string_apple_test.mm in Sources */ = {isa = PBXBuildFile; fileRef = B68B1E002213A764008977EF /* to_string_apple_test.mm */; }; 2ABA80088D70E7A58F95F7D8 /* delayed_constructor_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = D0A6E9136804A41CEC9D55D4 /* delayed_constructor_test.cc */; }; + 2AD2CB51469AE35331C39258 /* pipeline.pb.cc in Sources */ = {isa = PBXBuildFile; fileRef = 7142B5EC46E88349FAB3384F /* pipeline.pb.cc */; }; 2AD8EE91928AE68DF268BEDA /* limbo_spec_test.json in Resources */ = {isa = PBXBuildFile; fileRef = 54DA129E1F315EE100DD57A1 /* limbo_spec_test.json */; }; 2AD98CD29CC6F820A74CDD5E /* Validation_BloomFilterTest_MD5_1_0001_bloom_filter_proto.json in Resources */ = {isa = PBXBuildFile; fileRef = 4B59C0A7B2A4548496ED4E7D /* Validation_BloomFilterTest_MD5_1_0001_bloom_filter_proto.json */; }; 2AE3914BBC4EDF91BD852939 /* memory_query_engine_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 8EF6A33BC2D84233C355F1D0 /* memory_query_engine_test.cc */; }; @@ -342,6 +345,7 @@ 32F022CB75AEE48CDDAF2982 /* mutation_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = C8522DE226C467C54E6788D8 /* mutation_test.cc */; }; 32F8B4652010E8224E353041 /* persistence_spec_test.json in Resources */ = {isa = PBXBuildFile; fileRef = 54DA12A31F315EE100DD57A1 /* persistence_spec_test.json */; }; 330DE2A5AE6AF8D66C9C849F /* Validation_BloomFilterTest_MD5_5000_0001_membership_test_result.json in Resources */ = {isa = PBXBuildFile; fileRef = C8582DFD74E8060C7072104B /* Validation_BloomFilterTest_MD5_5000_0001_membership_test_result.json */; }; + 332E7D2D8489E6DA42947C59 /* field_behavior.pb.cc in Sources */ = {isa = PBXBuildFile; fileRef = FAAF1A69F4A315C38357BDC4 /* field_behavior.pb.cc */; }; 336E415DD06E719F9C9E2A14 /* grpc_stream_tester.cc in Sources */ = {isa = PBXBuildFile; fileRef = 87553338E42B8ECA05BA987E /* grpc_stream_tester.cc */; }; 338DFD5BCD142DF6C82A0D56 /* cc_compilation_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 1B342370EAE3AA02393E33EB /* cc_compilation_test.cc */; }; 339CFFD1323BDCA61EAAFE31 /* query_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = B9C261C26C5D311E1E3C0CB9 /* query_test.cc */; }; @@ -392,6 +396,7 @@ 3B256CCF6AEEE12E22F16BB8 /* hashing_test_apple.mm in Sources */ = {isa = PBXBuildFile; fileRef = B69CF3F02227386500B281C8 /* hashing_test_apple.mm */; }; 3B37BD3C13A66625EC82CF77 /* hard_assert_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 444B7AB3F5A2929070CB1363 /* hard_assert_test.cc */; }; 3B47CC43DBA24434E215B8ED /* memory_index_manager_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = DB5A1E760451189DA36028B3 /* memory_index_manager_test.cc */; }; + 3B4CFB45208A7EEF1EA58ADC /* pipeline.pb.cc in Sources */ = {isa = PBXBuildFile; fileRef = 7142B5EC46E88349FAB3384F /* pipeline.pb.cc */; }; 3B5CEA04AC1627256A1AE8BA /* bloom_filter_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = A2E6F09AD1EE0A6A452E9A08 /* bloom_filter_test.cc */; }; 3B843E4C1F3A182900548890 /* remote_store_spec_test.json in Resources */ = {isa = PBXBuildFile; fileRef = 3B843E4A1F3930A400548890 /* remote_store_spec_test.json */; }; 3BA4EEA6153B3833F86B8104 /* writer_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = BC3C788D290A935C353CEAA1 /* writer_test.cc */; }; @@ -515,6 +520,7 @@ 50454F81EC4584D4EB5F5ED5 /* serializer_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 61F72C5520BC48FD001A68CB /* serializer_test.cc */; }; 50B749CA98365368AE34B71C /* filter_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = F02F734F272C3C70D1307076 /* filter_test.cc */; }; 50C852E08626CFA7DC889EEA /* field_index_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = BF76A8DA34B5B67B4DD74666 /* field_index_test.cc */; }; + 50EA1F41D766C92894E9B078 /* explain_stats.pb.cc in Sources */ = {isa = PBXBuildFile; fileRef = 682582E5728F3F1C531990EA /* explain_stats.pb.cc */; }; 51018EA27CF914DD1CC79CB3 /* thread_safe_memoizer_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 1A8141230C7E3986EACEF0B6 /* thread_safe_memoizer_test.cc */; }; 513D34C9964E8C60C5C2EE1C /* leveldb_bundle_cache_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 8E9CD82E60893DDD7757B798 /* leveldb_bundle_cache_test.cc */; }; 5150E9F256E6E82D6F3CB3F1 /* bundle_cache_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = F7FC06E0A47D393DE1759AE1 /* bundle_cache_test.cc */; }; @@ -783,6 +789,7 @@ 66DFEA9E324797E6EA81CBA9 /* perf_spec_test.json in Resources */ = {isa = PBXBuildFile; fileRef = D5B2593BCB52957D62F1C9D3 /* perf_spec_test.json */; }; 66FAB8EAC012A3822BD4D0C9 /* leveldb_util_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 332485C4DCC6BA0DBB5E31B7 /* leveldb_util_test.cc */; }; 6711E75A10EBA662341F5C9D /* leveldb_document_overlay_cache_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = AE89CFF09C6804573841397F /* leveldb_document_overlay_cache_test.cc */; }; + 676933F59F2F0A0D221A4F8F /* explain_stats.pb.cc in Sources */ = {isa = PBXBuildFile; fileRef = 682582E5728F3F1C531990EA /* explain_stats.pb.cc */; }; 677C833244550767B71DB1BA /* log_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 54C2294E1FECABAE007D065B /* log_test.cc */; }; 67B8C34BDF0FFD7532D7BE4F /* Validation_BloomFilterTest_MD5_500_0001_membership_test_result.json in Resources */ = {isa = PBXBuildFile; fileRef = 478DC75A0DCA6249A616DD30 /* Validation_BloomFilterTest_MD5_500_0001_membership_test_result.json */; }; 67BC2B77C1CC47388E79D774 /* FIRSnapshotMetadataTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5492E04D202154AA00B64F25 /* FIRSnapshotMetadataTests.mm */; }; @@ -840,6 +847,7 @@ 6FF2B680CC8631B06C7BD7AB /* FSTMemorySpecTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5492E02F20213FFC00B64F25 /* FSTMemorySpecTests.mm */; }; 70A171FC43BE328767D1B243 /* path_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 403DBF6EFB541DFD01582AA3 /* path_test.cc */; }; 70AB665EB6A473FF6C4CFD31 /* CodableTimestampTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B65C996438B84DBC7616640 /* CodableTimestampTests.swift */; }; + 715A0E92C83AE4384A13B882 /* pipeline.pb.cc in Sources */ = {isa = PBXBuildFile; fileRef = 7142B5EC46E88349FAB3384F /* pipeline.pb.cc */; }; 716289F99B5316B3CC5E5CE9 /* FIRSnapshotMetadataTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5492E04D202154AA00B64F25 /* FIRSnapshotMetadataTests.mm */; }; 71702588BFBF5D3A670508E7 /* ordered_code_benchmark.cc in Sources */ = {isa = PBXBuildFile; fileRef = 0473AFFF5567E667A125347B /* ordered_code_benchmark.cc */; }; 71719F9F1E33DC2100824A3D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 71719F9D1E33DC2100824A3D /* LaunchScreen.storyboard */; }; @@ -861,6 +869,7 @@ 73E42D984FB36173A2BDA57C /* FSTEventAccumulator.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5492E0392021401F00B64F25 /* FSTEventAccumulator.mm */; }; 73FE5066020EF9B2892C86BF /* hard_assert_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 444B7AB3F5A2929070CB1363 /* hard_assert_test.cc */; }; 743DF2DF38CE289F13F44043 /* status_testing.cc in Sources */ = {isa = PBXBuildFile; fileRef = 3CAA33F964042646FDDAF9F9 /* status_testing.cc */; }; + 7492C447277CDC8CB7A165CB /* explain_stats.pb.cc in Sources */ = {isa = PBXBuildFile; fileRef = 682582E5728F3F1C531990EA /* explain_stats.pb.cc */; }; 7495E3BAE536CD839EE20F31 /* FSTLevelDBSpecTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5492E02C20213FFB00B64F25 /* FSTLevelDBSpecTests.mm */; }; 74985DE2C7EF4150D7A455FD /* statusor_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 54A0352D20A3B3D7003E0143 /* statusor_test.cc */; }; 74A63A931F834D1D6CF3BA9A /* Validation_BloomFilterTest_MD5_1_1_membership_test_result.json in Resources */ = {isa = PBXBuildFile; fileRef = 3369AC938F82A70685C5ED58 /* Validation_BloomFilterTest_MD5_1_1_membership_test_result.json */; }; @@ -972,6 +981,7 @@ 8683BBC3AC7B01937606A83B /* firestore.pb.cc in Sources */ = {isa = PBXBuildFile; fileRef = 544129D421C2DDC800EFB9CC /* firestore.pb.cc */; }; 86B413EC49E3BBBEBF1FB7A0 /* Validation_BloomFilterTest_MD5_500_1_membership_test_result.json in Resources */ = {isa = PBXBuildFile; fileRef = 8AB49283E544497A9C5A0E59 /* Validation_BloomFilterTest_MD5_500_1_membership_test_result.json */; }; 86E6FC2B7657C35B342E1436 /* sorted_map_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 549CCA4E20A36DBB00BCEB75 /* sorted_map_test.cc */; }; + 86E73F6286E87834CF37D5D9 /* field_behavior.pb.cc in Sources */ = {isa = PBXBuildFile; fileRef = FAAF1A69F4A315C38357BDC4 /* field_behavior.pb.cc */; }; 8705C4856498F66E471A0997 /* FIRWriteBatchTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5492E06F202154D600B64F25 /* FIRWriteBatchTests.mm */; }; 873B8AEB1B1F5CCA007FD442 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 873B8AEA1B1F5CCA007FD442 /* Main.storyboard */; }; 8778C1711059598070F86D3C /* leveldb_globals_cache_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = FC44D934D4A52C790659C8D6 /* leveldb_globals_cache_test.cc */; }; @@ -1006,6 +1016,7 @@ 8F3AE423677A4C50F7E0E5C0 /* database_info_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = AB38D92E20235D22000A432D /* database_info_test.cc */; }; 8F4F40E9BC7ED588F67734D5 /* app_testing.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5467FB07203E6A44009C9584 /* app_testing.mm */; }; 8F781F527ED72DC6C123689E /* autoid_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 54740A521FC913E500713A1A /* autoid_test.cc */; }; + 8FE63980976481EBA001B789 /* explain_stats.pb.cc in Sources */ = {isa = PBXBuildFile; fileRef = 682582E5728F3F1C531990EA /* explain_stats.pb.cc */; }; 9009C285F418EA80C46CF06B /* fake_target_metadata_provider.cc in Sources */ = {isa = PBXBuildFile; fileRef = 71140E5D09C6E76F7C71B2FC /* fake_target_metadata_provider.cc */; }; 900D0E9F18CE3DB954DD0D1E /* async_queue_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = B6FB467B208E9A8200554BA2 /* async_queue_test.cc */; }; 9012B0E121B99B9C7E54160B /* query_engine_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = B8A853940305237AFDA8050B /* query_engine_test.cc */; }; @@ -1024,6 +1035,7 @@ 920B6ABF76FDB3547F1CCD84 /* firestore.pb.cc in Sources */ = {isa = PBXBuildFile; fileRef = 544129D421C2DDC800EFB9CC /* firestore.pb.cc */; }; 9236478E01DF2EC7DF58B1FC /* index_backfiller_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 1F50E872B3F117A674DA8E94 /* index_backfiller_test.cc */; }; 925BE64990449E93242A00A2 /* memory_mutation_queue_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 74FBEFA4FE4B12C435011763 /* memory_mutation_queue_test.cc */; }; + 92B593DCD86543D8C90F64F9 /* pipeline.pb.cc in Sources */ = {isa = PBXBuildFile; fileRef = 7142B5EC46E88349FAB3384F /* pipeline.pb.cc */; }; 92D7081085679497DC112EDB /* persistence_testing.cc in Sources */ = {isa = PBXBuildFile; fileRef = 9113B6F513D0473AEABBAF1F /* persistence_testing.cc */; }; 92EFF0CC2993B43CBC7A61FF /* grpc_streaming_reader_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = B6D964922154AB8F00EB9CFB /* grpc_streaming_reader_test.cc */; }; 9382BE7190E7750EE7CCCE7C /* write_spec_test.json in Resources */ = {isa = PBXBuildFile; fileRef = 54DA12A51F315EE100DD57A1 /* write_spec_test.json */; }; @@ -1070,6 +1082,7 @@ 9C366448F9BA7A4AC0821AF7 /* bundle_spec_test.json in Resources */ = {isa = PBXBuildFile; fileRef = 79EAA9F7B1B9592B5F053923 /* bundle_spec_test.json */; }; 9C86EEDEA131BFD50255EEF1 /* comparison_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 548DB928200D59F600E00ABC /* comparison_test.cc */; }; 9CC32ACF397022BB7DF11B52 /* Validation_BloomFilterTest_MD5_500_0001_bloom_filter_proto.json in Resources */ = {isa = PBXBuildFile; fileRef = D22D4C211AC32E4F8B4883DA /* Validation_BloomFilterTest_MD5_500_0001_bloom_filter_proto.json */; }; + 9CD1E9301EC44ED10DAEA5FB /* pipeline.pb.cc in Sources */ = {isa = PBXBuildFile; fileRef = 7142B5EC46E88349FAB3384F /* pipeline.pb.cc */; }; 9CE07BAAD3D3BC5F069D38FE /* grpc_streaming_reader_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = B6D964922154AB8F00EB9CFB /* grpc_streaming_reader_test.cc */; }; 9CFF379C7404F7CE6B26AF29 /* listen_source_spec_test.json in Resources */ = {isa = PBXBuildFile; fileRef = 4D9E51DA7A275D8B1CAEAEB2 /* listen_source_spec_test.json */; }; 9D71628E38D9F64C965DF29E /* FSTAPIHelpers.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5492E04E202154AA00B64F25 /* FSTAPIHelpers.mm */; }; @@ -1105,6 +1118,7 @@ A4AD189BDEF7A609953457A6 /* leveldb_key_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 54995F6E205B6E12004EFFA0 /* leveldb_key_test.cc */; }; A4ECA8335000CBDF94586C94 /* FSTDatastoreTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5492E07E202154EC00B64F25 /* FSTDatastoreTests.mm */; }; A5175CA2E677E13CC5F23D72 /* document_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = AB6B908320322E4D00CC290A /* document_test.cc */; }; + A5301AA55748A11801E3EE47 /* field_behavior.pb.cc in Sources */ = {isa = PBXBuildFile; fileRef = FAAF1A69F4A315C38357BDC4 /* field_behavior.pb.cc */; }; A55266E6C986251D283CE948 /* FIRCursorTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5492E070202154D600B64F25 /* FIRCursorTests.mm */; }; A5583822218F9D5B1E86FCAC /* overlay_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E1459FA70B8FC18DE4B80D0D /* overlay_test.cc */; }; A57EC303CD2D6AA4F4745551 /* FIRFieldValueTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5492E04A202154AA00B64F25 /* FIRFieldValueTests.mm */; }; @@ -1194,6 +1208,7 @@ B220E091D8F4E6DE1EA44F57 /* executor_libdispatch_test.mm in Sources */ = {isa = PBXBuildFile; fileRef = B6FB4689208F9B9100554BA2 /* executor_libdispatch_test.mm */; }; B235E260EA0DCB7BAC04F69B /* field_path_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = B686F2AD2023DDB20028D6BE /* field_path_test.cc */; }; B2554A2BA211D10823646DBE /* Validation_BloomFilterTest_MD5_500_01_bloom_filter_proto.json in Resources */ = {isa = PBXBuildFile; fileRef = 4BD051DBE754950FEAC7A446 /* Validation_BloomFilterTest_MD5_500_01_bloom_filter_proto.json */; }; + B280370F84393808250B28BC /* explain_stats.pb.cc in Sources */ = {isa = PBXBuildFile; fileRef = 682582E5728F3F1C531990EA /* explain_stats.pb.cc */; }; B28ACC69EB1F232AE612E77B /* async_testing.cc in Sources */ = {isa = PBXBuildFile; fileRef = 872C92ABD71B12784A1C5520 /* async_testing.cc */; }; B2A9965ED0114E39A911FD09 /* Validation_BloomFilterTest_MD5_5000_1_bloom_filter_proto.json in Resources */ = {isa = PBXBuildFile; fileRef = 4375BDCDBCA9938C7F086730 /* Validation_BloomFilterTest_MD5_5000_1_bloom_filter_proto.json */; }; B31B5E0D4EA72C5916CC71F5 /* thread_safe_memoizer_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 1A8141230C7E3986EACEF0B6 /* thread_safe_memoizer_test.cc */; }; @@ -1419,6 +1434,7 @@ D73BBA4AB42940AB187169E3 /* listen_spec_test.json in Resources */ = {isa = PBXBuildFile; fileRef = 54DA12A01F315EE100DD57A1 /* listen_spec_test.json */; }; D756A1A63E626572EE8DF592 /* firestore.pb.cc in Sources */ = {isa = PBXBuildFile; fileRef = 544129D421C2DDC800EFB9CC /* firestore.pb.cc */; }; D77941FD93DBE862AEF1F623 /* FSTTransactionTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5492E07B202154EB00B64F25 /* FSTTransactionTests.mm */; }; + D8F427680C3165DCD1A6BA2A /* field_behavior.pb.cc in Sources */ = {isa = PBXBuildFile; fileRef = FAAF1A69F4A315C38357BDC4 /* field_behavior.pb.cc */; }; D91D86B29B86A60C05879A48 /* timestamp_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = ABF6506B201131F8005F2C74 /* timestamp_test.cc */; }; D928302820891CCCAD0437DD /* thread_safe_memoizer_testing.cc in Sources */ = {isa = PBXBuildFile; fileRef = 6E42FA109D363EA7F3387AAE /* thread_safe_memoizer_testing.cc */; }; D9366A834BFF13246DC3AF9E /* field_path_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = B686F2AD2023DDB20028D6BE /* field_path_test.cc */; }; @@ -1454,6 +1470,7 @@ DD6C480629B3F87933FAF440 /* filesystem_testing.cc in Sources */ = {isa = PBXBuildFile; fileRef = BA02DA2FCD0001CFC6EB08DA /* filesystem_testing.cc */; }; DD935E243A64A4EB688E4C1C /* credentials_provider_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 2F4FA4576525144C5069A7A5 /* credentials_provider_test.cc */; }; DD941BF189E38312E7A2CB21 /* Validation_BloomFilterTest_MD5_500_1_bloom_filter_proto.json in Resources */ = {isa = PBXBuildFile; fileRef = D8E530B27D5641B9C26A452C /* Validation_BloomFilterTest_MD5_500_1_bloom_filter_proto.json */; }; + DDABEDF95A5B44E590064EF7 /* field_behavior.pb.cc in Sources */ = {isa = PBXBuildFile; fileRef = FAAF1A69F4A315C38357BDC4 /* field_behavior.pb.cc */; }; DDD219222EEE13E3F9F2C703 /* leveldb_transaction_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 88CF09277CFA45EE1273E3BA /* leveldb_transaction_test.cc */; }; DDDE74C752E65DE7D39A7166 /* view_testing.cc in Sources */ = {isa = PBXBuildFile; fileRef = A5466E7809AD2871FFDE6C76 /* view_testing.cc */; }; DE03B2D41F2149D600A30B9C /* XCTest.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6003F5AF195388D20070C39A /* XCTest.framework */; }; @@ -1601,6 +1618,7 @@ F58A23FEF328EB74F681FE83 /* index_manager_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = AE4A9E38D65688EE000EE2A1 /* index_manager_test.cc */; }; F5A654E92FF6F3FF16B93E6B /* mutation_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = C8522DE226C467C54E6788D8 /* mutation_test.cc */; }; F5B1F219E912F645FB79D08E /* firebase_app_check_credentials_provider_test.mm in Sources */ = {isa = PBXBuildFile; fileRef = F119BDDF2F06B3C0883B8297 /* firebase_app_check_credentials_provider_test.mm */; }; + F5BA649242983E2E54345BDD /* pipeline.pb.cc in Sources */ = {isa = PBXBuildFile; fileRef = 7142B5EC46E88349FAB3384F /* pipeline.pb.cc */; }; F5BDECEB3B43BD1591EEADBD /* FSTUserDataReaderTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 8D9892F204959C50613F16C8 /* FSTUserDataReaderTests.mm */; }; F6079BFC9460B190DA85C2E6 /* pretty_printing_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = AB323F9553050F4F6490F9FF /* pretty_printing_test.cc */; }; F609600E9A88A4D44FD1FCEB /* FSTSpecTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5492E03020213FFC00B64F25 /* FSTSpecTests.mm */; }; @@ -1729,6 +1747,7 @@ 1A8141230C7E3986EACEF0B6 /* thread_safe_memoizer_test.cc */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; path = thread_safe_memoizer_test.cc; sourceTree = ""; }; 1B342370EAE3AA02393E33EB /* cc_compilation_test.cc */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; name = cc_compilation_test.cc; path = api/cc_compilation_test.cc; sourceTree = ""; }; 1B9F95EC29FAD3F100EEC075 /* FIRAggregateQueryUnitTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = FIRAggregateQueryUnitTests.mm; sourceTree = ""; }; + 1BAFC713D2B1A2DBD55B2593 /* field_behavior.pb.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = field_behavior.pb.h; sourceTree = ""; }; 1C01D8CE367C56BB2624E299 /* index.pb.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = index.pb.h; path = admin/index.pb.h; sourceTree = ""; }; 1C3F7302BF4AE6CBC00ECDD0 /* resource.pb.cc */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; path = resource.pb.cc; sourceTree = ""; }; 1CA9800A53669EFBFFB824E3 /* memory_remote_document_cache_test.cc */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; path = memory_remote_document_cache_test.cc; sourceTree = ""; }; @@ -1736,6 +1755,7 @@ 1F50E872B3F117A674DA8E94 /* index_backfiller_test.cc */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; path = index_backfiller_test.cc; sourceTree = ""; }; 214877F52A705012D6720CA0 /* object_value_test.cc */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; path = object_value_test.cc; sourceTree = ""; }; 2220F583583EFC28DE792ABE /* Pods_Firestore_IntegrationTests_tvOS.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Firestore_IntegrationTests_tvOS.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 2258E6EBCFB8E8B1693C1347 /* explain_stats.pb.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = explain_stats.pb.h; sourceTree = ""; }; 2286F308EFB0534B1BDE05B9 /* memory_target_cache_test.cc */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; path = memory_target_cache_test.cc; sourceTree = ""; }; 26DDBA115DEB88631B93F203 /* thread_safe_memoizer_testing.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = thread_safe_memoizer_testing.h; sourceTree = ""; }; 277EAACC4DD7C21332E8496A /* lru_garbage_collector_test.cc */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; path = lru_garbage_collector_test.cc; sourceTree = ""; }; @@ -1942,6 +1962,7 @@ 64AA92CFA356A2360F3C5646 /* filesystem_testing.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = filesystem_testing.h; sourceTree = ""; }; 65AF0AB593C3AD81A1F1A57E /* FIRCompositeIndexQueryTests.mm */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.objcpp; path = FIRCompositeIndexQueryTests.mm; sourceTree = ""; }; 67786C62C76A740AEDBD8CD3 /* FSTTestingHooks.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = FSTTestingHooks.h; sourceTree = ""; }; + 682582E5728F3F1C531990EA /* explain_stats.pb.cc */ = {isa = PBXFileReference; includeInIndex = 1; path = explain_stats.pb.cc; sourceTree = ""; }; 69E6C311558EC77729A16CF1 /* Pods-Firestore_Example_iOS-Firestore_SwiftTests_iOS.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Firestore_Example_iOS-Firestore_SwiftTests_iOS.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Firestore_Example_iOS-Firestore_SwiftTests_iOS/Pods-Firestore_Example_iOS-Firestore_SwiftTests_iOS.debug.xcconfig"; sourceTree = ""; }; 6A7A30A2DB3367E08939E789 /* bloom_filter.pb.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = bloom_filter.pb.h; sourceTree = ""; }; 6AE927CDFC7A72BF825BE4CB /* Pods-Firestore_Tests_tvOS.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Firestore_Tests_tvOS.release.xcconfig"; path = "Pods/Target Support Files/Pods-Firestore_Tests_tvOS/Pods-Firestore_Tests_tvOS.release.xcconfig"; sourceTree = ""; }; @@ -1958,6 +1979,7 @@ 6F57521E161450FAF89075ED /* event_manager_test.cc */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; path = event_manager_test.cc; sourceTree = ""; }; 6F5B6C1399F92FD60F2C582B /* nanopb_util_test.cc */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; name = nanopb_util_test.cc; path = nanopb/nanopb_util_test.cc; sourceTree = ""; }; 71140E5D09C6E76F7C71B2FC /* fake_target_metadata_provider.cc */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; path = fake_target_metadata_provider.cc; sourceTree = ""; }; + 7142B5EC46E88349FAB3384F /* pipeline.pb.cc */ = {isa = PBXFileReference; includeInIndex = 1; path = pipeline.pb.cc; sourceTree = ""; }; 71719F9E1E33DC2100824A3D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 728F617782600536F2561463 /* Validation_BloomFilterTest_MD5_5000_0001_bloom_filter_proto.json */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.json; name = Validation_BloomFilterTest_MD5_5000_0001_bloom_filter_proto.json; path = bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_5000_0001_bloom_filter_proto.json; sourceTree = ""; }; 731541602214AFFA0037F4DC /* query_spec_test.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = query_spec_test.json; sourceTree = ""; }; @@ -2094,6 +2116,7 @@ D85AC18C55650ED230A71B82 /* FSTTestingHooks.mm */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.objcpp; path = FSTTestingHooks.mm; sourceTree = ""; }; D872D754B8AD88E28AF28B28 /* aggregation_result.pb.cc */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; path = aggregation_result.pb.cc; sourceTree = ""; }; D8A6D52723B1BABE1B7B8D8F /* leveldb_overlay_migration_manager_test.cc */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; path = leveldb_overlay_migration_manager_test.cc; sourceTree = ""; }; + D8DAE1269481D15A291E0B49 /* pipeline.pb.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = pipeline.pb.h; sourceTree = ""; }; D8E530B27D5641B9C26A452C /* Validation_BloomFilterTest_MD5_500_1_bloom_filter_proto.json */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.json; name = Validation_BloomFilterTest_MD5_500_1_bloom_filter_proto.json; path = bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_500_1_bloom_filter_proto.json; sourceTree = ""; }; D9D94300B9C02F7069523C00 /* leveldb_snappy_test.cc */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; path = leveldb_snappy_test.cc; sourceTree = ""; }; DAFF0CF521E64AC30062958F /* Firestore_Example_macOS.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Firestore_Example_macOS.app; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -2141,6 +2164,7 @@ F848C41C03A25C42AD5A4BC2 /* target_cache_test.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = target_cache_test.h; sourceTree = ""; }; F869D85E900E5AF6CD02E2FC /* firebase_auth_credentials_provider_test.mm */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.objcpp; name = firebase_auth_credentials_provider_test.mm; path = credentials/firebase_auth_credentials_provider_test.mm; sourceTree = ""; }; FA2E9952BA2B299C1156C43C /* Pods-Firestore_Benchmarks_iOS.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Firestore_Benchmarks_iOS.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Firestore_Benchmarks_iOS/Pods-Firestore_Benchmarks_iOS.debug.xcconfig"; sourceTree = ""; }; + FAAF1A69F4A315C38357BDC4 /* field_behavior.pb.cc */ = {isa = PBXFileReference; includeInIndex = 1; path = field_behavior.pb.cc; sourceTree = ""; }; FC44D934D4A52C790659C8D6 /* leveldb_globals_cache_test.cc */ = {isa = PBXFileReference; includeInIndex = 1; path = leveldb_globals_cache_test.cc; sourceTree = ""; }; FC738525340E594EBFAB121E /* Pods-Firestore_Example_tvOS.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Firestore_Example_tvOS.release.xcconfig"; path = "Pods/Target Support Files/Pods-Firestore_Example_tvOS/Pods-Firestore_Example_tvOS.release.xcconfig"; sourceTree = ""; }; FF73B39D04D1760190E6B84A /* FIRQueryUnitTests.mm */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.objcpp; path = FIRQueryUnitTests.mm; sourceTree = ""; }; @@ -2310,8 +2334,12 @@ 544129D121C2DDC800EFB9CC /* common.pb.h */, 544129D821C2DDC800EFB9CC /* document.pb.cc */, 544129D721C2DDC800EFB9CC /* document.pb.h */, + 682582E5728F3F1C531990EA /* explain_stats.pb.cc */, + 2258E6EBCFB8E8B1693C1347 /* explain_stats.pb.h */, 544129D421C2DDC800EFB9CC /* firestore.pb.cc */, 544129D321C2DDC800EFB9CC /* firestore.pb.h */, + 7142B5EC46E88349FAB3384F /* pipeline.pb.cc */, + D8DAE1269481D15A291E0B49 /* pipeline.pb.h */, 544129D621C2DDC800EFB9CC /* query.pb.cc */, 544129D021C2DDC800EFB9CC /* query.pb.h */, 544129D921C2DDC800EFB9CC /* write.pb.cc */, @@ -2778,6 +2806,8 @@ children = ( 618BBE9520B89AAC00B5BCE7 /* annotations.pb.cc */, 618BBE9620B89AAC00B5BCE7 /* annotations.pb.h */, + FAAF1A69F4A315C38357BDC4 /* field_behavior.pb.cc */, + 1BAFC713D2B1A2DBD55B2593 /* field_behavior.pb.h */, 618BBE9720B89AAC00B5BCE7 /* http.pb.cc */, 618BBE9420B89AAC00B5BCE7 /* http.pb.h */, 1C3F7302BF4AE6CBC00ECDD0 /* resource.pb.cc */, @@ -4227,8 +4257,10 @@ AC6C1E57B18730428CB15E03 /* executor_libdispatch_test.mm in Sources */, E7D415B8717701B952C344E5 /* executor_std_test.cc in Sources */, 470A37727BBF516B05ED276A /* executor_test.cc in Sources */, + B280370F84393808250B28BC /* explain_stats.pb.cc in Sources */, 2E0BBA7E627EB240BA11B0D0 /* exponential_backoff_test.cc in Sources */, 9009C285F418EA80C46CF06B /* fake_target_metadata_provider.cc in Sources */, + A5301AA55748A11801E3EE47 /* field_behavior.pb.cc in Sources */, 2E373EA9D5FF8C6DE2507675 /* field_index_test.cc in Sources */, 07B1E8C62772758BC82FEBEE /* field_mask_test.cc in Sources */, D9366A834BFF13246DC3AF9E /* field_path_test.cc in Sources */, @@ -4304,6 +4336,7 @@ BE1D7C7E413449AFFBA21BCB /* overlay_test.cc in Sources */, DB7E9C5A59CCCDDB7F0C238A /* path_test.cc in Sources */, E30BF9E316316446371C956C /* persistence_testing.cc in Sources */, + 715A0E92C83AE4384A13B882 /* pipeline.pb.cc in Sources */, 0455FC6E2A281BD755FD933A /* precondition_test.cc in Sources */, 5ECE040F87E9FCD0A5D215DB /* pretty_printing_test.cc in Sources */, 938F2AF6EC5CD0B839300DB0 /* query.pb.cc in Sources */, @@ -4450,8 +4483,10 @@ B220E091D8F4E6DE1EA44F57 /* executor_libdispatch_test.mm in Sources */, BAB43C839445782040657239 /* executor_std_test.cc in Sources */, 3A7CB01751697ED599F2D9A1 /* executor_test.cc in Sources */, + 8FE63980976481EBA001B789 /* explain_stats.pb.cc in Sources */, EF3518F84255BAF3EBD317F6 /* exponential_backoff_test.cc in Sources */, 4DAFC3A3FD5E96910A517320 /* fake_target_metadata_provider.cc in Sources */, + 86E73F6286E87834CF37D5D9 /* field_behavior.pb.cc in Sources */, 69D3AD697D1A7BF803A08160 /* field_index_test.cc in Sources */, ED4E2AC80CAF2A8FDDAC3DEE /* field_mask_test.cc in Sources */, 41EAC526C543064B8F3F7EDA /* field_path_test.cc in Sources */, @@ -4527,6 +4562,7 @@ 2045517602D767BD01EA71D9 /* overlay_test.cc in Sources */, 0963F6D7B0F9AE1E24B82866 /* path_test.cc in Sources */, 92D7081085679497DC112EDB /* persistence_testing.cc in Sources */, + 9CD1E9301EC44ED10DAEA5FB /* pipeline.pb.cc in Sources */, 152543FD706D5E8851C8DA92 /* precondition_test.cc in Sources */, 2639ABDA17EECEB7F62D1D83 /* pretty_printing_test.cc in Sources */, 5FA3DB52A478B01384D3A2ED /* query.pb.cc in Sources */, @@ -4697,8 +4733,10 @@ 5F6CE37B34C542704C5605A4 /* executor_libdispatch_test.mm in Sources */, AECCD9663BB3DC52199F954A /* executor_std_test.cc in Sources */, 18F644E6AA98E6D6F3F1F809 /* executor_test.cc in Sources */, + 0E7A39BD9C87CC33F91A672F /* explain_stats.pb.cc in Sources */, 6938575C8B5E6FE0D562547A /* exponential_backoff_test.cc in Sources */, 258B372CF33B7E7984BBA659 /* fake_target_metadata_provider.cc in Sources */, + D8F427680C3165DCD1A6BA2A /* field_behavior.pb.cc in Sources */, F8BD2F61EFA35C2D5120D9EB /* field_index_test.cc in Sources */, F272A8C41D2353700A11D1FB /* field_mask_test.cc in Sources */, AF6D6C47F9A25C65BFDCBBA0 /* field_path_test.cc in Sources */, @@ -4774,6 +4812,7 @@ A5583822218F9D5B1E86FCAC /* overlay_test.cc in Sources */, 70A171FC43BE328767D1B243 /* path_test.cc in Sources */, EECC1EC64CA963A8376FA55C /* persistence_testing.cc in Sources */, + 92B593DCD86543D8C90F64F9 /* pipeline.pb.cc in Sources */, 34D69886DAD4A2029BFC5C63 /* precondition_test.cc in Sources */, F56E9334642C207D7D85D428 /* pretty_printing_test.cc in Sources */, 22A00AC39CAB3426A943E037 /* query.pb.cc in Sources */, @@ -4944,8 +4983,10 @@ 49C593017B5438B216FAF593 /* executor_libdispatch_test.mm in Sources */, 17DFF30CF61D87883986E8B6 /* executor_std_test.cc in Sources */, 814724DE70EFC3DDF439CD78 /* executor_test.cc in Sources */, + 7492C447277CDC8CB7A165CB /* explain_stats.pb.cc in Sources */, BD6CC8614970A3D7D2CF0D49 /* exponential_backoff_test.cc in Sources */, 4D2655C5675D83205C3749DC /* fake_target_metadata_provider.cc in Sources */, + DDABEDF95A5B44E590064EF7 /* field_behavior.pb.cc in Sources */, 50C852E08626CFA7DC889EEA /* field_index_test.cc in Sources */, A1563EFEB021936D3FFE07E3 /* field_mask_test.cc in Sources */, B235E260EA0DCB7BAC04F69B /* field_path_test.cc in Sources */, @@ -5021,6 +5062,7 @@ D1BCDAEACF6408200DFB9870 /* overlay_test.cc in Sources */, B3A309CCF5D75A555C7196E1 /* path_test.cc in Sources */, 46EAC2828CD942F27834F497 /* persistence_testing.cc in Sources */, + 3B4CFB45208A7EEF1EA58ADC /* pipeline.pb.cc in Sources */, 9EE1447AA8E68DF98D0590FF /* precondition_test.cc in Sources */, F6079BFC9460B190DA85C2E6 /* pretty_printing_test.cc in Sources */, 7B0F073BDB6D0D6E542E23D4 /* query.pb.cc in Sources */, @@ -5177,8 +5219,10 @@ B6FB468E208F9BAB00554BA2 /* executor_libdispatch_test.mm in Sources */, B6FB468F208F9BAE00554BA2 /* executor_std_test.cc in Sources */, B6FB4690208F9BB300554BA2 /* executor_test.cc in Sources */, + 50EA1F41D766C92894E9B078 /* explain_stats.pb.cc in Sources */, B6D1B68520E2AB1B00B35856 /* exponential_backoff_test.cc in Sources */, FAE5DA6ED3E1842DC21453EE /* fake_target_metadata_provider.cc in Sources */, + 1F9FFAE375C88EFF88CBB6F8 /* field_behavior.pb.cc in Sources */, 03AEB9E07A605AE1B5827548 /* field_index_test.cc in Sources */, 549CCA5720A36E1F00BCEB75 /* field_mask_test.cc in Sources */, B686F2AF2023DDEE0028D6BE /* field_path_test.cc in Sources */, @@ -5254,6 +5298,7 @@ 4D20563D846FA0F3BEBFDE9D /* overlay_test.cc in Sources */, 5A080105CCBFDB6BF3F3772D /* path_test.cc in Sources */, 21C17F15579341289AD01051 /* persistence_testing.cc in Sources */, + F5BA649242983E2E54345BDD /* pipeline.pb.cc in Sources */, 549CCA5920A36E1F00BCEB75 /* precondition_test.cc in Sources */, 6A94393D83EB338DFAF6A0D2 /* pretty_printing_test.cc in Sources */, 544129DC21C2DDC800EFB9CC /* query.pb.cc in Sources */, @@ -5443,8 +5488,10 @@ B6BF6EFEF887B072068BA658 /* executor_libdispatch_test.mm in Sources */, 125B1048ECB755C2106802EB /* executor_std_test.cc in Sources */, DABB9FB61B1733F985CBF713 /* executor_test.cc in Sources */, + 676933F59F2F0A0D221A4F8F /* explain_stats.pb.cc in Sources */, 7BCF050BA04537B0E7D44730 /* exponential_backoff_test.cc in Sources */, BA1C5EAE87393D8E60F5AE6D /* fake_target_metadata_provider.cc in Sources */, + 332E7D2D8489E6DA42947C59 /* field_behavior.pb.cc in Sources */, 84285C3F63D916A4786724A8 /* field_index_test.cc in Sources */, 6A40835DB2C02B9F07C02E88 /* field_mask_test.cc in Sources */, D00E69F7FDF2BE674115AD3F /* field_path_test.cc in Sources */, @@ -5520,6 +5567,7 @@ 4D7900401B1BF3D3C24DDC7E /* overlay_test.cc in Sources */, 6105A1365831B79A7DEEA4F3 /* path_test.cc in Sources */, CB8BEF34CC4A996C7BE85119 /* persistence_testing.cc in Sources */, + 2AD2CB51469AE35331C39258 /* pipeline.pb.cc in Sources */, 4194B7BB8B0352E1AC5D69B9 /* precondition_test.cc in Sources */, 0EA40EDACC28F445F9A3F32F /* pretty_printing_test.cc in Sources */, 63B91FC476F3915A44F00796 /* query.pb.cc in Sources */, diff --git a/Firestore/Example/Firestore.xcodeproj/xcshareddata/xcschemes/Firestore_IntegrationTests_macOS.xcscheme b/Firestore/Example/Firestore.xcodeproj/xcshareddata/xcschemes/Firestore_IntegrationTests_macOS.xcscheme index 809a72983a5..b6e7d07944b 100644 --- a/Firestore/Example/Firestore.xcodeproj/xcshareddata/xcschemes/Firestore_IntegrationTests_macOS.xcscheme +++ b/Firestore/Example/Firestore.xcodeproj/xcshareddata/xcschemes/Firestore_IntegrationTests_macOS.xcscheme @@ -27,6 +27,15 @@ selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" shouldUseLaunchSchemeArgsEnv = "YES"> + + + + @@ -39,17 +48,6 @@ - - - - - - - - +#include "google/protobuf/io/coded_stream.h" +#include "google/protobuf/extension_set.h" +#include "google/protobuf/wire_format_lite.h" +#include "google/protobuf/descriptor.h" +#include "google/protobuf/generated_message_reflection.h" +#include "google/protobuf/reflection_ops.h" +#include "google/protobuf/wire_format.h" +#include "google/protobuf/generated_message_tctable_impl.h" +// @@protoc_insertion_point(includes) + +// Must be included last. +#include "google/protobuf/port_def.inc" +PROTOBUF_PRAGMA_INIT_SEG +namespace _pb = ::google::protobuf; +namespace _pbi = ::google::protobuf::internal; +namespace _fl = ::google::protobuf::internal::field_layout; +namespace google { +namespace api { +} // namespace api +} // namespace google +static const ::_pb::EnumDescriptor* file_level_enum_descriptors_google_2fapi_2ffield_5fbehavior_2eproto[1]; +static constexpr const ::_pb::ServiceDescriptor** + file_level_service_descriptors_google_2fapi_2ffield_5fbehavior_2eproto = nullptr; +const ::uint32_t TableStruct_google_2fapi_2ffield_5fbehavior_2eproto::offsets[1] = {}; +static constexpr ::_pbi::MigrationSchema* schemas = nullptr; +static constexpr ::_pb::Message* const* file_default_instances = nullptr; +const char descriptor_table_protodef_google_2fapi_2ffield_5fbehavior_2eproto[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) = { + "\n\037google/api/field_behavior.proto\022\ngoogl" + "e.api\032 google/protobuf/descriptor.proto*" + "\266\001\n\rFieldBehavior\022\036\n\032FIELD_BEHAVIOR_UNSP" + "ECIFIED\020\000\022\014\n\010OPTIONAL\020\001\022\014\n\010REQUIRED\020\002\022\017\n" + "\013OUTPUT_ONLY\020\003\022\016\n\nINPUT_ONLY\020\004\022\r\n\tIMMUTA" + "BLE\020\005\022\022\n\016UNORDERED_LIST\020\006\022\025\n\021NON_EMPTY_D" + "EFAULT\020\007\022\016\n\nIDENTIFIER\020\010:U\n\016field_behavi" + "or\022\035.google.protobuf.FieldOptions\030\234\010 \003(\016" + "2\031.google.api.FieldBehaviorB\002\020\000Bp\n\016com.g" + "oogle.apiB\022FieldBehaviorProtoP\001ZAgoogle." + "golang.org/genproto/googleapis/api/annot" + "ations;annotations\242\002\004GAPIb\006proto3" +}; +static const ::_pbi::DescriptorTable* const descriptor_table_google_2fapi_2ffield_5fbehavior_2eproto_deps[1] = + { + &::descriptor_table_google_2fprotobuf_2fdescriptor_2eproto, +}; +static ::absl::once_flag descriptor_table_google_2fapi_2ffield_5fbehavior_2eproto_once; +const ::_pbi::DescriptorTable descriptor_table_google_2fapi_2ffield_5fbehavior_2eproto = { + false, + false, + 473, + descriptor_table_protodef_google_2fapi_2ffield_5fbehavior_2eproto, + "google/api/field_behavior.proto", + &descriptor_table_google_2fapi_2ffield_5fbehavior_2eproto_once, + descriptor_table_google_2fapi_2ffield_5fbehavior_2eproto_deps, + 1, + 0, + schemas, + file_default_instances, + TableStruct_google_2fapi_2ffield_5fbehavior_2eproto::offsets, + nullptr, + file_level_enum_descriptors_google_2fapi_2ffield_5fbehavior_2eproto, + file_level_service_descriptors_google_2fapi_2ffield_5fbehavior_2eproto, +}; + +// This function exists to be marked as weak. +// It can significantly speed up compilation by breaking up LLVM's SCC +// in the .pb.cc translation units. Large translation units see a +// reduction of more than 35% of walltime for optimized builds. Without +// the weak attribute all the messages in the file, including all the +// vtables and everything they use become part of the same SCC through +// a cycle like: +// GetMetadata -> descriptor table -> default instances -> +// vtables -> GetMetadata +// By adding a weak function here we break the connection from the +// individual vtables back into the descriptor table. +PROTOBUF_ATTRIBUTE_WEAK const ::_pbi::DescriptorTable* descriptor_table_google_2fapi_2ffield_5fbehavior_2eproto_getter() { + return &descriptor_table_google_2fapi_2ffield_5fbehavior_2eproto; +} +// Force running AddDescriptors() at dynamic initialization time. +PROTOBUF_ATTRIBUTE_INIT_PRIORITY2 +static ::_pbi::AddDescriptorsRunner dynamic_init_dummy_google_2fapi_2ffield_5fbehavior_2eproto(&descriptor_table_google_2fapi_2ffield_5fbehavior_2eproto); +namespace google { +namespace api { +const ::google::protobuf::EnumDescriptor* FieldBehavior_descriptor() { + ::google::protobuf::internal::AssignDescriptors(&descriptor_table_google_2fapi_2ffield_5fbehavior_2eproto); + return file_level_enum_descriptors_google_2fapi_2ffield_5fbehavior_2eproto[0]; +} +PROTOBUF_CONSTINIT const uint32_t FieldBehavior_internal_data_[] = { + 589824u, 0u, }; +bool FieldBehavior_IsValid(int value) { + return 0 <= value && value <= 8; +} +PROTOBUF_ATTRIBUTE_INIT_PRIORITY2 ::google::protobuf::internal::ExtensionIdentifier< ::google::protobuf::FieldOptions, + ::google::protobuf::internal::RepeatedEnumTypeTraits< ::google::api::FieldBehavior, ::google::api::FieldBehavior_IsValid>, 14, false> + field_behavior(kFieldBehaviorFieldNumber, static_cast< ::google::api::FieldBehavior >(0), nullptr); +// @@protoc_insertion_point(namespace_scope) +} // namespace api +} // namespace google +namespace google { +namespace protobuf { +} // namespace protobuf +} // namespace google +// @@protoc_insertion_point(global_scope) +#include "google/protobuf/port_undef.inc" diff --git a/Firestore/Protos/cpp/google/api/field_behavior.pb.h b/Firestore/Protos/cpp/google/api/field_behavior.pb.h new file mode 100644 index 00000000000..e04739e7ce7 --- /dev/null +++ b/Firestore/Protos/cpp/google/api/field_behavior.pb.h @@ -0,0 +1,168 @@ +/* + * Copyright 2025 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. + */ + +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: google/api/field_behavior.proto +// Protobuf C++ Version: 4.25.1 + +#ifndef GOOGLE_PROTOBUF_INCLUDED_google_2fapi_2ffield_5fbehavior_2eproto_2epb_2eh +#define GOOGLE_PROTOBUF_INCLUDED_google_2fapi_2ffield_5fbehavior_2eproto_2epb_2eh + +#include +#include +#include +#include + +#include "google/protobuf/port_def.inc" +#if PROTOBUF_VERSION < 4025000 +#error "This file was generated by a newer version of protoc which is" +#error "incompatible with your Protocol Buffer headers. Please update" +#error "your headers." +#endif // PROTOBUF_VERSION + +#if 4025001 < PROTOBUF_MIN_PROTOC_VERSION +#error "This file was generated by an older version of protoc which is" +#error "incompatible with your Protocol Buffer headers. Please" +#error "regenerate this file with a newer version of protoc." +#endif // PROTOBUF_MIN_PROTOC_VERSION +#include "google/protobuf/port_undef.inc" +#include "google/protobuf/io/coded_stream.h" +#include "google/protobuf/arena.h" +#include "google/protobuf/arenastring.h" +#include "google/protobuf/generated_message_tctable_decl.h" +#include "google/protobuf/generated_message_util.h" +#include "google/protobuf/metadata_lite.h" +#include "google/protobuf/generated_message_reflection.h" +#include "google/protobuf/repeated_field.h" // IWYU pragma: export +#include "google/protobuf/extension_set.h" // IWYU pragma: export +#include "google/protobuf/generated_enum_reflection.h" +#include "google/protobuf/descriptor.pb.h" +// @@protoc_insertion_point(includes) + +// Must be included last. +#include "google/protobuf/port_def.inc" + +#define PROTOBUF_INTERNAL_EXPORT_google_2fapi_2ffield_5fbehavior_2eproto + +namespace google { +namespace protobuf { +namespace internal { +class AnyMetadata; +} // namespace internal +} // namespace protobuf +} // namespace google + +// Internal implementation detail -- do not use these members. +struct TableStruct_google_2fapi_2ffield_5fbehavior_2eproto { + static const ::uint32_t offsets[]; +}; +extern const ::google::protobuf::internal::DescriptorTable + descriptor_table_google_2fapi_2ffield_5fbehavior_2eproto; +namespace google { +namespace protobuf { +} // namespace protobuf +} // namespace google + +namespace google { +namespace api { +enum FieldBehavior : int { + FIELD_BEHAVIOR_UNSPECIFIED = 0, + OPTIONAL = 1, + REQUIRED = 2, + OUTPUT_ONLY = 3, + INPUT_ONLY = 4, + IMMUTABLE = 5, + UNORDERED_LIST = 6, + NON_EMPTY_DEFAULT = 7, + IDENTIFIER = 8, + FieldBehavior_INT_MIN_SENTINEL_DO_NOT_USE_ = + std::numeric_limits<::int32_t>::min(), + FieldBehavior_INT_MAX_SENTINEL_DO_NOT_USE_ = + std::numeric_limits<::int32_t>::max(), +}; + +bool FieldBehavior_IsValid(int value); +extern const uint32_t FieldBehavior_internal_data_[]; +constexpr FieldBehavior FieldBehavior_MIN = static_cast(0); +constexpr FieldBehavior FieldBehavior_MAX = static_cast(8); +constexpr int FieldBehavior_ARRAYSIZE = 8 + 1; +const ::google::protobuf::EnumDescriptor* +FieldBehavior_descriptor(); +template +const std::string& FieldBehavior_Name(T value) { + static_assert(std::is_same::value || + std::is_integral::value, + "Incorrect type passed to FieldBehavior_Name()."); + return FieldBehavior_Name(static_cast(value)); +} +template <> +inline const std::string& FieldBehavior_Name(FieldBehavior value) { + return ::google::protobuf::internal::NameOfDenseEnum( + static_cast(value)); +} +inline bool FieldBehavior_Parse(absl::string_view name, FieldBehavior* value) { + return ::google::protobuf::internal::ParseNamedEnum( + FieldBehavior_descriptor(), name, value); +} + +// =================================================================== + + + +// =================================================================== + + + +static const int kFieldBehaviorFieldNumber = 1052; +extern ::google::protobuf::internal::ExtensionIdentifier< ::google::protobuf::FieldOptions, + ::google::protobuf::internal::RepeatedEnumTypeTraits< ::google::api::FieldBehavior, ::google::api::FieldBehavior_IsValid>, 14, false > + field_behavior; + +// =================================================================== + + +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wstrict-aliasing" +#endif // __GNUC__ +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif // __GNUC__ + +// @@protoc_insertion_point(namespace_scope) +} // namespace api +} // namespace google + + +namespace google { +namespace protobuf { + +template <> +struct is_proto_enum<::google::api::FieldBehavior> : std::true_type {}; +template <> +inline const EnumDescriptor* GetEnumDescriptor<::google::api::FieldBehavior>() { + return ::google::api::FieldBehavior_descriptor(); +} + +} // namespace protobuf +} // namespace google + +// @@protoc_insertion_point(global_scope) + +#include "google/protobuf/port_undef.inc" + +#endif // GOOGLE_PROTOBUF_INCLUDED_google_2fapi_2ffield_5fbehavior_2eproto_2epb_2eh diff --git a/Firestore/Protos/cpp/google/api/http.pb.cc b/Firestore/Protos/cpp/google/api/http.pb.cc index 3964f8fc33e..c6a9fa49c1b 100644 --- a/Firestore/Protos/cpp/google/api/http.pb.cc +++ b/Firestore/Protos/cpp/google/api/http.pb.cc @@ -1,5 +1,5 @@ /* - * Copyright 2024 Google LLC + * Copyright 2025 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/Firestore/Protos/cpp/google/api/http.pb.h b/Firestore/Protos/cpp/google/api/http.pb.h index 54c6bad8167..bc1f7426a3c 100644 --- a/Firestore/Protos/cpp/google/api/http.pb.h +++ b/Firestore/Protos/cpp/google/api/http.pb.h @@ -1,5 +1,5 @@ /* - * Copyright 2024 Google LLC + * Copyright 2025 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/Firestore/Protos/cpp/google/api/resource.pb.cc b/Firestore/Protos/cpp/google/api/resource.pb.cc index fd34f4f0934..2ea1c7562ff 100644 --- a/Firestore/Protos/cpp/google/api/resource.pb.cc +++ b/Firestore/Protos/cpp/google/api/resource.pb.cc @@ -1,5 +1,5 @@ /* - * Copyright 2024 Google LLC + * Copyright 2025 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/Firestore/Protos/cpp/google/api/resource.pb.h b/Firestore/Protos/cpp/google/api/resource.pb.h index 458c078fb57..de855a0a335 100644 --- a/Firestore/Protos/cpp/google/api/resource.pb.h +++ b/Firestore/Protos/cpp/google/api/resource.pb.h @@ -1,5 +1,5 @@ /* - * Copyright 2024 Google LLC + * Copyright 2025 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/Firestore/Protos/cpp/google/firestore/admin/index.pb.cc b/Firestore/Protos/cpp/google/firestore/admin/index.pb.cc index 9e7a2a53d6a..d0ee81c51aa 100644 --- a/Firestore/Protos/cpp/google/firestore/admin/index.pb.cc +++ b/Firestore/Protos/cpp/google/firestore/admin/index.pb.cc @@ -1,5 +1,5 @@ /* - * Copyright 2024 Google LLC + * Copyright 2025 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/Firestore/Protos/cpp/google/firestore/admin/index.pb.h b/Firestore/Protos/cpp/google/firestore/admin/index.pb.h index 6095d8eba33..474abbd3b56 100644 --- a/Firestore/Protos/cpp/google/firestore/admin/index.pb.h +++ b/Firestore/Protos/cpp/google/firestore/admin/index.pb.h @@ -1,5 +1,5 @@ /* - * Copyright 2024 Google LLC + * Copyright 2025 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/Firestore/Protos/cpp/google/firestore/v1/aggregation_result.pb.cc b/Firestore/Protos/cpp/google/firestore/v1/aggregation_result.pb.cc index 2b6366af7fa..1302ce50dff 100644 --- a/Firestore/Protos/cpp/google/firestore/v1/aggregation_result.pb.cc +++ b/Firestore/Protos/cpp/google/firestore/v1/aggregation_result.pb.cc @@ -1,5 +1,5 @@ /* - * Copyright 2024 Google LLC + * Copyright 2025 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/Firestore/Protos/cpp/google/firestore/v1/aggregation_result.pb.h b/Firestore/Protos/cpp/google/firestore/v1/aggregation_result.pb.h index 26750c24e40..604f7d4d266 100644 --- a/Firestore/Protos/cpp/google/firestore/v1/aggregation_result.pb.h +++ b/Firestore/Protos/cpp/google/firestore/v1/aggregation_result.pb.h @@ -1,5 +1,5 @@ /* - * Copyright 2024 Google LLC + * Copyright 2025 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/Firestore/Protos/cpp/google/firestore/v1/bloom_filter.pb.cc b/Firestore/Protos/cpp/google/firestore/v1/bloom_filter.pb.cc index f3ad4ff4ae2..850d8b10da2 100644 --- a/Firestore/Protos/cpp/google/firestore/v1/bloom_filter.pb.cc +++ b/Firestore/Protos/cpp/google/firestore/v1/bloom_filter.pb.cc @@ -1,5 +1,5 @@ /* - * Copyright 2024 Google LLC + * Copyright 2025 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/Firestore/Protos/cpp/google/firestore/v1/bloom_filter.pb.h b/Firestore/Protos/cpp/google/firestore/v1/bloom_filter.pb.h index e4e2fa8331b..69d2b086157 100644 --- a/Firestore/Protos/cpp/google/firestore/v1/bloom_filter.pb.h +++ b/Firestore/Protos/cpp/google/firestore/v1/bloom_filter.pb.h @@ -1,5 +1,5 @@ /* - * Copyright 2024 Google LLC + * Copyright 2025 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/Firestore/Protos/cpp/google/firestore/v1/common.pb.cc b/Firestore/Protos/cpp/google/firestore/v1/common.pb.cc index f3113c8ed9c..c92596182be 100644 --- a/Firestore/Protos/cpp/google/firestore/v1/common.pb.cc +++ b/Firestore/Protos/cpp/google/firestore/v1/common.pb.cc @@ -1,5 +1,5 @@ /* - * Copyright 2024 Google LLC + * Copyright 2025 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/Firestore/Protos/cpp/google/firestore/v1/common.pb.h b/Firestore/Protos/cpp/google/firestore/v1/common.pb.h index 814ed5c9723..45e09440cc3 100644 --- a/Firestore/Protos/cpp/google/firestore/v1/common.pb.h +++ b/Firestore/Protos/cpp/google/firestore/v1/common.pb.h @@ -1,5 +1,5 @@ /* - * Copyright 2024 Google LLC + * Copyright 2025 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/Firestore/Protos/cpp/google/firestore/v1/document.pb.cc b/Firestore/Protos/cpp/google/firestore/v1/document.pb.cc index 3167a814ee4..8f299b1a166 100644 --- a/Firestore/Protos/cpp/google/firestore/v1/document.pb.cc +++ b/Firestore/Protos/cpp/google/firestore/v1/document.pb.cc @@ -1,5 +1,5 @@ /* - * Copyright 2024 Google LLC + * Copyright 2025 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -59,6 +59,41 @@ struct ArrayValueDefaultTypeInternal { PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 ArrayValueDefaultTypeInternal _ArrayValue_default_instance_; +inline constexpr Function::Impl_::Impl_( + ::_pbi::ConstantInitialized) noexcept + : args_{}, + options_{}, + name_( + &::google::protobuf::internal::fixed_address_empty_string, + ::_pbi::ConstantInitialized()), + _cached_size_{0} {} + +template +PROTOBUF_CONSTEXPR Function::Function(::_pbi::ConstantInitialized) + : _impl_(::_pbi::ConstantInitialized()) {} +struct FunctionDefaultTypeInternal { + PROTOBUF_CONSTEXPR FunctionDefaultTypeInternal() : _instance(::_pbi::ConstantInitialized{}) {} + ~FunctionDefaultTypeInternal() {} + union { + Function _instance; + }; +}; + +PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT + PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 FunctionDefaultTypeInternal _Function_default_instance_; + template +PROTOBUF_CONSTEXPR Function_OptionsEntry_DoNotUse::Function_OptionsEntry_DoNotUse(::_pbi::ConstantInitialized) {} +struct Function_OptionsEntry_DoNotUseDefaultTypeInternal { + PROTOBUF_CONSTEXPR Function_OptionsEntry_DoNotUseDefaultTypeInternal() : _instance(::_pbi::ConstantInitialized{}) {} + ~Function_OptionsEntry_DoNotUseDefaultTypeInternal() {} + union { + Function_OptionsEntry_DoNotUse _instance; + }; +}; + +PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT + PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 Function_OptionsEntry_DoNotUseDefaultTypeInternal _Function_OptionsEntry_DoNotUse_default_instance_; + inline constexpr MapValue::Impl_::Impl_( ::_pbi::ConstantInitialized) noexcept : fields_{}, @@ -90,6 +125,60 @@ struct MapValue_FieldsEntry_DoNotUseDefaultTypeInternal { PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 MapValue_FieldsEntry_DoNotUseDefaultTypeInternal _MapValue_FieldsEntry_DoNotUse_default_instance_; +inline constexpr Pipeline::Impl_::Impl_( + ::_pbi::ConstantInitialized) noexcept + : stages_{}, + _cached_size_{0} {} + +template +PROTOBUF_CONSTEXPR Pipeline::Pipeline(::_pbi::ConstantInitialized) + : _impl_(::_pbi::ConstantInitialized()) {} +struct PipelineDefaultTypeInternal { + PROTOBUF_CONSTEXPR PipelineDefaultTypeInternal() : _instance(::_pbi::ConstantInitialized{}) {} + ~PipelineDefaultTypeInternal() {} + union { + Pipeline _instance; + }; +}; + +PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT + PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 PipelineDefaultTypeInternal _Pipeline_default_instance_; + +inline constexpr Pipeline_Stage::Impl_::Impl_( + ::_pbi::ConstantInitialized) noexcept + : args_{}, + options_{}, + name_( + &::google::protobuf::internal::fixed_address_empty_string, + ::_pbi::ConstantInitialized()), + _cached_size_{0} {} + +template +PROTOBUF_CONSTEXPR Pipeline_Stage::Pipeline_Stage(::_pbi::ConstantInitialized) + : _impl_(::_pbi::ConstantInitialized()) {} +struct Pipeline_StageDefaultTypeInternal { + PROTOBUF_CONSTEXPR Pipeline_StageDefaultTypeInternal() : _instance(::_pbi::ConstantInitialized{}) {} + ~Pipeline_StageDefaultTypeInternal() {} + union { + Pipeline_Stage _instance; + }; +}; + +PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT + PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 Pipeline_StageDefaultTypeInternal _Pipeline_Stage_default_instance_; + template +PROTOBUF_CONSTEXPR Pipeline_Stage_OptionsEntry_DoNotUse::Pipeline_Stage_OptionsEntry_DoNotUse(::_pbi::ConstantInitialized) {} +struct Pipeline_Stage_OptionsEntry_DoNotUseDefaultTypeInternal { + PROTOBUF_CONSTEXPR Pipeline_Stage_OptionsEntry_DoNotUseDefaultTypeInternal() : _instance(::_pbi::ConstantInitialized{}) {} + ~Pipeline_Stage_OptionsEntry_DoNotUseDefaultTypeInternal() {} + union { + Pipeline_Stage_OptionsEntry_DoNotUse _instance; + }; +}; + +PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT + PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 Pipeline_Stage_OptionsEntry_DoNotUseDefaultTypeInternal _Pipeline_Stage_OptionsEntry_DoNotUse_default_instance_; + inline constexpr Value::Impl_::Impl_( ::_pbi::ConstantInitialized) noexcept : value_type_{}, @@ -148,7 +237,7 @@ PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT } // namespace v1 } // namespace firestore } // namespace google -static ::_pb::Metadata file_level_metadata_google_2ffirestore_2fv1_2fdocument_2eproto[6]; +static ::_pb::Metadata file_level_metadata_google_2ffirestore_2fv1_2fdocument_2eproto[11]; static constexpr const ::_pb::EnumDescriptor** file_level_enum_descriptors_google_2ffirestore_2fv1_2fdocument_2eproto = nullptr; static constexpr const ::_pb::ServiceDescriptor** @@ -202,6 +291,9 @@ const ::uint32_t TableStruct_google_2ffirestore_2fv1_2fdocument_2eproto::offsets ::_pbi::kInvalidFieldOffsetTag, ::_pbi::kInvalidFieldOffsetTag, ::_pbi::kInvalidFieldOffsetTag, + ::_pbi::kInvalidFieldOffsetTag, + ::_pbi::kInvalidFieldOffsetTag, + ::_pbi::kInvalidFieldOffsetTag, PROTOBUF_FIELD_OFFSET(::google::firestore::v1::Value, _impl_.value_type_), ~0u, // no _has_bits_ PROTOBUF_FIELD_OFFSET(::google::firestore::v1::ArrayValue, _internal_metadata_), @@ -233,6 +325,61 @@ const ::uint32_t TableStruct_google_2ffirestore_2fv1_2fdocument_2eproto::offsets ~0u, // no _split_ ~0u, // no sizeof(Split) PROTOBUF_FIELD_OFFSET(::google::firestore::v1::MapValue, _impl_.fields_), + PROTOBUF_FIELD_OFFSET(::google::firestore::v1::Function_OptionsEntry_DoNotUse, _has_bits_), + PROTOBUF_FIELD_OFFSET(::google::firestore::v1::Function_OptionsEntry_DoNotUse, _internal_metadata_), + ~0u, // no _extensions_ + ~0u, // no _oneof_case_ + ~0u, // no _weak_field_map_ + ~0u, // no _inlined_string_donated_ + ~0u, // no _split_ + ~0u, // no sizeof(Split) + PROTOBUF_FIELD_OFFSET(::google::firestore::v1::Function_OptionsEntry_DoNotUse, key_), + PROTOBUF_FIELD_OFFSET(::google::firestore::v1::Function_OptionsEntry_DoNotUse, value_), + 0, + 1, + ~0u, // no _has_bits_ + PROTOBUF_FIELD_OFFSET(::google::firestore::v1::Function, _internal_metadata_), + ~0u, // no _extensions_ + ~0u, // no _oneof_case_ + ~0u, // no _weak_field_map_ + ~0u, // no _inlined_string_donated_ + ~0u, // no _split_ + ~0u, // no sizeof(Split) + PROTOBUF_FIELD_OFFSET(::google::firestore::v1::Function, _impl_.name_), + PROTOBUF_FIELD_OFFSET(::google::firestore::v1::Function, _impl_.args_), + PROTOBUF_FIELD_OFFSET(::google::firestore::v1::Function, _impl_.options_), + PROTOBUF_FIELD_OFFSET(::google::firestore::v1::Pipeline_Stage_OptionsEntry_DoNotUse, _has_bits_), + PROTOBUF_FIELD_OFFSET(::google::firestore::v1::Pipeline_Stage_OptionsEntry_DoNotUse, _internal_metadata_), + ~0u, // no _extensions_ + ~0u, // no _oneof_case_ + ~0u, // no _weak_field_map_ + ~0u, // no _inlined_string_donated_ + ~0u, // no _split_ + ~0u, // no sizeof(Split) + PROTOBUF_FIELD_OFFSET(::google::firestore::v1::Pipeline_Stage_OptionsEntry_DoNotUse, key_), + PROTOBUF_FIELD_OFFSET(::google::firestore::v1::Pipeline_Stage_OptionsEntry_DoNotUse, value_), + 0, + 1, + ~0u, // no _has_bits_ + PROTOBUF_FIELD_OFFSET(::google::firestore::v1::Pipeline_Stage, _internal_metadata_), + ~0u, // no _extensions_ + ~0u, // no _oneof_case_ + ~0u, // no _weak_field_map_ + ~0u, // no _inlined_string_donated_ + ~0u, // no _split_ + ~0u, // no sizeof(Split) + PROTOBUF_FIELD_OFFSET(::google::firestore::v1::Pipeline_Stage, _impl_.name_), + PROTOBUF_FIELD_OFFSET(::google::firestore::v1::Pipeline_Stage, _impl_.args_), + PROTOBUF_FIELD_OFFSET(::google::firestore::v1::Pipeline_Stage, _impl_.options_), + ~0u, // no _has_bits_ + PROTOBUF_FIELD_OFFSET(::google::firestore::v1::Pipeline, _internal_metadata_), + ~0u, // no _extensions_ + ~0u, // no _oneof_case_ + ~0u, // no _weak_field_map_ + ~0u, // no _inlined_string_donated_ + ~0u, // no _split_ + ~0u, // no sizeof(Split) + PROTOBUF_FIELD_OFFSET(::google::firestore::v1::Pipeline, _impl_.stages_), }; static const ::_pbi::MigrationSchema @@ -240,9 +387,14 @@ static const ::_pbi::MigrationSchema {0, 10, -1, sizeof(::google::firestore::v1::Document_FieldsEntry_DoNotUse)}, {12, 24, -1, sizeof(::google::firestore::v1::Document)}, {28, -1, -1, sizeof(::google::firestore::v1::Value)}, - {48, -1, -1, sizeof(::google::firestore::v1::ArrayValue)}, - {57, 67, -1, sizeof(::google::firestore::v1::MapValue_FieldsEntry_DoNotUse)}, - {69, -1, -1, sizeof(::google::firestore::v1::MapValue)}, + {51, -1, -1, sizeof(::google::firestore::v1::ArrayValue)}, + {60, 70, -1, sizeof(::google::firestore::v1::MapValue_FieldsEntry_DoNotUse)}, + {72, -1, -1, sizeof(::google::firestore::v1::MapValue)}, + {81, 91, -1, sizeof(::google::firestore::v1::Function_OptionsEntry_DoNotUse)}, + {93, -1, -1, sizeof(::google::firestore::v1::Function)}, + {104, 114, -1, sizeof(::google::firestore::v1::Pipeline_Stage_OptionsEntry_DoNotUse)}, + {116, -1, -1, sizeof(::google::firestore::v1::Pipeline_Stage)}, + {127, -1, -1, sizeof(::google::firestore::v1::Pipeline)}, }; static const ::_pb::Message* const file_default_instances[] = { @@ -252,42 +404,66 @@ static const ::_pb::Message* const file_default_instances[] = { &::google::firestore::v1::_ArrayValue_default_instance_._instance, &::google::firestore::v1::_MapValue_FieldsEntry_DoNotUse_default_instance_._instance, &::google::firestore::v1::_MapValue_default_instance_._instance, + &::google::firestore::v1::_Function_OptionsEntry_DoNotUse_default_instance_._instance, + &::google::firestore::v1::_Function_default_instance_._instance, + &::google::firestore::v1::_Pipeline_Stage_OptionsEntry_DoNotUse_default_instance_._instance, + &::google::firestore::v1::_Pipeline_Stage_default_instance_._instance, + &::google::firestore::v1::_Pipeline_default_instance_._instance, }; const char descriptor_table_protodef_google_2ffirestore_2fv1_2fdocument_2eproto[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) = { "\n\"google/firestore/v1/document.proto\022\023go" - "ogle.firestore.v1\032\034google/protobuf/struc" - "t.proto\032\037google/protobuf/timestamp.proto" - "\032\030google/type/latlng.proto\"\200\002\n\010Document\022" - "\014\n\004name\030\001 \001(\t\0229\n\006fields\030\002 \003(\0132).google.f" - "irestore.v1.Document.FieldsEntry\022/\n\013crea" - "te_time\030\003 \001(\0132\032.google.protobuf.Timestam" - "p\022/\n\013update_time\030\004 \001(\0132\032.google.protobuf" - ".Timestamp\032I\n\013FieldsEntry\022\013\n\003key\030\001 \001(\t\022)" - "\n\005value\030\002 \001(\0132\032.google.firestore.v1.Valu" - "e:\0028\001\"\256\003\n\005Value\0220\n\nnull_value\030\013 \001(\0162\032.go" - "ogle.protobuf.NullValueH\000\022\027\n\rboolean_val" - "ue\030\001 \001(\010H\000\022\027\n\rinteger_value\030\002 \001(\003H\000\022\026\n\014d" - "ouble_value\030\003 \001(\001H\000\0225\n\017timestamp_value\030\n" - " \001(\0132\032.google.protobuf.TimestampH\000\022\026\n\014st" - "ring_value\030\021 \001(\tH\000\022\025\n\013bytes_value\030\022 \001(\014H" - "\000\022\031\n\017reference_value\030\005 \001(\tH\000\022.\n\017geo_poin" - "t_value\030\010 \001(\0132\023.google.type.LatLngH\000\0226\n\013" - "array_value\030\t \001(\0132\037.google.firestore.v1." - "ArrayValueH\000\0222\n\tmap_value\030\006 \001(\0132\035.google" - ".firestore.v1.MapValueH\000B\014\n\nvalue_type\"8" - "\n\nArrayValue\022*\n\006values\030\001 \003(\0132\032.google.fi" - "restore.v1.Value\"\220\001\n\010MapValue\0229\n\006fields\030" - "\001 \003(\0132).google.firestore.v1.MapValue.Fie" - "ldsEntry\032I\n\013FieldsEntry\022\013\n\003key\030\001 \001(\t\022)\n\005" - "value\030\002 \001(\0132\032.google.firestore.v1.Value:" - "\0028\001B\261\001\n\027com.google.firestore.v1B\rDocumen" - "tProtoP\001Z_impl_.value_type_.map_value_; } +const ::google::firestore::v1::Function& Value::_Internal::function_value(const Value* msg) { + return *msg->_impl_.value_type_.function_value_; +} +const ::google::firestore::v1::Pipeline& Value::_Internal::pipeline_value(const Value* msg) { + return *msg->_impl_.value_type_.pipeline_value_; +} void Value::set_allocated_timestamp_value(::google::protobuf::Timestamp* timestamp_value) { ::google::protobuf::Arena* message_arena = GetArena(); clear_value_type(); @@ -790,6 +974,32 @@ void Value::set_allocated_map_value(::google::firestore::v1::MapValue* map_value } // @@protoc_insertion_point(field_set_allocated:google.firestore.v1.Value.map_value) } +void Value::set_allocated_function_value(::google::firestore::v1::Function* function_value) { + ::google::protobuf::Arena* message_arena = GetArena(); + clear_value_type(); + if (function_value) { + ::google::protobuf::Arena* submessage_arena = function_value->GetArena(); + if (message_arena != submessage_arena) { + function_value = ::google::protobuf::internal::GetOwnedMessage(message_arena, function_value, submessage_arena); + } + set_has_function_value(); + _impl_.value_type_.function_value_ = function_value; + } + // @@protoc_insertion_point(field_set_allocated:google.firestore.v1.Value.function_value) +} +void Value::set_allocated_pipeline_value(::google::firestore::v1::Pipeline* pipeline_value) { + ::google::protobuf::Arena* message_arena = GetArena(); + clear_value_type(); + if (pipeline_value) { + ::google::protobuf::Arena* submessage_arena = pipeline_value->GetArena(); + if (message_arena != submessage_arena) { + pipeline_value = ::google::protobuf::internal::GetOwnedMessage(message_arena, pipeline_value, submessage_arena); + } + set_has_pipeline_value(); + _impl_.value_type_.pipeline_value_ = pipeline_value; + } + // @@protoc_insertion_point(field_set_allocated:google.firestore.v1.Value.pipeline_value) +} Value::Value(::google::protobuf::Arena* arena) : ::google::protobuf::Message(arena) { SharedCtor(arena); @@ -847,6 +1057,15 @@ Value::Value( case kMapValue: _impl_.value_type_.map_value_ = CreateMaybeMessage<::google::firestore::v1::MapValue>(arena, *from._impl_.value_type_.map_value_); break; + case kFieldReferenceValue: + new (&_impl_.value_type_.field_reference_value_) decltype(_impl_.value_type_.field_reference_value_){arena, from._impl_.value_type_.field_reference_value_}; + break; + case kFunctionValue: + _impl_.value_type_.function_value_ = CreateMaybeMessage<::google::firestore::v1::Function>(arena, *from._impl_.value_type_.function_value_); + break; + case kPipelineValue: + _impl_.value_type_.pipeline_value_ = CreateMaybeMessage<::google::firestore::v1::Pipeline>(arena, *from._impl_.value_type_.pipeline_value_); + break; } // @@protoc_insertion_point(copy_constructor:google.firestore.v1.Value) @@ -930,6 +1149,22 @@ void Value::clear_value_type() { } break; } + case kFieldReferenceValue: { + _impl_.value_type_.field_reference_value_.Destroy(); + break; + } + case kFunctionValue: { + if (GetArena() == nullptr) { + delete _impl_.value_type_.function_value_; + } + break; + } + case kPipelineValue: { + if (GetArena() == nullptr) { + delete _impl_.value_type_.pipeline_value_; + } + break; + } case VALUE_TYPE_NOT_SET: { break; } @@ -957,16 +1192,16 @@ const char* Value::_InternalParse( PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 -const ::_pbi::TcParseTable<0, 11, 4, 69, 2> Value::_table_ = { +const ::_pbi::TcParseTable<0, 14, 6, 90, 2> Value::_table_ = { { 0, // no _has_bits_ 0, // no _extensions_ - 18, 0, // max_field_number, fast_idx_mask + 21, 0, // max_field_number, fast_idx_mask offsetof(decltype(_table_), field_lookup_table), - 4294768712, // skipmap + 4292933704, // skipmap offsetof(decltype(_table_), field_entries), - 11, // num_field_entries - 4, // num_aux_entries + 14, // num_field_entries + 6, // num_aux_entries offsetof(decltype(_table_), aux_entries), &_Value_default_instance_._instance, ::_pbi::TcParser::GenericFallback, // fallback @@ -1008,16 +1243,28 @@ const ::_pbi::TcParseTable<0, 11, 4, 69, 2> Value::_table_ = { // bytes bytes_value = 18; {PROTOBUF_FIELD_OFFSET(Value, _impl_.value_type_.bytes_value_), _Internal::kOneofCaseOffset + 0, 0, (0 | ::_fl::kFcOneof | ::_fl::kBytes | ::_fl::kRepAString)}, + // string field_reference_value = 19; + {PROTOBUF_FIELD_OFFSET(Value, _impl_.value_type_.field_reference_value_), _Internal::kOneofCaseOffset + 0, 0, + (0 | ::_fl::kFcOneof | ::_fl::kUtf8String | ::_fl::kRepAString)}, + // .google.firestore.v1.Function function_value = 20; + {PROTOBUF_FIELD_OFFSET(Value, _impl_.value_type_.function_value_), _Internal::kOneofCaseOffset + 0, 4, + (0 | ::_fl::kFcOneof | ::_fl::kMessage | ::_fl::kTvTable)}, + // .google.firestore.v1.Pipeline pipeline_value = 21; + {PROTOBUF_FIELD_OFFSET(Value, _impl_.value_type_.pipeline_value_), _Internal::kOneofCaseOffset + 0, 5, + (0 | ::_fl::kFcOneof | ::_fl::kMessage | ::_fl::kTvTable)}, }}, {{ {::_pbi::TcParser::GetTable<::google::firestore::v1::MapValue>()}, {::_pbi::TcParser::GetTable<::google::type::LatLng>()}, {::_pbi::TcParser::GetTable<::google::firestore::v1::ArrayValue>()}, {::_pbi::TcParser::GetTable<::google::protobuf::Timestamp>()}, + {::_pbi::TcParser::GetTable<::google::firestore::v1::Function>()}, + {::_pbi::TcParser::GetTable<::google::firestore::v1::Pipeline>()}, }}, {{ - "\31\0\0\0\17\0\0\0\0\0\14\0\0\0\0\0" + "\31\0\0\0\17\0\0\0\0\0\14\0\25\0\0\0" "google.firestore.v1.Value" "reference_value" "string_value" + "field_reference_value" }}, }; @@ -1096,6 +1343,25 @@ ::uint8_t* Value::_InternalSerialize( target = stream->WriteBytesMaybeAliased(18, _s, target); break; } + case kFieldReferenceValue: { + const std::string& _s = this->_internal_field_reference_value(); + ::google::protobuf::internal::WireFormatLite::VerifyUtf8String( + _s.data(), static_cast(_s.length()), ::google::protobuf::internal::WireFormatLite::SERIALIZE, "google.firestore.v1.Value.field_reference_value"); + target = stream->WriteStringMaybeAliased(19, _s, target); + break; + } + case kFunctionValue: { + target = ::google::protobuf::internal::WireFormatLite::InternalWriteMessage( + 20, _Internal::function_value(this), + _Internal::function_value(this).GetCachedSize(), target, stream); + break; + } + case kPipelineValue: { + target = ::google::protobuf::internal::WireFormatLite::InternalWriteMessage( + 21, _Internal::pipeline_value(this), + _Internal::pipeline_value(this).GetCachedSize(), target, stream); + break; + } default: break; } @@ -1181,6 +1447,24 @@ ::size_t Value::ByteSizeLong() const { 1 + ::google::protobuf::internal::WireFormatLite::MessageSize(*_impl_.value_type_.map_value_); break; } + // string field_reference_value = 19; + case kFieldReferenceValue: { + total_size += 2 + ::google::protobuf::internal::WireFormatLite::StringSize( + this->_internal_field_reference_value()); + break; + } + // .google.firestore.v1.Function function_value = 20; + case kFunctionValue: { + total_size += + 2 + ::google::protobuf::internal::WireFormatLite::MessageSize(*_impl_.value_type_.function_value_); + break; + } + // .google.firestore.v1.Pipeline pipeline_value = 21; + case kPipelineValue: { + total_size += + 2 + ::google::protobuf::internal::WireFormatLite::MessageSize(*_impl_.value_type_.pipeline_value_); + break; + } case VALUE_TYPE_NOT_SET: { break; } @@ -1253,6 +1537,20 @@ void Value::MergeImpl(::google::protobuf::Message& to_msg, const ::google::proto from._internal_map_value()); break; } + case kFieldReferenceValue: { + _this->_internal_set_field_reference_value(from._internal_field_reference_value()); + break; + } + case kFunctionValue: { + _this->_internal_mutable_function_value()->::google::firestore::v1::Function::MergeFrom( + from._internal_function_value()); + break; + } + case kPipelineValue: { + _this->_internal_mutable_pipeline_value()->::google::firestore::v1::Pipeline::MergeFrom( + from._internal_pipeline_value()); + break; + } case VALUE_TYPE_NOT_SET: { break; } @@ -1686,6 +1984,737 @@ ::google::protobuf::Metadata MapValue::GetMetadata() const { &descriptor_table_google_2ffirestore_2fv1_2fdocument_2eproto_getter, &descriptor_table_google_2ffirestore_2fv1_2fdocument_2eproto_once, file_level_metadata_google_2ffirestore_2fv1_2fdocument_2eproto[5]); } +// =================================================================== + +Function_OptionsEntry_DoNotUse::Function_OptionsEntry_DoNotUse() {} +Function_OptionsEntry_DoNotUse::Function_OptionsEntry_DoNotUse(::google::protobuf::Arena* arena) + : SuperType(arena) {} +::google::protobuf::Metadata Function_OptionsEntry_DoNotUse::GetMetadata() const { + return ::_pbi::AssignDescriptors( + &descriptor_table_google_2ffirestore_2fv1_2fdocument_2eproto_getter, &descriptor_table_google_2ffirestore_2fv1_2fdocument_2eproto_once, + file_level_metadata_google_2ffirestore_2fv1_2fdocument_2eproto[6]); +} +// =================================================================== + +class Function::_Internal { + public: +}; + +Function::Function(::google::protobuf::Arena* arena) + : ::google::protobuf::Message(arena) { + SharedCtor(arena); + // @@protoc_insertion_point(arena_constructor:google.firestore.v1.Function) +} +inline PROTOBUF_NDEBUG_INLINE Function::Impl_::Impl_( + ::google::protobuf::internal::InternalVisibility visibility, ::google::protobuf::Arena* arena, + const Impl_& from) + : args_{visibility, arena, from.args_}, + options_{visibility, arena, from.options_}, + name_(arena, from.name_), + _cached_size_{0} {} + +Function::Function( + ::google::protobuf::Arena* arena, + const Function& from) + : ::google::protobuf::Message(arena) { + Function* const _this = this; + (void)_this; + _internal_metadata_.MergeFrom<::google::protobuf::UnknownFieldSet>( + from._internal_metadata_); + new (&_impl_) Impl_(internal_visibility(), arena, from._impl_); + + // @@protoc_insertion_point(copy_constructor:google.firestore.v1.Function) +} +inline PROTOBUF_NDEBUG_INLINE Function::Impl_::Impl_( + ::google::protobuf::internal::InternalVisibility visibility, + ::google::protobuf::Arena* arena) + : args_{visibility, arena}, + options_{visibility, arena}, + name_(arena), + _cached_size_{0} {} + +inline void Function::SharedCtor(::_pb::Arena* arena) { + new (&_impl_) Impl_(internal_visibility(), arena); +} +Function::~Function() { + // @@protoc_insertion_point(destructor:google.firestore.v1.Function) + _internal_metadata_.Delete<::google::protobuf::UnknownFieldSet>(); + SharedDtor(); +} +inline void Function::SharedDtor() { + ABSL_DCHECK(GetArena() == nullptr); + _impl_.name_.Destroy(); + _impl_.~Impl_(); +} + +PROTOBUF_NOINLINE void Function::Clear() { +// @@protoc_insertion_point(message_clear_start:google.firestore.v1.Function) + PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); + ::uint32_t cached_has_bits = 0; + // Prevent compiler warnings about cached_has_bits being unused + (void) cached_has_bits; + + _impl_.args_.Clear(); + _impl_.options_.Clear(); + _impl_.name_.ClearToEmpty(); + _internal_metadata_.Clear<::google::protobuf::UnknownFieldSet>(); +} + +const char* Function::_InternalParse( + const char* ptr, ::_pbi::ParseContext* ctx) { + ptr = ::_pbi::TcParser::ParseLoop(this, ptr, ctx, &_table_.header); + return ptr; +} + + +PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 +const ::_pbi::TcParseTable<1, 3, 3, 48, 2> Function::_table_ = { + { + 0, // no _has_bits_ + 0, // no _extensions_ + 3, 8, // max_field_number, fast_idx_mask + offsetof(decltype(_table_), field_lookup_table), + 4294967288, // skipmap + offsetof(decltype(_table_), field_entries), + 3, // num_field_entries + 3, // num_aux_entries + offsetof(decltype(_table_), aux_entries), + &_Function_default_instance_._instance, + ::_pbi::TcParser::GenericFallback, // fallback + }, {{ + // repeated .google.firestore.v1.Value args = 2 [(.google.api.field_behavior) = OPTIONAL]; + {::_pbi::TcParser::FastMtR1, + {18, 63, 0, PROTOBUF_FIELD_OFFSET(Function, _impl_.args_)}}, + // string name = 1 [(.google.api.field_behavior) = REQUIRED]; + {::_pbi::TcParser::FastUS1, + {10, 63, 0, PROTOBUF_FIELD_OFFSET(Function, _impl_.name_)}}, + }}, {{ + 65535, 65535 + }}, {{ + // string name = 1 [(.google.api.field_behavior) = REQUIRED]; + {PROTOBUF_FIELD_OFFSET(Function, _impl_.name_), 0, 0, + (0 | ::_fl::kFcSingular | ::_fl::kUtf8String | ::_fl::kRepAString)}, + // repeated .google.firestore.v1.Value args = 2 [(.google.api.field_behavior) = OPTIONAL]; + {PROTOBUF_FIELD_OFFSET(Function, _impl_.args_), 0, 0, + (0 | ::_fl::kFcRepeated | ::_fl::kMessage | ::_fl::kTvTable)}, + // map options = 3 [(.google.api.field_behavior) = OPTIONAL]; + {PROTOBUF_FIELD_OFFSET(Function, _impl_.options_), 0, 1, + (0 | ::_fl::kFcRepeated | ::_fl::kMap)}, + }}, {{ + {::_pbi::TcParser::GetTable<::google::firestore::v1::Value>()}, + {::_pbi::TcParser::GetMapAuxInfo< + decltype(Function()._impl_.options_)>( + 1, 0, 0, 9, + 11)}, + {::_pbi::TcParser::CreateInArenaStorageCb<::google::firestore::v1::Value>}, + }}, {{ + "\34\4\0\7\0\0\0\0" + "google.firestore.v1.Function" + "name" + "options" + }}, +}; + +::uint8_t* Function::_InternalSerialize( + ::uint8_t* target, + ::google::protobuf::io::EpsCopyOutputStream* stream) const { + // @@protoc_insertion_point(serialize_to_array_start:google.firestore.v1.Function) + ::uint32_t cached_has_bits = 0; + (void)cached_has_bits; + + // string name = 1 [(.google.api.field_behavior) = REQUIRED]; + if (!this->_internal_name().empty()) { + const std::string& _s = this->_internal_name(); + ::google::protobuf::internal::WireFormatLite::VerifyUtf8String( + _s.data(), static_cast(_s.length()), ::google::protobuf::internal::WireFormatLite::SERIALIZE, "google.firestore.v1.Function.name"); + target = stream->WriteStringMaybeAliased(1, _s, target); + } + + // repeated .google.firestore.v1.Value args = 2 [(.google.api.field_behavior) = OPTIONAL]; + for (unsigned i = 0, + n = static_cast(this->_internal_args_size()); i < n; i++) { + const auto& repfield = this->_internal_args().Get(i); + target = ::google::protobuf::internal::WireFormatLite:: + InternalWriteMessage(2, repfield, repfield.GetCachedSize(), target, stream); + } + + // map options = 3 [(.google.api.field_behavior) = OPTIONAL]; + if (!_internal_options().empty()) { + using MapType = ::google::protobuf::Map; + using WireHelper = _pbi::MapEntryFuncs; + const auto& field = _internal_options(); + + if (stream->IsSerializationDeterministic() && field.size() > 1) { + for (const auto& entry : ::google::protobuf::internal::MapSorterPtr(field)) { + target = WireHelper::InternalSerialize( + 3, entry.first, entry.second, target, stream); + ::google::protobuf::internal::WireFormatLite::VerifyUtf8String( + entry.first.data(), static_cast(entry.first.length()), + ::google::protobuf::internal::WireFormatLite::SERIALIZE, "google.firestore.v1.Function.options"); + } + } else { + for (const auto& entry : field) { + target = WireHelper::InternalSerialize( + 3, entry.first, entry.second, target, stream); + ::google::protobuf::internal::WireFormatLite::VerifyUtf8String( + entry.first.data(), static_cast(entry.first.length()), + ::google::protobuf::internal::WireFormatLite::SERIALIZE, "google.firestore.v1.Function.options"); + } + } + } + + if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) { + target = + ::_pbi::WireFormat::InternalSerializeUnknownFieldsToArray( + _internal_metadata_.unknown_fields<::google::protobuf::UnknownFieldSet>(::google::protobuf::UnknownFieldSet::default_instance), target, stream); + } + // @@protoc_insertion_point(serialize_to_array_end:google.firestore.v1.Function) + return target; +} + +::size_t Function::ByteSizeLong() const { +// @@protoc_insertion_point(message_byte_size_start:google.firestore.v1.Function) + ::size_t total_size = 0; + + ::uint32_t cached_has_bits = 0; + // Prevent compiler warnings about cached_has_bits being unused + (void) cached_has_bits; + + // repeated .google.firestore.v1.Value args = 2 [(.google.api.field_behavior) = OPTIONAL]; + total_size += 1UL * this->_internal_args_size(); + for (const auto& msg : this->_internal_args()) { + total_size += + ::google::protobuf::internal::WireFormatLite::MessageSize(msg); + } + // map options = 3 [(.google.api.field_behavior) = OPTIONAL]; + total_size += 1 * ::google::protobuf::internal::FromIntSize(_internal_options_size()); + for (const auto& entry : _internal_options()) { + total_size += _pbi::MapEntryFuncs::ByteSizeLong(entry.first, entry.second); + } + // string name = 1 [(.google.api.field_behavior) = REQUIRED]; + if (!this->_internal_name().empty()) { + total_size += 1 + ::google::protobuf::internal::WireFormatLite::StringSize( + this->_internal_name()); + } + + return MaybeComputeUnknownFieldsSize(total_size, &_impl_._cached_size_); +} + +const ::google::protobuf::Message::ClassData Function::_class_data_ = { + Function::MergeImpl, + nullptr, // OnDemandRegisterArenaDtor +}; +const ::google::protobuf::Message::ClassData* Function::GetClassData() const { + return &_class_data_; +} + +void Function::MergeImpl(::google::protobuf::Message& to_msg, const ::google::protobuf::Message& from_msg) { + auto* const _this = static_cast(&to_msg); + auto& from = static_cast(from_msg); + // @@protoc_insertion_point(class_specific_merge_from_start:google.firestore.v1.Function) + ABSL_DCHECK_NE(&from, _this); + ::uint32_t cached_has_bits = 0; + (void) cached_has_bits; + + _this->_internal_mutable_args()->MergeFrom( + from._internal_args()); + _this->_impl_.options_.MergeFrom(from._impl_.options_); + if (!from._internal_name().empty()) { + _this->_internal_set_name(from._internal_name()); + } + _this->_internal_metadata_.MergeFrom<::google::protobuf::UnknownFieldSet>(from._internal_metadata_); +} + +void Function::CopyFrom(const Function& from) { +// @@protoc_insertion_point(class_specific_copy_from_start:google.firestore.v1.Function) + if (&from == this) return; + Clear(); + MergeFrom(from); +} + +PROTOBUF_NOINLINE bool Function::IsInitialized() const { + return true; +} + +::_pbi::CachedSize* Function::AccessCachedSize() const { + return &_impl_._cached_size_; +} +void Function::InternalSwap(Function* PROTOBUF_RESTRICT other) { + using std::swap; + auto* arena = GetArena(); + ABSL_DCHECK_EQ(arena, other->GetArena()); + _internal_metadata_.InternalSwap(&other->_internal_metadata_); + _impl_.args_.InternalSwap(&other->_impl_.args_); + _impl_.options_.InternalSwap(&other->_impl_.options_); + ::_pbi::ArenaStringPtr::InternalSwap(&_impl_.name_, &other->_impl_.name_, arena); +} + +::google::protobuf::Metadata Function::GetMetadata() const { + return ::_pbi::AssignDescriptors( + &descriptor_table_google_2ffirestore_2fv1_2fdocument_2eproto_getter, &descriptor_table_google_2ffirestore_2fv1_2fdocument_2eproto_once, + file_level_metadata_google_2ffirestore_2fv1_2fdocument_2eproto[7]); +} +// =================================================================== + +Pipeline_Stage_OptionsEntry_DoNotUse::Pipeline_Stage_OptionsEntry_DoNotUse() {} +Pipeline_Stage_OptionsEntry_DoNotUse::Pipeline_Stage_OptionsEntry_DoNotUse(::google::protobuf::Arena* arena) + : SuperType(arena) {} +::google::protobuf::Metadata Pipeline_Stage_OptionsEntry_DoNotUse::GetMetadata() const { + return ::_pbi::AssignDescriptors( + &descriptor_table_google_2ffirestore_2fv1_2fdocument_2eproto_getter, &descriptor_table_google_2ffirestore_2fv1_2fdocument_2eproto_once, + file_level_metadata_google_2ffirestore_2fv1_2fdocument_2eproto[8]); +} +// =================================================================== + +class Pipeline_Stage::_Internal { + public: +}; + +Pipeline_Stage::Pipeline_Stage(::google::protobuf::Arena* arena) + : ::google::protobuf::Message(arena) { + SharedCtor(arena); + // @@protoc_insertion_point(arena_constructor:google.firestore.v1.Pipeline.Stage) +} +inline PROTOBUF_NDEBUG_INLINE Pipeline_Stage::Impl_::Impl_( + ::google::protobuf::internal::InternalVisibility visibility, ::google::protobuf::Arena* arena, + const Impl_& from) + : args_{visibility, arena, from.args_}, + options_{visibility, arena, from.options_}, + name_(arena, from.name_), + _cached_size_{0} {} + +Pipeline_Stage::Pipeline_Stage( + ::google::protobuf::Arena* arena, + const Pipeline_Stage& from) + : ::google::protobuf::Message(arena) { + Pipeline_Stage* const _this = this; + (void)_this; + _internal_metadata_.MergeFrom<::google::protobuf::UnknownFieldSet>( + from._internal_metadata_); + new (&_impl_) Impl_(internal_visibility(), arena, from._impl_); + + // @@protoc_insertion_point(copy_constructor:google.firestore.v1.Pipeline.Stage) +} +inline PROTOBUF_NDEBUG_INLINE Pipeline_Stage::Impl_::Impl_( + ::google::protobuf::internal::InternalVisibility visibility, + ::google::protobuf::Arena* arena) + : args_{visibility, arena}, + options_{visibility, arena}, + name_(arena), + _cached_size_{0} {} + +inline void Pipeline_Stage::SharedCtor(::_pb::Arena* arena) { + new (&_impl_) Impl_(internal_visibility(), arena); +} +Pipeline_Stage::~Pipeline_Stage() { + // @@protoc_insertion_point(destructor:google.firestore.v1.Pipeline.Stage) + _internal_metadata_.Delete<::google::protobuf::UnknownFieldSet>(); + SharedDtor(); +} +inline void Pipeline_Stage::SharedDtor() { + ABSL_DCHECK(GetArena() == nullptr); + _impl_.name_.Destroy(); + _impl_.~Impl_(); +} + +PROTOBUF_NOINLINE void Pipeline_Stage::Clear() { +// @@protoc_insertion_point(message_clear_start:google.firestore.v1.Pipeline.Stage) + PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); + ::uint32_t cached_has_bits = 0; + // Prevent compiler warnings about cached_has_bits being unused + (void) cached_has_bits; + + _impl_.args_.Clear(); + _impl_.options_.Clear(); + _impl_.name_.ClearToEmpty(); + _internal_metadata_.Clear<::google::protobuf::UnknownFieldSet>(); +} + +const char* Pipeline_Stage::_InternalParse( + const char* ptr, ::_pbi::ParseContext* ctx) { + ptr = ::_pbi::TcParser::ParseLoop(this, ptr, ctx, &_table_.header); + return ptr; +} + + +PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 +const ::_pbi::TcParseTable<1, 3, 3, 54, 2> Pipeline_Stage::_table_ = { + { + 0, // no _has_bits_ + 0, // no _extensions_ + 3, 8, // max_field_number, fast_idx_mask + offsetof(decltype(_table_), field_lookup_table), + 4294967288, // skipmap + offsetof(decltype(_table_), field_entries), + 3, // num_field_entries + 3, // num_aux_entries + offsetof(decltype(_table_), aux_entries), + &_Pipeline_Stage_default_instance_._instance, + ::_pbi::TcParser::GenericFallback, // fallback + }, {{ + // repeated .google.firestore.v1.Value args = 2 [(.google.api.field_behavior) = OPTIONAL]; + {::_pbi::TcParser::FastMtR1, + {18, 63, 0, PROTOBUF_FIELD_OFFSET(Pipeline_Stage, _impl_.args_)}}, + // string name = 1 [(.google.api.field_behavior) = REQUIRED]; + {::_pbi::TcParser::FastUS1, + {10, 63, 0, PROTOBUF_FIELD_OFFSET(Pipeline_Stage, _impl_.name_)}}, + }}, {{ + 65535, 65535 + }}, {{ + // string name = 1 [(.google.api.field_behavior) = REQUIRED]; + {PROTOBUF_FIELD_OFFSET(Pipeline_Stage, _impl_.name_), 0, 0, + (0 | ::_fl::kFcSingular | ::_fl::kUtf8String | ::_fl::kRepAString)}, + // repeated .google.firestore.v1.Value args = 2 [(.google.api.field_behavior) = OPTIONAL]; + {PROTOBUF_FIELD_OFFSET(Pipeline_Stage, _impl_.args_), 0, 0, + (0 | ::_fl::kFcRepeated | ::_fl::kMessage | ::_fl::kTvTable)}, + // map options = 3 [(.google.api.field_behavior) = OPTIONAL]; + {PROTOBUF_FIELD_OFFSET(Pipeline_Stage, _impl_.options_), 0, 1, + (0 | ::_fl::kFcRepeated | ::_fl::kMap)}, + }}, {{ + {::_pbi::TcParser::GetTable<::google::firestore::v1::Value>()}, + {::_pbi::TcParser::GetMapAuxInfo< + decltype(Pipeline_Stage()._impl_.options_)>( + 1, 0, 0, 9, + 11)}, + {::_pbi::TcParser::CreateInArenaStorageCb<::google::firestore::v1::Value>}, + }}, {{ + "\42\4\0\7\0\0\0\0" + "google.firestore.v1.Pipeline.Stage" + "name" + "options" + }}, +}; + +::uint8_t* Pipeline_Stage::_InternalSerialize( + ::uint8_t* target, + ::google::protobuf::io::EpsCopyOutputStream* stream) const { + // @@protoc_insertion_point(serialize_to_array_start:google.firestore.v1.Pipeline.Stage) + ::uint32_t cached_has_bits = 0; + (void)cached_has_bits; + + // string name = 1 [(.google.api.field_behavior) = REQUIRED]; + if (!this->_internal_name().empty()) { + const std::string& _s = this->_internal_name(); + ::google::protobuf::internal::WireFormatLite::VerifyUtf8String( + _s.data(), static_cast(_s.length()), ::google::protobuf::internal::WireFormatLite::SERIALIZE, "google.firestore.v1.Pipeline.Stage.name"); + target = stream->WriteStringMaybeAliased(1, _s, target); + } + + // repeated .google.firestore.v1.Value args = 2 [(.google.api.field_behavior) = OPTIONAL]; + for (unsigned i = 0, + n = static_cast(this->_internal_args_size()); i < n; i++) { + const auto& repfield = this->_internal_args().Get(i); + target = ::google::protobuf::internal::WireFormatLite:: + InternalWriteMessage(2, repfield, repfield.GetCachedSize(), target, stream); + } + + // map options = 3 [(.google.api.field_behavior) = OPTIONAL]; + if (!_internal_options().empty()) { + using MapType = ::google::protobuf::Map; + using WireHelper = _pbi::MapEntryFuncs; + const auto& field = _internal_options(); + + if (stream->IsSerializationDeterministic() && field.size() > 1) { + for (const auto& entry : ::google::protobuf::internal::MapSorterPtr(field)) { + target = WireHelper::InternalSerialize( + 3, entry.first, entry.second, target, stream); + ::google::protobuf::internal::WireFormatLite::VerifyUtf8String( + entry.first.data(), static_cast(entry.first.length()), + ::google::protobuf::internal::WireFormatLite::SERIALIZE, "google.firestore.v1.Pipeline.Stage.options"); + } + } else { + for (const auto& entry : field) { + target = WireHelper::InternalSerialize( + 3, entry.first, entry.second, target, stream); + ::google::protobuf::internal::WireFormatLite::VerifyUtf8String( + entry.first.data(), static_cast(entry.first.length()), + ::google::protobuf::internal::WireFormatLite::SERIALIZE, "google.firestore.v1.Pipeline.Stage.options"); + } + } + } + + if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) { + target = + ::_pbi::WireFormat::InternalSerializeUnknownFieldsToArray( + _internal_metadata_.unknown_fields<::google::protobuf::UnknownFieldSet>(::google::protobuf::UnknownFieldSet::default_instance), target, stream); + } + // @@protoc_insertion_point(serialize_to_array_end:google.firestore.v1.Pipeline.Stage) + return target; +} + +::size_t Pipeline_Stage::ByteSizeLong() const { +// @@protoc_insertion_point(message_byte_size_start:google.firestore.v1.Pipeline.Stage) + ::size_t total_size = 0; + + ::uint32_t cached_has_bits = 0; + // Prevent compiler warnings about cached_has_bits being unused + (void) cached_has_bits; + + // repeated .google.firestore.v1.Value args = 2 [(.google.api.field_behavior) = OPTIONAL]; + total_size += 1UL * this->_internal_args_size(); + for (const auto& msg : this->_internal_args()) { + total_size += + ::google::protobuf::internal::WireFormatLite::MessageSize(msg); + } + // map options = 3 [(.google.api.field_behavior) = OPTIONAL]; + total_size += 1 * ::google::protobuf::internal::FromIntSize(_internal_options_size()); + for (const auto& entry : _internal_options()) { + total_size += _pbi::MapEntryFuncs::ByteSizeLong(entry.first, entry.second); + } + // string name = 1 [(.google.api.field_behavior) = REQUIRED]; + if (!this->_internal_name().empty()) { + total_size += 1 + ::google::protobuf::internal::WireFormatLite::StringSize( + this->_internal_name()); + } + + return MaybeComputeUnknownFieldsSize(total_size, &_impl_._cached_size_); +} + +const ::google::protobuf::Message::ClassData Pipeline_Stage::_class_data_ = { + Pipeline_Stage::MergeImpl, + nullptr, // OnDemandRegisterArenaDtor +}; +const ::google::protobuf::Message::ClassData* Pipeline_Stage::GetClassData() const { + return &_class_data_; +} + +void Pipeline_Stage::MergeImpl(::google::protobuf::Message& to_msg, const ::google::protobuf::Message& from_msg) { + auto* const _this = static_cast(&to_msg); + auto& from = static_cast(from_msg); + // @@protoc_insertion_point(class_specific_merge_from_start:google.firestore.v1.Pipeline.Stage) + ABSL_DCHECK_NE(&from, _this); + ::uint32_t cached_has_bits = 0; + (void) cached_has_bits; + + _this->_internal_mutable_args()->MergeFrom( + from._internal_args()); + _this->_impl_.options_.MergeFrom(from._impl_.options_); + if (!from._internal_name().empty()) { + _this->_internal_set_name(from._internal_name()); + } + _this->_internal_metadata_.MergeFrom<::google::protobuf::UnknownFieldSet>(from._internal_metadata_); +} + +void Pipeline_Stage::CopyFrom(const Pipeline_Stage& from) { +// @@protoc_insertion_point(class_specific_copy_from_start:google.firestore.v1.Pipeline.Stage) + if (&from == this) return; + Clear(); + MergeFrom(from); +} + +PROTOBUF_NOINLINE bool Pipeline_Stage::IsInitialized() const { + return true; +} + +::_pbi::CachedSize* Pipeline_Stage::AccessCachedSize() const { + return &_impl_._cached_size_; +} +void Pipeline_Stage::InternalSwap(Pipeline_Stage* PROTOBUF_RESTRICT other) { + using std::swap; + auto* arena = GetArena(); + ABSL_DCHECK_EQ(arena, other->GetArena()); + _internal_metadata_.InternalSwap(&other->_internal_metadata_); + _impl_.args_.InternalSwap(&other->_impl_.args_); + _impl_.options_.InternalSwap(&other->_impl_.options_); + ::_pbi::ArenaStringPtr::InternalSwap(&_impl_.name_, &other->_impl_.name_, arena); +} + +::google::protobuf::Metadata Pipeline_Stage::GetMetadata() const { + return ::_pbi::AssignDescriptors( + &descriptor_table_google_2ffirestore_2fv1_2fdocument_2eproto_getter, &descriptor_table_google_2ffirestore_2fv1_2fdocument_2eproto_once, + file_level_metadata_google_2ffirestore_2fv1_2fdocument_2eproto[9]); +} +// =================================================================== + +class Pipeline::_Internal { + public: +}; + +Pipeline::Pipeline(::google::protobuf::Arena* arena) + : ::google::protobuf::Message(arena) { + SharedCtor(arena); + // @@protoc_insertion_point(arena_constructor:google.firestore.v1.Pipeline) +} +inline PROTOBUF_NDEBUG_INLINE Pipeline::Impl_::Impl_( + ::google::protobuf::internal::InternalVisibility visibility, ::google::protobuf::Arena* arena, + const Impl_& from) + : stages_{visibility, arena, from.stages_}, + _cached_size_{0} {} + +Pipeline::Pipeline( + ::google::protobuf::Arena* arena, + const Pipeline& from) + : ::google::protobuf::Message(arena) { + Pipeline* const _this = this; + (void)_this; + _internal_metadata_.MergeFrom<::google::protobuf::UnknownFieldSet>( + from._internal_metadata_); + new (&_impl_) Impl_(internal_visibility(), arena, from._impl_); + + // @@protoc_insertion_point(copy_constructor:google.firestore.v1.Pipeline) +} +inline PROTOBUF_NDEBUG_INLINE Pipeline::Impl_::Impl_( + ::google::protobuf::internal::InternalVisibility visibility, + ::google::protobuf::Arena* arena) + : stages_{visibility, arena}, + _cached_size_{0} {} + +inline void Pipeline::SharedCtor(::_pb::Arena* arena) { + new (&_impl_) Impl_(internal_visibility(), arena); +} +Pipeline::~Pipeline() { + // @@protoc_insertion_point(destructor:google.firestore.v1.Pipeline) + _internal_metadata_.Delete<::google::protobuf::UnknownFieldSet>(); + SharedDtor(); +} +inline void Pipeline::SharedDtor() { + ABSL_DCHECK(GetArena() == nullptr); + _impl_.~Impl_(); +} + +PROTOBUF_NOINLINE void Pipeline::Clear() { +// @@protoc_insertion_point(message_clear_start:google.firestore.v1.Pipeline) + PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); + ::uint32_t cached_has_bits = 0; + // Prevent compiler warnings about cached_has_bits being unused + (void) cached_has_bits; + + _impl_.stages_.Clear(); + _internal_metadata_.Clear<::google::protobuf::UnknownFieldSet>(); +} + +const char* Pipeline::_InternalParse( + const char* ptr, ::_pbi::ParseContext* ctx) { + ptr = ::_pbi::TcParser::ParseLoop(this, ptr, ctx, &_table_.header); + return ptr; +} + + +PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 +const ::_pbi::TcParseTable<0, 1, 1, 0, 2> Pipeline::_table_ = { + { + 0, // no _has_bits_ + 0, // no _extensions_ + 1, 0, // max_field_number, fast_idx_mask + offsetof(decltype(_table_), field_lookup_table), + 4294967294, // skipmap + offsetof(decltype(_table_), field_entries), + 1, // num_field_entries + 1, // num_aux_entries + offsetof(decltype(_table_), aux_entries), + &_Pipeline_default_instance_._instance, + ::_pbi::TcParser::GenericFallback, // fallback + }, {{ + // repeated .google.firestore.v1.Pipeline.Stage stages = 1 [(.google.api.field_behavior) = REQUIRED]; + {::_pbi::TcParser::FastMtR1, + {10, 63, 0, PROTOBUF_FIELD_OFFSET(Pipeline, _impl_.stages_)}}, + }}, {{ + 65535, 65535 + }}, {{ + // repeated .google.firestore.v1.Pipeline.Stage stages = 1 [(.google.api.field_behavior) = REQUIRED]; + {PROTOBUF_FIELD_OFFSET(Pipeline, _impl_.stages_), 0, 0, + (0 | ::_fl::kFcRepeated | ::_fl::kMessage | ::_fl::kTvTable)}, + }}, {{ + {::_pbi::TcParser::GetTable<::google::firestore::v1::Pipeline_Stage>()}, + }}, {{ + }}, +}; + +::uint8_t* Pipeline::_InternalSerialize( + ::uint8_t* target, + ::google::protobuf::io::EpsCopyOutputStream* stream) const { + // @@protoc_insertion_point(serialize_to_array_start:google.firestore.v1.Pipeline) + ::uint32_t cached_has_bits = 0; + (void)cached_has_bits; + + // repeated .google.firestore.v1.Pipeline.Stage stages = 1 [(.google.api.field_behavior) = REQUIRED]; + for (unsigned i = 0, + n = static_cast(this->_internal_stages_size()); i < n; i++) { + const auto& repfield = this->_internal_stages().Get(i); + target = ::google::protobuf::internal::WireFormatLite:: + InternalWriteMessage(1, repfield, repfield.GetCachedSize(), target, stream); + } + + if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) { + target = + ::_pbi::WireFormat::InternalSerializeUnknownFieldsToArray( + _internal_metadata_.unknown_fields<::google::protobuf::UnknownFieldSet>(::google::protobuf::UnknownFieldSet::default_instance), target, stream); + } + // @@protoc_insertion_point(serialize_to_array_end:google.firestore.v1.Pipeline) + return target; +} + +::size_t Pipeline::ByteSizeLong() const { +// @@protoc_insertion_point(message_byte_size_start:google.firestore.v1.Pipeline) + ::size_t total_size = 0; + + ::uint32_t cached_has_bits = 0; + // Prevent compiler warnings about cached_has_bits being unused + (void) cached_has_bits; + + // repeated .google.firestore.v1.Pipeline.Stage stages = 1 [(.google.api.field_behavior) = REQUIRED]; + total_size += 1UL * this->_internal_stages_size(); + for (const auto& msg : this->_internal_stages()) { + total_size += + ::google::protobuf::internal::WireFormatLite::MessageSize(msg); + } + return MaybeComputeUnknownFieldsSize(total_size, &_impl_._cached_size_); +} + +const ::google::protobuf::Message::ClassData Pipeline::_class_data_ = { + Pipeline::MergeImpl, + nullptr, // OnDemandRegisterArenaDtor +}; +const ::google::protobuf::Message::ClassData* Pipeline::GetClassData() const { + return &_class_data_; +} + +void Pipeline::MergeImpl(::google::protobuf::Message& to_msg, const ::google::protobuf::Message& from_msg) { + auto* const _this = static_cast(&to_msg); + auto& from = static_cast(from_msg); + // @@protoc_insertion_point(class_specific_merge_from_start:google.firestore.v1.Pipeline) + ABSL_DCHECK_NE(&from, _this); + ::uint32_t cached_has_bits = 0; + (void) cached_has_bits; + + _this->_internal_mutable_stages()->MergeFrom( + from._internal_stages()); + _this->_internal_metadata_.MergeFrom<::google::protobuf::UnknownFieldSet>(from._internal_metadata_); +} + +void Pipeline::CopyFrom(const Pipeline& from) { +// @@protoc_insertion_point(class_specific_copy_from_start:google.firestore.v1.Pipeline) + if (&from == this) return; + Clear(); + MergeFrom(from); +} + +PROTOBUF_NOINLINE bool Pipeline::IsInitialized() const { + return true; +} + +::_pbi::CachedSize* Pipeline::AccessCachedSize() const { + return &_impl_._cached_size_; +} +void Pipeline::InternalSwap(Pipeline* PROTOBUF_RESTRICT other) { + using std::swap; + _internal_metadata_.InternalSwap(&other->_internal_metadata_); + _impl_.stages_.InternalSwap(&other->_impl_.stages_); +} + +::google::protobuf::Metadata Pipeline::GetMetadata() const { + return ::_pbi::AssignDescriptors( + &descriptor_table_google_2ffirestore_2fv1_2fdocument_2eproto_getter, &descriptor_table_google_2ffirestore_2fv1_2fdocument_2eproto_once, + file_level_metadata_google_2ffirestore_2fv1_2fdocument_2eproto[10]); +} // @@protoc_insertion_point(namespace_scope) } // namespace v1 } // namespace firestore diff --git a/Firestore/Protos/cpp/google/firestore/v1/document.pb.h b/Firestore/Protos/cpp/google/firestore/v1/document.pb.h index 440f2d29ffc..9e1fabdf0a3 100644 --- a/Firestore/Protos/cpp/google/firestore/v1/document.pb.h +++ b/Firestore/Protos/cpp/google/firestore/v1/document.pb.h @@ -1,5 +1,5 @@ /* - * Copyright 2024 Google LLC + * Copyright 2025 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -53,6 +53,7 @@ #include "google/protobuf/map_entry.h" #include "google/protobuf/map_field_inl.h" #include "google/protobuf/unknown_field_set.h" +#include "google/api/field_behavior.pb.h" #include "google/protobuf/struct.pb.h" #include "google/protobuf/timestamp.pb.h" #include "google/type/latlng.pb.h" @@ -89,12 +90,27 @@ extern DocumentDefaultTypeInternal _Document_default_instance_; class Document_FieldsEntry_DoNotUse; struct Document_FieldsEntry_DoNotUseDefaultTypeInternal; extern Document_FieldsEntry_DoNotUseDefaultTypeInternal _Document_FieldsEntry_DoNotUse_default_instance_; +class Function; +struct FunctionDefaultTypeInternal; +extern FunctionDefaultTypeInternal _Function_default_instance_; +class Function_OptionsEntry_DoNotUse; +struct Function_OptionsEntry_DoNotUseDefaultTypeInternal; +extern Function_OptionsEntry_DoNotUseDefaultTypeInternal _Function_OptionsEntry_DoNotUse_default_instance_; class MapValue; struct MapValueDefaultTypeInternal; extern MapValueDefaultTypeInternal _MapValue_default_instance_; class MapValue_FieldsEntry_DoNotUse; struct MapValue_FieldsEntry_DoNotUseDefaultTypeInternal; extern MapValue_FieldsEntry_DoNotUseDefaultTypeInternal _MapValue_FieldsEntry_DoNotUse_default_instance_; +class Pipeline; +struct PipelineDefaultTypeInternal; +extern PipelineDefaultTypeInternal _Pipeline_default_instance_; +class Pipeline_Stage; +struct Pipeline_StageDefaultTypeInternal; +extern Pipeline_StageDefaultTypeInternal _Pipeline_Stage_default_instance_; +class Pipeline_Stage_OptionsEntry_DoNotUse; +struct Pipeline_Stage_OptionsEntry_DoNotUseDefaultTypeInternal; +extern Pipeline_Stage_OptionsEntry_DoNotUseDefaultTypeInternal _Pipeline_Stage_OptionsEntry_DoNotUse_default_instance_; class Value; struct ValueDefaultTypeInternal; extern ValueDefaultTypeInternal _Value_default_instance_; @@ -296,6 +312,256 @@ class ArrayValue final : friend struct ::TableStruct_google_2ffirestore_2fv1_2fdocument_2eproto; };// ------------------------------------------------------------------- +class Function final : + public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:google.firestore.v1.Function) */ { + public: + inline Function() : Function(nullptr) {} + ~Function() override; + template + explicit PROTOBUF_CONSTEXPR Function(::google::protobuf::internal::ConstantInitialized); + + inline Function(const Function& from) + : Function(nullptr, from) {} + Function(Function&& from) noexcept + : Function() { + *this = ::std::move(from); + } + + inline Function& operator=(const Function& from) { + CopyFrom(from); + return *this; + } + inline Function& operator=(Function&& from) noexcept { + if (this == &from) return *this; + if (GetArena() == from.GetArena() + #ifdef PROTOBUF_FORCE_COPY_IN_MOVE + && GetArena() != nullptr + #endif // !PROTOBUF_FORCE_COPY_IN_MOVE + ) { + InternalSwap(&from); + } else { + CopyFrom(from); + } + return *this; + } + + inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const + ABSL_ATTRIBUTE_LIFETIME_BOUND { + return _internal_metadata_.unknown_fields<::google::protobuf::UnknownFieldSet>(::google::protobuf::UnknownFieldSet::default_instance); + } + inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() + ABSL_ATTRIBUTE_LIFETIME_BOUND { + return _internal_metadata_.mutable_unknown_fields<::google::protobuf::UnknownFieldSet>(); + } + + static const ::google::protobuf::Descriptor* descriptor() { + return GetDescriptor(); + } + static const ::google::protobuf::Descriptor* GetDescriptor() { + return default_instance().GetMetadata().descriptor; + } + static const ::google::protobuf::Reflection* GetReflection() { + return default_instance().GetMetadata().reflection; + } + static const Function& default_instance() { + return *internal_default_instance(); + } + static inline const Function* internal_default_instance() { + return reinterpret_cast( + &_Function_default_instance_); + } + static constexpr int kIndexInFileMessages = + 7; + + friend void swap(Function& a, Function& b) { + a.Swap(&b); + } + inline void Swap(Function* other) { + if (other == this) return; + #ifdef PROTOBUF_FORCE_COPY_IN_SWAP + if (GetArena() != nullptr && + GetArena() == other->GetArena()) { + #else // PROTOBUF_FORCE_COPY_IN_SWAP + if (GetArena() == other->GetArena()) { + #endif // !PROTOBUF_FORCE_COPY_IN_SWAP + InternalSwap(other); + } else { + ::google::protobuf::internal::GenericSwap(this, other); + } + } + void UnsafeArenaSwap(Function* other) { + if (other == this) return; + ABSL_DCHECK(GetArena() == other->GetArena()); + InternalSwap(other); + } + + // implements Message ---------------------------------------------- + + Function* New(::google::protobuf::Arena* arena = nullptr) const final { + return CreateMaybeMessage(arena); + } + using ::google::protobuf::Message::CopyFrom; + void CopyFrom(const Function& from); + using ::google::protobuf::Message::MergeFrom; + void MergeFrom( const Function& from) { + Function::MergeImpl(*this, from); + } + private: + static void MergeImpl(::google::protobuf::Message& to_msg, const ::google::protobuf::Message& from_msg); + public: + PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final; + bool IsInitialized() const final; + + ::size_t ByteSizeLong() const final; + const char* _InternalParse(const char* ptr, ::google::protobuf::internal::ParseContext* ctx) final; + ::uint8_t* _InternalSerialize( + ::uint8_t* target, ::google::protobuf::io::EpsCopyOutputStream* stream) const final; + int GetCachedSize() const { return _impl_._cached_size_.Get(); } + + private: + ::google::protobuf::internal::CachedSize* AccessCachedSize() const final; + void SharedCtor(::google::protobuf::Arena* arena); + void SharedDtor(); + void InternalSwap(Function* other); + + private: + friend class ::google::protobuf::internal::AnyMetadata; + static ::absl::string_view FullMessageName() { + return "google.firestore.v1.Function"; + } + protected: + explicit Function(::google::protobuf::Arena* arena); + Function(::google::protobuf::Arena* arena, const Function& from); + public: + + static const ClassData _class_data_; + const ::google::protobuf::Message::ClassData*GetClassData() const final; + + ::google::protobuf::Metadata GetMetadata() const final; + + // nested types ---------------------------------------------------- + + + // accessors ------------------------------------------------------- + + enum : int { + kArgsFieldNumber = 2, + kOptionsFieldNumber = 3, + kNameFieldNumber = 1, + }; + // repeated .google.firestore.v1.Value args = 2 [(.google.api.field_behavior) = OPTIONAL]; + int args_size() const; + private: + int _internal_args_size() const; + + public: + void clear_args() ; + ::google::firestore::v1::Value* mutable_args(int index); + ::google::protobuf::RepeatedPtrField< ::google::firestore::v1::Value >* + mutable_args(); + private: + const ::google::protobuf::RepeatedPtrField<::google::firestore::v1::Value>& _internal_args() const; + ::google::protobuf::RepeatedPtrField<::google::firestore::v1::Value>* _internal_mutable_args(); + public: + const ::google::firestore::v1::Value& args(int index) const; + ::google::firestore::v1::Value* add_args(); + const ::google::protobuf::RepeatedPtrField< ::google::firestore::v1::Value >& + args() const; + // map options = 3 [(.google.api.field_behavior) = OPTIONAL]; + int options_size() const; + private: + int _internal_options_size() const; + + public: + void clear_options() ; + const ::google::protobuf::Map& options() const; + ::google::protobuf::Map* mutable_options(); + + private: + const ::google::protobuf::Map& _internal_options() const; + ::google::protobuf::Map* _internal_mutable_options(); + + public: + // string name = 1 [(.google.api.field_behavior) = REQUIRED]; + void clear_name() ; + const std::string& name() const; + template + void set_name(Arg_&& arg, Args_... args); + std::string* mutable_name(); + PROTOBUF_NODISCARD std::string* release_name(); + void set_allocated_name(std::string* value); + + private: + const std::string& _internal_name() const; + inline PROTOBUF_ALWAYS_INLINE void _internal_set_name( + const std::string& value); + std::string* _internal_mutable_name(); + + public: + // @@protoc_insertion_point(class_scope:google.firestore.v1.Function) + private: + class _Internal; + + friend class ::google::protobuf::internal::TcParser; + static const ::google::protobuf::internal::TcParseTable< + 1, 3, 3, + 48, 2> + _table_; + friend class ::google::protobuf::MessageLite; + friend class ::google::protobuf::Arena; + template + friend class ::google::protobuf::Arena::InternalHelper; + using InternalArenaConstructable_ = void; + using DestructorSkippable_ = void; + struct Impl_ { + + inline explicit constexpr Impl_( + ::google::protobuf::internal::ConstantInitialized) noexcept; + inline explicit Impl_(::google::protobuf::internal::InternalVisibility visibility, + ::google::protobuf::Arena* arena); + inline explicit Impl_(::google::protobuf::internal::InternalVisibility visibility, + ::google::protobuf::Arena* arena, const Impl_& from); + ::google::protobuf::RepeatedPtrField< ::google::firestore::v1::Value > args_; + ::google::protobuf::internal::MapField + options_; + ::google::protobuf::internal::ArenaStringPtr name_; + mutable ::google::protobuf::internal::CachedSize _cached_size_; + PROTOBUF_TSAN_DECLARE_MEMBER + }; + union { Impl_ _impl_; }; + friend struct ::TableStruct_google_2ffirestore_2fv1_2fdocument_2eproto; +};// ------------------------------------------------------------------- + +class Function_OptionsEntry_DoNotUse final + : public ::google::protobuf::internal::MapEntry< + Function_OptionsEntry_DoNotUse, std::string, ::google::firestore::v1::Value, + ::google::protobuf::internal::WireFormatLite::TYPE_STRING, + ::google::protobuf::internal::WireFormatLite::TYPE_MESSAGE> { + public: + using SuperType = ::google::protobuf::internal::MapEntry< + Function_OptionsEntry_DoNotUse, std::string, ::google::firestore::v1::Value, + ::google::protobuf::internal::WireFormatLite::TYPE_STRING, + ::google::protobuf::internal::WireFormatLite::TYPE_MESSAGE>; + Function_OptionsEntry_DoNotUse(); + template + explicit PROTOBUF_CONSTEXPR Function_OptionsEntry_DoNotUse( + ::google::protobuf::internal::ConstantInitialized); + explicit Function_OptionsEntry_DoNotUse(::google::protobuf::Arena* arena); + static const Function_OptionsEntry_DoNotUse* internal_default_instance() { + return reinterpret_cast( + &_Function_OptionsEntry_DoNotUse_default_instance_); + } + static bool ValidateKey(std::string* s) { + return ::google::protobuf::internal::WireFormatLite::VerifyUtf8String(s->data(), static_cast(s->size()), ::google::protobuf::internal::WireFormatLite::PARSE, "google.firestore.v1.Function.OptionsEntry.key"); + } + static bool ValidateValue(void*) { return true; } + ::google::protobuf::Metadata GetMetadata() const final; + friend struct ::TableStruct_google_2ffirestore_2fv1_2fdocument_2eproto; +}; +// ------------------------------------------------------------------- + class MapValue final : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:google.firestore.v1.MapValue) */ { public: @@ -508,26 +774,26 @@ class MapValue_FieldsEntry_DoNotUse final }; // ------------------------------------------------------------------- -class Value final : - public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:google.firestore.v1.Value) */ { +class Pipeline final : + public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:google.firestore.v1.Pipeline) */ { public: - inline Value() : Value(nullptr) {} - ~Value() override; + inline Pipeline() : Pipeline(nullptr) {} + ~Pipeline() override; template - explicit PROTOBUF_CONSTEXPR Value(::google::protobuf::internal::ConstantInitialized); + explicit PROTOBUF_CONSTEXPR Pipeline(::google::protobuf::internal::ConstantInitialized); - inline Value(const Value& from) - : Value(nullptr, from) {} - Value(Value&& from) noexcept - : Value() { + inline Pipeline(const Pipeline& from) + : Pipeline(nullptr, from) {} + Pipeline(Pipeline&& from) noexcept + : Pipeline() { *this = ::std::move(from); } - inline Value& operator=(const Value& from) { + inline Pipeline& operator=(const Pipeline& from) { CopyFrom(from); return *this; } - inline Value& operator=(Value&& from) noexcept { + inline Pipeline& operator=(Pipeline&& from) noexcept { if (this == &from) return *this; if (GetArena() == from.GetArena() #ifdef PROTOBUF_FORCE_COPY_IN_MOVE @@ -559,35 +825,20 @@ class Value final : static const ::google::protobuf::Reflection* GetReflection() { return default_instance().GetMetadata().reflection; } - static const Value& default_instance() { + static const Pipeline& default_instance() { return *internal_default_instance(); } - enum ValueTypeCase { - kNullValue = 11, - kBooleanValue = 1, - kIntegerValue = 2, - kDoubleValue = 3, - kTimestampValue = 10, - kStringValue = 17, - kBytesValue = 18, - kReferenceValue = 5, - kGeoPointValue = 8, - kArrayValue = 9, - kMapValue = 6, - VALUE_TYPE_NOT_SET = 0, - }; - - static inline const Value* internal_default_instance() { - return reinterpret_cast( - &_Value_default_instance_); + static inline const Pipeline* internal_default_instance() { + return reinterpret_cast( + &_Pipeline_default_instance_); } static constexpr int kIndexInFileMessages = - 2; + 10; - friend void swap(Value& a, Value& b) { + friend void swap(Pipeline& a, Pipeline& b) { a.Swap(&b); } - inline void Swap(Value* other) { + inline void Swap(Pipeline* other) { if (other == this) return; #ifdef PROTOBUF_FORCE_COPY_IN_SWAP if (GetArena() != nullptr && @@ -600,7 +851,7 @@ class Value final : ::google::protobuf::internal::GenericSwap(this, other); } } - void UnsafeArenaSwap(Value* other) { + void UnsafeArenaSwap(Pipeline* other) { if (other == this) return; ABSL_DCHECK(GetArena() == other->GetArena()); InternalSwap(other); @@ -608,14 +859,14 @@ class Value final : // implements Message ---------------------------------------------- - Value* New(::google::protobuf::Arena* arena = nullptr) const final { - return CreateMaybeMessage(arena); + Pipeline* New(::google::protobuf::Arena* arena = nullptr) const final { + return CreateMaybeMessage(arena); } using ::google::protobuf::Message::CopyFrom; - void CopyFrom(const Value& from); + void CopyFrom(const Pipeline& from); using ::google::protobuf::Message::MergeFrom; - void MergeFrom( const Value& from) { - Value::MergeImpl(*this, from); + void MergeFrom( const Pipeline& from) { + Pipeline::MergeImpl(*this, from); } private: static void MergeImpl(::google::protobuf::Message& to_msg, const ::google::protobuf::Message& from_msg); @@ -633,16 +884,16 @@ class Value final : ::google::protobuf::internal::CachedSize* AccessCachedSize() const final; void SharedCtor(::google::protobuf::Arena* arena); void SharedDtor(); - void InternalSwap(Value* other); + void InternalSwap(Pipeline* other); private: friend class ::google::protobuf::internal::AnyMetadata; static ::absl::string_view FullMessageName() { - return "google.firestore.v1.Value"; + return "google.firestore.v1.Pipeline"; } protected: - explicit Value(::google::protobuf::Arena* arena); - Value(::google::protobuf::Arena* arena, const Value& from); + explicit Pipeline(::google::protobuf::Arena* arena); + Pipeline(::google::protobuf::Arena* arena, const Pipeline& from); public: static const ClassData _class_data_; @@ -652,42 +903,498 @@ class Value final : // nested types ---------------------------------------------------- + using Stage = Pipeline_Stage; + // accessors ------------------------------------------------------- enum : int { - kNullValueFieldNumber = 11, - kBooleanValueFieldNumber = 1, - kIntegerValueFieldNumber = 2, - kDoubleValueFieldNumber = 3, - kTimestampValueFieldNumber = 10, - kStringValueFieldNumber = 17, - kBytesValueFieldNumber = 18, - kReferenceValueFieldNumber = 5, - kGeoPointValueFieldNumber = 8, - kArrayValueFieldNumber = 9, - kMapValueFieldNumber = 6, + kStagesFieldNumber = 1, }; - // .google.protobuf.NullValue null_value = 11; - bool has_null_value() const; - void clear_null_value() ; - ::google::protobuf::NullValue null_value() const; - void set_null_value(::google::protobuf::NullValue value); - + // repeated .google.firestore.v1.Pipeline.Stage stages = 1 [(.google.api.field_behavior) = REQUIRED]; + int stages_size() const; private: - ::google::protobuf::NullValue _internal_null_value() const; - void _internal_set_null_value(::google::protobuf::NullValue value); + int _internal_stages_size() const; public: - // bool boolean_value = 1; - bool has_boolean_value() const; - void clear_boolean_value() ; - bool boolean_value() const; - void set_boolean_value(bool value); - + void clear_stages() ; + ::google::firestore::v1::Pipeline_Stage* mutable_stages(int index); + ::google::protobuf::RepeatedPtrField< ::google::firestore::v1::Pipeline_Stage >* + mutable_stages(); private: - bool _internal_boolean_value() const; - void _internal_set_boolean_value(bool value); - + const ::google::protobuf::RepeatedPtrField<::google::firestore::v1::Pipeline_Stage>& _internal_stages() const; + ::google::protobuf::RepeatedPtrField<::google::firestore::v1::Pipeline_Stage>* _internal_mutable_stages(); + public: + const ::google::firestore::v1::Pipeline_Stage& stages(int index) const; + ::google::firestore::v1::Pipeline_Stage* add_stages(); + const ::google::protobuf::RepeatedPtrField< ::google::firestore::v1::Pipeline_Stage >& + stages() const; + // @@protoc_insertion_point(class_scope:google.firestore.v1.Pipeline) + private: + class _Internal; + + friend class ::google::protobuf::internal::TcParser; + static const ::google::protobuf::internal::TcParseTable< + 0, 1, 1, + 0, 2> + _table_; + friend class ::google::protobuf::MessageLite; + friend class ::google::protobuf::Arena; + template + friend class ::google::protobuf::Arena::InternalHelper; + using InternalArenaConstructable_ = void; + using DestructorSkippable_ = void; + struct Impl_ { + + inline explicit constexpr Impl_( + ::google::protobuf::internal::ConstantInitialized) noexcept; + inline explicit Impl_(::google::protobuf::internal::InternalVisibility visibility, + ::google::protobuf::Arena* arena); + inline explicit Impl_(::google::protobuf::internal::InternalVisibility visibility, + ::google::protobuf::Arena* arena, const Impl_& from); + ::google::protobuf::RepeatedPtrField< ::google::firestore::v1::Pipeline_Stage > stages_; + mutable ::google::protobuf::internal::CachedSize _cached_size_; + PROTOBUF_TSAN_DECLARE_MEMBER + }; + union { Impl_ _impl_; }; + friend struct ::TableStruct_google_2ffirestore_2fv1_2fdocument_2eproto; +};// ------------------------------------------------------------------- + +class Pipeline_Stage final : + public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:google.firestore.v1.Pipeline.Stage) */ { + public: + inline Pipeline_Stage() : Pipeline_Stage(nullptr) {} + ~Pipeline_Stage() override; + template + explicit PROTOBUF_CONSTEXPR Pipeline_Stage(::google::protobuf::internal::ConstantInitialized); + + inline Pipeline_Stage(const Pipeline_Stage& from) + : Pipeline_Stage(nullptr, from) {} + Pipeline_Stage(Pipeline_Stage&& from) noexcept + : Pipeline_Stage() { + *this = ::std::move(from); + } + + inline Pipeline_Stage& operator=(const Pipeline_Stage& from) { + CopyFrom(from); + return *this; + } + inline Pipeline_Stage& operator=(Pipeline_Stage&& from) noexcept { + if (this == &from) return *this; + if (GetArena() == from.GetArena() + #ifdef PROTOBUF_FORCE_COPY_IN_MOVE + && GetArena() != nullptr + #endif // !PROTOBUF_FORCE_COPY_IN_MOVE + ) { + InternalSwap(&from); + } else { + CopyFrom(from); + } + return *this; + } + + inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const + ABSL_ATTRIBUTE_LIFETIME_BOUND { + return _internal_metadata_.unknown_fields<::google::protobuf::UnknownFieldSet>(::google::protobuf::UnknownFieldSet::default_instance); + } + inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() + ABSL_ATTRIBUTE_LIFETIME_BOUND { + return _internal_metadata_.mutable_unknown_fields<::google::protobuf::UnknownFieldSet>(); + } + + static const ::google::protobuf::Descriptor* descriptor() { + return GetDescriptor(); + } + static const ::google::protobuf::Descriptor* GetDescriptor() { + return default_instance().GetMetadata().descriptor; + } + static const ::google::protobuf::Reflection* GetReflection() { + return default_instance().GetMetadata().reflection; + } + static const Pipeline_Stage& default_instance() { + return *internal_default_instance(); + } + static inline const Pipeline_Stage* internal_default_instance() { + return reinterpret_cast( + &_Pipeline_Stage_default_instance_); + } + static constexpr int kIndexInFileMessages = + 9; + + friend void swap(Pipeline_Stage& a, Pipeline_Stage& b) { + a.Swap(&b); + } + inline void Swap(Pipeline_Stage* other) { + if (other == this) return; + #ifdef PROTOBUF_FORCE_COPY_IN_SWAP + if (GetArena() != nullptr && + GetArena() == other->GetArena()) { + #else // PROTOBUF_FORCE_COPY_IN_SWAP + if (GetArena() == other->GetArena()) { + #endif // !PROTOBUF_FORCE_COPY_IN_SWAP + InternalSwap(other); + } else { + ::google::protobuf::internal::GenericSwap(this, other); + } + } + void UnsafeArenaSwap(Pipeline_Stage* other) { + if (other == this) return; + ABSL_DCHECK(GetArena() == other->GetArena()); + InternalSwap(other); + } + + // implements Message ---------------------------------------------- + + Pipeline_Stage* New(::google::protobuf::Arena* arena = nullptr) const final { + return CreateMaybeMessage(arena); + } + using ::google::protobuf::Message::CopyFrom; + void CopyFrom(const Pipeline_Stage& from); + using ::google::protobuf::Message::MergeFrom; + void MergeFrom( const Pipeline_Stage& from) { + Pipeline_Stage::MergeImpl(*this, from); + } + private: + static void MergeImpl(::google::protobuf::Message& to_msg, const ::google::protobuf::Message& from_msg); + public: + PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final; + bool IsInitialized() const final; + + ::size_t ByteSizeLong() const final; + const char* _InternalParse(const char* ptr, ::google::protobuf::internal::ParseContext* ctx) final; + ::uint8_t* _InternalSerialize( + ::uint8_t* target, ::google::protobuf::io::EpsCopyOutputStream* stream) const final; + int GetCachedSize() const { return _impl_._cached_size_.Get(); } + + private: + ::google::protobuf::internal::CachedSize* AccessCachedSize() const final; + void SharedCtor(::google::protobuf::Arena* arena); + void SharedDtor(); + void InternalSwap(Pipeline_Stage* other); + + private: + friend class ::google::protobuf::internal::AnyMetadata; + static ::absl::string_view FullMessageName() { + return "google.firestore.v1.Pipeline.Stage"; + } + protected: + explicit Pipeline_Stage(::google::protobuf::Arena* arena); + Pipeline_Stage(::google::protobuf::Arena* arena, const Pipeline_Stage& from); + public: + + static const ClassData _class_data_; + const ::google::protobuf::Message::ClassData*GetClassData() const final; + + ::google::protobuf::Metadata GetMetadata() const final; + + // nested types ---------------------------------------------------- + + + // accessors ------------------------------------------------------- + + enum : int { + kArgsFieldNumber = 2, + kOptionsFieldNumber = 3, + kNameFieldNumber = 1, + }; + // repeated .google.firestore.v1.Value args = 2 [(.google.api.field_behavior) = OPTIONAL]; + int args_size() const; + private: + int _internal_args_size() const; + + public: + void clear_args() ; + ::google::firestore::v1::Value* mutable_args(int index); + ::google::protobuf::RepeatedPtrField< ::google::firestore::v1::Value >* + mutable_args(); + private: + const ::google::protobuf::RepeatedPtrField<::google::firestore::v1::Value>& _internal_args() const; + ::google::protobuf::RepeatedPtrField<::google::firestore::v1::Value>* _internal_mutable_args(); + public: + const ::google::firestore::v1::Value& args(int index) const; + ::google::firestore::v1::Value* add_args(); + const ::google::protobuf::RepeatedPtrField< ::google::firestore::v1::Value >& + args() const; + // map options = 3 [(.google.api.field_behavior) = OPTIONAL]; + int options_size() const; + private: + int _internal_options_size() const; + + public: + void clear_options() ; + const ::google::protobuf::Map& options() const; + ::google::protobuf::Map* mutable_options(); + + private: + const ::google::protobuf::Map& _internal_options() const; + ::google::protobuf::Map* _internal_mutable_options(); + + public: + // string name = 1 [(.google.api.field_behavior) = REQUIRED]; + void clear_name() ; + const std::string& name() const; + template + void set_name(Arg_&& arg, Args_... args); + std::string* mutable_name(); + PROTOBUF_NODISCARD std::string* release_name(); + void set_allocated_name(std::string* value); + + private: + const std::string& _internal_name() const; + inline PROTOBUF_ALWAYS_INLINE void _internal_set_name( + const std::string& value); + std::string* _internal_mutable_name(); + + public: + // @@protoc_insertion_point(class_scope:google.firestore.v1.Pipeline.Stage) + private: + class _Internal; + + friend class ::google::protobuf::internal::TcParser; + static const ::google::protobuf::internal::TcParseTable< + 1, 3, 3, + 54, 2> + _table_; + friend class ::google::protobuf::MessageLite; + friend class ::google::protobuf::Arena; + template + friend class ::google::protobuf::Arena::InternalHelper; + using InternalArenaConstructable_ = void; + using DestructorSkippable_ = void; + struct Impl_ { + + inline explicit constexpr Impl_( + ::google::protobuf::internal::ConstantInitialized) noexcept; + inline explicit Impl_(::google::protobuf::internal::InternalVisibility visibility, + ::google::protobuf::Arena* arena); + inline explicit Impl_(::google::protobuf::internal::InternalVisibility visibility, + ::google::protobuf::Arena* arena, const Impl_& from); + ::google::protobuf::RepeatedPtrField< ::google::firestore::v1::Value > args_; + ::google::protobuf::internal::MapField + options_; + ::google::protobuf::internal::ArenaStringPtr name_; + mutable ::google::protobuf::internal::CachedSize _cached_size_; + PROTOBUF_TSAN_DECLARE_MEMBER + }; + union { Impl_ _impl_; }; + friend struct ::TableStruct_google_2ffirestore_2fv1_2fdocument_2eproto; +};// ------------------------------------------------------------------- + +class Pipeline_Stage_OptionsEntry_DoNotUse final + : public ::google::protobuf::internal::MapEntry< + Pipeline_Stage_OptionsEntry_DoNotUse, std::string, ::google::firestore::v1::Value, + ::google::protobuf::internal::WireFormatLite::TYPE_STRING, + ::google::protobuf::internal::WireFormatLite::TYPE_MESSAGE> { + public: + using SuperType = ::google::protobuf::internal::MapEntry< + Pipeline_Stage_OptionsEntry_DoNotUse, std::string, ::google::firestore::v1::Value, + ::google::protobuf::internal::WireFormatLite::TYPE_STRING, + ::google::protobuf::internal::WireFormatLite::TYPE_MESSAGE>; + Pipeline_Stage_OptionsEntry_DoNotUse(); + template + explicit PROTOBUF_CONSTEXPR Pipeline_Stage_OptionsEntry_DoNotUse( + ::google::protobuf::internal::ConstantInitialized); + explicit Pipeline_Stage_OptionsEntry_DoNotUse(::google::protobuf::Arena* arena); + static const Pipeline_Stage_OptionsEntry_DoNotUse* internal_default_instance() { + return reinterpret_cast( + &_Pipeline_Stage_OptionsEntry_DoNotUse_default_instance_); + } + static bool ValidateKey(std::string* s) { + return ::google::protobuf::internal::WireFormatLite::VerifyUtf8String(s->data(), static_cast(s->size()), ::google::protobuf::internal::WireFormatLite::PARSE, "google.firestore.v1.Pipeline.Stage.OptionsEntry.key"); + } + static bool ValidateValue(void*) { return true; } + ::google::protobuf::Metadata GetMetadata() const final; + friend struct ::TableStruct_google_2ffirestore_2fv1_2fdocument_2eproto; +}; +// ------------------------------------------------------------------- + +class Value final : + public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:google.firestore.v1.Value) */ { + public: + inline Value() : Value(nullptr) {} + ~Value() override; + template + explicit PROTOBUF_CONSTEXPR Value(::google::protobuf::internal::ConstantInitialized); + + inline Value(const Value& from) + : Value(nullptr, from) {} + Value(Value&& from) noexcept + : Value() { + *this = ::std::move(from); + } + + inline Value& operator=(const Value& from) { + CopyFrom(from); + return *this; + } + inline Value& operator=(Value&& from) noexcept { + if (this == &from) return *this; + if (GetArena() == from.GetArena() + #ifdef PROTOBUF_FORCE_COPY_IN_MOVE + && GetArena() != nullptr + #endif // !PROTOBUF_FORCE_COPY_IN_MOVE + ) { + InternalSwap(&from); + } else { + CopyFrom(from); + } + return *this; + } + + inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const + ABSL_ATTRIBUTE_LIFETIME_BOUND { + return _internal_metadata_.unknown_fields<::google::protobuf::UnknownFieldSet>(::google::protobuf::UnknownFieldSet::default_instance); + } + inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() + ABSL_ATTRIBUTE_LIFETIME_BOUND { + return _internal_metadata_.mutable_unknown_fields<::google::protobuf::UnknownFieldSet>(); + } + + static const ::google::protobuf::Descriptor* descriptor() { + return GetDescriptor(); + } + static const ::google::protobuf::Descriptor* GetDescriptor() { + return default_instance().GetMetadata().descriptor; + } + static const ::google::protobuf::Reflection* GetReflection() { + return default_instance().GetMetadata().reflection; + } + static const Value& default_instance() { + return *internal_default_instance(); + } + enum ValueTypeCase { + kNullValue = 11, + kBooleanValue = 1, + kIntegerValue = 2, + kDoubleValue = 3, + kTimestampValue = 10, + kStringValue = 17, + kBytesValue = 18, + kReferenceValue = 5, + kGeoPointValue = 8, + kArrayValue = 9, + kMapValue = 6, + kFieldReferenceValue = 19, + kFunctionValue = 20, + kPipelineValue = 21, + VALUE_TYPE_NOT_SET = 0, + }; + + static inline const Value* internal_default_instance() { + return reinterpret_cast( + &_Value_default_instance_); + } + static constexpr int kIndexInFileMessages = + 2; + + friend void swap(Value& a, Value& b) { + a.Swap(&b); + } + inline void Swap(Value* other) { + if (other == this) return; + #ifdef PROTOBUF_FORCE_COPY_IN_SWAP + if (GetArena() != nullptr && + GetArena() == other->GetArena()) { + #else // PROTOBUF_FORCE_COPY_IN_SWAP + if (GetArena() == other->GetArena()) { + #endif // !PROTOBUF_FORCE_COPY_IN_SWAP + InternalSwap(other); + } else { + ::google::protobuf::internal::GenericSwap(this, other); + } + } + void UnsafeArenaSwap(Value* other) { + if (other == this) return; + ABSL_DCHECK(GetArena() == other->GetArena()); + InternalSwap(other); + } + + // implements Message ---------------------------------------------- + + Value* New(::google::protobuf::Arena* arena = nullptr) const final { + return CreateMaybeMessage(arena); + } + using ::google::protobuf::Message::CopyFrom; + void CopyFrom(const Value& from); + using ::google::protobuf::Message::MergeFrom; + void MergeFrom( const Value& from) { + Value::MergeImpl(*this, from); + } + private: + static void MergeImpl(::google::protobuf::Message& to_msg, const ::google::protobuf::Message& from_msg); + public: + PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final; + bool IsInitialized() const final; + + ::size_t ByteSizeLong() const final; + const char* _InternalParse(const char* ptr, ::google::protobuf::internal::ParseContext* ctx) final; + ::uint8_t* _InternalSerialize( + ::uint8_t* target, ::google::protobuf::io::EpsCopyOutputStream* stream) const final; + int GetCachedSize() const { return _impl_._cached_size_.Get(); } + + private: + ::google::protobuf::internal::CachedSize* AccessCachedSize() const final; + void SharedCtor(::google::protobuf::Arena* arena); + void SharedDtor(); + void InternalSwap(Value* other); + + private: + friend class ::google::protobuf::internal::AnyMetadata; + static ::absl::string_view FullMessageName() { + return "google.firestore.v1.Value"; + } + protected: + explicit Value(::google::protobuf::Arena* arena); + Value(::google::protobuf::Arena* arena, const Value& from); + public: + + static const ClassData _class_data_; + const ::google::protobuf::Message::ClassData*GetClassData() const final; + + ::google::protobuf::Metadata GetMetadata() const final; + + // nested types ---------------------------------------------------- + + // accessors ------------------------------------------------------- + + enum : int { + kNullValueFieldNumber = 11, + kBooleanValueFieldNumber = 1, + kIntegerValueFieldNumber = 2, + kDoubleValueFieldNumber = 3, + kTimestampValueFieldNumber = 10, + kStringValueFieldNumber = 17, + kBytesValueFieldNumber = 18, + kReferenceValueFieldNumber = 5, + kGeoPointValueFieldNumber = 8, + kArrayValueFieldNumber = 9, + kMapValueFieldNumber = 6, + kFieldReferenceValueFieldNumber = 19, + kFunctionValueFieldNumber = 20, + kPipelineValueFieldNumber = 21, + }; + // .google.protobuf.NullValue null_value = 11; + bool has_null_value() const; + void clear_null_value() ; + ::google::protobuf::NullValue null_value() const; + void set_null_value(::google::protobuf::NullValue value); + + private: + ::google::protobuf::NullValue _internal_null_value() const; + void _internal_set_null_value(::google::protobuf::NullValue value); + + public: + // bool boolean_value = 1; + bool has_boolean_value() const; + void clear_boolean_value() ; + bool boolean_value() const; + void set_boolean_value(bool value); + + private: + bool _internal_boolean_value() const; + void _internal_set_boolean_value(bool value); + public: // int64 integer_value = 2; bool has_integer_value() const; @@ -837,6 +1544,61 @@ class Value final : const ::google::firestore::v1::MapValue& _internal_map_value() const; ::google::firestore::v1::MapValue* _internal_mutable_map_value(); + public: + // string field_reference_value = 19; + bool has_field_reference_value() const; + void clear_field_reference_value() ; + const std::string& field_reference_value() const; + template + void set_field_reference_value(Arg_&& arg, Args_... args); + std::string* mutable_field_reference_value(); + PROTOBUF_NODISCARD std::string* release_field_reference_value(); + void set_allocated_field_reference_value(std::string* value); + + private: + const std::string& _internal_field_reference_value() const; + inline PROTOBUF_ALWAYS_INLINE void _internal_set_field_reference_value( + const std::string& value); + std::string* _internal_mutable_field_reference_value(); + + public: + // .google.firestore.v1.Function function_value = 20; + bool has_function_value() const; + private: + bool _internal_has_function_value() const; + + public: + void clear_function_value() ; + const ::google::firestore::v1::Function& function_value() const; + PROTOBUF_NODISCARD ::google::firestore::v1::Function* release_function_value(); + ::google::firestore::v1::Function* mutable_function_value(); + void set_allocated_function_value(::google::firestore::v1::Function* value); + void unsafe_arena_set_allocated_function_value(::google::firestore::v1::Function* value); + ::google::firestore::v1::Function* unsafe_arena_release_function_value(); + + private: + const ::google::firestore::v1::Function& _internal_function_value() const; + ::google::firestore::v1::Function* _internal_mutable_function_value(); + + public: + // .google.firestore.v1.Pipeline pipeline_value = 21; + bool has_pipeline_value() const; + private: + bool _internal_has_pipeline_value() const; + + public: + void clear_pipeline_value() ; + const ::google::firestore::v1::Pipeline& pipeline_value() const; + PROTOBUF_NODISCARD ::google::firestore::v1::Pipeline* release_pipeline_value(); + ::google::firestore::v1::Pipeline* mutable_pipeline_value(); + void set_allocated_pipeline_value(::google::firestore::v1::Pipeline* value); + void unsafe_arena_set_allocated_pipeline_value(::google::firestore::v1::Pipeline* value); + ::google::firestore::v1::Pipeline* unsafe_arena_release_pipeline_value(); + + private: + const ::google::firestore::v1::Pipeline& _internal_pipeline_value() const; + ::google::firestore::v1::Pipeline* _internal_mutable_pipeline_value(); + public: void clear_value_type(); ValueTypeCase value_type_case() const; @@ -854,14 +1616,17 @@ class Value final : void set_has_geo_point_value(); void set_has_array_value(); void set_has_map_value(); + void set_has_field_reference_value(); + void set_has_function_value(); + void set_has_pipeline_value(); inline bool has_value_type() const; inline void clear_has_value_type(); friend class ::google::protobuf::internal::TcParser; static const ::google::protobuf::internal::TcParseTable< - 0, 11, 4, - 69, 2> + 0, 14, 6, + 90, 2> _table_; friend class ::google::protobuf::MessageLite; friend class ::google::protobuf::Arena; @@ -891,6 +1656,9 @@ class Value final : ::google::type::LatLng* geo_point_value_; ::google::firestore::v1::ArrayValue* array_value_; ::google::firestore::v1::MapValue* map_value_; + ::google::protobuf::internal::ArenaStringPtr field_reference_value_; + ::google::firestore::v1::Function* function_value_; + ::google::firestore::v1::Pipeline* pipeline_value_; } value_type_; mutable ::google::protobuf::internal::CachedSize _cached_size_; ::uint32_t _oneof_case_[1]; @@ -1984,155 +2752,392 @@ inline ::google::type::LatLng* Value::mutable_geo_point_value() ABSL_ATTRIBUTE_L return _msg; } -// .google.firestore.v1.ArrayValue array_value = 9; -inline bool Value::has_array_value() const { - return value_type_case() == kArrayValue; +// .google.firestore.v1.ArrayValue array_value = 9; +inline bool Value::has_array_value() const { + return value_type_case() == kArrayValue; +} +inline bool Value::_internal_has_array_value() const { + return value_type_case() == kArrayValue; +} +inline void Value::set_has_array_value() { + _impl_._oneof_case_[0] = kArrayValue; +} +inline void Value::clear_array_value() { + PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); + if (value_type_case() == kArrayValue) { + if (GetArena() == nullptr) { + delete _impl_.value_type_.array_value_; + } + clear_has_value_type(); + } +} +inline ::google::firestore::v1::ArrayValue* Value::release_array_value() { + // @@protoc_insertion_point(field_release:google.firestore.v1.Value.array_value) + if (value_type_case() == kArrayValue) { + clear_has_value_type(); + auto* temp = _impl_.value_type_.array_value_; + if (GetArena() != nullptr) { + temp = ::google::protobuf::internal::DuplicateIfNonNull(temp); + } + _impl_.value_type_.array_value_ = nullptr; + return temp; + } else { + return nullptr; + } +} +inline const ::google::firestore::v1::ArrayValue& Value::_internal_array_value() const { + return value_type_case() == kArrayValue ? *_impl_.value_type_.array_value_ : reinterpret_cast<::google::firestore::v1::ArrayValue&>(::google::firestore::v1::_ArrayValue_default_instance_); +} +inline const ::google::firestore::v1::ArrayValue& Value::array_value() const ABSL_ATTRIBUTE_LIFETIME_BOUND { + // @@protoc_insertion_point(field_get:google.firestore.v1.Value.array_value) + return _internal_array_value(); +} +inline ::google::firestore::v1::ArrayValue* Value::unsafe_arena_release_array_value() { + // @@protoc_insertion_point(field_unsafe_arena_release:google.firestore.v1.Value.array_value) + if (value_type_case() == kArrayValue) { + clear_has_value_type(); + auto* temp = _impl_.value_type_.array_value_; + _impl_.value_type_.array_value_ = nullptr; + return temp; + } else { + return nullptr; + } +} +inline void Value::unsafe_arena_set_allocated_array_value(::google::firestore::v1::ArrayValue* value) { + // We rely on the oneof clear method to free the earlier contents + // of this oneof. We can directly use the pointer we're given to + // set the new value. + clear_value_type(); + if (value) { + set_has_array_value(); + _impl_.value_type_.array_value_ = value; + } + // @@protoc_insertion_point(field_unsafe_arena_set_allocated:google.firestore.v1.Value.array_value) +} +inline ::google::firestore::v1::ArrayValue* Value::_internal_mutable_array_value() { + if (value_type_case() != kArrayValue) { + clear_value_type(); + set_has_array_value(); + _impl_.value_type_.array_value_ = CreateMaybeMessage<::google::firestore::v1::ArrayValue>(GetArena()); + } + return _impl_.value_type_.array_value_; +} +inline ::google::firestore::v1::ArrayValue* Value::mutable_array_value() ABSL_ATTRIBUTE_LIFETIME_BOUND { + ::google::firestore::v1::ArrayValue* _msg = _internal_mutable_array_value(); + // @@protoc_insertion_point(field_mutable:google.firestore.v1.Value.array_value) + return _msg; +} + +// .google.firestore.v1.MapValue map_value = 6; +inline bool Value::has_map_value() const { + return value_type_case() == kMapValue; +} +inline bool Value::_internal_has_map_value() const { + return value_type_case() == kMapValue; +} +inline void Value::set_has_map_value() { + _impl_._oneof_case_[0] = kMapValue; +} +inline void Value::clear_map_value() { + PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); + if (value_type_case() == kMapValue) { + if (GetArena() == nullptr) { + delete _impl_.value_type_.map_value_; + } + clear_has_value_type(); + } +} +inline ::google::firestore::v1::MapValue* Value::release_map_value() { + // @@protoc_insertion_point(field_release:google.firestore.v1.Value.map_value) + if (value_type_case() == kMapValue) { + clear_has_value_type(); + auto* temp = _impl_.value_type_.map_value_; + if (GetArena() != nullptr) { + temp = ::google::protobuf::internal::DuplicateIfNonNull(temp); + } + _impl_.value_type_.map_value_ = nullptr; + return temp; + } else { + return nullptr; + } +} +inline const ::google::firestore::v1::MapValue& Value::_internal_map_value() const { + return value_type_case() == kMapValue ? *_impl_.value_type_.map_value_ : reinterpret_cast<::google::firestore::v1::MapValue&>(::google::firestore::v1::_MapValue_default_instance_); +} +inline const ::google::firestore::v1::MapValue& Value::map_value() const ABSL_ATTRIBUTE_LIFETIME_BOUND { + // @@protoc_insertion_point(field_get:google.firestore.v1.Value.map_value) + return _internal_map_value(); +} +inline ::google::firestore::v1::MapValue* Value::unsafe_arena_release_map_value() { + // @@protoc_insertion_point(field_unsafe_arena_release:google.firestore.v1.Value.map_value) + if (value_type_case() == kMapValue) { + clear_has_value_type(); + auto* temp = _impl_.value_type_.map_value_; + _impl_.value_type_.map_value_ = nullptr; + return temp; + } else { + return nullptr; + } +} +inline void Value::unsafe_arena_set_allocated_map_value(::google::firestore::v1::MapValue* value) { + // We rely on the oneof clear method to free the earlier contents + // of this oneof. We can directly use the pointer we're given to + // set the new value. + clear_value_type(); + if (value) { + set_has_map_value(); + _impl_.value_type_.map_value_ = value; + } + // @@protoc_insertion_point(field_unsafe_arena_set_allocated:google.firestore.v1.Value.map_value) +} +inline ::google::firestore::v1::MapValue* Value::_internal_mutable_map_value() { + if (value_type_case() != kMapValue) { + clear_value_type(); + set_has_map_value(); + _impl_.value_type_.map_value_ = CreateMaybeMessage<::google::firestore::v1::MapValue>(GetArena()); + } + return _impl_.value_type_.map_value_; +} +inline ::google::firestore::v1::MapValue* Value::mutable_map_value() ABSL_ATTRIBUTE_LIFETIME_BOUND { + ::google::firestore::v1::MapValue* _msg = _internal_mutable_map_value(); + // @@protoc_insertion_point(field_mutable:google.firestore.v1.Value.map_value) + return _msg; +} + +// string field_reference_value = 19; +inline bool Value::has_field_reference_value() const { + return value_type_case() == kFieldReferenceValue; +} +inline void Value::set_has_field_reference_value() { + _impl_._oneof_case_[0] = kFieldReferenceValue; +} +inline void Value::clear_field_reference_value() { + PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); + if (value_type_case() == kFieldReferenceValue) { + _impl_.value_type_.field_reference_value_.Destroy(); + clear_has_value_type(); + } +} +inline const std::string& Value::field_reference_value() const + ABSL_ATTRIBUTE_LIFETIME_BOUND { + // @@protoc_insertion_point(field_get:google.firestore.v1.Value.field_reference_value) + return _internal_field_reference_value(); +} +template +inline PROTOBUF_ALWAYS_INLINE void Value::set_field_reference_value(Arg_&& arg, + Args_... args) { + PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); + if (value_type_case() != kFieldReferenceValue) { + clear_value_type(); + + set_has_field_reference_value(); + _impl_.value_type_.field_reference_value_.InitDefault(); + } + _impl_.value_type_.field_reference_value_.Set(static_cast(arg), args..., GetArena()); + // @@protoc_insertion_point(field_set:google.firestore.v1.Value.field_reference_value) +} +inline std::string* Value::mutable_field_reference_value() ABSL_ATTRIBUTE_LIFETIME_BOUND { + std::string* _s = _internal_mutable_field_reference_value(); + // @@protoc_insertion_point(field_mutable:google.firestore.v1.Value.field_reference_value) + return _s; +} +inline const std::string& Value::_internal_field_reference_value() const { + PROTOBUF_TSAN_READ(&_impl_._tsan_detect_race); + if (value_type_case() != kFieldReferenceValue) { + return ::google::protobuf::internal::GetEmptyStringAlreadyInited(); + } + return _impl_.value_type_.field_reference_value_.Get(); +} +inline void Value::_internal_set_field_reference_value(const std::string& value) { + PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); + if (value_type_case() != kFieldReferenceValue) { + clear_value_type(); + + set_has_field_reference_value(); + _impl_.value_type_.field_reference_value_.InitDefault(); + } + _impl_.value_type_.field_reference_value_.Set(value, GetArena()); +} +inline std::string* Value::_internal_mutable_field_reference_value() { + PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); + if (value_type_case() != kFieldReferenceValue) { + clear_value_type(); + + set_has_field_reference_value(); + _impl_.value_type_.field_reference_value_.InitDefault(); + } + return _impl_.value_type_.field_reference_value_.Mutable( GetArena()); +} +inline std::string* Value::release_field_reference_value() { + PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); + // @@protoc_insertion_point(field_release:google.firestore.v1.Value.field_reference_value) + if (value_type_case() != kFieldReferenceValue) { + return nullptr; + } + clear_has_value_type(); + return _impl_.value_type_.field_reference_value_.Release(); +} +inline void Value::set_allocated_field_reference_value(std::string* value) { + PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); + if (has_value_type()) { + clear_value_type(); + } + if (value != nullptr) { + set_has_field_reference_value(); + _impl_.value_type_.field_reference_value_.InitAllocated(value, GetArena()); + } + // @@protoc_insertion_point(field_set_allocated:google.firestore.v1.Value.field_reference_value) +} + +// .google.firestore.v1.Function function_value = 20; +inline bool Value::has_function_value() const { + return value_type_case() == kFunctionValue; } -inline bool Value::_internal_has_array_value() const { - return value_type_case() == kArrayValue; +inline bool Value::_internal_has_function_value() const { + return value_type_case() == kFunctionValue; } -inline void Value::set_has_array_value() { - _impl_._oneof_case_[0] = kArrayValue; +inline void Value::set_has_function_value() { + _impl_._oneof_case_[0] = kFunctionValue; } -inline void Value::clear_array_value() { +inline void Value::clear_function_value() { PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); - if (value_type_case() == kArrayValue) { + if (value_type_case() == kFunctionValue) { if (GetArena() == nullptr) { - delete _impl_.value_type_.array_value_; + delete _impl_.value_type_.function_value_; } clear_has_value_type(); } } -inline ::google::firestore::v1::ArrayValue* Value::release_array_value() { - // @@protoc_insertion_point(field_release:google.firestore.v1.Value.array_value) - if (value_type_case() == kArrayValue) { +inline ::google::firestore::v1::Function* Value::release_function_value() { + // @@protoc_insertion_point(field_release:google.firestore.v1.Value.function_value) + if (value_type_case() == kFunctionValue) { clear_has_value_type(); - auto* temp = _impl_.value_type_.array_value_; + auto* temp = _impl_.value_type_.function_value_; if (GetArena() != nullptr) { temp = ::google::protobuf::internal::DuplicateIfNonNull(temp); } - _impl_.value_type_.array_value_ = nullptr; + _impl_.value_type_.function_value_ = nullptr; return temp; } else { return nullptr; } } -inline const ::google::firestore::v1::ArrayValue& Value::_internal_array_value() const { - return value_type_case() == kArrayValue ? *_impl_.value_type_.array_value_ : reinterpret_cast<::google::firestore::v1::ArrayValue&>(::google::firestore::v1::_ArrayValue_default_instance_); +inline const ::google::firestore::v1::Function& Value::_internal_function_value() const { + return value_type_case() == kFunctionValue ? *_impl_.value_type_.function_value_ : reinterpret_cast<::google::firestore::v1::Function&>(::google::firestore::v1::_Function_default_instance_); } -inline const ::google::firestore::v1::ArrayValue& Value::array_value() const ABSL_ATTRIBUTE_LIFETIME_BOUND { - // @@protoc_insertion_point(field_get:google.firestore.v1.Value.array_value) - return _internal_array_value(); +inline const ::google::firestore::v1::Function& Value::function_value() const ABSL_ATTRIBUTE_LIFETIME_BOUND { + // @@protoc_insertion_point(field_get:google.firestore.v1.Value.function_value) + return _internal_function_value(); } -inline ::google::firestore::v1::ArrayValue* Value::unsafe_arena_release_array_value() { - // @@protoc_insertion_point(field_unsafe_arena_release:google.firestore.v1.Value.array_value) - if (value_type_case() == kArrayValue) { +inline ::google::firestore::v1::Function* Value::unsafe_arena_release_function_value() { + // @@protoc_insertion_point(field_unsafe_arena_release:google.firestore.v1.Value.function_value) + if (value_type_case() == kFunctionValue) { clear_has_value_type(); - auto* temp = _impl_.value_type_.array_value_; - _impl_.value_type_.array_value_ = nullptr; + auto* temp = _impl_.value_type_.function_value_; + _impl_.value_type_.function_value_ = nullptr; return temp; } else { return nullptr; } } -inline void Value::unsafe_arena_set_allocated_array_value(::google::firestore::v1::ArrayValue* value) { +inline void Value::unsafe_arena_set_allocated_function_value(::google::firestore::v1::Function* value) { // We rely on the oneof clear method to free the earlier contents // of this oneof. We can directly use the pointer we're given to // set the new value. clear_value_type(); if (value) { - set_has_array_value(); - _impl_.value_type_.array_value_ = value; + set_has_function_value(); + _impl_.value_type_.function_value_ = value; } - // @@protoc_insertion_point(field_unsafe_arena_set_allocated:google.firestore.v1.Value.array_value) + // @@protoc_insertion_point(field_unsafe_arena_set_allocated:google.firestore.v1.Value.function_value) } -inline ::google::firestore::v1::ArrayValue* Value::_internal_mutable_array_value() { - if (value_type_case() != kArrayValue) { +inline ::google::firestore::v1::Function* Value::_internal_mutable_function_value() { + if (value_type_case() != kFunctionValue) { clear_value_type(); - set_has_array_value(); - _impl_.value_type_.array_value_ = CreateMaybeMessage<::google::firestore::v1::ArrayValue>(GetArena()); + set_has_function_value(); + _impl_.value_type_.function_value_ = CreateMaybeMessage<::google::firestore::v1::Function>(GetArena()); } - return _impl_.value_type_.array_value_; + return _impl_.value_type_.function_value_; } -inline ::google::firestore::v1::ArrayValue* Value::mutable_array_value() ABSL_ATTRIBUTE_LIFETIME_BOUND { - ::google::firestore::v1::ArrayValue* _msg = _internal_mutable_array_value(); - // @@protoc_insertion_point(field_mutable:google.firestore.v1.Value.array_value) +inline ::google::firestore::v1::Function* Value::mutable_function_value() ABSL_ATTRIBUTE_LIFETIME_BOUND { + ::google::firestore::v1::Function* _msg = _internal_mutable_function_value(); + // @@protoc_insertion_point(field_mutable:google.firestore.v1.Value.function_value) return _msg; } -// .google.firestore.v1.MapValue map_value = 6; -inline bool Value::has_map_value() const { - return value_type_case() == kMapValue; +// .google.firestore.v1.Pipeline pipeline_value = 21; +inline bool Value::has_pipeline_value() const { + return value_type_case() == kPipelineValue; } -inline bool Value::_internal_has_map_value() const { - return value_type_case() == kMapValue; +inline bool Value::_internal_has_pipeline_value() const { + return value_type_case() == kPipelineValue; } -inline void Value::set_has_map_value() { - _impl_._oneof_case_[0] = kMapValue; +inline void Value::set_has_pipeline_value() { + _impl_._oneof_case_[0] = kPipelineValue; } -inline void Value::clear_map_value() { +inline void Value::clear_pipeline_value() { PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); - if (value_type_case() == kMapValue) { + if (value_type_case() == kPipelineValue) { if (GetArena() == nullptr) { - delete _impl_.value_type_.map_value_; + delete _impl_.value_type_.pipeline_value_; } clear_has_value_type(); } } -inline ::google::firestore::v1::MapValue* Value::release_map_value() { - // @@protoc_insertion_point(field_release:google.firestore.v1.Value.map_value) - if (value_type_case() == kMapValue) { +inline ::google::firestore::v1::Pipeline* Value::release_pipeline_value() { + // @@protoc_insertion_point(field_release:google.firestore.v1.Value.pipeline_value) + if (value_type_case() == kPipelineValue) { clear_has_value_type(); - auto* temp = _impl_.value_type_.map_value_; + auto* temp = _impl_.value_type_.pipeline_value_; if (GetArena() != nullptr) { temp = ::google::protobuf::internal::DuplicateIfNonNull(temp); } - _impl_.value_type_.map_value_ = nullptr; + _impl_.value_type_.pipeline_value_ = nullptr; return temp; } else { return nullptr; } } -inline const ::google::firestore::v1::MapValue& Value::_internal_map_value() const { - return value_type_case() == kMapValue ? *_impl_.value_type_.map_value_ : reinterpret_cast<::google::firestore::v1::MapValue&>(::google::firestore::v1::_MapValue_default_instance_); +inline const ::google::firestore::v1::Pipeline& Value::_internal_pipeline_value() const { + return value_type_case() == kPipelineValue ? *_impl_.value_type_.pipeline_value_ : reinterpret_cast<::google::firestore::v1::Pipeline&>(::google::firestore::v1::_Pipeline_default_instance_); } -inline const ::google::firestore::v1::MapValue& Value::map_value() const ABSL_ATTRIBUTE_LIFETIME_BOUND { - // @@protoc_insertion_point(field_get:google.firestore.v1.Value.map_value) - return _internal_map_value(); +inline const ::google::firestore::v1::Pipeline& Value::pipeline_value() const ABSL_ATTRIBUTE_LIFETIME_BOUND { + // @@protoc_insertion_point(field_get:google.firestore.v1.Value.pipeline_value) + return _internal_pipeline_value(); } -inline ::google::firestore::v1::MapValue* Value::unsafe_arena_release_map_value() { - // @@protoc_insertion_point(field_unsafe_arena_release:google.firestore.v1.Value.map_value) - if (value_type_case() == kMapValue) { +inline ::google::firestore::v1::Pipeline* Value::unsafe_arena_release_pipeline_value() { + // @@protoc_insertion_point(field_unsafe_arena_release:google.firestore.v1.Value.pipeline_value) + if (value_type_case() == kPipelineValue) { clear_has_value_type(); - auto* temp = _impl_.value_type_.map_value_; - _impl_.value_type_.map_value_ = nullptr; + auto* temp = _impl_.value_type_.pipeline_value_; + _impl_.value_type_.pipeline_value_ = nullptr; return temp; } else { return nullptr; } } -inline void Value::unsafe_arena_set_allocated_map_value(::google::firestore::v1::MapValue* value) { +inline void Value::unsafe_arena_set_allocated_pipeline_value(::google::firestore::v1::Pipeline* value) { // We rely on the oneof clear method to free the earlier contents // of this oneof. We can directly use the pointer we're given to // set the new value. clear_value_type(); if (value) { - set_has_map_value(); - _impl_.value_type_.map_value_ = value; + set_has_pipeline_value(); + _impl_.value_type_.pipeline_value_ = value; } - // @@protoc_insertion_point(field_unsafe_arena_set_allocated:google.firestore.v1.Value.map_value) + // @@protoc_insertion_point(field_unsafe_arena_set_allocated:google.firestore.v1.Value.pipeline_value) } -inline ::google::firestore::v1::MapValue* Value::_internal_mutable_map_value() { - if (value_type_case() != kMapValue) { +inline ::google::firestore::v1::Pipeline* Value::_internal_mutable_pipeline_value() { + if (value_type_case() != kPipelineValue) { clear_value_type(); - set_has_map_value(); - _impl_.value_type_.map_value_ = CreateMaybeMessage<::google::firestore::v1::MapValue>(GetArena()); + set_has_pipeline_value(); + _impl_.value_type_.pipeline_value_ = CreateMaybeMessage<::google::firestore::v1::Pipeline>(GetArena()); } - return _impl_.value_type_.map_value_; + return _impl_.value_type_.pipeline_value_; } -inline ::google::firestore::v1::MapValue* Value::mutable_map_value() ABSL_ATTRIBUTE_LIFETIME_BOUND { - ::google::firestore::v1::MapValue* _msg = _internal_mutable_map_value(); - // @@protoc_insertion_point(field_mutable:google.firestore.v1.Value.map_value) +inline ::google::firestore::v1::Pipeline* Value::mutable_pipeline_value() ABSL_ATTRIBUTE_LIFETIME_BOUND { + ::google::firestore::v1::Pipeline* _msg = _internal_mutable_pipeline_value(); + // @@protoc_insertion_point(field_mutable:google.firestore.v1.Value.pipeline_value) return _msg; } @@ -2232,6 +3237,331 @@ inline ::google::protobuf::Map* Map return _internal_mutable_fields(); } +// ------------------------------------------------------------------- + +// ------------------------------------------------------------------- + +// Function + +// string name = 1 [(.google.api.field_behavior) = REQUIRED]; +inline void Function::clear_name() { + PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); + _impl_.name_.ClearToEmpty(); +} +inline const std::string& Function::name() const + ABSL_ATTRIBUTE_LIFETIME_BOUND { + // @@protoc_insertion_point(field_get:google.firestore.v1.Function.name) + return _internal_name(); +} +template +inline PROTOBUF_ALWAYS_INLINE void Function::set_name(Arg_&& arg, + Args_... args) { + PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); + ; + _impl_.name_.Set(static_cast(arg), args..., GetArena()); + // @@protoc_insertion_point(field_set:google.firestore.v1.Function.name) +} +inline std::string* Function::mutable_name() ABSL_ATTRIBUTE_LIFETIME_BOUND { + std::string* _s = _internal_mutable_name(); + // @@protoc_insertion_point(field_mutable:google.firestore.v1.Function.name) + return _s; +} +inline const std::string& Function::_internal_name() const { + PROTOBUF_TSAN_READ(&_impl_._tsan_detect_race); + return _impl_.name_.Get(); +} +inline void Function::_internal_set_name(const std::string& value) { + PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); + ; + _impl_.name_.Set(value, GetArena()); +} +inline std::string* Function::_internal_mutable_name() { + PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); + ; + return _impl_.name_.Mutable( GetArena()); +} +inline std::string* Function::release_name() { + PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); + // @@protoc_insertion_point(field_release:google.firestore.v1.Function.name) + return _impl_.name_.Release(); +} +inline void Function::set_allocated_name(std::string* value) { + PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); + _impl_.name_.SetAllocated(value, GetArena()); + #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING + if (_impl_.name_.IsDefault()) { + _impl_.name_.Set("", GetArena()); + } + #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING + // @@protoc_insertion_point(field_set_allocated:google.firestore.v1.Function.name) +} + +// repeated .google.firestore.v1.Value args = 2 [(.google.api.field_behavior) = OPTIONAL]; +inline int Function::_internal_args_size() const { + return _internal_args().size(); +} +inline int Function::args_size() const { + return _internal_args_size(); +} +inline void Function::clear_args() { + PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); + _impl_.args_.Clear(); +} +inline ::google::firestore::v1::Value* Function::mutable_args(int index) + ABSL_ATTRIBUTE_LIFETIME_BOUND { + // @@protoc_insertion_point(field_mutable:google.firestore.v1.Function.args) + return _internal_mutable_args()->Mutable(index); +} +inline ::google::protobuf::RepeatedPtrField<::google::firestore::v1::Value>* Function::mutable_args() + ABSL_ATTRIBUTE_LIFETIME_BOUND { + // @@protoc_insertion_point(field_mutable_list:google.firestore.v1.Function.args) + PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); + return _internal_mutable_args(); +} +inline const ::google::firestore::v1::Value& Function::args(int index) const + ABSL_ATTRIBUTE_LIFETIME_BOUND { + // @@protoc_insertion_point(field_get:google.firestore.v1.Function.args) + return _internal_args().Get(index); +} +inline ::google::firestore::v1::Value* Function::add_args() ABSL_ATTRIBUTE_LIFETIME_BOUND { + PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); + ::google::firestore::v1::Value* _add = _internal_mutable_args()->Add(); + // @@protoc_insertion_point(field_add:google.firestore.v1.Function.args) + return _add; +} +inline const ::google::protobuf::RepeatedPtrField<::google::firestore::v1::Value>& Function::args() const + ABSL_ATTRIBUTE_LIFETIME_BOUND { + // @@protoc_insertion_point(field_list:google.firestore.v1.Function.args) + return _internal_args(); +} +inline const ::google::protobuf::RepeatedPtrField<::google::firestore::v1::Value>& +Function::_internal_args() const { + PROTOBUF_TSAN_READ(&_impl_._tsan_detect_race); + return _impl_.args_; +} +inline ::google::protobuf::RepeatedPtrField<::google::firestore::v1::Value>* +Function::_internal_mutable_args() { + PROTOBUF_TSAN_READ(&_impl_._tsan_detect_race); + return &_impl_.args_; +} + +// map options = 3 [(.google.api.field_behavior) = OPTIONAL]; +inline int Function::_internal_options_size() const { + return _internal_options().size(); +} +inline int Function::options_size() const { + return _internal_options_size(); +} +inline void Function::clear_options() { + PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); + _impl_.options_.Clear(); +} +inline const ::google::protobuf::Map& Function::_internal_options() const { + PROTOBUF_TSAN_READ(&_impl_._tsan_detect_race); + return _impl_.options_.GetMap(); +} +inline const ::google::protobuf::Map& Function::options() const ABSL_ATTRIBUTE_LIFETIME_BOUND { + // @@protoc_insertion_point(field_map:google.firestore.v1.Function.options) + return _internal_options(); +} +inline ::google::protobuf::Map* Function::_internal_mutable_options() { + PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); + return _impl_.options_.MutableMap(); +} +inline ::google::protobuf::Map* Function::mutable_options() ABSL_ATTRIBUTE_LIFETIME_BOUND { + // @@protoc_insertion_point(field_mutable_map:google.firestore.v1.Function.options) + return _internal_mutable_options(); +} + +// ------------------------------------------------------------------- + +// ------------------------------------------------------------------- + +// Pipeline_Stage + +// string name = 1 [(.google.api.field_behavior) = REQUIRED]; +inline void Pipeline_Stage::clear_name() { + PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); + _impl_.name_.ClearToEmpty(); +} +inline const std::string& Pipeline_Stage::name() const + ABSL_ATTRIBUTE_LIFETIME_BOUND { + // @@protoc_insertion_point(field_get:google.firestore.v1.Pipeline.Stage.name) + return _internal_name(); +} +template +inline PROTOBUF_ALWAYS_INLINE void Pipeline_Stage::set_name(Arg_&& arg, + Args_... args) { + PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); + ; + _impl_.name_.Set(static_cast(arg), args..., GetArena()); + // @@protoc_insertion_point(field_set:google.firestore.v1.Pipeline.Stage.name) +} +inline std::string* Pipeline_Stage::mutable_name() ABSL_ATTRIBUTE_LIFETIME_BOUND { + std::string* _s = _internal_mutable_name(); + // @@protoc_insertion_point(field_mutable:google.firestore.v1.Pipeline.Stage.name) + return _s; +} +inline const std::string& Pipeline_Stage::_internal_name() const { + PROTOBUF_TSAN_READ(&_impl_._tsan_detect_race); + return _impl_.name_.Get(); +} +inline void Pipeline_Stage::_internal_set_name(const std::string& value) { + PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); + ; + _impl_.name_.Set(value, GetArena()); +} +inline std::string* Pipeline_Stage::_internal_mutable_name() { + PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); + ; + return _impl_.name_.Mutable( GetArena()); +} +inline std::string* Pipeline_Stage::release_name() { + PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); + // @@protoc_insertion_point(field_release:google.firestore.v1.Pipeline.Stage.name) + return _impl_.name_.Release(); +} +inline void Pipeline_Stage::set_allocated_name(std::string* value) { + PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); + _impl_.name_.SetAllocated(value, GetArena()); + #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING + if (_impl_.name_.IsDefault()) { + _impl_.name_.Set("", GetArena()); + } + #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING + // @@protoc_insertion_point(field_set_allocated:google.firestore.v1.Pipeline.Stage.name) +} + +// repeated .google.firestore.v1.Value args = 2 [(.google.api.field_behavior) = OPTIONAL]; +inline int Pipeline_Stage::_internal_args_size() const { + return _internal_args().size(); +} +inline int Pipeline_Stage::args_size() const { + return _internal_args_size(); +} +inline void Pipeline_Stage::clear_args() { + PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); + _impl_.args_.Clear(); +} +inline ::google::firestore::v1::Value* Pipeline_Stage::mutable_args(int index) + ABSL_ATTRIBUTE_LIFETIME_BOUND { + // @@protoc_insertion_point(field_mutable:google.firestore.v1.Pipeline.Stage.args) + return _internal_mutable_args()->Mutable(index); +} +inline ::google::protobuf::RepeatedPtrField<::google::firestore::v1::Value>* Pipeline_Stage::mutable_args() + ABSL_ATTRIBUTE_LIFETIME_BOUND { + // @@protoc_insertion_point(field_mutable_list:google.firestore.v1.Pipeline.Stage.args) + PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); + return _internal_mutable_args(); +} +inline const ::google::firestore::v1::Value& Pipeline_Stage::args(int index) const + ABSL_ATTRIBUTE_LIFETIME_BOUND { + // @@protoc_insertion_point(field_get:google.firestore.v1.Pipeline.Stage.args) + return _internal_args().Get(index); +} +inline ::google::firestore::v1::Value* Pipeline_Stage::add_args() ABSL_ATTRIBUTE_LIFETIME_BOUND { + PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); + ::google::firestore::v1::Value* _add = _internal_mutable_args()->Add(); + // @@protoc_insertion_point(field_add:google.firestore.v1.Pipeline.Stage.args) + return _add; +} +inline const ::google::protobuf::RepeatedPtrField<::google::firestore::v1::Value>& Pipeline_Stage::args() const + ABSL_ATTRIBUTE_LIFETIME_BOUND { + // @@protoc_insertion_point(field_list:google.firestore.v1.Pipeline.Stage.args) + return _internal_args(); +} +inline const ::google::protobuf::RepeatedPtrField<::google::firestore::v1::Value>& +Pipeline_Stage::_internal_args() const { + PROTOBUF_TSAN_READ(&_impl_._tsan_detect_race); + return _impl_.args_; +} +inline ::google::protobuf::RepeatedPtrField<::google::firestore::v1::Value>* +Pipeline_Stage::_internal_mutable_args() { + PROTOBUF_TSAN_READ(&_impl_._tsan_detect_race); + return &_impl_.args_; +} + +// map options = 3 [(.google.api.field_behavior) = OPTIONAL]; +inline int Pipeline_Stage::_internal_options_size() const { + return _internal_options().size(); +} +inline int Pipeline_Stage::options_size() const { + return _internal_options_size(); +} +inline void Pipeline_Stage::clear_options() { + PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); + _impl_.options_.Clear(); +} +inline const ::google::protobuf::Map& Pipeline_Stage::_internal_options() const { + PROTOBUF_TSAN_READ(&_impl_._tsan_detect_race); + return _impl_.options_.GetMap(); +} +inline const ::google::protobuf::Map& Pipeline_Stage::options() const ABSL_ATTRIBUTE_LIFETIME_BOUND { + // @@protoc_insertion_point(field_map:google.firestore.v1.Pipeline.Stage.options) + return _internal_options(); +} +inline ::google::protobuf::Map* Pipeline_Stage::_internal_mutable_options() { + PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); + return _impl_.options_.MutableMap(); +} +inline ::google::protobuf::Map* Pipeline_Stage::mutable_options() ABSL_ATTRIBUTE_LIFETIME_BOUND { + // @@protoc_insertion_point(field_mutable_map:google.firestore.v1.Pipeline.Stage.options) + return _internal_mutable_options(); +} + +// ------------------------------------------------------------------- + +// Pipeline + +// repeated .google.firestore.v1.Pipeline.Stage stages = 1 [(.google.api.field_behavior) = REQUIRED]; +inline int Pipeline::_internal_stages_size() const { + return _internal_stages().size(); +} +inline int Pipeline::stages_size() const { + return _internal_stages_size(); +} +inline void Pipeline::clear_stages() { + PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); + _impl_.stages_.Clear(); +} +inline ::google::firestore::v1::Pipeline_Stage* Pipeline::mutable_stages(int index) + ABSL_ATTRIBUTE_LIFETIME_BOUND { + // @@protoc_insertion_point(field_mutable:google.firestore.v1.Pipeline.stages) + return _internal_mutable_stages()->Mutable(index); +} +inline ::google::protobuf::RepeatedPtrField<::google::firestore::v1::Pipeline_Stage>* Pipeline::mutable_stages() + ABSL_ATTRIBUTE_LIFETIME_BOUND { + // @@protoc_insertion_point(field_mutable_list:google.firestore.v1.Pipeline.stages) + PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); + return _internal_mutable_stages(); +} +inline const ::google::firestore::v1::Pipeline_Stage& Pipeline::stages(int index) const + ABSL_ATTRIBUTE_LIFETIME_BOUND { + // @@protoc_insertion_point(field_get:google.firestore.v1.Pipeline.stages) + return _internal_stages().Get(index); +} +inline ::google::firestore::v1::Pipeline_Stage* Pipeline::add_stages() ABSL_ATTRIBUTE_LIFETIME_BOUND { + PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); + ::google::firestore::v1::Pipeline_Stage* _add = _internal_mutable_stages()->Add(); + // @@protoc_insertion_point(field_add:google.firestore.v1.Pipeline.stages) + return _add; +} +inline const ::google::protobuf::RepeatedPtrField<::google::firestore::v1::Pipeline_Stage>& Pipeline::stages() const + ABSL_ATTRIBUTE_LIFETIME_BOUND { + // @@protoc_insertion_point(field_list:google.firestore.v1.Pipeline.stages) + return _internal_stages(); +} +inline const ::google::protobuf::RepeatedPtrField<::google::firestore::v1::Pipeline_Stage>& +Pipeline::_internal_stages() const { + PROTOBUF_TSAN_READ(&_impl_._tsan_detect_race); + return _impl_.stages_; +} +inline ::google::protobuf::RepeatedPtrField<::google::firestore::v1::Pipeline_Stage>* +Pipeline::_internal_mutable_stages() { + PROTOBUF_TSAN_READ(&_impl_._tsan_detect_race); + return &_impl_.stages_; +} + #ifdef __GNUC__ #pragma GCC diagnostic pop #endif // __GNUC__ diff --git a/Firestore/Protos/cpp/google/firestore/v1/explain_stats.pb.cc b/Firestore/Protos/cpp/google/firestore/v1/explain_stats.pb.cc new file mode 100644 index 00000000000..56f6a17eec0 --- /dev/null +++ b/Firestore/Protos/cpp/google/firestore/v1/explain_stats.pb.cc @@ -0,0 +1,366 @@ +/* + * Copyright 2025 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. + */ + +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: google/firestore/v1/explain_stats.proto + +#include "google/firestore/v1/explain_stats.pb.h" + +#include +#include "google/protobuf/io/coded_stream.h" +#include "google/protobuf/extension_set.h" +#include "google/protobuf/wire_format_lite.h" +#include "google/protobuf/descriptor.h" +#include "google/protobuf/generated_message_reflection.h" +#include "google/protobuf/reflection_ops.h" +#include "google/protobuf/wire_format.h" +#include "google/protobuf/generated_message_tctable_impl.h" +// @@protoc_insertion_point(includes) + +// Must be included last. +#include "google/protobuf/port_def.inc" +PROTOBUF_PRAGMA_INIT_SEG +namespace _pb = ::google::protobuf; +namespace _pbi = ::google::protobuf::internal; +namespace _fl = ::google::protobuf::internal::field_layout; +namespace google { +namespace firestore { +namespace v1 { + +inline constexpr ExplainStats::Impl_::Impl_( + ::_pbi::ConstantInitialized) noexcept + : _cached_size_{0}, + data_{nullptr} {} + +template +PROTOBUF_CONSTEXPR ExplainStats::ExplainStats(::_pbi::ConstantInitialized) + : _impl_(::_pbi::ConstantInitialized()) {} +struct ExplainStatsDefaultTypeInternal { + PROTOBUF_CONSTEXPR ExplainStatsDefaultTypeInternal() : _instance(::_pbi::ConstantInitialized{}) {} + ~ExplainStatsDefaultTypeInternal() {} + union { + ExplainStats _instance; + }; +}; + +PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT + PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 ExplainStatsDefaultTypeInternal _ExplainStats_default_instance_; +} // namespace v1 +} // namespace firestore +} // namespace google +static ::_pb::Metadata file_level_metadata_google_2ffirestore_2fv1_2fexplain_5fstats_2eproto[1]; +static constexpr const ::_pb::EnumDescriptor** + file_level_enum_descriptors_google_2ffirestore_2fv1_2fexplain_5fstats_2eproto = nullptr; +static constexpr const ::_pb::ServiceDescriptor** + file_level_service_descriptors_google_2ffirestore_2fv1_2fexplain_5fstats_2eproto = nullptr; +const ::uint32_t TableStruct_google_2ffirestore_2fv1_2fexplain_5fstats_2eproto::offsets[] PROTOBUF_SECTION_VARIABLE( + protodesc_cold) = { + PROTOBUF_FIELD_OFFSET(::google::firestore::v1::ExplainStats, _impl_._has_bits_), + PROTOBUF_FIELD_OFFSET(::google::firestore::v1::ExplainStats, _internal_metadata_), + ~0u, // no _extensions_ + ~0u, // no _oneof_case_ + ~0u, // no _weak_field_map_ + ~0u, // no _inlined_string_donated_ + ~0u, // no _split_ + ~0u, // no sizeof(Split) + PROTOBUF_FIELD_OFFSET(::google::firestore::v1::ExplainStats, _impl_.data_), + 0, +}; + +static const ::_pbi::MigrationSchema + schemas[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) = { + {0, 9, -1, sizeof(::google::firestore::v1::ExplainStats)}, +}; + +static const ::_pb::Message* const file_default_instances[] = { + &::google::firestore::v1::_ExplainStats_default_instance_._instance, +}; +const char descriptor_table_protodef_google_2ffirestore_2fv1_2fexplain_5fstats_2eproto[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) = { + "\n\'google/firestore/v1/explain_stats.prot" + "o\022\023google.firestore.v1\032\031google/protobuf/" + "any.proto\"2\n\014ExplainStats\022\"\n\004data\030\001 \001(\0132" + "\024.google.protobuf.AnyB\302\001\n\027com.google.fir" + "estore.v1B\021ExplainStatsProtoP\001Z;cloud.go" + "ogle.com/go/firestore/apiv1/firestorepb;" + "firestorepb\252\002\031Google.Cloud.Firestore.V1\312" + "\002\031Google\\Cloud\\Firestore\\V1\352\002\034Google::Cl" + "oud::Firestore::V1b\006proto3" +}; +static const ::_pbi::DescriptorTable* const descriptor_table_google_2ffirestore_2fv1_2fexplain_5fstats_2eproto_deps[1] = + { + &::descriptor_table_google_2fprotobuf_2fany_2eproto, +}; +static ::absl::once_flag descriptor_table_google_2ffirestore_2fv1_2fexplain_5fstats_2eproto_once; +const ::_pbi::DescriptorTable descriptor_table_google_2ffirestore_2fv1_2fexplain_5fstats_2eproto = { + false, + false, + 346, + descriptor_table_protodef_google_2ffirestore_2fv1_2fexplain_5fstats_2eproto, + "google/firestore/v1/explain_stats.proto", + &descriptor_table_google_2ffirestore_2fv1_2fexplain_5fstats_2eproto_once, + descriptor_table_google_2ffirestore_2fv1_2fexplain_5fstats_2eproto_deps, + 1, + 1, + schemas, + file_default_instances, + TableStruct_google_2ffirestore_2fv1_2fexplain_5fstats_2eproto::offsets, + file_level_metadata_google_2ffirestore_2fv1_2fexplain_5fstats_2eproto, + file_level_enum_descriptors_google_2ffirestore_2fv1_2fexplain_5fstats_2eproto, + file_level_service_descriptors_google_2ffirestore_2fv1_2fexplain_5fstats_2eproto, +}; + +// This function exists to be marked as weak. +// It can significantly speed up compilation by breaking up LLVM's SCC +// in the .pb.cc translation units. Large translation units see a +// reduction of more than 35% of walltime for optimized builds. Without +// the weak attribute all the messages in the file, including all the +// vtables and everything they use become part of the same SCC through +// a cycle like: +// GetMetadata -> descriptor table -> default instances -> +// vtables -> GetMetadata +// By adding a weak function here we break the connection from the +// individual vtables back into the descriptor table. +PROTOBUF_ATTRIBUTE_WEAK const ::_pbi::DescriptorTable* descriptor_table_google_2ffirestore_2fv1_2fexplain_5fstats_2eproto_getter() { + return &descriptor_table_google_2ffirestore_2fv1_2fexplain_5fstats_2eproto; +} +// Force running AddDescriptors() at dynamic initialization time. +PROTOBUF_ATTRIBUTE_INIT_PRIORITY2 +static ::_pbi::AddDescriptorsRunner dynamic_init_dummy_google_2ffirestore_2fv1_2fexplain_5fstats_2eproto(&descriptor_table_google_2ffirestore_2fv1_2fexplain_5fstats_2eproto); +namespace google { +namespace firestore { +namespace v1 { +// =================================================================== + +class ExplainStats::_Internal { + public: + using HasBits = decltype(std::declval()._impl_._has_bits_); + static constexpr ::int32_t kHasBitsOffset = + 8 * PROTOBUF_FIELD_OFFSET(ExplainStats, _impl_._has_bits_); + static const ::google::protobuf::Any& data(const ExplainStats* msg); + static void set_has_data(HasBits* has_bits) { + (*has_bits)[0] |= 1u; + } +}; + +const ::google::protobuf::Any& ExplainStats::_Internal::data(const ExplainStats* msg) { + return *msg->_impl_.data_; +} +void ExplainStats::clear_data() { + PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); + if (_impl_.data_ != nullptr) _impl_.data_->Clear(); + _impl_._has_bits_[0] &= ~0x00000001u; +} +ExplainStats::ExplainStats(::google::protobuf::Arena* arena) + : ::google::protobuf::Message(arena) { + SharedCtor(arena); + // @@protoc_insertion_point(arena_constructor:google.firestore.v1.ExplainStats) +} +inline PROTOBUF_NDEBUG_INLINE ExplainStats::Impl_::Impl_( + ::google::protobuf::internal::InternalVisibility visibility, ::google::protobuf::Arena* arena, + const Impl_& from) + : _has_bits_{from._has_bits_}, + _cached_size_{0} {} + +ExplainStats::ExplainStats( + ::google::protobuf::Arena* arena, + const ExplainStats& from) + : ::google::protobuf::Message(arena) { + ExplainStats* const _this = this; + (void)_this; + _internal_metadata_.MergeFrom<::google::protobuf::UnknownFieldSet>( + from._internal_metadata_); + new (&_impl_) Impl_(internal_visibility(), arena, from._impl_); + ::uint32_t cached_has_bits = _impl_._has_bits_[0]; + _impl_.data_ = (cached_has_bits & 0x00000001u) + ? CreateMaybeMessage<::google::protobuf::Any>(arena, *from._impl_.data_) + : nullptr; + + // @@protoc_insertion_point(copy_constructor:google.firestore.v1.ExplainStats) +} +inline PROTOBUF_NDEBUG_INLINE ExplainStats::Impl_::Impl_( + ::google::protobuf::internal::InternalVisibility visibility, + ::google::protobuf::Arena* arena) + : _cached_size_{0} {} + +inline void ExplainStats::SharedCtor(::_pb::Arena* arena) { + new (&_impl_) Impl_(internal_visibility(), arena); + _impl_.data_ = {}; +} +ExplainStats::~ExplainStats() { + // @@protoc_insertion_point(destructor:google.firestore.v1.ExplainStats) + _internal_metadata_.Delete<::google::protobuf::UnknownFieldSet>(); + SharedDtor(); +} +inline void ExplainStats::SharedDtor() { + ABSL_DCHECK(GetArena() == nullptr); + delete _impl_.data_; + _impl_.~Impl_(); +} + +PROTOBUF_NOINLINE void ExplainStats::Clear() { +// @@protoc_insertion_point(message_clear_start:google.firestore.v1.ExplainStats) + PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); + ::uint32_t cached_has_bits = 0; + // Prevent compiler warnings about cached_has_bits being unused + (void) cached_has_bits; + + cached_has_bits = _impl_._has_bits_[0]; + if (cached_has_bits & 0x00000001u) { + ABSL_DCHECK(_impl_.data_ != nullptr); + _impl_.data_->Clear(); + } + _impl_._has_bits_.Clear(); + _internal_metadata_.Clear<::google::protobuf::UnknownFieldSet>(); +} + +const char* ExplainStats::_InternalParse( + const char* ptr, ::_pbi::ParseContext* ctx) { + ptr = ::_pbi::TcParser::ParseLoop(this, ptr, ctx, &_table_.header); + return ptr; +} + + +PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 +const ::_pbi::TcParseTable<0, 1, 1, 0, 2> ExplainStats::_table_ = { + { + PROTOBUF_FIELD_OFFSET(ExplainStats, _impl_._has_bits_), + 0, // no _extensions_ + 1, 0, // max_field_number, fast_idx_mask + offsetof(decltype(_table_), field_lookup_table), + 4294967294, // skipmap + offsetof(decltype(_table_), field_entries), + 1, // num_field_entries + 1, // num_aux_entries + offsetof(decltype(_table_), aux_entries), + &_ExplainStats_default_instance_._instance, + ::_pbi::TcParser::GenericFallback, // fallback + }, {{ + // .google.protobuf.Any data = 1; + {::_pbi::TcParser::FastMtS1, + {10, 0, 0, PROTOBUF_FIELD_OFFSET(ExplainStats, _impl_.data_)}}, + }}, {{ + 65535, 65535 + }}, {{ + // .google.protobuf.Any data = 1; + {PROTOBUF_FIELD_OFFSET(ExplainStats, _impl_.data_), _Internal::kHasBitsOffset + 0, 0, + (0 | ::_fl::kFcOptional | ::_fl::kMessage | ::_fl::kTvTable)}, + }}, {{ + {::_pbi::TcParser::GetTable<::google::protobuf::Any>()}, + }}, {{ + }}, +}; + +::uint8_t* ExplainStats::_InternalSerialize( + ::uint8_t* target, + ::google::protobuf::io::EpsCopyOutputStream* stream) const { + // @@protoc_insertion_point(serialize_to_array_start:google.firestore.v1.ExplainStats) + ::uint32_t cached_has_bits = 0; + (void)cached_has_bits; + + cached_has_bits = _impl_._has_bits_[0]; + // .google.protobuf.Any data = 1; + if (cached_has_bits & 0x00000001u) { + target = ::google::protobuf::internal::WireFormatLite::InternalWriteMessage( + 1, _Internal::data(this), + _Internal::data(this).GetCachedSize(), target, stream); + } + + if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) { + target = + ::_pbi::WireFormat::InternalSerializeUnknownFieldsToArray( + _internal_metadata_.unknown_fields<::google::protobuf::UnknownFieldSet>(::google::protobuf::UnknownFieldSet::default_instance), target, stream); + } + // @@protoc_insertion_point(serialize_to_array_end:google.firestore.v1.ExplainStats) + return target; +} + +::size_t ExplainStats::ByteSizeLong() const { +// @@protoc_insertion_point(message_byte_size_start:google.firestore.v1.ExplainStats) + ::size_t total_size = 0; + + ::uint32_t cached_has_bits = 0; + // Prevent compiler warnings about cached_has_bits being unused + (void) cached_has_bits; + + // .google.protobuf.Any data = 1; + cached_has_bits = _impl_._has_bits_[0]; + if (cached_has_bits & 0x00000001u) { + total_size += + 1 + ::google::protobuf::internal::WireFormatLite::MessageSize(*_impl_.data_); + } + + return MaybeComputeUnknownFieldsSize(total_size, &_impl_._cached_size_); +} + +const ::google::protobuf::Message::ClassData ExplainStats::_class_data_ = { + ExplainStats::MergeImpl, + nullptr, // OnDemandRegisterArenaDtor +}; +const ::google::protobuf::Message::ClassData* ExplainStats::GetClassData() const { + return &_class_data_; +} + +void ExplainStats::MergeImpl(::google::protobuf::Message& to_msg, const ::google::protobuf::Message& from_msg) { + auto* const _this = static_cast(&to_msg); + auto& from = static_cast(from_msg); + // @@protoc_insertion_point(class_specific_merge_from_start:google.firestore.v1.ExplainStats) + ABSL_DCHECK_NE(&from, _this); + ::uint32_t cached_has_bits = 0; + (void) cached_has_bits; + + if ((from._impl_._has_bits_[0] & 0x00000001u) != 0) { + _this->_internal_mutable_data()->::google::protobuf::Any::MergeFrom( + from._internal_data()); + } + _this->_internal_metadata_.MergeFrom<::google::protobuf::UnknownFieldSet>(from._internal_metadata_); +} + +void ExplainStats::CopyFrom(const ExplainStats& from) { +// @@protoc_insertion_point(class_specific_copy_from_start:google.firestore.v1.ExplainStats) + if (&from == this) return; + Clear(); + MergeFrom(from); +} + +PROTOBUF_NOINLINE bool ExplainStats::IsInitialized() const { + return true; +} + +::_pbi::CachedSize* ExplainStats::AccessCachedSize() const { + return &_impl_._cached_size_; +} +void ExplainStats::InternalSwap(ExplainStats* PROTOBUF_RESTRICT other) { + using std::swap; + _internal_metadata_.InternalSwap(&other->_internal_metadata_); + swap(_impl_._has_bits_[0], other->_impl_._has_bits_[0]); + swap(_impl_.data_, other->_impl_.data_); +} + +::google::protobuf::Metadata ExplainStats::GetMetadata() const { + return ::_pbi::AssignDescriptors( + &descriptor_table_google_2ffirestore_2fv1_2fexplain_5fstats_2eproto_getter, &descriptor_table_google_2ffirestore_2fv1_2fexplain_5fstats_2eproto_once, + file_level_metadata_google_2ffirestore_2fv1_2fexplain_5fstats_2eproto[0]); +} +// @@protoc_insertion_point(namespace_scope) +} // namespace v1 +} // namespace firestore +} // namespace google +namespace google { +namespace protobuf { +} // namespace protobuf +} // namespace google +// @@protoc_insertion_point(global_scope) +#include "google/protobuf/port_undef.inc" diff --git a/Firestore/Protos/cpp/google/firestore/v1/explain_stats.pb.h b/Firestore/Protos/cpp/google/firestore/v1/explain_stats.pb.h new file mode 100644 index 00000000000..9dfa833e6bc --- /dev/null +++ b/Firestore/Protos/cpp/google/firestore/v1/explain_stats.pb.h @@ -0,0 +1,398 @@ +/* + * Copyright 2025 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. + */ + +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: google/firestore/v1/explain_stats.proto +// Protobuf C++ Version: 4.25.1 + +#ifndef GOOGLE_PROTOBUF_INCLUDED_google_2ffirestore_2fv1_2fexplain_5fstats_2eproto_2epb_2eh +#define GOOGLE_PROTOBUF_INCLUDED_google_2ffirestore_2fv1_2fexplain_5fstats_2eproto_2epb_2eh + +#include +#include +#include +#include + +#include "google/protobuf/port_def.inc" +#if PROTOBUF_VERSION < 4025000 +#error "This file was generated by a newer version of protoc which is" +#error "incompatible with your Protocol Buffer headers. Please update" +#error "your headers." +#endif // PROTOBUF_VERSION + +#if 4025001 < PROTOBUF_MIN_PROTOC_VERSION +#error "This file was generated by an older version of protoc which is" +#error "incompatible with your Protocol Buffer headers. Please" +#error "regenerate this file with a newer version of protoc." +#endif // PROTOBUF_MIN_PROTOC_VERSION +#include "google/protobuf/port_undef.inc" +#include "google/protobuf/io/coded_stream.h" +#include "google/protobuf/arena.h" +#include "google/protobuf/arenastring.h" +#include "google/protobuf/generated_message_tctable_decl.h" +#include "google/protobuf/generated_message_util.h" +#include "google/protobuf/metadata_lite.h" +#include "google/protobuf/generated_message_reflection.h" +#include "google/protobuf/message.h" +#include "google/protobuf/repeated_field.h" // IWYU pragma: export +#include "google/protobuf/extension_set.h" // IWYU pragma: export +#include "google/protobuf/unknown_field_set.h" +#include "google/protobuf/any.pb.h" +// @@protoc_insertion_point(includes) + +// Must be included last. +#include "google/protobuf/port_def.inc" + +#define PROTOBUF_INTERNAL_EXPORT_google_2ffirestore_2fv1_2fexplain_5fstats_2eproto + +namespace google { +namespace protobuf { +namespace internal { +class AnyMetadata; +} // namespace internal +} // namespace protobuf +} // namespace google + +// Internal implementation detail -- do not use these members. +struct TableStruct_google_2ffirestore_2fv1_2fexplain_5fstats_2eproto { + static const ::uint32_t offsets[]; +}; +extern const ::google::protobuf::internal::DescriptorTable + descriptor_table_google_2ffirestore_2fv1_2fexplain_5fstats_2eproto; +namespace google { +namespace firestore { +namespace v1 { +class ExplainStats; +struct ExplainStatsDefaultTypeInternal; +extern ExplainStatsDefaultTypeInternal _ExplainStats_default_instance_; +} // namespace v1 +} // namespace firestore +namespace protobuf { +} // namespace protobuf +} // namespace google + +namespace google { +namespace firestore { +namespace v1 { + +// =================================================================== + + +// ------------------------------------------------------------------- + +class ExplainStats final : + public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:google.firestore.v1.ExplainStats) */ { + public: + inline ExplainStats() : ExplainStats(nullptr) {} + ~ExplainStats() override; + template + explicit PROTOBUF_CONSTEXPR ExplainStats(::google::protobuf::internal::ConstantInitialized); + + inline ExplainStats(const ExplainStats& from) + : ExplainStats(nullptr, from) {} + ExplainStats(ExplainStats&& from) noexcept + : ExplainStats() { + *this = ::std::move(from); + } + + inline ExplainStats& operator=(const ExplainStats& from) { + CopyFrom(from); + return *this; + } + inline ExplainStats& operator=(ExplainStats&& from) noexcept { + if (this == &from) return *this; + if (GetArena() == from.GetArena() + #ifdef PROTOBUF_FORCE_COPY_IN_MOVE + && GetArena() != nullptr + #endif // !PROTOBUF_FORCE_COPY_IN_MOVE + ) { + InternalSwap(&from); + } else { + CopyFrom(from); + } + return *this; + } + + inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const + ABSL_ATTRIBUTE_LIFETIME_BOUND { + return _internal_metadata_.unknown_fields<::google::protobuf::UnknownFieldSet>(::google::protobuf::UnknownFieldSet::default_instance); + } + inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() + ABSL_ATTRIBUTE_LIFETIME_BOUND { + return _internal_metadata_.mutable_unknown_fields<::google::protobuf::UnknownFieldSet>(); + } + + static const ::google::protobuf::Descriptor* descriptor() { + return GetDescriptor(); + } + static const ::google::protobuf::Descriptor* GetDescriptor() { + return default_instance().GetMetadata().descriptor; + } + static const ::google::protobuf::Reflection* GetReflection() { + return default_instance().GetMetadata().reflection; + } + static const ExplainStats& default_instance() { + return *internal_default_instance(); + } + static inline const ExplainStats* internal_default_instance() { + return reinterpret_cast( + &_ExplainStats_default_instance_); + } + static constexpr int kIndexInFileMessages = + 0; + + friend void swap(ExplainStats& a, ExplainStats& b) { + a.Swap(&b); + } + inline void Swap(ExplainStats* other) { + if (other == this) return; + #ifdef PROTOBUF_FORCE_COPY_IN_SWAP + if (GetArena() != nullptr && + GetArena() == other->GetArena()) { + #else // PROTOBUF_FORCE_COPY_IN_SWAP + if (GetArena() == other->GetArena()) { + #endif // !PROTOBUF_FORCE_COPY_IN_SWAP + InternalSwap(other); + } else { + ::google::protobuf::internal::GenericSwap(this, other); + } + } + void UnsafeArenaSwap(ExplainStats* other) { + if (other == this) return; + ABSL_DCHECK(GetArena() == other->GetArena()); + InternalSwap(other); + } + + // implements Message ---------------------------------------------- + + ExplainStats* New(::google::protobuf::Arena* arena = nullptr) const final { + return CreateMaybeMessage(arena); + } + using ::google::protobuf::Message::CopyFrom; + void CopyFrom(const ExplainStats& from); + using ::google::protobuf::Message::MergeFrom; + void MergeFrom( const ExplainStats& from) { + ExplainStats::MergeImpl(*this, from); + } + private: + static void MergeImpl(::google::protobuf::Message& to_msg, const ::google::protobuf::Message& from_msg); + public: + PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final; + bool IsInitialized() const final; + + ::size_t ByteSizeLong() const final; + const char* _InternalParse(const char* ptr, ::google::protobuf::internal::ParseContext* ctx) final; + ::uint8_t* _InternalSerialize( + ::uint8_t* target, ::google::protobuf::io::EpsCopyOutputStream* stream) const final; + int GetCachedSize() const { return _impl_._cached_size_.Get(); } + + private: + ::google::protobuf::internal::CachedSize* AccessCachedSize() const final; + void SharedCtor(::google::protobuf::Arena* arena); + void SharedDtor(); + void InternalSwap(ExplainStats* other); + + private: + friend class ::google::protobuf::internal::AnyMetadata; + static ::absl::string_view FullMessageName() { + return "google.firestore.v1.ExplainStats"; + } + protected: + explicit ExplainStats(::google::protobuf::Arena* arena); + ExplainStats(::google::protobuf::Arena* arena, const ExplainStats& from); + public: + + static const ClassData _class_data_; + const ::google::protobuf::Message::ClassData*GetClassData() const final; + + ::google::protobuf::Metadata GetMetadata() const final; + + // nested types ---------------------------------------------------- + + // accessors ------------------------------------------------------- + + enum : int { + kDataFieldNumber = 1, + }; + // .google.protobuf.Any data = 1; + bool has_data() const; + void clear_data() ; + const ::google::protobuf::Any& data() const; + PROTOBUF_NODISCARD ::google::protobuf::Any* release_data(); + ::google::protobuf::Any* mutable_data(); + void set_allocated_data(::google::protobuf::Any* value); + void unsafe_arena_set_allocated_data(::google::protobuf::Any* value); + ::google::protobuf::Any* unsafe_arena_release_data(); + + private: + const ::google::protobuf::Any& _internal_data() const; + ::google::protobuf::Any* _internal_mutable_data(); + + public: + // @@protoc_insertion_point(class_scope:google.firestore.v1.ExplainStats) + private: + class _Internal; + + friend class ::google::protobuf::internal::TcParser; + static const ::google::protobuf::internal::TcParseTable< + 0, 1, 1, + 0, 2> + _table_; + friend class ::google::protobuf::MessageLite; + friend class ::google::protobuf::Arena; + template + friend class ::google::protobuf::Arena::InternalHelper; + using InternalArenaConstructable_ = void; + using DestructorSkippable_ = void; + struct Impl_ { + + inline explicit constexpr Impl_( + ::google::protobuf::internal::ConstantInitialized) noexcept; + inline explicit Impl_(::google::protobuf::internal::InternalVisibility visibility, + ::google::protobuf::Arena* arena); + inline explicit Impl_(::google::protobuf::internal::InternalVisibility visibility, + ::google::protobuf::Arena* arena, const Impl_& from); + ::google::protobuf::internal::HasBits<1> _has_bits_; + mutable ::google::protobuf::internal::CachedSize _cached_size_; + ::google::protobuf::Any* data_; + PROTOBUF_TSAN_DECLARE_MEMBER + }; + union { Impl_ _impl_; }; + friend struct ::TableStruct_google_2ffirestore_2fv1_2fexplain_5fstats_2eproto; +}; + +// =================================================================== + + + + +// =================================================================== + + +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wstrict-aliasing" +#endif // __GNUC__ +// ------------------------------------------------------------------- + +// ExplainStats + +// .google.protobuf.Any data = 1; +inline bool ExplainStats::has_data() const { + bool value = (_impl_._has_bits_[0] & 0x00000001u) != 0; + PROTOBUF_ASSUME(!value || _impl_.data_ != nullptr); + return value; +} +inline const ::google::protobuf::Any& ExplainStats::_internal_data() const { + PROTOBUF_TSAN_READ(&_impl_._tsan_detect_race); + const ::google::protobuf::Any* p = _impl_.data_; + return p != nullptr ? *p : reinterpret_cast(::google::protobuf::_Any_default_instance_); +} +inline const ::google::protobuf::Any& ExplainStats::data() const ABSL_ATTRIBUTE_LIFETIME_BOUND { + // @@protoc_insertion_point(field_get:google.firestore.v1.ExplainStats.data) + return _internal_data(); +} +inline void ExplainStats::unsafe_arena_set_allocated_data(::google::protobuf::Any* value) { + PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); + if (GetArena() == nullptr) { + delete reinterpret_cast<::google::protobuf::MessageLite*>(_impl_.data_); + } + _impl_.data_ = reinterpret_cast<::google::protobuf::Any*>(value); + if (value != nullptr) { + _impl_._has_bits_[0] |= 0x00000001u; + } else { + _impl_._has_bits_[0] &= ~0x00000001u; + } + // @@protoc_insertion_point(field_unsafe_arena_set_allocated:google.firestore.v1.ExplainStats.data) +} +inline ::google::protobuf::Any* ExplainStats::release_data() { + PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); + + _impl_._has_bits_[0] &= ~0x00000001u; + ::google::protobuf::Any* released = _impl_.data_; + _impl_.data_ = nullptr; +#ifdef PROTOBUF_FORCE_COPY_IN_RELEASE + auto* old = reinterpret_cast<::google::protobuf::MessageLite*>(released); + released = ::google::protobuf::internal::DuplicateIfNonNull(released); + if (GetArena() == nullptr) { + delete old; + } +#else // PROTOBUF_FORCE_COPY_IN_RELEASE + if (GetArena() != nullptr) { + released = ::google::protobuf::internal::DuplicateIfNonNull(released); + } +#endif // !PROTOBUF_FORCE_COPY_IN_RELEASE + return released; +} +inline ::google::protobuf::Any* ExplainStats::unsafe_arena_release_data() { + PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); + // @@protoc_insertion_point(field_release:google.firestore.v1.ExplainStats.data) + + _impl_._has_bits_[0] &= ~0x00000001u; + ::google::protobuf::Any* temp = _impl_.data_; + _impl_.data_ = nullptr; + return temp; +} +inline ::google::protobuf::Any* ExplainStats::_internal_mutable_data() { + PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); + _impl_._has_bits_[0] |= 0x00000001u; + if (_impl_.data_ == nullptr) { + auto* p = CreateMaybeMessage<::google::protobuf::Any>(GetArena()); + _impl_.data_ = reinterpret_cast<::google::protobuf::Any*>(p); + } + return _impl_.data_; +} +inline ::google::protobuf::Any* ExplainStats::mutable_data() ABSL_ATTRIBUTE_LIFETIME_BOUND { + ::google::protobuf::Any* _msg = _internal_mutable_data(); + // @@protoc_insertion_point(field_mutable:google.firestore.v1.ExplainStats.data) + return _msg; +} +inline void ExplainStats::set_allocated_data(::google::protobuf::Any* value) { + ::google::protobuf::Arena* message_arena = GetArena(); + PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); + if (message_arena == nullptr) { + delete reinterpret_cast<::google::protobuf::MessageLite*>(_impl_.data_); + } + + if (value != nullptr) { + ::google::protobuf::Arena* submessage_arena = reinterpret_cast<::google::protobuf::MessageLite*>(value)->GetArena(); + if (message_arena != submessage_arena) { + value = ::google::protobuf::internal::GetOwnedMessage(message_arena, value, submessage_arena); + } + _impl_._has_bits_[0] |= 0x00000001u; + } else { + _impl_._has_bits_[0] &= ~0x00000001u; + } + + _impl_.data_ = reinterpret_cast<::google::protobuf::Any*>(value); + // @@protoc_insertion_point(field_set_allocated:google.firestore.v1.ExplainStats.data) +} + +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif // __GNUC__ + +// @@protoc_insertion_point(namespace_scope) +} // namespace v1 +} // namespace firestore +} // namespace google + + +// @@protoc_insertion_point(global_scope) + +#include "google/protobuf/port_undef.inc" + +#endif // GOOGLE_PROTOBUF_INCLUDED_google_2ffirestore_2fv1_2fexplain_5fstats_2eproto_2epb_2eh diff --git a/Firestore/Protos/cpp/google/firestore/v1/firestore.pb.cc b/Firestore/Protos/cpp/google/firestore/v1/firestore.pb.cc index 7cf9b349839..93dfc7f88b2 100644 --- a/Firestore/Protos/cpp/google/firestore/v1/firestore.pb.cc +++ b/Firestore/Protos/cpp/google/firestore/v1/firestore.pb.cc @@ -1,5 +1,5 @@ /* - * Copyright 2024 Google LLC + * Copyright 2025 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -466,6 +466,54 @@ struct ListDocumentsResponseDefaultTypeInternal { PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 ListDocumentsResponseDefaultTypeInternal _ListDocumentsResponse_default_instance_; +inline constexpr ExecutePipelineResponse::Impl_::Impl_( + ::_pbi::ConstantInitialized) noexcept + : _cached_size_{0}, + results_{}, + transaction_( + &::google::protobuf::internal::fixed_address_empty_string, + ::_pbi::ConstantInitialized()), + execution_time_{nullptr}, + explain_stats_{nullptr} {} + +template +PROTOBUF_CONSTEXPR ExecutePipelineResponse::ExecutePipelineResponse(::_pbi::ConstantInitialized) + : _impl_(::_pbi::ConstantInitialized()) {} +struct ExecutePipelineResponseDefaultTypeInternal { + PROTOBUF_CONSTEXPR ExecutePipelineResponseDefaultTypeInternal() : _instance(::_pbi::ConstantInitialized{}) {} + ~ExecutePipelineResponseDefaultTypeInternal() {} + union { + ExecutePipelineResponse _instance; + }; +}; + +PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT + PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 ExecutePipelineResponseDefaultTypeInternal _ExecutePipelineResponse_default_instance_; + +inline constexpr ExecutePipelineRequest::Impl_::Impl_( + ::_pbi::ConstantInitialized) noexcept + : database_( + &::google::protobuf::internal::fixed_address_empty_string, + ::_pbi::ConstantInitialized()), + pipeline_type_{}, + consistency_selector_{}, + _cached_size_{0}, + _oneof_case_{} {} + +template +PROTOBUF_CONSTEXPR ExecutePipelineRequest::ExecutePipelineRequest(::_pbi::ConstantInitialized) + : _impl_(::_pbi::ConstantInitialized()) {} +struct ExecutePipelineRequestDefaultTypeInternal { + PROTOBUF_CONSTEXPR ExecutePipelineRequestDefaultTypeInternal() : _instance(::_pbi::ConstantInitialized{}) {} + ~ExecutePipelineRequestDefaultTypeInternal() {} + union { + ExecutePipelineRequest _instance; + }; +}; + +PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT + PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 ExecutePipelineRequestDefaultTypeInternal _ExecutePipelineRequest_default_instance_; + inline constexpr CreateDocumentRequest::Impl_::Impl_( ::_pbi::ConstantInitialized) noexcept : _cached_size_{0}, @@ -714,7 +762,7 @@ PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT } // namespace v1 } // namespace firestore } // namespace google -static ::_pb::Metadata file_level_metadata_google_2ffirestore_2fv1_2ffirestore_2eproto[29]; +static ::_pb::Metadata file_level_metadata_google_2ffirestore_2fv1_2ffirestore_2eproto[31]; static const ::_pb::EnumDescriptor* file_level_enum_descriptors_google_2ffirestore_2fv1_2ffirestore_2eproto[1]; static constexpr const ::_pb::ServiceDescriptor** file_level_service_descriptors_google_2ffirestore_2fv1_2ffirestore_2eproto = nullptr; @@ -944,6 +992,37 @@ const ::uint32_t TableStruct_google_2ffirestore_2fv1_2ffirestore_2eproto::offset 1, ~0u, ~0u, // no _has_bits_ + PROTOBUF_FIELD_OFFSET(::google::firestore::v1::ExecutePipelineRequest, _internal_metadata_), + ~0u, // no _extensions_ + PROTOBUF_FIELD_OFFSET(::google::firestore::v1::ExecutePipelineRequest, _impl_._oneof_case_[0]), + ~0u, // no _weak_field_map_ + ~0u, // no _inlined_string_donated_ + ~0u, // no _split_ + ~0u, // no sizeof(Split) + PROTOBUF_FIELD_OFFSET(::google::firestore::v1::ExecutePipelineRequest, _impl_.database_), + ::_pbi::kInvalidFieldOffsetTag, + ::_pbi::kInvalidFieldOffsetTag, + ::_pbi::kInvalidFieldOffsetTag, + ::_pbi::kInvalidFieldOffsetTag, + PROTOBUF_FIELD_OFFSET(::google::firestore::v1::ExecutePipelineRequest, _impl_.pipeline_type_), + PROTOBUF_FIELD_OFFSET(::google::firestore::v1::ExecutePipelineRequest, _impl_.consistency_selector_), + PROTOBUF_FIELD_OFFSET(::google::firestore::v1::ExecutePipelineResponse, _impl_._has_bits_), + PROTOBUF_FIELD_OFFSET(::google::firestore::v1::ExecutePipelineResponse, _internal_metadata_), + ~0u, // no _extensions_ + ~0u, // no _oneof_case_ + ~0u, // no _weak_field_map_ + ~0u, // no _inlined_string_donated_ + ~0u, // no _split_ + ~0u, // no sizeof(Split) + PROTOBUF_FIELD_OFFSET(::google::firestore::v1::ExecutePipelineResponse, _impl_.transaction_), + PROTOBUF_FIELD_OFFSET(::google::firestore::v1::ExecutePipelineResponse, _impl_.results_), + PROTOBUF_FIELD_OFFSET(::google::firestore::v1::ExecutePipelineResponse, _impl_.execution_time_), + PROTOBUF_FIELD_OFFSET(::google::firestore::v1::ExecutePipelineResponse, _impl_.explain_stats_), + ~0u, + ~0u, + 0, + 1, + ~0u, // no _has_bits_ PROTOBUF_FIELD_OFFSET(::google::firestore::v1::RunAggregationQueryRequest, _internal_metadata_), ~0u, // no _extensions_ PROTOBUF_FIELD_OFFSET(::google::firestore::v1::RunAggregationQueryRequest, _impl_._oneof_case_[0]), @@ -1154,20 +1233,22 @@ static const ::_pbi::MigrationSchema {182, -1, -1, sizeof(::google::firestore::v1::RollbackRequest)}, {192, -1, -1, sizeof(::google::firestore::v1::RunQueryRequest)}, {207, 219, -1, sizeof(::google::firestore::v1::RunQueryResponse)}, - {223, -1, -1, sizeof(::google::firestore::v1::RunAggregationQueryRequest)}, - {238, 249, -1, sizeof(::google::firestore::v1::RunAggregationQueryResponse)}, - {252, 262, -1, sizeof(::google::firestore::v1::WriteRequest_LabelsEntry_DoNotUse)}, - {264, -1, -1, sizeof(::google::firestore::v1::WriteRequest)}, - {277, 289, -1, sizeof(::google::firestore::v1::WriteResponse)}, - {293, 303, -1, sizeof(::google::firestore::v1::ListenRequest_LabelsEntry_DoNotUse)}, - {305, -1, -1, sizeof(::google::firestore::v1::ListenRequest)}, - {318, -1, -1, sizeof(::google::firestore::v1::ListenResponse)}, - {332, -1, -1, sizeof(::google::firestore::v1::Target_DocumentsTarget)}, - {341, -1, -1, sizeof(::google::firestore::v1::Target_QueryTarget)}, - {352, 369, -1, sizeof(::google::firestore::v1::Target)}, - {376, 389, -1, sizeof(::google::firestore::v1::TargetChange)}, - {394, -1, -1, sizeof(::google::firestore::v1::ListCollectionIdsRequest)}, - {405, -1, -1, sizeof(::google::firestore::v1::ListCollectionIdsResponse)}, + {223, -1, -1, sizeof(::google::firestore::v1::ExecutePipelineRequest)}, + {238, 250, -1, sizeof(::google::firestore::v1::ExecutePipelineResponse)}, + {254, -1, -1, sizeof(::google::firestore::v1::RunAggregationQueryRequest)}, + {269, 280, -1, sizeof(::google::firestore::v1::RunAggregationQueryResponse)}, + {283, 293, -1, sizeof(::google::firestore::v1::WriteRequest_LabelsEntry_DoNotUse)}, + {295, -1, -1, sizeof(::google::firestore::v1::WriteRequest)}, + {308, 320, -1, sizeof(::google::firestore::v1::WriteResponse)}, + {324, 334, -1, sizeof(::google::firestore::v1::ListenRequest_LabelsEntry_DoNotUse)}, + {336, -1, -1, sizeof(::google::firestore::v1::ListenRequest)}, + {349, -1, -1, sizeof(::google::firestore::v1::ListenResponse)}, + {363, -1, -1, sizeof(::google::firestore::v1::Target_DocumentsTarget)}, + {372, -1, -1, sizeof(::google::firestore::v1::Target_QueryTarget)}, + {383, 400, -1, sizeof(::google::firestore::v1::Target)}, + {407, 420, -1, sizeof(::google::firestore::v1::TargetChange)}, + {425, -1, -1, sizeof(::google::firestore::v1::ListCollectionIdsRequest)}, + {436, -1, -1, sizeof(::google::firestore::v1::ListCollectionIdsResponse)}, }; static const ::_pb::Message* const file_default_instances[] = { @@ -1186,6 +1267,8 @@ static const ::_pb::Message* const file_default_instances[] = { &::google::firestore::v1::_RollbackRequest_default_instance_._instance, &::google::firestore::v1::_RunQueryRequest_default_instance_._instance, &::google::firestore::v1::_RunQueryResponse_default_instance_._instance, + &::google::firestore::v1::_ExecutePipelineRequest_default_instance_._instance, + &::google::firestore::v1::_ExecutePipelineResponse_default_instance_._instance, &::google::firestore::v1::_RunAggregationQueryRequest_default_instance_._instance, &::google::firestore::v1::_RunAggregationQueryResponse_default_instance_._instance, &::google::firestore::v1::_WriteRequest_LabelsEntry_DoNotUse_default_instance_._instance, @@ -1204,211 +1287,234 @@ static const ::_pb::Message* const file_default_instances[] = { const char descriptor_table_protodef_google_2ffirestore_2fv1_2ffirestore_2eproto[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) = { "\n#google/firestore/v1/firestore.proto\022\023g" "oogle.firestore.v1\032\034google/api/annotatio" - "ns.proto\032,google/firestore/v1/aggregatio" - "n_result.proto\032 google/firestore/v1/comm" - "on.proto\032\"google/firestore/v1/document.p" - "roto\032\037google/firestore/v1/query.proto\032\037g" - "oogle/firestore/v1/write.proto\032\033google/p" - "rotobuf/empty.proto\032\037google/protobuf/tim" - "estamp.proto\032\036google/protobuf/wrappers.p" - "roto\032\027google/rpc/status.proto\"\263\001\n\022GetDoc" - "umentRequest\022\014\n\004name\030\001 \001(\t\022/\n\004mask\030\002 \001(\013" - "2!.google.firestore.v1.DocumentMask\022\025\n\013t" - "ransaction\030\003 \001(\014H\000\022/\n\tread_time\030\005 \001(\0132\032." - "google.protobuf.TimestampH\000B\026\n\024consisten" - "cy_selector\"\235\002\n\024ListDocumentsRequest\022\016\n\006" - "parent\030\001 \001(\t\022\025\n\rcollection_id\030\002 \001(\t\022\021\n\tp" - "age_size\030\003 \001(\005\022\022\n\npage_token\030\004 \001(\t\022\020\n\010or" - "der_by\030\006 \001(\t\022/\n\004mask\030\007 \001(\0132!.google.fire" - "store.v1.DocumentMask\022\025\n\013transaction\030\010 \001" - "(\014H\000\022/\n\tread_time\030\n \001(\0132\032.google.protobu" - "f.TimestampH\000\022\024\n\014show_missing\030\014 \001(\010B\026\n\024c" - "onsistency_selector\"b\n\025ListDocumentsResp" - "onse\0220\n\tdocuments\030\001 \003(\0132\035.google.firesto" - "re.v1.Document\022\027\n\017next_page_token\030\002 \001(\t\"" - "\265\001\n\025CreateDocumentRequest\022\016\n\006parent\030\001 \001(" - "\t\022\025\n\rcollection_id\030\002 \001(\t\022\023\n\013document_id\030" - "\003 \001(\t\022/\n\010document\030\004 \001(\0132\035.google.firesto" - "re.v1.Document\022/\n\004mask\030\005 \001(\0132!.google.fi" - "restore.v1.DocumentMask\"\356\001\n\025UpdateDocume" - "ntRequest\022/\n\010document\030\001 \001(\0132\035.google.fir" - "estore.v1.Document\0226\n\013update_mask\030\002 \001(\0132" - "!.google.firestore.v1.DocumentMask\022/\n\004ma" - "sk\030\003 \001(\0132!.google.firestore.v1.DocumentM" - "ask\022;\n\020current_document\030\004 \001(\0132!.google.f" - "irestore.v1.Precondition\"b\n\025DeleteDocume" - "ntRequest\022\014\n\004name\030\001 \001(\t\022;\n\020current_docum" - "ent\030\002 \001(\0132!.google.firestore.v1.Precondi" - "tion\"\224\002\n\030BatchGetDocumentsRequest\022\020\n\010dat" - "abase\030\001 \001(\t\022\021\n\tdocuments\030\002 \003(\t\022/\n\004mask\030\003" - " \001(\0132!.google.firestore.v1.DocumentMask\022" - "\025\n\013transaction\030\004 \001(\014H\000\022B\n\017new_transactio" - "n\030\005 \001(\0132\'.google.firestore.v1.Transactio" - "nOptionsH\000\022/\n\tread_time\030\007 \001(\0132\032.google.p" - "rotobuf.TimestampH\000B\026\n\024consistency_selec" - "tor\"\254\001\n\031BatchGetDocumentsResponse\022.\n\005fou" - "nd\030\001 \001(\0132\035.google.firestore.v1.DocumentH" - "\000\022\021\n\007missing\030\002 \001(\tH\000\022\023\n\013transaction\030\003 \001(" - "\014\022-\n\tread_time\030\004 \001(\0132\032.google.protobuf.T" - "imestampB\010\n\006result\"e\n\027BeginTransactionRe" - "quest\022\020\n\010database\030\001 \001(\t\0228\n\007options\030\002 \001(\013" - "2\'.google.firestore.v1.TransactionOption" - "s\"/\n\030BeginTransactionResponse\022\023\n\013transac" - "tion\030\001 \001(\014\"b\n\rCommitRequest\022\020\n\010database\030" - "\001 \001(\t\022*\n\006writes\030\002 \003(\0132\032.google.firestore" - ".v1.Write\022\023\n\013transaction\030\003 \001(\014\"z\n\016Commit" - "Response\0227\n\rwrite_results\030\001 \003(\0132 .google" - ".firestore.v1.WriteResult\022/\n\013commit_time" - "\030\002 \001(\0132\032.google.protobuf.Timestamp\"8\n\017Ro" - "llbackRequest\022\020\n\010database\030\001 \001(\t\022\023\n\013trans" - "action\030\002 \001(\014\"\225\002\n\017RunQueryRequest\022\016\n\006pare" - "nt\030\001 \001(\t\022@\n\020structured_query\030\002 \001(\0132$.goo" - "gle.firestore.v1.StructuredQueryH\000\022\025\n\013tr" - "ansaction\030\005 \001(\014H\001\022B\n\017new_transaction\030\006 \001" - "(\0132\'.google.firestore.v1.TransactionOpti" - "onsH\001\022/\n\tread_time\030\007 \001(\0132\032.google.protob" - "uf.TimestampH\001B\014\n\nquery_typeB\026\n\024consiste" - "ncy_selector\"\240\001\n\020RunQueryResponse\022\023\n\013tra" - "nsaction\030\002 \001(\014\022/\n\010document\030\001 \001(\0132\035.googl" - "e.firestore.v1.Document\022-\n\tread_time\030\003 \001" - "(\0132\032.google.protobuf.Timestamp\022\027\n\017skippe" - "d_results\030\004 \001(\005\"\267\002\n\032RunAggregationQueryR" - "equest\022\016\n\006parent\030\001 \001(\t\022W\n\034structured_agg" - "regation_query\030\002 \001(\0132/.google.firestore." - "v1.StructuredAggregationQueryH\000\022\025\n\013trans" - "action\030\004 \001(\014H\001\022B\n\017new_transaction\030\005 \001(\0132" - "\'.google.firestore.v1.TransactionOptions" - "H\001\022/\n\tread_time\030\006 \001(\0132\032.google.protobuf." - "TimestampH\001B\014\n\nquery_typeB\026\n\024consistency" - "_selector\"\231\001\n\033RunAggregationQueryRespons" - "e\0226\n\006result\030\001 \001(\0132&.google.firestore.v1." - "AggregationResult\022\023\n\013transaction\030\002 \001(\014\022-" - "\n\tread_time\030\003 \001(\0132\032.google.protobuf.Time" - "stamp\"\343\001\n\014WriteRequest\022\020\n\010database\030\001 \001(\t" - "\022\021\n\tstream_id\030\002 \001(\t\022*\n\006writes\030\003 \003(\0132\032.go" - "ogle.firestore.v1.Write\022\024\n\014stream_token\030" - "\004 \001(\014\022=\n\006labels\030\005 \003(\0132-.google.firestore" - ".v1.WriteRequest.LabelsEntry\032-\n\013LabelsEn" - "try\022\013\n\003key\030\001 \001(\t\022\r\n\005value\030\002 \001(\t:\0028\001\"\242\001\n\r" - "WriteResponse\022\021\n\tstream_id\030\001 \001(\t\022\024\n\014stre" - "am_token\030\002 \001(\014\0227\n\rwrite_results\030\003 \003(\0132 ." - "google.firestore.v1.WriteResult\022/\n\013commi" - "t_time\030\004 \001(\0132\032.google.protobuf.Timestamp" - "\"\355\001\n\rListenRequest\022\020\n\010database\030\001 \001(\t\0221\n\n" - "add_target\030\002 \001(\0132\033.google.firestore.v1.T" - "argetH\000\022\027\n\rremove_target\030\003 \001(\005H\000\022>\n\006labe" - "ls\030\004 \003(\0132..google.firestore.v1.ListenReq" - "uest.LabelsEntry\032-\n\013LabelsEntry\022\013\n\003key\030\001" - " \001(\t\022\r\n\005value\030\002 \001(\t:\0028\001B\017\n\rtarget_change" - "\"\325\002\n\016ListenResponse\022:\n\rtarget_change\030\002 \001" - "(\0132!.google.firestore.v1.TargetChangeH\000\022" - ">\n\017document_change\030\003 \001(\0132#.google.firest" - "ore.v1.DocumentChangeH\000\022>\n\017document_dele" - "te\030\004 \001(\0132#.google.firestore.v1.DocumentD" - "eleteH\000\022>\n\017document_remove\030\006 \001(\0132#.googl" - "e.firestore.v1.DocumentRemoveH\000\0226\n\006filte" - "r\030\005 \001(\0132$.google.firestore.v1.ExistenceF" - "ilterH\000B\017\n\rresponse_type\"\326\003\n\006Target\0228\n\005q" - "uery\030\002 \001(\0132\'.google.firestore.v1.Target." - "QueryTargetH\000\022@\n\tdocuments\030\003 \001(\0132+.googl" - "e.firestore.v1.Target.DocumentsTargetH\000\022" - "\026\n\014resume_token\030\004 \001(\014H\001\022/\n\tread_time\030\013 \001" - "(\0132\032.google.protobuf.TimestampH\001\022\021\n\ttarg" - "et_id\030\005 \001(\005\022\014\n\004once\030\006 \001(\010\0223\n\016expected_co" - "unt\030\014 \001(\0132\033.google.protobuf.Int32Value\032$" - "\n\017DocumentsTarget\022\021\n\tdocuments\030\002 \003(\t\032m\n\013" - "QueryTarget\022\016\n\006parent\030\001 \001(\t\022@\n\020structure" - "d_query\030\002 \001(\0132$.google.firestore.v1.Stru" - "cturedQueryH\000B\014\n\nquery_typeB\r\n\013target_ty" - "peB\r\n\013resume_type\"\252\002\n\014TargetChange\022N\n\022ta" - "rget_change_type\030\001 \001(\01622.google.firestor" - "e.v1.TargetChange.TargetChangeType\022\022\n\nta" - "rget_ids\030\002 \003(\005\022!\n\005cause\030\003 \001(\0132\022.google.r" - "pc.Status\022\024\n\014resume_token\030\004 \001(\014\022-\n\tread_" - "time\030\006 \001(\0132\032.google.protobuf.Timestamp\"N" - "\n\020TargetChangeType\022\r\n\tNO_CHANGE\020\000\022\007\n\003ADD" - "\020\001\022\n\n\006REMOVE\020\002\022\013\n\007CURRENT\020\003\022\t\n\005RESET\020\004\"Q" - "\n\030ListCollectionIdsRequest\022\016\n\006parent\030\001 \001" - "(\t\022\021\n\tpage_size\030\002 \001(\005\022\022\n\npage_token\030\003 \001(" - "\t\"L\n\031ListCollectionIdsResponse\022\026\n\016collec" - "tion_ids\030\001 \003(\t\022\027\n\017next_page_token\030\002 \001(\t2" - "\236\024\n\tFirestore\022\217\001\n\013GetDocument\022\'.google.f" - "irestore.v1.GetDocumentRequest\032\035.google." - "firestore.v1.Document\"8\202\323\344\223\0022\0220/v1/{name" - "=projects/*/databases/*/documents/*/**}\022" - "\262\001\n\rListDocuments\022).google.firestore.v1." - "ListDocumentsRequest\032*.google.firestore." - "v1.ListDocumentsResponse\"J\202\323\344\223\002D\022B/v1/{p" - "arent=projects/*/databases/*/documents/*" - "/**}/{collection_id}\022\257\001\n\016CreateDocument\022" - "*.google.firestore.v1.CreateDocumentRequ" - "est\032\035.google.firestore.v1.Document\"R\202\323\344\223" - "\002L\"@/v1/{parent=projects/*/databases/*/d" - "ocuments/**}/{collection_id}:\010document\022\250" - "\001\n\016UpdateDocument\022*.google.firestore.v1." - "UpdateDocumentRequest\032\035.google.firestore" - ".v1.Document\"K\202\323\344\223\002E29/v1/{document.name" - "=projects/*/databases/*/documents/*/**}:" - "\010document\022\216\001\n\016DeleteDocument\022*.google.fi" - "restore.v1.DeleteDocumentRequest\032\026.googl" - "e.protobuf.Empty\"8\202\323\344\223\0022*0/v1/{name=proj" - "ects/*/databases/*/documents/*/**}\022\271\001\n\021B" - "atchGetDocuments\022-.google.firestore.v1.B" - "atchGetDocumentsRequest\032..google.firesto" - "re.v1.BatchGetDocumentsResponse\"C\202\323\344\223\002=\"" - "8/v1/{database=projects/*/databases/*}/d" - "ocuments:batchGet:\001*0\001\022\274\001\n\020BeginTransact" - "ion\022,.google.firestore.v1.BeginTransacti" - "onRequest\032-.google.firestore.v1.BeginTra" - "nsactionResponse\"K\202\323\344\223\002E\"@/v1/{database=" - "projects/*/databases/*}/documents:beginT" - "ransaction:\001*\022\224\001\n\006Commit\022\".google.firest" - "ore.v1.CommitRequest\032#.google.firestore." - "v1.CommitResponse\"A\202\323\344\223\002;\"6/v1/{database" - "=projects/*/databases/*}/documents:commi" - "t:\001*\022\215\001\n\010Rollback\022$.google.firestore.v1." - "RollbackRequest\032\026.google.protobuf.Empty\"" - "C\202\323\344\223\002=\"8/v1/{database=projects/*/databa" - "ses/*}/documents:rollback:\001*\022\337\001\n\010RunQuer" - "y\022$.google.firestore.v1.RunQueryRequest\032" - "%.google.firestore.v1.RunQueryResponse\"\203" - "\001\202\323\344\223\002}\"6/v1/{parent=projects/*/database" - "s/*/documents}:runQuery:\001*Z@\";/v1/{paren" + "ns.proto\032\037google/api/field_behavior.prot" + "o\032,google/firestore/v1/aggregation_resul" + "t.proto\032 google/firestore/v1/common.prot" + "o\032\"google/firestore/v1/document.proto\032\'g" + "oogle/firestore/v1/explain_stats.proto\032\"" + "google/firestore/v1/pipeline.proto\032\037goog" + "le/firestore/v1/query.proto\032\037google/fire" + "store/v1/write.proto\032\033google/protobuf/em" + "pty.proto\032\037google/protobuf/timestamp.pro" + "to\032\036google/protobuf/wrappers.proto\032\027goog" + "le/rpc/status.proto\"\263\001\n\022GetDocumentReque" + "st\022\014\n\004name\030\001 \001(\t\022/\n\004mask\030\002 \001(\0132!.google." + "firestore.v1.DocumentMask\022\025\n\013transaction" + "\030\003 \001(\014H\000\022/\n\tread_time\030\005 \001(\0132\032.google.pro" + "tobuf.TimestampH\000B\026\n\024consistency_selecto" + "r\"\235\002\n\024ListDocumentsRequest\022\016\n\006parent\030\001 \001" + "(\t\022\025\n\rcollection_id\030\002 \001(\t\022\021\n\tpage_size\030\003" + " \001(\005\022\022\n\npage_token\030\004 \001(\t\022\020\n\010order_by\030\006 \001" + "(\t\022/\n\004mask\030\007 \001(\0132!.google.firestore.v1.D" + "ocumentMask\022\025\n\013transaction\030\010 \001(\014H\000\022/\n\tre" + "ad_time\030\n \001(\0132\032.google.protobuf.Timestam" + "pH\000\022\024\n\014show_missing\030\014 \001(\010B\026\n\024consistency" + "_selector\"b\n\025ListDocumentsResponse\0220\n\tdo" + "cuments\030\001 \003(\0132\035.google.firestore.v1.Docu" + "ment\022\027\n\017next_page_token\030\002 \001(\t\"\265\001\n\025Create" + "DocumentRequest\022\016\n\006parent\030\001 \001(\t\022\025\n\rcolle" + "ction_id\030\002 \001(\t\022\023\n\013document_id\030\003 \001(\t\022/\n\010d" + "ocument\030\004 \001(\0132\035.google.firestore.v1.Docu" + "ment\022/\n\004mask\030\005 \001(\0132!.google.firestore.v1" + ".DocumentMask\"\356\001\n\025UpdateDocumentRequest\022" + "/\n\010document\030\001 \001(\0132\035.google.firestore.v1." + "Document\0226\n\013update_mask\030\002 \001(\0132!.google.f" + "irestore.v1.DocumentMask\022/\n\004mask\030\003 \001(\0132!" + ".google.firestore.v1.DocumentMask\022;\n\020cur" + "rent_document\030\004 \001(\0132!.google.firestore.v" + "1.Precondition\"b\n\025DeleteDocumentRequest\022" + "\014\n\004name\030\001 \001(\t\022;\n\020current_document\030\002 \001(\0132" + "!.google.firestore.v1.Precondition\"\224\002\n\030B" + "atchGetDocumentsRequest\022\020\n\010database\030\001 \001(" + "\t\022\021\n\tdocuments\030\002 \003(\t\022/\n\004mask\030\003 \001(\0132!.goo" + "gle.firestore.v1.DocumentMask\022\025\n\013transac" + "tion\030\004 \001(\014H\000\022B\n\017new_transaction\030\005 \001(\0132\'." + "google.firestore.v1.TransactionOptionsH\000" + "\022/\n\tread_time\030\007 \001(\0132\032.google.protobuf.Ti" + "mestampH\000B\026\n\024consistency_selector\"\254\001\n\031Ba" + "tchGetDocumentsResponse\022.\n\005found\030\001 \001(\0132\035" + ".google.firestore.v1.DocumentH\000\022\021\n\007missi" + "ng\030\002 \001(\tH\000\022\023\n\013transaction\030\003 \001(\014\022-\n\tread_" + "time\030\004 \001(\0132\032.google.protobuf.TimestampB\010" + "\n\006result\"e\n\027BeginTransactionRequest\022\020\n\010d" + "atabase\030\001 \001(\t\0228\n\007options\030\002 \001(\0132\'.google." + "firestore.v1.TransactionOptions\"/\n\030Begin" + "TransactionResponse\022\023\n\013transaction\030\001 \001(\014" + "\"b\n\rCommitRequest\022\020\n\010database\030\001 \001(\t\022*\n\006w" + "rites\030\002 \003(\0132\032.google.firestore.v1.Write\022" + "\023\n\013transaction\030\003 \001(\014\"z\n\016CommitResponse\0227" + "\n\rwrite_results\030\001 \003(\0132 .google.firestore" + ".v1.WriteResult\022/\n\013commit_time\030\002 \001(\0132\032.g" + "oogle.protobuf.Timestamp\"8\n\017RollbackRequ" + "est\022\020\n\010database\030\001 \001(\t\022\023\n\013transaction\030\002 \001" + "(\014\"\225\002\n\017RunQueryRequest\022\016\n\006parent\030\001 \001(\t\022@" + "\n\020structured_query\030\002 \001(\0132$.google.firest" + "ore.v1.StructuredQueryH\000\022\025\n\013transaction\030" + "\005 \001(\014H\001\022B\n\017new_transaction\030\006 \001(\0132\'.googl" + "e.firestore.v1.TransactionOptionsH\001\022/\n\tr" + "ead_time\030\007 \001(\0132\032.google.protobuf.Timesta" + "mpH\001B\014\n\nquery_typeB\026\n\024consistency_select" + "or\"\240\001\n\020RunQueryResponse\022\023\n\013transaction\030\002" + " \001(\014\022/\n\010document\030\001 \001(\0132\035.google.firestor" + "e.v1.Document\022-\n\tread_time\030\003 \001(\0132\032.googl" + "e.protobuf.Timestamp\022\027\n\017skipped_results\030" + "\004 \001(\005\"\254\002\n\026ExecutePipelineRequest\022\025\n\010data" + "base\030\001 \001(\tB\003\340A\002\022F\n\023structured_pipeline\030\002" + " \001(\0132\'.google.firestore.v1.StructuredPip" + "elineH\000\022\025\n\013transaction\030\005 \001(\014H\001\022B\n\017new_tr" + "ansaction\030\006 \001(\0132\'.google.firestore.v1.Tr" + "ansactionOptionsH\001\022/\n\tread_time\030\007 \001(\0132\032." + "google.protobuf.TimestampH\001B\017\n\rpipeline_" + "typeB\026\n\024consistency_selector\"\314\001\n\027Execute" + "PipelineResponse\022\023\n\013transaction\030\001 \001(\014\022.\n" + "\007results\030\002 \003(\0132\035.google.firestore.v1.Doc" + "ument\0222\n\016execution_time\030\003 \001(\0132\032.google.p" + "rotobuf.Timestamp\0228\n\rexplain_stats\030\004 \001(\013" + "2!.google.firestore.v1.ExplainStats\"\267\002\n\032" + "RunAggregationQueryRequest\022\016\n\006parent\030\001 \001" + "(\t\022W\n\034structured_aggregation_query\030\002 \001(\013" + "2/.google.firestore.v1.StructuredAggrega" + "tionQueryH\000\022\025\n\013transaction\030\004 \001(\014H\001\022B\n\017ne" + "w_transaction\030\005 \001(\0132\'.google.firestore.v" + "1.TransactionOptionsH\001\022/\n\tread_time\030\006 \001(" + "\0132\032.google.protobuf.TimestampH\001B\014\n\nquery" + "_typeB\026\n\024consistency_selector\"\231\001\n\033RunAgg" + "regationQueryResponse\0226\n\006result\030\001 \001(\0132&." + "google.firestore.v1.AggregationResult\022\023\n" + "\013transaction\030\002 \001(\014\022-\n\tread_time\030\003 \001(\0132\032." + "google.protobuf.Timestamp\"\343\001\n\014WriteReque" + "st\022\020\n\010database\030\001 \001(\t\022\021\n\tstream_id\030\002 \001(\t\022" + "*\n\006writes\030\003 \003(\0132\032.google.firestore.v1.Wr" + "ite\022\024\n\014stream_token\030\004 \001(\014\022=\n\006labels\030\005 \003(" + "\0132-.google.firestore.v1.WriteRequest.Lab" + "elsEntry\032-\n\013LabelsEntry\022\013\n\003key\030\001 \001(\t\022\r\n\005" + "value\030\002 \001(\t:\0028\001\"\242\001\n\rWriteResponse\022\021\n\tstr" + "eam_id\030\001 \001(\t\022\024\n\014stream_token\030\002 \001(\014\0227\n\rwr" + "ite_results\030\003 \003(\0132 .google.firestore.v1." + "WriteResult\022/\n\013commit_time\030\004 \001(\0132\032.googl" + "e.protobuf.Timestamp\"\355\001\n\rListenRequest\022\020" + "\n\010database\030\001 \001(\t\0221\n\nadd_target\030\002 \001(\0132\033.g" + "oogle.firestore.v1.TargetH\000\022\027\n\rremove_ta" + "rget\030\003 \001(\005H\000\022>\n\006labels\030\004 \003(\0132..google.fi" + "restore.v1.ListenRequest.LabelsEntry\032-\n\013" + "LabelsEntry\022\013\n\003key\030\001 \001(\t\022\r\n\005value\030\002 \001(\t:" + "\0028\001B\017\n\rtarget_change\"\325\002\n\016ListenResponse\022" + ":\n\rtarget_change\030\002 \001(\0132!.google.firestor" + "e.v1.TargetChangeH\000\022>\n\017document_change\030\003" + " \001(\0132#.google.firestore.v1.DocumentChang" + "eH\000\022>\n\017document_delete\030\004 \001(\0132#.google.fi" + "restore.v1.DocumentDeleteH\000\022>\n\017document_" + "remove\030\006 \001(\0132#.google.firestore.v1.Docum" + "entRemoveH\000\0226\n\006filter\030\005 \001(\0132$.google.fir" + "estore.v1.ExistenceFilterH\000B\017\n\rresponse_" + "type\"\326\003\n\006Target\0228\n\005query\030\002 \001(\0132\'.google." + "firestore.v1.Target.QueryTargetH\000\022@\n\tdoc" + "uments\030\003 \001(\0132+.google.firestore.v1.Targe" + "t.DocumentsTargetH\000\022\026\n\014resume_token\030\004 \001(" + "\014H\001\022/\n\tread_time\030\013 \001(\0132\032.google.protobuf" + ".TimestampH\001\022\021\n\ttarget_id\030\005 \001(\005\022\014\n\004once\030" + "\006 \001(\010\0223\n\016expected_count\030\014 \001(\0132\033.google.p" + "rotobuf.Int32Value\032$\n\017DocumentsTarget\022\021\n" + "\tdocuments\030\002 \003(\t\032m\n\013QueryTarget\022\016\n\006paren" + "t\030\001 \001(\t\022@\n\020structured_query\030\002 \001(\0132$.goog" + "le.firestore.v1.StructuredQueryH\000B\014\n\nque" + "ry_typeB\r\n\013target_typeB\r\n\013resume_type\"\252\002" + "\n\014TargetChange\022N\n\022target_change_type\030\001 \001" + "(\01622.google.firestore.v1.TargetChange.Ta" + "rgetChangeType\022\022\n\ntarget_ids\030\002 \003(\005\022!\n\005ca" + "use\030\003 \001(\0132\022.google.rpc.Status\022\024\n\014resume_" + "token\030\004 \001(\014\022-\n\tread_time\030\006 \001(\0132\032.google." + "protobuf.Timestamp\"N\n\020TargetChangeType\022\r" + "\n\tNO_CHANGE\020\000\022\007\n\003ADD\020\001\022\n\n\006REMOVE\020\002\022\013\n\007CU" + "RRENT\020\003\022\t\n\005RESET\020\004\"Q\n\030ListCollectionIdsR" + "equest\022\016\n\006parent\030\001 \001(\t\022\021\n\tpage_size\030\002 \001(" + "\005\022\022\n\npage_token\030\003 \001(\t\"L\n\031ListCollectionI" + "dsResponse\022\026\n\016collection_ids\030\001 \003(\t\022\027\n\017ne" + "xt_page_token\030\002 \001(\t2\333\025\n\tFirestore\022\217\001\n\013Ge" + "tDocument\022\'.google.firestore.v1.GetDocum" + "entRequest\032\035.google.firestore.v1.Documen" + "t\"8\202\323\344\223\0022\0220/v1/{name=projects/*/database" + "s/*/documents/*/**}\022\262\001\n\rListDocuments\022)." + "google.firestore.v1.ListDocumentsRequest" + "\032*.google.firestore.v1.ListDocumentsResp" + "onse\"J\202\323\344\223\002D\022B/v1/{parent=projects/*/dat" + "abases/*/documents/*/**}/{collection_id}" + "\022\257\001\n\016CreateDocument\022*.google.firestore.v" + "1.CreateDocumentRequest\032\035.google.firesto" + "re.v1.Document\"R\202\323\344\223\002L\"@/v1/{parent=proj" + "ects/*/databases/*/documents/**}/{collec" + "tion_id}:\010document\022\250\001\n\016UpdateDocument\022*." + "google.firestore.v1.UpdateDocumentReques" + "t\032\035.google.firestore.v1.Document\"K\202\323\344\223\002E" + "29/v1/{document.name=projects/*/database" + "s/*/documents/*/**}:\010document\022\216\001\n\016Delete" + "Document\022*.google.firestore.v1.DeleteDoc" + "umentRequest\032\026.google.protobuf.Empty\"8\202\323" + "\344\223\0022*0/v1/{name=projects/*/databases/*/d" + "ocuments/*/**}\022\271\001\n\021BatchGetDocuments\022-.g" + "oogle.firestore.v1.BatchGetDocumentsRequ" + "est\032..google.firestore.v1.BatchGetDocume" + "ntsResponse\"C\202\323\344\223\002=\"8/v1/{database=proje" + "cts/*/databases/*}/documents:batchGet:\001*" + "0\001\022\274\001\n\020BeginTransaction\022,.google.firesto" + "re.v1.BeginTransactionRequest\032-.google.f" + "irestore.v1.BeginTransactionResponse\"K\202\323" + "\344\223\002E\"@/v1/{database=projects/*/databases" + "/*}/documents:beginTransaction:\001*\022\224\001\n\006Co" + "mmit\022\".google.firestore.v1.CommitRequest" + "\032#.google.firestore.v1.CommitResponse\"A\202" + "\323\344\223\002;\"6/v1/{database=projects/*/database" + "s/*}/documents:commit:\001*\022\215\001\n\010Rollback\022$." + "google.firestore.v1.RollbackRequest\032\026.go" + "ogle.protobuf.Empty\"C\202\323\344\223\002=\"8/v1/{databa" + "se=projects/*/databases/*}/documents:rol" + "lback:\001*\022\337\001\n\010RunQuery\022$.google.firestore" + ".v1.RunQueryRequest\032%.google.firestore.v" + "1.RunQueryResponse\"\203\001\202\323\344\223\002}\"6/v1/{parent" + "=projects/*/databases/*/documents}:runQu" + "ery:\001*Z@\";/v1/{parent=projects/*/databas" + "es/*/documents/*/**}:runQuery:\001*0\001\022\272\001\n\017E" + "xecutePipeline\022+.google.firestore.v1.Exe" + "cutePipelineRequest\032,.google.firestore.v" + "1.ExecutePipelineResponse\"J\202\323\344\223\002D\"\?/v1/{" + "database=projects/*/databases/*}/documen" + "ts:executePipeline:\001*0\001\022\227\002\n\023RunAggregati" + "onQuery\022/.google.firestore.v1.RunAggrega" + "tionQueryRequest\0320.google.firestore.v1.R" + "unAggregationQueryResponse\"\232\001\202\323\344\223\002\223\001\"A/v" + "1/{parent=projects/*/databases/*/documen" + "ts}:runAggregationQuery:\001*ZK\"F/v1/{paren" "t=projects/*/databases/*/documents/*/**}" - ":runQuery:\001*0\001\022\227\002\n\023RunAggregationQuery\022/" - ".google.firestore.v1.RunAggregationQuery" - "Request\0320.google.firestore.v1.RunAggrega" - "tionQueryResponse\"\232\001\202\323\344\223\002\223\001\"A/v1/{parent" - "=projects/*/databases/*/documents}:runAg" - "gregationQuery:\001*ZK\"F/v1/{parent=project" - "s/*/databases/*/documents/*/**}:runAggre" - "gationQuery:\001*0\001\022\224\001\n\005Write\022!.google.fire" - "store.v1.WriteRequest\032\".google.firestore" - ".v1.WriteResponse\"@\202\323\344\223\002:\"5/v1/{database" - "=projects/*/databases/*}/documents:write" - ":\001*(\0010\001\022\230\001\n\006Listen\022\".google.firestore.v1" - ".ListenRequest\032#.google.firestore.v1.Lis" - "tenResponse\"A\202\323\344\223\002;\"6/v1/{database=proje" - "cts/*/databases/*}/documents:listen:\001*(\001" - "0\001\022\213\002\n\021ListCollectionIds\022-.google.firest" - "ore.v1.ListCollectionIdsRequest\032..google" - ".firestore.v1.ListCollectionIdsResponse\"" - "\226\001\202\323\344\223\002\217\001\"\?/v1/{parent=projects/*/databa" - "ses/*/documents}:listCollectionIds:\001*ZI\"" - "D/v1/{parent=projects/*/databases/*/docu" - "ments/*/**}:listCollectionIds:\001*B\262\001\n\027com" - ".google.firestore.v1B\016FirestoreProtoP\001Z<" - "google.golang.org/genproto/googleapis/fi" - "restore/v1;firestore\242\002\004GCFS\252\002\036Google.Clo" - "ud.Firestore.V1Beta1\312\002\036Google\\Cloud\\Fire" - "store\\V1beta1b\006proto3" + ":runAggregationQuery:\001*0\001\022\224\001\n\005Write\022!.go" + "ogle.firestore.v1.WriteRequest\032\".google." + "firestore.v1.WriteResponse\"@\202\323\344\223\002:\"5/v1/" + "{database=projects/*/databases/*}/docume" + "nts:write:\001*(\0010\001\022\230\001\n\006Listen\022\".google.fir" + "estore.v1.ListenRequest\032#.google.firesto" + "re.v1.ListenResponse\"A\202\323\344\223\002;\"6/v1/{datab" + "ase=projects/*/databases/*}/documents:li" + "sten:\001*(\0010\001\022\213\002\n\021ListCollectionIds\022-.goog" + "le.firestore.v1.ListCollectionIdsRequest" + "\032..google.firestore.v1.ListCollectionIds" + "Response\"\226\001\202\323\344\223\002\217\001\"\?/v1/{parent=projects" + "/*/databases/*/documents}:listCollection" + "Ids:\001*ZI\"D/v1/{parent=projects/*/databas" + "es/*/documents/*/**}:listCollectionIds:\001" + "*B\262\001\n\027com.google.firestore.v1B\016Firestore" + "ProtoP\001Z_impl_.query_type_.structured_aggregation_query_; +const ::google::firestore::v1::StructuredPipeline& ExecutePipelineRequest::_Internal::structured_pipeline(const ExecutePipelineRequest* msg) { + return *msg->_impl_.pipeline_type_.structured_pipeline_; } -const ::google::firestore::v1::TransactionOptions& RunAggregationQueryRequest::_Internal::new_transaction(const RunAggregationQueryRequest* msg) { +const ::google::firestore::v1::TransactionOptions& ExecutePipelineRequest::_Internal::new_transaction(const ExecutePipelineRequest* msg) { return *msg->_impl_.consistency_selector_.new_transaction_; } -const ::google::protobuf::Timestamp& RunAggregationQueryRequest::_Internal::read_time(const RunAggregationQueryRequest* msg) { +const ::google::protobuf::Timestamp& ExecutePipelineRequest::_Internal::read_time(const ExecutePipelineRequest* msg) { return *msg->_impl_.consistency_selector_.read_time_; } -void RunAggregationQueryRequest::set_allocated_structured_aggregation_query(::google::firestore::v1::StructuredAggregationQuery* structured_aggregation_query) { +void ExecutePipelineRequest::set_allocated_structured_pipeline(::google::firestore::v1::StructuredPipeline* structured_pipeline) { ::google::protobuf::Arena* message_arena = GetArena(); - clear_query_type(); - if (structured_aggregation_query) { - ::google::protobuf::Arena* submessage_arena = reinterpret_cast<::google::protobuf::MessageLite*>(structured_aggregation_query)->GetArena(); + clear_pipeline_type(); + if (structured_pipeline) { + ::google::protobuf::Arena* submessage_arena = reinterpret_cast<::google::protobuf::MessageLite*>(structured_pipeline)->GetArena(); if (message_arena != submessage_arena) { - structured_aggregation_query = ::google::protobuf::internal::GetOwnedMessage(message_arena, structured_aggregation_query, submessage_arena); + structured_pipeline = ::google::protobuf::internal::GetOwnedMessage(message_arena, structured_pipeline, submessage_arena); } - set_has_structured_aggregation_query(); - _impl_.query_type_.structured_aggregation_query_ = structured_aggregation_query; + set_has_structured_pipeline(); + _impl_.pipeline_type_.structured_pipeline_ = structured_pipeline; } - // @@protoc_insertion_point(field_set_allocated:google.firestore.v1.RunAggregationQueryRequest.structured_aggregation_query) + // @@protoc_insertion_point(field_set_allocated:google.firestore.v1.ExecutePipelineRequest.structured_pipeline) } -void RunAggregationQueryRequest::clear_structured_aggregation_query() { +void ExecutePipelineRequest::clear_structured_pipeline() { PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); - if (query_type_case() == kStructuredAggregationQuery) { + if (pipeline_type_case() == kStructuredPipeline) { if (GetArena() == nullptr) { - delete _impl_.query_type_.structured_aggregation_query_; + delete _impl_.pipeline_type_.structured_pipeline_; } - clear_has_query_type(); + clear_has_pipeline_type(); } } -void RunAggregationQueryRequest::set_allocated_new_transaction(::google::firestore::v1::TransactionOptions* new_transaction) { +void ExecutePipelineRequest::set_allocated_new_transaction(::google::firestore::v1::TransactionOptions* new_transaction) { ::google::protobuf::Arena* message_arena = GetArena(); clear_consistency_selector(); if (new_transaction) { @@ -6357,9 +6463,9 @@ void RunAggregationQueryRequest::set_allocated_new_transaction(::google::firesto set_has_new_transaction(); _impl_.consistency_selector_.new_transaction_ = new_transaction; } - // @@protoc_insertion_point(field_set_allocated:google.firestore.v1.RunAggregationQueryRequest.new_transaction) + // @@protoc_insertion_point(field_set_allocated:google.firestore.v1.ExecutePipelineRequest.new_transaction) } -void RunAggregationQueryRequest::clear_new_transaction() { +void ExecutePipelineRequest::clear_new_transaction() { PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); if (consistency_selector_case() == kNewTransaction) { if (GetArena() == nullptr) { @@ -6368,7 +6474,7 @@ void RunAggregationQueryRequest::clear_new_transaction() { clear_has_consistency_selector(); } } -void RunAggregationQueryRequest::set_allocated_read_time(::google::protobuf::Timestamp* read_time) { +void ExecutePipelineRequest::set_allocated_read_time(::google::protobuf::Timestamp* read_time) { ::google::protobuf::Arena* message_arena = GetArena(); clear_consistency_selector(); if (read_time) { @@ -6379,9 +6485,9 @@ void RunAggregationQueryRequest::set_allocated_read_time(::google::protobuf::Tim set_has_read_time(); _impl_.consistency_selector_.read_time_ = read_time; } - // @@protoc_insertion_point(field_set_allocated:google.firestore.v1.RunAggregationQueryRequest.read_time) + // @@protoc_insertion_point(field_set_allocated:google.firestore.v1.ExecutePipelineRequest.read_time) } -void RunAggregationQueryRequest::clear_read_time() { +void ExecutePipelineRequest::clear_read_time() { PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); if (consistency_selector_case() == kReadTime) { if (GetArena() == nullptr) { @@ -6390,34 +6496,34 @@ void RunAggregationQueryRequest::clear_read_time() { clear_has_consistency_selector(); } } -RunAggregationQueryRequest::RunAggregationQueryRequest(::google::protobuf::Arena* arena) +ExecutePipelineRequest::ExecutePipelineRequest(::google::protobuf::Arena* arena) : ::google::protobuf::Message(arena) { SharedCtor(arena); - // @@protoc_insertion_point(arena_constructor:google.firestore.v1.RunAggregationQueryRequest) + // @@protoc_insertion_point(arena_constructor:google.firestore.v1.ExecutePipelineRequest) } -inline PROTOBUF_NDEBUG_INLINE RunAggregationQueryRequest::Impl_::Impl_( +inline PROTOBUF_NDEBUG_INLINE ExecutePipelineRequest::Impl_::Impl_( ::google::protobuf::internal::InternalVisibility visibility, ::google::protobuf::Arena* arena, const Impl_& from) - : parent_(arena, from.parent_), - query_type_{}, + : database_(arena, from.database_), + pipeline_type_{}, consistency_selector_{}, _cached_size_{0}, _oneof_case_{from._oneof_case_[0], from._oneof_case_[1]} {} -RunAggregationQueryRequest::RunAggregationQueryRequest( +ExecutePipelineRequest::ExecutePipelineRequest( ::google::protobuf::Arena* arena, - const RunAggregationQueryRequest& from) + const ExecutePipelineRequest& from) : ::google::protobuf::Message(arena) { - RunAggregationQueryRequest* const _this = this; + ExecutePipelineRequest* const _this = this; (void)_this; _internal_metadata_.MergeFrom<::google::protobuf::UnknownFieldSet>( from._internal_metadata_); new (&_impl_) Impl_(internal_visibility(), arena, from._impl_); - switch (query_type_case()) { - case QUERY_TYPE_NOT_SET: + switch (pipeline_type_case()) { + case PIPELINE_TYPE_NOT_SET: break; - case kStructuredAggregationQuery: - _impl_.query_type_.structured_aggregation_query_ = CreateMaybeMessage<::google::firestore::v1::StructuredAggregationQuery>(arena, *from._impl_.query_type_.structured_aggregation_query_); + case kStructuredPipeline: + _impl_.pipeline_type_.structured_pipeline_ = CreateMaybeMessage<::google::firestore::v1::StructuredPipeline>(arena, *from._impl_.pipeline_type_.structured_pipeline_); break; } switch (consistency_selector_case()) { @@ -6434,30 +6540,30 @@ RunAggregationQueryRequest::RunAggregationQueryRequest( break; } - // @@protoc_insertion_point(copy_constructor:google.firestore.v1.RunAggregationQueryRequest) + // @@protoc_insertion_point(copy_constructor:google.firestore.v1.ExecutePipelineRequest) } -inline PROTOBUF_NDEBUG_INLINE RunAggregationQueryRequest::Impl_::Impl_( +inline PROTOBUF_NDEBUG_INLINE ExecutePipelineRequest::Impl_::Impl_( ::google::protobuf::internal::InternalVisibility visibility, ::google::protobuf::Arena* arena) - : parent_(arena), - query_type_{}, + : database_(arena), + pipeline_type_{}, consistency_selector_{}, _cached_size_{0}, _oneof_case_{} {} -inline void RunAggregationQueryRequest::SharedCtor(::_pb::Arena* arena) { +inline void ExecutePipelineRequest::SharedCtor(::_pb::Arena* arena) { new (&_impl_) Impl_(internal_visibility(), arena); } -RunAggregationQueryRequest::~RunAggregationQueryRequest() { - // @@protoc_insertion_point(destructor:google.firestore.v1.RunAggregationQueryRequest) +ExecutePipelineRequest::~ExecutePipelineRequest() { + // @@protoc_insertion_point(destructor:google.firestore.v1.ExecutePipelineRequest) _internal_metadata_.Delete<::google::protobuf::UnknownFieldSet>(); SharedDtor(); } -inline void RunAggregationQueryRequest::SharedDtor() { +inline void ExecutePipelineRequest::SharedDtor() { ABSL_DCHECK(GetArena() == nullptr); - _impl_.parent_.Destroy(); - if (has_query_type()) { - clear_query_type(); + _impl_.database_.Destroy(); + if (has_pipeline_type()) { + clear_pipeline_type(); } if (has_consistency_selector()) { clear_consistency_selector(); @@ -6465,25 +6571,25 @@ inline void RunAggregationQueryRequest::SharedDtor() { _impl_.~Impl_(); } -void RunAggregationQueryRequest::clear_query_type() { -// @@protoc_insertion_point(one_of_clear_start:google.firestore.v1.RunAggregationQueryRequest) +void ExecutePipelineRequest::clear_pipeline_type() { +// @@protoc_insertion_point(one_of_clear_start:google.firestore.v1.ExecutePipelineRequest) PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); - switch (query_type_case()) { - case kStructuredAggregationQuery: { + switch (pipeline_type_case()) { + case kStructuredPipeline: { if (GetArena() == nullptr) { - delete _impl_.query_type_.structured_aggregation_query_; + delete _impl_.pipeline_type_.structured_pipeline_; } break; } - case QUERY_TYPE_NOT_SET: { + case PIPELINE_TYPE_NOT_SET: { break; } } - _impl_._oneof_case_[0] = QUERY_TYPE_NOT_SET; + _impl_._oneof_case_[0] = PIPELINE_TYPE_NOT_SET; } -void RunAggregationQueryRequest::clear_consistency_selector() { -// @@protoc_insertion_point(one_of_clear_start:google.firestore.v1.RunAggregationQueryRequest) +void ExecutePipelineRequest::clear_consistency_selector() { +// @@protoc_insertion_point(one_of_clear_start:google.firestore.v1.ExecutePipelineRequest) PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); switch (consistency_selector_case()) { case kTransaction: { @@ -6510,20 +6616,20 @@ void RunAggregationQueryRequest::clear_consistency_selector() { } -PROTOBUF_NOINLINE void RunAggregationQueryRequest::Clear() { -// @@protoc_insertion_point(message_clear_start:google.firestore.v1.RunAggregationQueryRequest) +PROTOBUF_NOINLINE void ExecutePipelineRequest::Clear() { +// @@protoc_insertion_point(message_clear_start:google.firestore.v1.ExecutePipelineRequest) PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); ::uint32_t cached_has_bits = 0; // Prevent compiler warnings about cached_has_bits being unused (void) cached_has_bits; - _impl_.parent_.ClearToEmpty(); - clear_query_type(); + _impl_.database_.ClearToEmpty(); + clear_pipeline_type(); clear_consistency_selector(); _internal_metadata_.Clear<::google::protobuf::UnknownFieldSet>(); } -const char* RunAggregationQueryRequest::_InternalParse( +const char* ExecutePipelineRequest::_InternalParse( const char* ptr, ::_pbi::ParseContext* ctx) { ptr = ::_pbi::TcParser::ParseLoop(this, ptr, ctx, &_table_.header); return ptr; @@ -6531,89 +6637,89 @@ const char* RunAggregationQueryRequest::_InternalParse( PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 -const ::_pbi::TcParseTable<0, 5, 3, 61, 2> RunAggregationQueryRequest::_table_ = { +const ::_pbi::TcParseTable<0, 5, 3, 59, 2> ExecutePipelineRequest::_table_ = { { 0, // no _has_bits_ 0, // no _extensions_ - 6, 0, // max_field_number, fast_idx_mask + 7, 0, // max_field_number, fast_idx_mask offsetof(decltype(_table_), field_lookup_table), - 4294967236, // skipmap + 4294967180, // skipmap offsetof(decltype(_table_), field_entries), 5, // num_field_entries 3, // num_aux_entries offsetof(decltype(_table_), aux_entries), - &_RunAggregationQueryRequest_default_instance_._instance, + &_ExecutePipelineRequest_default_instance_._instance, ::_pbi::TcParser::GenericFallback, // fallback }, {{ - // string parent = 1; + // string database = 1 [(.google.api.field_behavior) = REQUIRED]; {::_pbi::TcParser::FastUS1, - {10, 63, 0, PROTOBUF_FIELD_OFFSET(RunAggregationQueryRequest, _impl_.parent_)}}, + {10, 63, 0, PROTOBUF_FIELD_OFFSET(ExecutePipelineRequest, _impl_.database_)}}, }}, {{ 65535, 65535 }}, {{ - // string parent = 1; - {PROTOBUF_FIELD_OFFSET(RunAggregationQueryRequest, _impl_.parent_), 0, 0, + // string database = 1 [(.google.api.field_behavior) = REQUIRED]; + {PROTOBUF_FIELD_OFFSET(ExecutePipelineRequest, _impl_.database_), 0, 0, (0 | ::_fl::kFcSingular | ::_fl::kUtf8String | ::_fl::kRepAString)}, - // .google.firestore.v1.StructuredAggregationQuery structured_aggregation_query = 2; - {PROTOBUF_FIELD_OFFSET(RunAggregationQueryRequest, _impl_.query_type_.structured_aggregation_query_), _Internal::kOneofCaseOffset + 0, 0, + // .google.firestore.v1.StructuredPipeline structured_pipeline = 2; + {PROTOBUF_FIELD_OFFSET(ExecutePipelineRequest, _impl_.pipeline_type_.structured_pipeline_), _Internal::kOneofCaseOffset + 0, 0, (0 | ::_fl::kFcOneof | ::_fl::kMessage | ::_fl::kTvTable)}, - // bytes transaction = 4; - {PROTOBUF_FIELD_OFFSET(RunAggregationQueryRequest, _impl_.consistency_selector_.transaction_), _Internal::kOneofCaseOffset + 4, 0, + // bytes transaction = 5; + {PROTOBUF_FIELD_OFFSET(ExecutePipelineRequest, _impl_.consistency_selector_.transaction_), _Internal::kOneofCaseOffset + 4, 0, (0 | ::_fl::kFcOneof | ::_fl::kBytes | ::_fl::kRepAString)}, - // .google.firestore.v1.TransactionOptions new_transaction = 5; - {PROTOBUF_FIELD_OFFSET(RunAggregationQueryRequest, _impl_.consistency_selector_.new_transaction_), _Internal::kOneofCaseOffset + 4, 1, + // .google.firestore.v1.TransactionOptions new_transaction = 6; + {PROTOBUF_FIELD_OFFSET(ExecutePipelineRequest, _impl_.consistency_selector_.new_transaction_), _Internal::kOneofCaseOffset + 4, 1, (0 | ::_fl::kFcOneof | ::_fl::kMessage | ::_fl::kTvTable)}, - // .google.protobuf.Timestamp read_time = 6; - {PROTOBUF_FIELD_OFFSET(RunAggregationQueryRequest, _impl_.consistency_selector_.read_time_), _Internal::kOneofCaseOffset + 4, 2, + // .google.protobuf.Timestamp read_time = 7; + {PROTOBUF_FIELD_OFFSET(ExecutePipelineRequest, _impl_.consistency_selector_.read_time_), _Internal::kOneofCaseOffset + 4, 2, (0 | ::_fl::kFcOneof | ::_fl::kMessage | ::_fl::kTvTable)}, }}, {{ - {::_pbi::TcParser::GetTable<::google::firestore::v1::StructuredAggregationQuery>()}, + {::_pbi::TcParser::GetTable<::google::firestore::v1::StructuredPipeline>()}, {::_pbi::TcParser::GetTable<::google::firestore::v1::TransactionOptions>()}, {::_pbi::TcParser::GetTable<::google::protobuf::Timestamp>()}, }}, {{ - "\56\6\0\0\0\0\0\0" - "google.firestore.v1.RunAggregationQueryRequest" - "parent" + "\52\10\0\0\0\0\0\0" + "google.firestore.v1.ExecutePipelineRequest" + "database" }}, }; -::uint8_t* RunAggregationQueryRequest::_InternalSerialize( +::uint8_t* ExecutePipelineRequest::_InternalSerialize( ::uint8_t* target, ::google::protobuf::io::EpsCopyOutputStream* stream) const { - // @@protoc_insertion_point(serialize_to_array_start:google.firestore.v1.RunAggregationQueryRequest) + // @@protoc_insertion_point(serialize_to_array_start:google.firestore.v1.ExecutePipelineRequest) ::uint32_t cached_has_bits = 0; (void)cached_has_bits; - // string parent = 1; - if (!this->_internal_parent().empty()) { - const std::string& _s = this->_internal_parent(); + // string database = 1 [(.google.api.field_behavior) = REQUIRED]; + if (!this->_internal_database().empty()) { + const std::string& _s = this->_internal_database(); ::google::protobuf::internal::WireFormatLite::VerifyUtf8String( - _s.data(), static_cast(_s.length()), ::google::protobuf::internal::WireFormatLite::SERIALIZE, "google.firestore.v1.RunAggregationQueryRequest.parent"); + _s.data(), static_cast(_s.length()), ::google::protobuf::internal::WireFormatLite::SERIALIZE, "google.firestore.v1.ExecutePipelineRequest.database"); target = stream->WriteStringMaybeAliased(1, _s, target); } - // .google.firestore.v1.StructuredAggregationQuery structured_aggregation_query = 2; - if (query_type_case() == kStructuredAggregationQuery) { + // .google.firestore.v1.StructuredPipeline structured_pipeline = 2; + if (pipeline_type_case() == kStructuredPipeline) { target = ::google::protobuf::internal::WireFormatLite::InternalWriteMessage( - 2, _Internal::structured_aggregation_query(this), - _Internal::structured_aggregation_query(this).GetCachedSize(), target, stream); + 2, _Internal::structured_pipeline(this), + _Internal::structured_pipeline(this).GetCachedSize(), target, stream); } switch (consistency_selector_case()) { case kTransaction: { const std::string& _s = this->_internal_transaction(); - target = stream->WriteBytesMaybeAliased(4, _s, target); + target = stream->WriteBytesMaybeAliased(5, _s, target); break; } case kNewTransaction: { target = ::google::protobuf::internal::WireFormatLite::InternalWriteMessage( - 5, _Internal::new_transaction(this), + 6, _Internal::new_transaction(this), _Internal::new_transaction(this).GetCachedSize(), target, stream); break; } case kReadTime: { target = ::google::protobuf::internal::WireFormatLite::InternalWriteMessage( - 6, _Internal::read_time(this), + 7, _Internal::read_time(this), _Internal::read_time(this).GetCachedSize(), target, stream); break; } @@ -6625,49 +6731,49 @@ ::uint8_t* RunAggregationQueryRequest::_InternalSerialize( ::_pbi::WireFormat::InternalSerializeUnknownFieldsToArray( _internal_metadata_.unknown_fields<::google::protobuf::UnknownFieldSet>(::google::protobuf::UnknownFieldSet::default_instance), target, stream); } - // @@protoc_insertion_point(serialize_to_array_end:google.firestore.v1.RunAggregationQueryRequest) + // @@protoc_insertion_point(serialize_to_array_end:google.firestore.v1.ExecutePipelineRequest) return target; } -::size_t RunAggregationQueryRequest::ByteSizeLong() const { -// @@protoc_insertion_point(message_byte_size_start:google.firestore.v1.RunAggregationQueryRequest) +::size_t ExecutePipelineRequest::ByteSizeLong() const { +// @@protoc_insertion_point(message_byte_size_start:google.firestore.v1.ExecutePipelineRequest) ::size_t total_size = 0; ::uint32_t cached_has_bits = 0; // Prevent compiler warnings about cached_has_bits being unused (void) cached_has_bits; - // string parent = 1; - if (!this->_internal_parent().empty()) { + // string database = 1 [(.google.api.field_behavior) = REQUIRED]; + if (!this->_internal_database().empty()) { total_size += 1 + ::google::protobuf::internal::WireFormatLite::StringSize( - this->_internal_parent()); + this->_internal_database()); } - switch (query_type_case()) { - // .google.firestore.v1.StructuredAggregationQuery structured_aggregation_query = 2; - case kStructuredAggregationQuery: { + switch (pipeline_type_case()) { + // .google.firestore.v1.StructuredPipeline structured_pipeline = 2; + case kStructuredPipeline: { total_size += - 1 + ::google::protobuf::internal::WireFormatLite::MessageSize(*_impl_.query_type_.structured_aggregation_query_); + 1 + ::google::protobuf::internal::WireFormatLite::MessageSize(*_impl_.pipeline_type_.structured_pipeline_); break; } - case QUERY_TYPE_NOT_SET: { + case PIPELINE_TYPE_NOT_SET: { break; } } switch (consistency_selector_case()) { - // bytes transaction = 4; + // bytes transaction = 5; case kTransaction: { total_size += 1 + ::google::protobuf::internal::WireFormatLite::BytesSize( this->_internal_transaction()); break; } - // .google.firestore.v1.TransactionOptions new_transaction = 5; + // .google.firestore.v1.TransactionOptions new_transaction = 6; case kNewTransaction: { total_size += 1 + ::google::protobuf::internal::WireFormatLite::MessageSize(*_impl_.consistency_selector_.new_transaction_); break; } - // .google.protobuf.Timestamp read_time = 6; + // .google.protobuf.Timestamp read_time = 7; case kReadTime: { total_size += 1 + ::google::protobuf::internal::WireFormatLite::MessageSize(*_impl_.consistency_selector_.read_time_); @@ -6680,32 +6786,32 @@ ::size_t RunAggregationQueryRequest::ByteSizeLong() const { return MaybeComputeUnknownFieldsSize(total_size, &_impl_._cached_size_); } -const ::google::protobuf::Message::ClassData RunAggregationQueryRequest::_class_data_ = { - RunAggregationQueryRequest::MergeImpl, +const ::google::protobuf::Message::ClassData ExecutePipelineRequest::_class_data_ = { + ExecutePipelineRequest::MergeImpl, nullptr, // OnDemandRegisterArenaDtor }; -const ::google::protobuf::Message::ClassData* RunAggregationQueryRequest::GetClassData() const { +const ::google::protobuf::Message::ClassData* ExecutePipelineRequest::GetClassData() const { return &_class_data_; } -void RunAggregationQueryRequest::MergeImpl(::google::protobuf::Message& to_msg, const ::google::protobuf::Message& from_msg) { - auto* const _this = static_cast(&to_msg); - auto& from = static_cast(from_msg); - // @@protoc_insertion_point(class_specific_merge_from_start:google.firestore.v1.RunAggregationQueryRequest) +void ExecutePipelineRequest::MergeImpl(::google::protobuf::Message& to_msg, const ::google::protobuf::Message& from_msg) { + auto* const _this = static_cast(&to_msg); + auto& from = static_cast(from_msg); + // @@protoc_insertion_point(class_specific_merge_from_start:google.firestore.v1.ExecutePipelineRequest) ABSL_DCHECK_NE(&from, _this); ::uint32_t cached_has_bits = 0; (void) cached_has_bits; - if (!from._internal_parent().empty()) { - _this->_internal_set_parent(from._internal_parent()); + if (!from._internal_database().empty()) { + _this->_internal_set_database(from._internal_database()); } - switch (from.query_type_case()) { - case kStructuredAggregationQuery: { - _this->_internal_mutable_structured_aggregation_query()->::google::firestore::v1::StructuredAggregationQuery::MergeFrom( - from._internal_structured_aggregation_query()); + switch (from.pipeline_type_case()) { + case kStructuredPipeline: { + _this->_internal_mutable_structured_pipeline()->::google::firestore::v1::StructuredPipeline::MergeFrom( + from._internal_structured_pipeline()); break; } - case QUERY_TYPE_NOT_SET: { + case PIPELINE_TYPE_NOT_SET: { break; } } @@ -6731,153 +6837,160 @@ void RunAggregationQueryRequest::MergeImpl(::google::protobuf::Message& to_msg, _this->_internal_metadata_.MergeFrom<::google::protobuf::UnknownFieldSet>(from._internal_metadata_); } -void RunAggregationQueryRequest::CopyFrom(const RunAggregationQueryRequest& from) { -// @@protoc_insertion_point(class_specific_copy_from_start:google.firestore.v1.RunAggregationQueryRequest) +void ExecutePipelineRequest::CopyFrom(const ExecutePipelineRequest& from) { +// @@protoc_insertion_point(class_specific_copy_from_start:google.firestore.v1.ExecutePipelineRequest) if (&from == this) return; Clear(); MergeFrom(from); } -PROTOBUF_NOINLINE bool RunAggregationQueryRequest::IsInitialized() const { +PROTOBUF_NOINLINE bool ExecutePipelineRequest::IsInitialized() const { return true; } -::_pbi::CachedSize* RunAggregationQueryRequest::AccessCachedSize() const { +::_pbi::CachedSize* ExecutePipelineRequest::AccessCachedSize() const { return &_impl_._cached_size_; } -void RunAggregationQueryRequest::InternalSwap(RunAggregationQueryRequest* PROTOBUF_RESTRICT other) { +void ExecutePipelineRequest::InternalSwap(ExecutePipelineRequest* PROTOBUF_RESTRICT other) { using std::swap; auto* arena = GetArena(); ABSL_DCHECK_EQ(arena, other->GetArena()); _internal_metadata_.InternalSwap(&other->_internal_metadata_); - ::_pbi::ArenaStringPtr::InternalSwap(&_impl_.parent_, &other->_impl_.parent_, arena); - swap(_impl_.query_type_, other->_impl_.query_type_); + ::_pbi::ArenaStringPtr::InternalSwap(&_impl_.database_, &other->_impl_.database_, arena); + swap(_impl_.pipeline_type_, other->_impl_.pipeline_type_); swap(_impl_.consistency_selector_, other->_impl_.consistency_selector_); swap(_impl_._oneof_case_[0], other->_impl_._oneof_case_[0]); swap(_impl_._oneof_case_[1], other->_impl_._oneof_case_[1]); } -::google::protobuf::Metadata RunAggregationQueryRequest::GetMetadata() const { +::google::protobuf::Metadata ExecutePipelineRequest::GetMetadata() const { return ::_pbi::AssignDescriptors( &descriptor_table_google_2ffirestore_2fv1_2ffirestore_2eproto_getter, &descriptor_table_google_2ffirestore_2fv1_2ffirestore_2eproto_once, file_level_metadata_google_2ffirestore_2fv1_2ffirestore_2eproto[15]); } // =================================================================== -class RunAggregationQueryResponse::_Internal { +class ExecutePipelineResponse::_Internal { public: - using HasBits = decltype(std::declval()._impl_._has_bits_); + using HasBits = decltype(std::declval()._impl_._has_bits_); static constexpr ::int32_t kHasBitsOffset = - 8 * PROTOBUF_FIELD_OFFSET(RunAggregationQueryResponse, _impl_._has_bits_); - static const ::google::firestore::v1::AggregationResult& result(const RunAggregationQueryResponse* msg); - static void set_has_result(HasBits* has_bits) { + 8 * PROTOBUF_FIELD_OFFSET(ExecutePipelineResponse, _impl_._has_bits_); + static const ::google::protobuf::Timestamp& execution_time(const ExecutePipelineResponse* msg); + static void set_has_execution_time(HasBits* has_bits) { (*has_bits)[0] |= 1u; } - static const ::google::protobuf::Timestamp& read_time(const RunAggregationQueryResponse* msg); - static void set_has_read_time(HasBits* has_bits) { + static const ::google::firestore::v1::ExplainStats& explain_stats(const ExecutePipelineResponse* msg); + static void set_has_explain_stats(HasBits* has_bits) { (*has_bits)[0] |= 2u; } }; -const ::google::firestore::v1::AggregationResult& RunAggregationQueryResponse::_Internal::result(const RunAggregationQueryResponse* msg) { - return *msg->_impl_.result_; +const ::google::protobuf::Timestamp& ExecutePipelineResponse::_Internal::execution_time(const ExecutePipelineResponse* msg) { + return *msg->_impl_.execution_time_; } -const ::google::protobuf::Timestamp& RunAggregationQueryResponse::_Internal::read_time(const RunAggregationQueryResponse* msg) { - return *msg->_impl_.read_time_; +const ::google::firestore::v1::ExplainStats& ExecutePipelineResponse::_Internal::explain_stats(const ExecutePipelineResponse* msg) { + return *msg->_impl_.explain_stats_; } -void RunAggregationQueryResponse::clear_result() { +void ExecutePipelineResponse::clear_results() { PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); - if (_impl_.result_ != nullptr) _impl_.result_->Clear(); + _impl_.results_.Clear(); +} +void ExecutePipelineResponse::clear_execution_time() { + PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); + if (_impl_.execution_time_ != nullptr) _impl_.execution_time_->Clear(); _impl_._has_bits_[0] &= ~0x00000001u; } -void RunAggregationQueryResponse::clear_read_time() { +void ExecutePipelineResponse::clear_explain_stats() { PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); - if (_impl_.read_time_ != nullptr) _impl_.read_time_->Clear(); + if (_impl_.explain_stats_ != nullptr) _impl_.explain_stats_->Clear(); _impl_._has_bits_[0] &= ~0x00000002u; } -RunAggregationQueryResponse::RunAggregationQueryResponse(::google::protobuf::Arena* arena) +ExecutePipelineResponse::ExecutePipelineResponse(::google::protobuf::Arena* arena) : ::google::protobuf::Message(arena) { SharedCtor(arena); - // @@protoc_insertion_point(arena_constructor:google.firestore.v1.RunAggregationQueryResponse) + // @@protoc_insertion_point(arena_constructor:google.firestore.v1.ExecutePipelineResponse) } -inline PROTOBUF_NDEBUG_INLINE RunAggregationQueryResponse::Impl_::Impl_( +inline PROTOBUF_NDEBUG_INLINE ExecutePipelineResponse::Impl_::Impl_( ::google::protobuf::internal::InternalVisibility visibility, ::google::protobuf::Arena* arena, const Impl_& from) : _has_bits_{from._has_bits_}, _cached_size_{0}, + results_{visibility, arena, from.results_}, transaction_(arena, from.transaction_) {} -RunAggregationQueryResponse::RunAggregationQueryResponse( +ExecutePipelineResponse::ExecutePipelineResponse( ::google::protobuf::Arena* arena, - const RunAggregationQueryResponse& from) + const ExecutePipelineResponse& from) : ::google::protobuf::Message(arena) { - RunAggregationQueryResponse* const _this = this; + ExecutePipelineResponse* const _this = this; (void)_this; _internal_metadata_.MergeFrom<::google::protobuf::UnknownFieldSet>( from._internal_metadata_); new (&_impl_) Impl_(internal_visibility(), arena, from._impl_); ::uint32_t cached_has_bits = _impl_._has_bits_[0]; - _impl_.result_ = (cached_has_bits & 0x00000001u) - ? CreateMaybeMessage<::google::firestore::v1::AggregationResult>(arena, *from._impl_.result_) + _impl_.execution_time_ = (cached_has_bits & 0x00000001u) + ? CreateMaybeMessage<::google::protobuf::Timestamp>(arena, *from._impl_.execution_time_) : nullptr; - _impl_.read_time_ = (cached_has_bits & 0x00000002u) - ? CreateMaybeMessage<::google::protobuf::Timestamp>(arena, *from._impl_.read_time_) + _impl_.explain_stats_ = (cached_has_bits & 0x00000002u) + ? CreateMaybeMessage<::google::firestore::v1::ExplainStats>(arena, *from._impl_.explain_stats_) : nullptr; - // @@protoc_insertion_point(copy_constructor:google.firestore.v1.RunAggregationQueryResponse) + // @@protoc_insertion_point(copy_constructor:google.firestore.v1.ExecutePipelineResponse) } -inline PROTOBUF_NDEBUG_INLINE RunAggregationQueryResponse::Impl_::Impl_( +inline PROTOBUF_NDEBUG_INLINE ExecutePipelineResponse::Impl_::Impl_( ::google::protobuf::internal::InternalVisibility visibility, ::google::protobuf::Arena* arena) : _cached_size_{0}, + results_{visibility, arena}, transaction_(arena) {} -inline void RunAggregationQueryResponse::SharedCtor(::_pb::Arena* arena) { +inline void ExecutePipelineResponse::SharedCtor(::_pb::Arena* arena) { new (&_impl_) Impl_(internal_visibility(), arena); ::memset(reinterpret_cast(&_impl_) + - offsetof(Impl_, result_), + offsetof(Impl_, execution_time_), 0, - offsetof(Impl_, read_time_) - - offsetof(Impl_, result_) + - sizeof(Impl_::read_time_)); + offsetof(Impl_, explain_stats_) - + offsetof(Impl_, execution_time_) + + sizeof(Impl_::explain_stats_)); } -RunAggregationQueryResponse::~RunAggregationQueryResponse() { - // @@protoc_insertion_point(destructor:google.firestore.v1.RunAggregationQueryResponse) +ExecutePipelineResponse::~ExecutePipelineResponse() { + // @@protoc_insertion_point(destructor:google.firestore.v1.ExecutePipelineResponse) _internal_metadata_.Delete<::google::protobuf::UnknownFieldSet>(); SharedDtor(); } -inline void RunAggregationQueryResponse::SharedDtor() { +inline void ExecutePipelineResponse::SharedDtor() { ABSL_DCHECK(GetArena() == nullptr); _impl_.transaction_.Destroy(); - delete _impl_.result_; - delete _impl_.read_time_; + delete _impl_.execution_time_; + delete _impl_.explain_stats_; _impl_.~Impl_(); } -PROTOBUF_NOINLINE void RunAggregationQueryResponse::Clear() { -// @@protoc_insertion_point(message_clear_start:google.firestore.v1.RunAggregationQueryResponse) +PROTOBUF_NOINLINE void ExecutePipelineResponse::Clear() { +// @@protoc_insertion_point(message_clear_start:google.firestore.v1.ExecutePipelineResponse) PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); ::uint32_t cached_has_bits = 0; // Prevent compiler warnings about cached_has_bits being unused (void) cached_has_bits; + _impl_.results_.Clear(); _impl_.transaction_.ClearToEmpty(); cached_has_bits = _impl_._has_bits_[0]; if (cached_has_bits & 0x00000003u) { if (cached_has_bits & 0x00000001u) { - ABSL_DCHECK(_impl_.result_ != nullptr); - _impl_.result_->Clear(); + ABSL_DCHECK(_impl_.execution_time_ != nullptr); + _impl_.execution_time_->Clear(); } if (cached_has_bits & 0x00000002u) { - ABSL_DCHECK(_impl_.read_time_ != nullptr); - _impl_.read_time_->Clear(); + ABSL_DCHECK(_impl_.explain_stats_ != nullptr); + _impl_.explain_stats_->Clear(); } } _impl_._has_bits_.Clear(); _internal_metadata_.Clear<::google::protobuf::UnknownFieldSet>(); } -const char* RunAggregationQueryResponse::_InternalParse( +const char* ExecutePipelineResponse::_InternalParse( const char* ptr, ::_pbi::ParseContext* ctx) { ptr = ::_pbi::TcParser::ParseLoop(this, ptr, ctx, &_table_.header); return ptr; @@ -6885,11 +6998,794 @@ const char* RunAggregationQueryResponse::_InternalParse( PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 -const ::_pbi::TcParseTable<2, 3, 2, 0, 2> RunAggregationQueryResponse::_table_ = { +const ::_pbi::TcParseTable<2, 4, 3, 0, 2> ExecutePipelineResponse::_table_ = { { - PROTOBUF_FIELD_OFFSET(RunAggregationQueryResponse, _impl_._has_bits_), + PROTOBUF_FIELD_OFFSET(ExecutePipelineResponse, _impl_._has_bits_), 0, // no _extensions_ - 3, 24, // max_field_number, fast_idx_mask + 4, 24, // max_field_number, fast_idx_mask + offsetof(decltype(_table_), field_lookup_table), + 4294967280, // skipmap + offsetof(decltype(_table_), field_entries), + 4, // num_field_entries + 3, // num_aux_entries + offsetof(decltype(_table_), aux_entries), + &_ExecutePipelineResponse_default_instance_._instance, + ::_pbi::TcParser::GenericFallback, // fallback + }, {{ + // .google.firestore.v1.ExplainStats explain_stats = 4; + {::_pbi::TcParser::FastMtS1, + {34, 1, 2, PROTOBUF_FIELD_OFFSET(ExecutePipelineResponse, _impl_.explain_stats_)}}, + // bytes transaction = 1; + {::_pbi::TcParser::FastBS1, + {10, 63, 0, PROTOBUF_FIELD_OFFSET(ExecutePipelineResponse, _impl_.transaction_)}}, + // repeated .google.firestore.v1.Document results = 2; + {::_pbi::TcParser::FastMtR1, + {18, 63, 0, PROTOBUF_FIELD_OFFSET(ExecutePipelineResponse, _impl_.results_)}}, + // .google.protobuf.Timestamp execution_time = 3; + {::_pbi::TcParser::FastMtS1, + {26, 0, 1, PROTOBUF_FIELD_OFFSET(ExecutePipelineResponse, _impl_.execution_time_)}}, + }}, {{ + 65535, 65535 + }}, {{ + // bytes transaction = 1; + {PROTOBUF_FIELD_OFFSET(ExecutePipelineResponse, _impl_.transaction_), -1, 0, + (0 | ::_fl::kFcSingular | ::_fl::kBytes | ::_fl::kRepAString)}, + // repeated .google.firestore.v1.Document results = 2; + {PROTOBUF_FIELD_OFFSET(ExecutePipelineResponse, _impl_.results_), -1, 0, + (0 | ::_fl::kFcRepeated | ::_fl::kMessage | ::_fl::kTvTable)}, + // .google.protobuf.Timestamp execution_time = 3; + {PROTOBUF_FIELD_OFFSET(ExecutePipelineResponse, _impl_.execution_time_), _Internal::kHasBitsOffset + 0, 1, + (0 | ::_fl::kFcOptional | ::_fl::kMessage | ::_fl::kTvTable)}, + // .google.firestore.v1.ExplainStats explain_stats = 4; + {PROTOBUF_FIELD_OFFSET(ExecutePipelineResponse, _impl_.explain_stats_), _Internal::kHasBitsOffset + 1, 2, + (0 | ::_fl::kFcOptional | ::_fl::kMessage | ::_fl::kTvTable)}, + }}, {{ + {::_pbi::TcParser::GetTable<::google::firestore::v1::Document>()}, + {::_pbi::TcParser::GetTable<::google::protobuf::Timestamp>()}, + {::_pbi::TcParser::GetTable<::google::firestore::v1::ExplainStats>()}, + }}, {{ + }}, +}; + +::uint8_t* ExecutePipelineResponse::_InternalSerialize( + ::uint8_t* target, + ::google::protobuf::io::EpsCopyOutputStream* stream) const { + // @@protoc_insertion_point(serialize_to_array_start:google.firestore.v1.ExecutePipelineResponse) + ::uint32_t cached_has_bits = 0; + (void)cached_has_bits; + + // bytes transaction = 1; + if (!this->_internal_transaction().empty()) { + const std::string& _s = this->_internal_transaction(); + target = stream->WriteBytesMaybeAliased(1, _s, target); + } + + // repeated .google.firestore.v1.Document results = 2; + for (unsigned i = 0, + n = static_cast(this->_internal_results_size()); i < n; i++) { + const auto& repfield = this->_internal_results().Get(i); + target = ::google::protobuf::internal::WireFormatLite:: + InternalWriteMessage(2, repfield, repfield.GetCachedSize(), target, stream); + } + + cached_has_bits = _impl_._has_bits_[0]; + // .google.protobuf.Timestamp execution_time = 3; + if (cached_has_bits & 0x00000001u) { + target = ::google::protobuf::internal::WireFormatLite::InternalWriteMessage( + 3, _Internal::execution_time(this), + _Internal::execution_time(this).GetCachedSize(), target, stream); + } + + // .google.firestore.v1.ExplainStats explain_stats = 4; + if (cached_has_bits & 0x00000002u) { + target = ::google::protobuf::internal::WireFormatLite::InternalWriteMessage( + 4, _Internal::explain_stats(this), + _Internal::explain_stats(this).GetCachedSize(), target, stream); + } + + if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) { + target = + ::_pbi::WireFormat::InternalSerializeUnknownFieldsToArray( + _internal_metadata_.unknown_fields<::google::protobuf::UnknownFieldSet>(::google::protobuf::UnknownFieldSet::default_instance), target, stream); + } + // @@protoc_insertion_point(serialize_to_array_end:google.firestore.v1.ExecutePipelineResponse) + return target; +} + +::size_t ExecutePipelineResponse::ByteSizeLong() const { +// @@protoc_insertion_point(message_byte_size_start:google.firestore.v1.ExecutePipelineResponse) + ::size_t total_size = 0; + + ::uint32_t cached_has_bits = 0; + // Prevent compiler warnings about cached_has_bits being unused + (void) cached_has_bits; + + // repeated .google.firestore.v1.Document results = 2; + total_size += 1UL * this->_internal_results_size(); + for (const auto& msg : this->_internal_results()) { + total_size += + ::google::protobuf::internal::WireFormatLite::MessageSize(msg); + } + // bytes transaction = 1; + if (!this->_internal_transaction().empty()) { + total_size += 1 + ::google::protobuf::internal::WireFormatLite::BytesSize( + this->_internal_transaction()); + } + + cached_has_bits = _impl_._has_bits_[0]; + if (cached_has_bits & 0x00000003u) { + // .google.protobuf.Timestamp execution_time = 3; + if (cached_has_bits & 0x00000001u) { + total_size += + 1 + ::google::protobuf::internal::WireFormatLite::MessageSize(*_impl_.execution_time_); + } + + // .google.firestore.v1.ExplainStats explain_stats = 4; + if (cached_has_bits & 0x00000002u) { + total_size += + 1 + ::google::protobuf::internal::WireFormatLite::MessageSize(*_impl_.explain_stats_); + } + + } + return MaybeComputeUnknownFieldsSize(total_size, &_impl_._cached_size_); +} + +const ::google::protobuf::Message::ClassData ExecutePipelineResponse::_class_data_ = { + ExecutePipelineResponse::MergeImpl, + nullptr, // OnDemandRegisterArenaDtor +}; +const ::google::protobuf::Message::ClassData* ExecutePipelineResponse::GetClassData() const { + return &_class_data_; +} + +void ExecutePipelineResponse::MergeImpl(::google::protobuf::Message& to_msg, const ::google::protobuf::Message& from_msg) { + auto* const _this = static_cast(&to_msg); + auto& from = static_cast(from_msg); + // @@protoc_insertion_point(class_specific_merge_from_start:google.firestore.v1.ExecutePipelineResponse) + ABSL_DCHECK_NE(&from, _this); + ::uint32_t cached_has_bits = 0; + (void) cached_has_bits; + + _this->_internal_mutable_results()->MergeFrom( + from._internal_results()); + if (!from._internal_transaction().empty()) { + _this->_internal_set_transaction(from._internal_transaction()); + } + cached_has_bits = from._impl_._has_bits_[0]; + if (cached_has_bits & 0x00000003u) { + if (cached_has_bits & 0x00000001u) { + _this->_internal_mutable_execution_time()->::google::protobuf::Timestamp::MergeFrom( + from._internal_execution_time()); + } + if (cached_has_bits & 0x00000002u) { + _this->_internal_mutable_explain_stats()->::google::firestore::v1::ExplainStats::MergeFrom( + from._internal_explain_stats()); + } + } + _this->_internal_metadata_.MergeFrom<::google::protobuf::UnknownFieldSet>(from._internal_metadata_); +} + +void ExecutePipelineResponse::CopyFrom(const ExecutePipelineResponse& from) { +// @@protoc_insertion_point(class_specific_copy_from_start:google.firestore.v1.ExecutePipelineResponse) + if (&from == this) return; + Clear(); + MergeFrom(from); +} + +PROTOBUF_NOINLINE bool ExecutePipelineResponse::IsInitialized() const { + return true; +} + +::_pbi::CachedSize* ExecutePipelineResponse::AccessCachedSize() const { + return &_impl_._cached_size_; +} +void ExecutePipelineResponse::InternalSwap(ExecutePipelineResponse* PROTOBUF_RESTRICT other) { + using std::swap; + auto* arena = GetArena(); + ABSL_DCHECK_EQ(arena, other->GetArena()); + _internal_metadata_.InternalSwap(&other->_internal_metadata_); + swap(_impl_._has_bits_[0], other->_impl_._has_bits_[0]); + _impl_.results_.InternalSwap(&other->_impl_.results_); + ::_pbi::ArenaStringPtr::InternalSwap(&_impl_.transaction_, &other->_impl_.transaction_, arena); + ::google::protobuf::internal::memswap< + PROTOBUF_FIELD_OFFSET(ExecutePipelineResponse, _impl_.explain_stats_) + + sizeof(ExecutePipelineResponse::_impl_.explain_stats_) + - PROTOBUF_FIELD_OFFSET(ExecutePipelineResponse, _impl_.execution_time_)>( + reinterpret_cast(&_impl_.execution_time_), + reinterpret_cast(&other->_impl_.execution_time_)); +} + +::google::protobuf::Metadata ExecutePipelineResponse::GetMetadata() const { + return ::_pbi::AssignDescriptors( + &descriptor_table_google_2ffirestore_2fv1_2ffirestore_2eproto_getter, &descriptor_table_google_2ffirestore_2fv1_2ffirestore_2eproto_once, + file_level_metadata_google_2ffirestore_2fv1_2ffirestore_2eproto[16]); +} +// =================================================================== + +class RunAggregationQueryRequest::_Internal { + public: + static constexpr ::int32_t kOneofCaseOffset = + PROTOBUF_FIELD_OFFSET(::google::firestore::v1::RunAggregationQueryRequest, _impl_._oneof_case_); + static const ::google::firestore::v1::StructuredAggregationQuery& structured_aggregation_query(const RunAggregationQueryRequest* msg); + static const ::google::firestore::v1::TransactionOptions& new_transaction(const RunAggregationQueryRequest* msg); + static const ::google::protobuf::Timestamp& read_time(const RunAggregationQueryRequest* msg); +}; + +const ::google::firestore::v1::StructuredAggregationQuery& RunAggregationQueryRequest::_Internal::structured_aggregation_query(const RunAggregationQueryRequest* msg) { + return *msg->_impl_.query_type_.structured_aggregation_query_; +} +const ::google::firestore::v1::TransactionOptions& RunAggregationQueryRequest::_Internal::new_transaction(const RunAggregationQueryRequest* msg) { + return *msg->_impl_.consistency_selector_.new_transaction_; +} +const ::google::protobuf::Timestamp& RunAggregationQueryRequest::_Internal::read_time(const RunAggregationQueryRequest* msg) { + return *msg->_impl_.consistency_selector_.read_time_; +} +void RunAggregationQueryRequest::set_allocated_structured_aggregation_query(::google::firestore::v1::StructuredAggregationQuery* structured_aggregation_query) { + ::google::protobuf::Arena* message_arena = GetArena(); + clear_query_type(); + if (structured_aggregation_query) { + ::google::protobuf::Arena* submessage_arena = reinterpret_cast<::google::protobuf::MessageLite*>(structured_aggregation_query)->GetArena(); + if (message_arena != submessage_arena) { + structured_aggregation_query = ::google::protobuf::internal::GetOwnedMessage(message_arena, structured_aggregation_query, submessage_arena); + } + set_has_structured_aggregation_query(); + _impl_.query_type_.structured_aggregation_query_ = structured_aggregation_query; + } + // @@protoc_insertion_point(field_set_allocated:google.firestore.v1.RunAggregationQueryRequest.structured_aggregation_query) +} +void RunAggregationQueryRequest::clear_structured_aggregation_query() { + PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); + if (query_type_case() == kStructuredAggregationQuery) { + if (GetArena() == nullptr) { + delete _impl_.query_type_.structured_aggregation_query_; + } + clear_has_query_type(); + } +} +void RunAggregationQueryRequest::set_allocated_new_transaction(::google::firestore::v1::TransactionOptions* new_transaction) { + ::google::protobuf::Arena* message_arena = GetArena(); + clear_consistency_selector(); + if (new_transaction) { + ::google::protobuf::Arena* submessage_arena = reinterpret_cast<::google::protobuf::MessageLite*>(new_transaction)->GetArena(); + if (message_arena != submessage_arena) { + new_transaction = ::google::protobuf::internal::GetOwnedMessage(message_arena, new_transaction, submessage_arena); + } + set_has_new_transaction(); + _impl_.consistency_selector_.new_transaction_ = new_transaction; + } + // @@protoc_insertion_point(field_set_allocated:google.firestore.v1.RunAggregationQueryRequest.new_transaction) +} +void RunAggregationQueryRequest::clear_new_transaction() { + PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); + if (consistency_selector_case() == kNewTransaction) { + if (GetArena() == nullptr) { + delete _impl_.consistency_selector_.new_transaction_; + } + clear_has_consistency_selector(); + } +} +void RunAggregationQueryRequest::set_allocated_read_time(::google::protobuf::Timestamp* read_time) { + ::google::protobuf::Arena* message_arena = GetArena(); + clear_consistency_selector(); + if (read_time) { + ::google::protobuf::Arena* submessage_arena = reinterpret_cast<::google::protobuf::MessageLite*>(read_time)->GetArena(); + if (message_arena != submessage_arena) { + read_time = ::google::protobuf::internal::GetOwnedMessage(message_arena, read_time, submessage_arena); + } + set_has_read_time(); + _impl_.consistency_selector_.read_time_ = read_time; + } + // @@protoc_insertion_point(field_set_allocated:google.firestore.v1.RunAggregationQueryRequest.read_time) +} +void RunAggregationQueryRequest::clear_read_time() { + PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); + if (consistency_selector_case() == kReadTime) { + if (GetArena() == nullptr) { + delete _impl_.consistency_selector_.read_time_; + } + clear_has_consistency_selector(); + } +} +RunAggregationQueryRequest::RunAggregationQueryRequest(::google::protobuf::Arena* arena) + : ::google::protobuf::Message(arena) { + SharedCtor(arena); + // @@protoc_insertion_point(arena_constructor:google.firestore.v1.RunAggregationQueryRequest) +} +inline PROTOBUF_NDEBUG_INLINE RunAggregationQueryRequest::Impl_::Impl_( + ::google::protobuf::internal::InternalVisibility visibility, ::google::protobuf::Arena* arena, + const Impl_& from) + : parent_(arena, from.parent_), + query_type_{}, + consistency_selector_{}, + _cached_size_{0}, + _oneof_case_{from._oneof_case_[0], from._oneof_case_[1]} {} + +RunAggregationQueryRequest::RunAggregationQueryRequest( + ::google::protobuf::Arena* arena, + const RunAggregationQueryRequest& from) + : ::google::protobuf::Message(arena) { + RunAggregationQueryRequest* const _this = this; + (void)_this; + _internal_metadata_.MergeFrom<::google::protobuf::UnknownFieldSet>( + from._internal_metadata_); + new (&_impl_) Impl_(internal_visibility(), arena, from._impl_); + switch (query_type_case()) { + case QUERY_TYPE_NOT_SET: + break; + case kStructuredAggregationQuery: + _impl_.query_type_.structured_aggregation_query_ = CreateMaybeMessage<::google::firestore::v1::StructuredAggregationQuery>(arena, *from._impl_.query_type_.structured_aggregation_query_); + break; + } + switch (consistency_selector_case()) { + case CONSISTENCY_SELECTOR_NOT_SET: + break; + case kTransaction: + new (&_impl_.consistency_selector_.transaction_) decltype(_impl_.consistency_selector_.transaction_){arena, from._impl_.consistency_selector_.transaction_}; + break; + case kNewTransaction: + _impl_.consistency_selector_.new_transaction_ = CreateMaybeMessage<::google::firestore::v1::TransactionOptions>(arena, *from._impl_.consistency_selector_.new_transaction_); + break; + case kReadTime: + _impl_.consistency_selector_.read_time_ = CreateMaybeMessage<::google::protobuf::Timestamp>(arena, *from._impl_.consistency_selector_.read_time_); + break; + } + + // @@protoc_insertion_point(copy_constructor:google.firestore.v1.RunAggregationQueryRequest) +} +inline PROTOBUF_NDEBUG_INLINE RunAggregationQueryRequest::Impl_::Impl_( + ::google::protobuf::internal::InternalVisibility visibility, + ::google::protobuf::Arena* arena) + : parent_(arena), + query_type_{}, + consistency_selector_{}, + _cached_size_{0}, + _oneof_case_{} {} + +inline void RunAggregationQueryRequest::SharedCtor(::_pb::Arena* arena) { + new (&_impl_) Impl_(internal_visibility(), arena); +} +RunAggregationQueryRequest::~RunAggregationQueryRequest() { + // @@protoc_insertion_point(destructor:google.firestore.v1.RunAggregationQueryRequest) + _internal_metadata_.Delete<::google::protobuf::UnknownFieldSet>(); + SharedDtor(); +} +inline void RunAggregationQueryRequest::SharedDtor() { + ABSL_DCHECK(GetArena() == nullptr); + _impl_.parent_.Destroy(); + if (has_query_type()) { + clear_query_type(); + } + if (has_consistency_selector()) { + clear_consistency_selector(); + } + _impl_.~Impl_(); +} + +void RunAggregationQueryRequest::clear_query_type() { +// @@protoc_insertion_point(one_of_clear_start:google.firestore.v1.RunAggregationQueryRequest) + PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); + switch (query_type_case()) { + case kStructuredAggregationQuery: { + if (GetArena() == nullptr) { + delete _impl_.query_type_.structured_aggregation_query_; + } + break; + } + case QUERY_TYPE_NOT_SET: { + break; + } + } + _impl_._oneof_case_[0] = QUERY_TYPE_NOT_SET; +} + +void RunAggregationQueryRequest::clear_consistency_selector() { +// @@protoc_insertion_point(one_of_clear_start:google.firestore.v1.RunAggregationQueryRequest) + PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); + switch (consistency_selector_case()) { + case kTransaction: { + _impl_.consistency_selector_.transaction_.Destroy(); + break; + } + case kNewTransaction: { + if (GetArena() == nullptr) { + delete _impl_.consistency_selector_.new_transaction_; + } + break; + } + case kReadTime: { + if (GetArena() == nullptr) { + delete _impl_.consistency_selector_.read_time_; + } + break; + } + case CONSISTENCY_SELECTOR_NOT_SET: { + break; + } + } + _impl_._oneof_case_[1] = CONSISTENCY_SELECTOR_NOT_SET; +} + + +PROTOBUF_NOINLINE void RunAggregationQueryRequest::Clear() { +// @@protoc_insertion_point(message_clear_start:google.firestore.v1.RunAggregationQueryRequest) + PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); + ::uint32_t cached_has_bits = 0; + // Prevent compiler warnings about cached_has_bits being unused + (void) cached_has_bits; + + _impl_.parent_.ClearToEmpty(); + clear_query_type(); + clear_consistency_selector(); + _internal_metadata_.Clear<::google::protobuf::UnknownFieldSet>(); +} + +const char* RunAggregationQueryRequest::_InternalParse( + const char* ptr, ::_pbi::ParseContext* ctx) { + ptr = ::_pbi::TcParser::ParseLoop(this, ptr, ctx, &_table_.header); + return ptr; +} + + +PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 +const ::_pbi::TcParseTable<0, 5, 3, 61, 2> RunAggregationQueryRequest::_table_ = { + { + 0, // no _has_bits_ + 0, // no _extensions_ + 6, 0, // max_field_number, fast_idx_mask + offsetof(decltype(_table_), field_lookup_table), + 4294967236, // skipmap + offsetof(decltype(_table_), field_entries), + 5, // num_field_entries + 3, // num_aux_entries + offsetof(decltype(_table_), aux_entries), + &_RunAggregationQueryRequest_default_instance_._instance, + ::_pbi::TcParser::GenericFallback, // fallback + }, {{ + // string parent = 1; + {::_pbi::TcParser::FastUS1, + {10, 63, 0, PROTOBUF_FIELD_OFFSET(RunAggregationQueryRequest, _impl_.parent_)}}, + }}, {{ + 65535, 65535 + }}, {{ + // string parent = 1; + {PROTOBUF_FIELD_OFFSET(RunAggregationQueryRequest, _impl_.parent_), 0, 0, + (0 | ::_fl::kFcSingular | ::_fl::kUtf8String | ::_fl::kRepAString)}, + // .google.firestore.v1.StructuredAggregationQuery structured_aggregation_query = 2; + {PROTOBUF_FIELD_OFFSET(RunAggregationQueryRequest, _impl_.query_type_.structured_aggregation_query_), _Internal::kOneofCaseOffset + 0, 0, + (0 | ::_fl::kFcOneof | ::_fl::kMessage | ::_fl::kTvTable)}, + // bytes transaction = 4; + {PROTOBUF_FIELD_OFFSET(RunAggregationQueryRequest, _impl_.consistency_selector_.transaction_), _Internal::kOneofCaseOffset + 4, 0, + (0 | ::_fl::kFcOneof | ::_fl::kBytes | ::_fl::kRepAString)}, + // .google.firestore.v1.TransactionOptions new_transaction = 5; + {PROTOBUF_FIELD_OFFSET(RunAggregationQueryRequest, _impl_.consistency_selector_.new_transaction_), _Internal::kOneofCaseOffset + 4, 1, + (0 | ::_fl::kFcOneof | ::_fl::kMessage | ::_fl::kTvTable)}, + // .google.protobuf.Timestamp read_time = 6; + {PROTOBUF_FIELD_OFFSET(RunAggregationQueryRequest, _impl_.consistency_selector_.read_time_), _Internal::kOneofCaseOffset + 4, 2, + (0 | ::_fl::kFcOneof | ::_fl::kMessage | ::_fl::kTvTable)}, + }}, {{ + {::_pbi::TcParser::GetTable<::google::firestore::v1::StructuredAggregationQuery>()}, + {::_pbi::TcParser::GetTable<::google::firestore::v1::TransactionOptions>()}, + {::_pbi::TcParser::GetTable<::google::protobuf::Timestamp>()}, + }}, {{ + "\56\6\0\0\0\0\0\0" + "google.firestore.v1.RunAggregationQueryRequest" + "parent" + }}, +}; + +::uint8_t* RunAggregationQueryRequest::_InternalSerialize( + ::uint8_t* target, + ::google::protobuf::io::EpsCopyOutputStream* stream) const { + // @@protoc_insertion_point(serialize_to_array_start:google.firestore.v1.RunAggregationQueryRequest) + ::uint32_t cached_has_bits = 0; + (void)cached_has_bits; + + // string parent = 1; + if (!this->_internal_parent().empty()) { + const std::string& _s = this->_internal_parent(); + ::google::protobuf::internal::WireFormatLite::VerifyUtf8String( + _s.data(), static_cast(_s.length()), ::google::protobuf::internal::WireFormatLite::SERIALIZE, "google.firestore.v1.RunAggregationQueryRequest.parent"); + target = stream->WriteStringMaybeAliased(1, _s, target); + } + + // .google.firestore.v1.StructuredAggregationQuery structured_aggregation_query = 2; + if (query_type_case() == kStructuredAggregationQuery) { + target = ::google::protobuf::internal::WireFormatLite::InternalWriteMessage( + 2, _Internal::structured_aggregation_query(this), + _Internal::structured_aggregation_query(this).GetCachedSize(), target, stream); + } + + switch (consistency_selector_case()) { + case kTransaction: { + const std::string& _s = this->_internal_transaction(); + target = stream->WriteBytesMaybeAliased(4, _s, target); + break; + } + case kNewTransaction: { + target = ::google::protobuf::internal::WireFormatLite::InternalWriteMessage( + 5, _Internal::new_transaction(this), + _Internal::new_transaction(this).GetCachedSize(), target, stream); + break; + } + case kReadTime: { + target = ::google::protobuf::internal::WireFormatLite::InternalWriteMessage( + 6, _Internal::read_time(this), + _Internal::read_time(this).GetCachedSize(), target, stream); + break; + } + default: + break; + } + if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) { + target = + ::_pbi::WireFormat::InternalSerializeUnknownFieldsToArray( + _internal_metadata_.unknown_fields<::google::protobuf::UnknownFieldSet>(::google::protobuf::UnknownFieldSet::default_instance), target, stream); + } + // @@protoc_insertion_point(serialize_to_array_end:google.firestore.v1.RunAggregationQueryRequest) + return target; +} + +::size_t RunAggregationQueryRequest::ByteSizeLong() const { +// @@protoc_insertion_point(message_byte_size_start:google.firestore.v1.RunAggregationQueryRequest) + ::size_t total_size = 0; + + ::uint32_t cached_has_bits = 0; + // Prevent compiler warnings about cached_has_bits being unused + (void) cached_has_bits; + + // string parent = 1; + if (!this->_internal_parent().empty()) { + total_size += 1 + ::google::protobuf::internal::WireFormatLite::StringSize( + this->_internal_parent()); + } + + switch (query_type_case()) { + // .google.firestore.v1.StructuredAggregationQuery structured_aggregation_query = 2; + case kStructuredAggregationQuery: { + total_size += + 1 + ::google::protobuf::internal::WireFormatLite::MessageSize(*_impl_.query_type_.structured_aggregation_query_); + break; + } + case QUERY_TYPE_NOT_SET: { + break; + } + } + switch (consistency_selector_case()) { + // bytes transaction = 4; + case kTransaction: { + total_size += 1 + ::google::protobuf::internal::WireFormatLite::BytesSize( + this->_internal_transaction()); + break; + } + // .google.firestore.v1.TransactionOptions new_transaction = 5; + case kNewTransaction: { + total_size += + 1 + ::google::protobuf::internal::WireFormatLite::MessageSize(*_impl_.consistency_selector_.new_transaction_); + break; + } + // .google.protobuf.Timestamp read_time = 6; + case kReadTime: { + total_size += + 1 + ::google::protobuf::internal::WireFormatLite::MessageSize(*_impl_.consistency_selector_.read_time_); + break; + } + case CONSISTENCY_SELECTOR_NOT_SET: { + break; + } + } + return MaybeComputeUnknownFieldsSize(total_size, &_impl_._cached_size_); +} + +const ::google::protobuf::Message::ClassData RunAggregationQueryRequest::_class_data_ = { + RunAggregationQueryRequest::MergeImpl, + nullptr, // OnDemandRegisterArenaDtor +}; +const ::google::protobuf::Message::ClassData* RunAggregationQueryRequest::GetClassData() const { + return &_class_data_; +} + +void RunAggregationQueryRequest::MergeImpl(::google::protobuf::Message& to_msg, const ::google::protobuf::Message& from_msg) { + auto* const _this = static_cast(&to_msg); + auto& from = static_cast(from_msg); + // @@protoc_insertion_point(class_specific_merge_from_start:google.firestore.v1.RunAggregationQueryRequest) + ABSL_DCHECK_NE(&from, _this); + ::uint32_t cached_has_bits = 0; + (void) cached_has_bits; + + if (!from._internal_parent().empty()) { + _this->_internal_set_parent(from._internal_parent()); + } + switch (from.query_type_case()) { + case kStructuredAggregationQuery: { + _this->_internal_mutable_structured_aggregation_query()->::google::firestore::v1::StructuredAggregationQuery::MergeFrom( + from._internal_structured_aggregation_query()); + break; + } + case QUERY_TYPE_NOT_SET: { + break; + } + } + switch (from.consistency_selector_case()) { + case kTransaction: { + _this->_internal_set_transaction(from._internal_transaction()); + break; + } + case kNewTransaction: { + _this->_internal_mutable_new_transaction()->::google::firestore::v1::TransactionOptions::MergeFrom( + from._internal_new_transaction()); + break; + } + case kReadTime: { + _this->_internal_mutable_read_time()->::google::protobuf::Timestamp::MergeFrom( + from._internal_read_time()); + break; + } + case CONSISTENCY_SELECTOR_NOT_SET: { + break; + } + } + _this->_internal_metadata_.MergeFrom<::google::protobuf::UnknownFieldSet>(from._internal_metadata_); +} + +void RunAggregationQueryRequest::CopyFrom(const RunAggregationQueryRequest& from) { +// @@protoc_insertion_point(class_specific_copy_from_start:google.firestore.v1.RunAggregationQueryRequest) + if (&from == this) return; + Clear(); + MergeFrom(from); +} + +PROTOBUF_NOINLINE bool RunAggregationQueryRequest::IsInitialized() const { + return true; +} + +::_pbi::CachedSize* RunAggregationQueryRequest::AccessCachedSize() const { + return &_impl_._cached_size_; +} +void RunAggregationQueryRequest::InternalSwap(RunAggregationQueryRequest* PROTOBUF_RESTRICT other) { + using std::swap; + auto* arena = GetArena(); + ABSL_DCHECK_EQ(arena, other->GetArena()); + _internal_metadata_.InternalSwap(&other->_internal_metadata_); + ::_pbi::ArenaStringPtr::InternalSwap(&_impl_.parent_, &other->_impl_.parent_, arena); + swap(_impl_.query_type_, other->_impl_.query_type_); + swap(_impl_.consistency_selector_, other->_impl_.consistency_selector_); + swap(_impl_._oneof_case_[0], other->_impl_._oneof_case_[0]); + swap(_impl_._oneof_case_[1], other->_impl_._oneof_case_[1]); +} + +::google::protobuf::Metadata RunAggregationQueryRequest::GetMetadata() const { + return ::_pbi::AssignDescriptors( + &descriptor_table_google_2ffirestore_2fv1_2ffirestore_2eproto_getter, &descriptor_table_google_2ffirestore_2fv1_2ffirestore_2eproto_once, + file_level_metadata_google_2ffirestore_2fv1_2ffirestore_2eproto[17]); +} +// =================================================================== + +class RunAggregationQueryResponse::_Internal { + public: + using HasBits = decltype(std::declval()._impl_._has_bits_); + static constexpr ::int32_t kHasBitsOffset = + 8 * PROTOBUF_FIELD_OFFSET(RunAggregationQueryResponse, _impl_._has_bits_); + static const ::google::firestore::v1::AggregationResult& result(const RunAggregationQueryResponse* msg); + static void set_has_result(HasBits* has_bits) { + (*has_bits)[0] |= 1u; + } + static const ::google::protobuf::Timestamp& read_time(const RunAggregationQueryResponse* msg); + static void set_has_read_time(HasBits* has_bits) { + (*has_bits)[0] |= 2u; + } +}; + +const ::google::firestore::v1::AggregationResult& RunAggregationQueryResponse::_Internal::result(const RunAggregationQueryResponse* msg) { + return *msg->_impl_.result_; +} +const ::google::protobuf::Timestamp& RunAggregationQueryResponse::_Internal::read_time(const RunAggregationQueryResponse* msg) { + return *msg->_impl_.read_time_; +} +void RunAggregationQueryResponse::clear_result() { + PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); + if (_impl_.result_ != nullptr) _impl_.result_->Clear(); + _impl_._has_bits_[0] &= ~0x00000001u; +} +void RunAggregationQueryResponse::clear_read_time() { + PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); + if (_impl_.read_time_ != nullptr) _impl_.read_time_->Clear(); + _impl_._has_bits_[0] &= ~0x00000002u; +} +RunAggregationQueryResponse::RunAggregationQueryResponse(::google::protobuf::Arena* arena) + : ::google::protobuf::Message(arena) { + SharedCtor(arena); + // @@protoc_insertion_point(arena_constructor:google.firestore.v1.RunAggregationQueryResponse) +} +inline PROTOBUF_NDEBUG_INLINE RunAggregationQueryResponse::Impl_::Impl_( + ::google::protobuf::internal::InternalVisibility visibility, ::google::protobuf::Arena* arena, + const Impl_& from) + : _has_bits_{from._has_bits_}, + _cached_size_{0}, + transaction_(arena, from.transaction_) {} + +RunAggregationQueryResponse::RunAggregationQueryResponse( + ::google::protobuf::Arena* arena, + const RunAggregationQueryResponse& from) + : ::google::protobuf::Message(arena) { + RunAggregationQueryResponse* const _this = this; + (void)_this; + _internal_metadata_.MergeFrom<::google::protobuf::UnknownFieldSet>( + from._internal_metadata_); + new (&_impl_) Impl_(internal_visibility(), arena, from._impl_); + ::uint32_t cached_has_bits = _impl_._has_bits_[0]; + _impl_.result_ = (cached_has_bits & 0x00000001u) + ? CreateMaybeMessage<::google::firestore::v1::AggregationResult>(arena, *from._impl_.result_) + : nullptr; + _impl_.read_time_ = (cached_has_bits & 0x00000002u) + ? CreateMaybeMessage<::google::protobuf::Timestamp>(arena, *from._impl_.read_time_) + : nullptr; + + // @@protoc_insertion_point(copy_constructor:google.firestore.v1.RunAggregationQueryResponse) +} +inline PROTOBUF_NDEBUG_INLINE RunAggregationQueryResponse::Impl_::Impl_( + ::google::protobuf::internal::InternalVisibility visibility, + ::google::protobuf::Arena* arena) + : _cached_size_{0}, + transaction_(arena) {} + +inline void RunAggregationQueryResponse::SharedCtor(::_pb::Arena* arena) { + new (&_impl_) Impl_(internal_visibility(), arena); + ::memset(reinterpret_cast(&_impl_) + + offsetof(Impl_, result_), + 0, + offsetof(Impl_, read_time_) - + offsetof(Impl_, result_) + + sizeof(Impl_::read_time_)); +} +RunAggregationQueryResponse::~RunAggregationQueryResponse() { + // @@protoc_insertion_point(destructor:google.firestore.v1.RunAggregationQueryResponse) + _internal_metadata_.Delete<::google::protobuf::UnknownFieldSet>(); + SharedDtor(); +} +inline void RunAggregationQueryResponse::SharedDtor() { + ABSL_DCHECK(GetArena() == nullptr); + _impl_.transaction_.Destroy(); + delete _impl_.result_; + delete _impl_.read_time_; + _impl_.~Impl_(); +} + +PROTOBUF_NOINLINE void RunAggregationQueryResponse::Clear() { +// @@protoc_insertion_point(message_clear_start:google.firestore.v1.RunAggregationQueryResponse) + PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); + ::uint32_t cached_has_bits = 0; + // Prevent compiler warnings about cached_has_bits being unused + (void) cached_has_bits; + + _impl_.transaction_.ClearToEmpty(); + cached_has_bits = _impl_._has_bits_[0]; + if (cached_has_bits & 0x00000003u) { + if (cached_has_bits & 0x00000001u) { + ABSL_DCHECK(_impl_.result_ != nullptr); + _impl_.result_->Clear(); + } + if (cached_has_bits & 0x00000002u) { + ABSL_DCHECK(_impl_.read_time_ != nullptr); + _impl_.read_time_->Clear(); + } + } + _impl_._has_bits_.Clear(); + _internal_metadata_.Clear<::google::protobuf::UnknownFieldSet>(); +} + +const char* RunAggregationQueryResponse::_InternalParse( + const char* ptr, ::_pbi::ParseContext* ctx) { + ptr = ::_pbi::TcParser::ParseLoop(this, ptr, ctx, &_table_.header); + return ptr; +} + + +PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 +const ::_pbi::TcParseTable<2, 3, 2, 0, 2> RunAggregationQueryResponse::_table_ = { + { + PROTOBUF_FIELD_OFFSET(RunAggregationQueryResponse, _impl_._has_bits_), + 0, // no _extensions_ + 3, 24, // max_field_number, fast_idx_mask offsetof(decltype(_table_), field_lookup_table), 4294967288, // skipmap offsetof(decltype(_table_), field_entries), @@ -7062,7 +7958,7 @@ void RunAggregationQueryResponse::InternalSwap(RunAggregationQueryResponse* PROT ::google::protobuf::Metadata RunAggregationQueryResponse::GetMetadata() const { return ::_pbi::AssignDescriptors( &descriptor_table_google_2ffirestore_2fv1_2ffirestore_2eproto_getter, &descriptor_table_google_2ffirestore_2fv1_2ffirestore_2eproto_once, - file_level_metadata_google_2ffirestore_2fv1_2ffirestore_2eproto[16]); + file_level_metadata_google_2ffirestore_2fv1_2ffirestore_2eproto[18]); } // =================================================================== @@ -7072,7 +7968,7 @@ WriteRequest_LabelsEntry_DoNotUse::WriteRequest_LabelsEntry_DoNotUse(::google::p ::google::protobuf::Metadata WriteRequest_LabelsEntry_DoNotUse::GetMetadata() const { return ::_pbi::AssignDescriptors( &descriptor_table_google_2ffirestore_2fv1_2ffirestore_2eproto_getter, &descriptor_table_google_2ffirestore_2fv1_2ffirestore_2eproto_once, - file_level_metadata_google_2ffirestore_2fv1_2ffirestore_2eproto[17]); + file_level_metadata_google_2ffirestore_2fv1_2ffirestore_2eproto[19]); } // =================================================================== @@ -7400,7 +8296,7 @@ void WriteRequest::InternalSwap(WriteRequest* PROTOBUF_RESTRICT other) { ::google::protobuf::Metadata WriteRequest::GetMetadata() const { return ::_pbi::AssignDescriptors( &descriptor_table_google_2ffirestore_2fv1_2ffirestore_2eproto_getter, &descriptor_table_google_2ffirestore_2fv1_2ffirestore_2eproto_once, - file_level_metadata_google_2ffirestore_2fv1_2ffirestore_2eproto[18]); + file_level_metadata_google_2ffirestore_2fv1_2ffirestore_2eproto[20]); } // =================================================================== @@ -7702,7 +8598,7 @@ void WriteResponse::InternalSwap(WriteResponse* PROTOBUF_RESTRICT other) { ::google::protobuf::Metadata WriteResponse::GetMetadata() const { return ::_pbi::AssignDescriptors( &descriptor_table_google_2ffirestore_2fv1_2ffirestore_2eproto_getter, &descriptor_table_google_2ffirestore_2fv1_2ffirestore_2eproto_once, - file_level_metadata_google_2ffirestore_2fv1_2ffirestore_2eproto[19]); + file_level_metadata_google_2ffirestore_2fv1_2ffirestore_2eproto[21]); } // =================================================================== @@ -7712,7 +8608,7 @@ ListenRequest_LabelsEntry_DoNotUse::ListenRequest_LabelsEntry_DoNotUse(::google: ::google::protobuf::Metadata ListenRequest_LabelsEntry_DoNotUse::GetMetadata() const { return ::_pbi::AssignDescriptors( &descriptor_table_google_2ffirestore_2fv1_2ffirestore_2eproto_getter, &descriptor_table_google_2ffirestore_2fv1_2ffirestore_2eproto_once, - file_level_metadata_google_2ffirestore_2fv1_2ffirestore_2eproto[20]); + file_level_metadata_google_2ffirestore_2fv1_2ffirestore_2eproto[22]); } // =================================================================== @@ -8069,7 +8965,7 @@ void ListenRequest::InternalSwap(ListenRequest* PROTOBUF_RESTRICT other) { ::google::protobuf::Metadata ListenRequest::GetMetadata() const { return ::_pbi::AssignDescriptors( &descriptor_table_google_2ffirestore_2fv1_2ffirestore_2eproto_getter, &descriptor_table_google_2ffirestore_2fv1_2ffirestore_2eproto_once, - file_level_metadata_google_2ffirestore_2fv1_2ffirestore_2eproto[21]); + file_level_metadata_google_2ffirestore_2fv1_2ffirestore_2eproto[23]); } // =================================================================== @@ -8539,7 +9435,7 @@ void ListenResponse::InternalSwap(ListenResponse* PROTOBUF_RESTRICT other) { ::google::protobuf::Metadata ListenResponse::GetMetadata() const { return ::_pbi::AssignDescriptors( &descriptor_table_google_2ffirestore_2fv1_2ffirestore_2eproto_getter, &descriptor_table_google_2ffirestore_2fv1_2ffirestore_2eproto_once, - file_level_metadata_google_2ffirestore_2fv1_2ffirestore_2eproto[22]); + file_level_metadata_google_2ffirestore_2fv1_2ffirestore_2eproto[24]); } // =================================================================== @@ -8724,7 +9620,7 @@ void Target_DocumentsTarget::InternalSwap(Target_DocumentsTarget* PROTOBUF_RESTR ::google::protobuf::Metadata Target_DocumentsTarget::GetMetadata() const { return ::_pbi::AssignDescriptors( &descriptor_table_google_2ffirestore_2fv1_2ffirestore_2eproto_getter, &descriptor_table_google_2ffirestore_2fv1_2ffirestore_2eproto_once, - file_level_metadata_google_2ffirestore_2fv1_2ffirestore_2eproto[23]); + file_level_metadata_google_2ffirestore_2fv1_2ffirestore_2eproto[25]); } // =================================================================== @@ -9008,7 +9904,7 @@ void Target_QueryTarget::InternalSwap(Target_QueryTarget* PROTOBUF_RESTRICT othe ::google::protobuf::Metadata Target_QueryTarget::GetMetadata() const { return ::_pbi::AssignDescriptors( &descriptor_table_google_2ffirestore_2fv1_2ffirestore_2eproto_getter, &descriptor_table_google_2ffirestore_2fv1_2ffirestore_2eproto_once, - file_level_metadata_google_2ffirestore_2fv1_2ffirestore_2eproto[24]); + file_level_metadata_google_2ffirestore_2fv1_2ffirestore_2eproto[26]); } // =================================================================== @@ -9536,7 +10432,7 @@ void Target::InternalSwap(Target* PROTOBUF_RESTRICT other) { ::google::protobuf::Metadata Target::GetMetadata() const { return ::_pbi::AssignDescriptors( &descriptor_table_google_2ffirestore_2fv1_2ffirestore_2eproto_getter, &descriptor_table_google_2ffirestore_2fv1_2ffirestore_2eproto_once, - file_level_metadata_google_2ffirestore_2fv1_2ffirestore_2eproto[25]); + file_level_metadata_google_2ffirestore_2fv1_2ffirestore_2eproto[27]); } // =================================================================== @@ -9899,7 +10795,7 @@ void TargetChange::InternalSwap(TargetChange* PROTOBUF_RESTRICT other) { ::google::protobuf::Metadata TargetChange::GetMetadata() const { return ::_pbi::AssignDescriptors( &descriptor_table_google_2ffirestore_2fv1_2ffirestore_2eproto_getter, &descriptor_table_google_2ffirestore_2fv1_2ffirestore_2eproto_once, - file_level_metadata_google_2ffirestore_2fv1_2ffirestore_2eproto[26]); + file_level_metadata_google_2ffirestore_2fv1_2ffirestore_2eproto[28]); } // =================================================================== @@ -10145,7 +11041,7 @@ void ListCollectionIdsRequest::InternalSwap(ListCollectionIdsRequest* PROTOBUF_R ::google::protobuf::Metadata ListCollectionIdsRequest::GetMetadata() const { return ::_pbi::AssignDescriptors( &descriptor_table_google_2ffirestore_2fv1_2ffirestore_2eproto_getter, &descriptor_table_google_2ffirestore_2fv1_2ffirestore_2eproto_once, - file_level_metadata_google_2ffirestore_2fv1_2ffirestore_2eproto[27]); + file_level_metadata_google_2ffirestore_2fv1_2ffirestore_2eproto[29]); } // =================================================================== @@ -10361,7 +11257,7 @@ void ListCollectionIdsResponse::InternalSwap(ListCollectionIdsResponse* PROTOBUF ::google::protobuf::Metadata ListCollectionIdsResponse::GetMetadata() const { return ::_pbi::AssignDescriptors( &descriptor_table_google_2ffirestore_2fv1_2ffirestore_2eproto_getter, &descriptor_table_google_2ffirestore_2fv1_2ffirestore_2eproto_once, - file_level_metadata_google_2ffirestore_2fv1_2ffirestore_2eproto[28]); + file_level_metadata_google_2ffirestore_2fv1_2ffirestore_2eproto[30]); } // @@protoc_insertion_point(namespace_scope) } // namespace v1 diff --git a/Firestore/Protos/cpp/google/firestore/v1/firestore.pb.h b/Firestore/Protos/cpp/google/firestore/v1/firestore.pb.h index 65e0c8bc1b1..d0678e25d8a 100644 --- a/Firestore/Protos/cpp/google/firestore/v1/firestore.pb.h +++ b/Firestore/Protos/cpp/google/firestore/v1/firestore.pb.h @@ -1,5 +1,5 @@ /* - * Copyright 2024 Google LLC + * Copyright 2025 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -55,9 +55,12 @@ #include "google/protobuf/generated_enum_reflection.h" #include "google/protobuf/unknown_field_set.h" #include "google/api/annotations.pb.h" +#include "google/api/field_behavior.pb.h" #include "google/firestore/v1/aggregation_result.pb.h" #include "google/firestore/v1/common.pb.h" #include "google/firestore/v1/document.pb.h" +#include "google/firestore/v1/explain_stats.pb.h" +#include "google/firestore/v1/pipeline.pb.h" #include "google/firestore/v1/query.pb.h" #include "google/firestore/v1/write.pb.h" #include "google/protobuf/empty.pb.h" @@ -112,6 +115,12 @@ extern CreateDocumentRequestDefaultTypeInternal _CreateDocumentRequest_default_i class DeleteDocumentRequest; struct DeleteDocumentRequestDefaultTypeInternal; extern DeleteDocumentRequestDefaultTypeInternal _DeleteDocumentRequest_default_instance_; +class ExecutePipelineRequest; +struct ExecutePipelineRequestDefaultTypeInternal; +extern ExecutePipelineRequestDefaultTypeInternal _ExecutePipelineRequest_default_instance_; +class ExecutePipelineResponse; +struct ExecutePipelineResponseDefaultTypeInternal; +extern ExecutePipelineResponseDefaultTypeInternal _ExecutePipelineResponse_default_instance_; class GetDocumentRequest; struct GetDocumentRequestDefaultTypeInternal; extern GetDocumentRequestDefaultTypeInternal _GetDocumentRequest_default_instance_; @@ -315,7 +324,7 @@ class Target_DocumentsTarget final : &_Target_DocumentsTarget_default_instance_); } static constexpr int kIndexInFileMessages = - 23; + 25; friend void swap(Target_DocumentsTarget& a, Target_DocumentsTarget& b) { a.Swap(&b); @@ -737,7 +746,7 @@ class ListCollectionIdsResponse final : &_ListCollectionIdsResponse_default_instance_); } static constexpr int kIndexInFileMessages = - 28; + 30; friend void swap(ListCollectionIdsResponse& a, ListCollectionIdsResponse& b) { a.Swap(&b); @@ -948,7 +957,7 @@ class ListCollectionIdsRequest final : &_ListCollectionIdsRequest_default_instance_); } static constexpr int kIndexInFileMessages = - 27; + 29; friend void swap(ListCollectionIdsRequest& a, ListCollectionIdsRequest& b) { a.Swap(&b); @@ -1934,7 +1943,7 @@ class TargetChange final : &_TargetChange_default_instance_); } static constexpr int kIndexInFileMessages = - 26; + 28; friend void swap(TargetChange& a, TargetChange& b) { a.Swap(&b); @@ -2405,7 +2414,7 @@ class WriteResponse final : &_WriteResponse_default_instance_); } static constexpr int kIndexInFileMessages = - 19; + 21; friend void swap(WriteResponse& a, WriteResponse& b) { a.Swap(&b); @@ -3813,7 +3822,7 @@ class RunAggregationQueryResponse final : &_RunAggregationQueryResponse_default_instance_); } static constexpr int kIndexInFileMessages = - 16; + 18; friend void swap(RunAggregationQueryResponse& a, RunAggregationQueryResponse& b) { a.Swap(&b); @@ -4171,26 +4180,26 @@ class ListDocumentsResponse final : friend struct ::TableStruct_google_2ffirestore_2fv1_2ffirestore_2eproto; };// ------------------------------------------------------------------- -class CreateDocumentRequest final : - public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:google.firestore.v1.CreateDocumentRequest) */ { +class ExecutePipelineResponse final : + public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:google.firestore.v1.ExecutePipelineResponse) */ { public: - inline CreateDocumentRequest() : CreateDocumentRequest(nullptr) {} - ~CreateDocumentRequest() override; + inline ExecutePipelineResponse() : ExecutePipelineResponse(nullptr) {} + ~ExecutePipelineResponse() override; template - explicit PROTOBUF_CONSTEXPR CreateDocumentRequest(::google::protobuf::internal::ConstantInitialized); + explicit PROTOBUF_CONSTEXPR ExecutePipelineResponse(::google::protobuf::internal::ConstantInitialized); - inline CreateDocumentRequest(const CreateDocumentRequest& from) - : CreateDocumentRequest(nullptr, from) {} - CreateDocumentRequest(CreateDocumentRequest&& from) noexcept - : CreateDocumentRequest() { + inline ExecutePipelineResponse(const ExecutePipelineResponse& from) + : ExecutePipelineResponse(nullptr, from) {} + ExecutePipelineResponse(ExecutePipelineResponse&& from) noexcept + : ExecutePipelineResponse() { *this = ::std::move(from); } - inline CreateDocumentRequest& operator=(const CreateDocumentRequest& from) { + inline ExecutePipelineResponse& operator=(const ExecutePipelineResponse& from) { CopyFrom(from); return *this; } - inline CreateDocumentRequest& operator=(CreateDocumentRequest&& from) noexcept { + inline ExecutePipelineResponse& operator=(ExecutePipelineResponse&& from) noexcept { if (this == &from) return *this; if (GetArena() == from.GetArena() #ifdef PROTOBUF_FORCE_COPY_IN_MOVE @@ -4222,20 +4231,20 @@ class CreateDocumentRequest final : static const ::google::protobuf::Reflection* GetReflection() { return default_instance().GetMetadata().reflection; } - static const CreateDocumentRequest& default_instance() { + static const ExecutePipelineResponse& default_instance() { return *internal_default_instance(); } - static inline const CreateDocumentRequest* internal_default_instance() { - return reinterpret_cast( - &_CreateDocumentRequest_default_instance_); + static inline const ExecutePipelineResponse* internal_default_instance() { + return reinterpret_cast( + &_ExecutePipelineResponse_default_instance_); } static constexpr int kIndexInFileMessages = - 3; + 16; - friend void swap(CreateDocumentRequest& a, CreateDocumentRequest& b) { + friend void swap(ExecutePipelineResponse& a, ExecutePipelineResponse& b) { a.Swap(&b); } - inline void Swap(CreateDocumentRequest* other) { + inline void Swap(ExecutePipelineResponse* other) { if (other == this) return; #ifdef PROTOBUF_FORCE_COPY_IN_SWAP if (GetArena() != nullptr && @@ -4248,7 +4257,7 @@ class CreateDocumentRequest final : ::google::protobuf::internal::GenericSwap(this, other); } } - void UnsafeArenaSwap(CreateDocumentRequest* other) { + void UnsafeArenaSwap(ExecutePipelineResponse* other) { if (other == this) return; ABSL_DCHECK(GetArena() == other->GetArena()); InternalSwap(other); @@ -4256,14 +4265,14 @@ class CreateDocumentRequest final : // implements Message ---------------------------------------------- - CreateDocumentRequest* New(::google::protobuf::Arena* arena = nullptr) const final { - return CreateMaybeMessage(arena); + ExecutePipelineResponse* New(::google::protobuf::Arena* arena = nullptr) const final { + return CreateMaybeMessage(arena); } using ::google::protobuf::Message::CopyFrom; - void CopyFrom(const CreateDocumentRequest& from); + void CopyFrom(const ExecutePipelineResponse& from); using ::google::protobuf::Message::MergeFrom; - void MergeFrom( const CreateDocumentRequest& from) { - CreateDocumentRequest::MergeImpl(*this, from); + void MergeFrom( const ExecutePipelineResponse& from) { + ExecutePipelineResponse::MergeImpl(*this, from); } private: static void MergeImpl(::google::protobuf::Message& to_msg, const ::google::protobuf::Message& from_msg); @@ -4281,16 +4290,16 @@ class CreateDocumentRequest final : ::google::protobuf::internal::CachedSize* AccessCachedSize() const final; void SharedCtor(::google::protobuf::Arena* arena); void SharedDtor(); - void InternalSwap(CreateDocumentRequest* other); + void InternalSwap(ExecutePipelineResponse* other); private: friend class ::google::protobuf::internal::AnyMetadata; static ::absl::string_view FullMessageName() { - return "google.firestore.v1.CreateDocumentRequest"; + return "google.firestore.v1.ExecutePipelineResponse"; } protected: - explicit CreateDocumentRequest(::google::protobuf::Arena* arena); - CreateDocumentRequest(::google::protobuf::Arena* arena, const CreateDocumentRequest& from); + explicit ExecutePipelineResponse(::google::protobuf::Arena* arena); + ExecutePipelineResponse(::google::protobuf::Arena* arena, const ExecutePipelineResponse& from); public: static const ClassData _class_data_; @@ -4303,98 +4312,83 @@ class CreateDocumentRequest final : // accessors ------------------------------------------------------- enum : int { - kParentFieldNumber = 1, - kCollectionIdFieldNumber = 2, - kDocumentIdFieldNumber = 3, - kDocumentFieldNumber = 4, - kMaskFieldNumber = 5, + kResultsFieldNumber = 2, + kTransactionFieldNumber = 1, + kExecutionTimeFieldNumber = 3, + kExplainStatsFieldNumber = 4, }; - // string parent = 1; - void clear_parent() ; - const std::string& parent() const; - template - void set_parent(Arg_&& arg, Args_... args); - std::string* mutable_parent(); - PROTOBUF_NODISCARD std::string* release_parent(); - void set_allocated_parent(std::string* value); - + // repeated .google.firestore.v1.Document results = 2; + int results_size() const; private: - const std::string& _internal_parent() const; - inline PROTOBUF_ALWAYS_INLINE void _internal_set_parent( - const std::string& value); - std::string* _internal_mutable_parent(); + int _internal_results_size() const; public: - // string collection_id = 2; - void clear_collection_id() ; - const std::string& collection_id() const; - template - void set_collection_id(Arg_&& arg, Args_... args); - std::string* mutable_collection_id(); - PROTOBUF_NODISCARD std::string* release_collection_id(); - void set_allocated_collection_id(std::string* value); - + void clear_results() ; + ::google::firestore::v1::Document* mutable_results(int index); + ::google::protobuf::RepeatedPtrField< ::google::firestore::v1::Document >* + mutable_results(); private: - const std::string& _internal_collection_id() const; - inline PROTOBUF_ALWAYS_INLINE void _internal_set_collection_id( - const std::string& value); - std::string* _internal_mutable_collection_id(); - + const ::google::protobuf::RepeatedPtrField<::google::firestore::v1::Document>& _internal_results() const; + ::google::protobuf::RepeatedPtrField<::google::firestore::v1::Document>* _internal_mutable_results(); public: - // string document_id = 3; - void clear_document_id() ; - const std::string& document_id() const; + const ::google::firestore::v1::Document& results(int index) const; + ::google::firestore::v1::Document* add_results(); + const ::google::protobuf::RepeatedPtrField< ::google::firestore::v1::Document >& + results() const; + // bytes transaction = 1; + void clear_transaction() ; + const std::string& transaction() const; template - void set_document_id(Arg_&& arg, Args_... args); - std::string* mutable_document_id(); - PROTOBUF_NODISCARD std::string* release_document_id(); - void set_allocated_document_id(std::string* value); + void set_transaction(Arg_&& arg, Args_... args); + std::string* mutable_transaction(); + PROTOBUF_NODISCARD std::string* release_transaction(); + void set_allocated_transaction(std::string* value); private: - const std::string& _internal_document_id() const; - inline PROTOBUF_ALWAYS_INLINE void _internal_set_document_id( + const std::string& _internal_transaction() const; + inline PROTOBUF_ALWAYS_INLINE void _internal_set_transaction( const std::string& value); - std::string* _internal_mutable_document_id(); + std::string* _internal_mutable_transaction(); public: - // .google.firestore.v1.Document document = 4; - bool has_document() const; - void clear_document() ; - const ::google::firestore::v1::Document& document() const; - PROTOBUF_NODISCARD ::google::firestore::v1::Document* release_document(); - ::google::firestore::v1::Document* mutable_document(); - void set_allocated_document(::google::firestore::v1::Document* value); - void unsafe_arena_set_allocated_document(::google::firestore::v1::Document* value); - ::google::firestore::v1::Document* unsafe_arena_release_document(); + // .google.protobuf.Timestamp execution_time = 3; + bool has_execution_time() const; + void clear_execution_time() ; + const ::google::protobuf::Timestamp& execution_time() const; + PROTOBUF_NODISCARD ::google::protobuf::Timestamp* release_execution_time(); + ::google::protobuf::Timestamp* mutable_execution_time(); + void set_allocated_execution_time(::google::protobuf::Timestamp* value); + void unsafe_arena_set_allocated_execution_time(::google::protobuf::Timestamp* value); + ::google::protobuf::Timestamp* unsafe_arena_release_execution_time(); private: - const ::google::firestore::v1::Document& _internal_document() const; - ::google::firestore::v1::Document* _internal_mutable_document(); + const ::google::protobuf::Timestamp& _internal_execution_time() const; + ::google::protobuf::Timestamp* _internal_mutable_execution_time(); public: - // .google.firestore.v1.DocumentMask mask = 5; - bool has_mask() const; - void clear_mask() ; - const ::google::firestore::v1::DocumentMask& mask() const; - PROTOBUF_NODISCARD ::google::firestore::v1::DocumentMask* release_mask(); - ::google::firestore::v1::DocumentMask* mutable_mask(); - void set_allocated_mask(::google::firestore::v1::DocumentMask* value); - void unsafe_arena_set_allocated_mask(::google::firestore::v1::DocumentMask* value); - ::google::firestore::v1::DocumentMask* unsafe_arena_release_mask(); + // .google.firestore.v1.ExplainStats explain_stats = 4; + bool has_explain_stats() const; + void clear_explain_stats() ; + const ::google::firestore::v1::ExplainStats& explain_stats() const; + PROTOBUF_NODISCARD ::google::firestore::v1::ExplainStats* release_explain_stats(); + ::google::firestore::v1::ExplainStats* mutable_explain_stats(); + void set_allocated_explain_stats(::google::firestore::v1::ExplainStats* value); + void unsafe_arena_set_allocated_explain_stats(::google::firestore::v1::ExplainStats* value); + ::google::firestore::v1::ExplainStats* unsafe_arena_release_explain_stats(); private: - const ::google::firestore::v1::DocumentMask& _internal_mask() const; - ::google::firestore::v1::DocumentMask* _internal_mutable_mask(); + const ::google::firestore::v1::ExplainStats& _internal_explain_stats() const; + ::google::firestore::v1::ExplainStats* _internal_mutable_explain_stats(); public: - // @@protoc_insertion_point(class_scope:google.firestore.v1.CreateDocumentRequest) + // @@protoc_insertion_point(class_scope:google.firestore.v1.ExecutePipelineResponse) private: class _Internal; friend class ::google::protobuf::internal::TcParser; static const ::google::protobuf::internal::TcParseTable< - 3, 5, 2, - 80, 2> + 2, 4, 3, + 0, 2> _table_; friend class ::google::protobuf::MessageLite; friend class ::google::protobuf::Arena; @@ -4412,37 +4406,36 @@ class CreateDocumentRequest final : ::google::protobuf::Arena* arena, const Impl_& from); ::google::protobuf::internal::HasBits<1> _has_bits_; mutable ::google::protobuf::internal::CachedSize _cached_size_; - ::google::protobuf::internal::ArenaStringPtr parent_; - ::google::protobuf::internal::ArenaStringPtr collection_id_; - ::google::protobuf::internal::ArenaStringPtr document_id_; - ::google::firestore::v1::Document* document_; - ::google::firestore::v1::DocumentMask* mask_; + ::google::protobuf::RepeatedPtrField< ::google::firestore::v1::Document > results_; + ::google::protobuf::internal::ArenaStringPtr transaction_; + ::google::protobuf::Timestamp* execution_time_; + ::google::firestore::v1::ExplainStats* explain_stats_; PROTOBUF_TSAN_DECLARE_MEMBER }; union { Impl_ _impl_; }; friend struct ::TableStruct_google_2ffirestore_2fv1_2ffirestore_2eproto; };// ------------------------------------------------------------------- -class BatchGetDocumentsResponse final : - public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:google.firestore.v1.BatchGetDocumentsResponse) */ { +class ExecutePipelineRequest final : + public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:google.firestore.v1.ExecutePipelineRequest) */ { public: - inline BatchGetDocumentsResponse() : BatchGetDocumentsResponse(nullptr) {} - ~BatchGetDocumentsResponse() override; + inline ExecutePipelineRequest() : ExecutePipelineRequest(nullptr) {} + ~ExecutePipelineRequest() override; template - explicit PROTOBUF_CONSTEXPR BatchGetDocumentsResponse(::google::protobuf::internal::ConstantInitialized); + explicit PROTOBUF_CONSTEXPR ExecutePipelineRequest(::google::protobuf::internal::ConstantInitialized); - inline BatchGetDocumentsResponse(const BatchGetDocumentsResponse& from) - : BatchGetDocumentsResponse(nullptr, from) {} - BatchGetDocumentsResponse(BatchGetDocumentsResponse&& from) noexcept - : BatchGetDocumentsResponse() { + inline ExecutePipelineRequest(const ExecutePipelineRequest& from) + : ExecutePipelineRequest(nullptr, from) {} + ExecutePipelineRequest(ExecutePipelineRequest&& from) noexcept + : ExecutePipelineRequest() { *this = ::std::move(from); } - inline BatchGetDocumentsResponse& operator=(const BatchGetDocumentsResponse& from) { + inline ExecutePipelineRequest& operator=(const ExecutePipelineRequest& from) { CopyFrom(from); return *this; } - inline BatchGetDocumentsResponse& operator=(BatchGetDocumentsResponse&& from) noexcept { + inline ExecutePipelineRequest& operator=(ExecutePipelineRequest&& from) noexcept { if (this == &from) return *this; if (GetArena() == from.GetArena() #ifdef PROTOBUF_FORCE_COPY_IN_MOVE @@ -4474,26 +4467,32 @@ class BatchGetDocumentsResponse final : static const ::google::protobuf::Reflection* GetReflection() { return default_instance().GetMetadata().reflection; } - static const BatchGetDocumentsResponse& default_instance() { + static const ExecutePipelineRequest& default_instance() { return *internal_default_instance(); } - enum ResultCase { - kFound = 1, - kMissing = 2, - RESULT_NOT_SET = 0, + enum PipelineTypeCase { + kStructuredPipeline = 2, + PIPELINE_TYPE_NOT_SET = 0, }; - static inline const BatchGetDocumentsResponse* internal_default_instance() { - return reinterpret_cast( - &_BatchGetDocumentsResponse_default_instance_); + enum ConsistencySelectorCase { + kTransaction = 5, + kNewTransaction = 6, + kReadTime = 7, + CONSISTENCY_SELECTOR_NOT_SET = 0, + }; + + static inline const ExecutePipelineRequest* internal_default_instance() { + return reinterpret_cast( + &_ExecutePipelineRequest_default_instance_); } static constexpr int kIndexInFileMessages = - 7; + 15; - friend void swap(BatchGetDocumentsResponse& a, BatchGetDocumentsResponse& b) { + friend void swap(ExecutePipelineRequest& a, ExecutePipelineRequest& b) { a.Swap(&b); } - inline void Swap(BatchGetDocumentsResponse* other) { + inline void Swap(ExecutePipelineRequest* other) { if (other == this) return; #ifdef PROTOBUF_FORCE_COPY_IN_SWAP if (GetArena() != nullptr && @@ -4506,7 +4505,7 @@ class BatchGetDocumentsResponse final : ::google::protobuf::internal::GenericSwap(this, other); } } - void UnsafeArenaSwap(BatchGetDocumentsResponse* other) { + void UnsafeArenaSwap(ExecutePipelineRequest* other) { if (other == this) return; ABSL_DCHECK(GetArena() == other->GetArena()); InternalSwap(other); @@ -4514,14 +4513,14 @@ class BatchGetDocumentsResponse final : // implements Message ---------------------------------------------- - BatchGetDocumentsResponse* New(::google::protobuf::Arena* arena = nullptr) const final { - return CreateMaybeMessage(arena); + ExecutePipelineRequest* New(::google::protobuf::Arena* arena = nullptr) const final { + return CreateMaybeMessage(arena); } using ::google::protobuf::Message::CopyFrom; - void CopyFrom(const BatchGetDocumentsResponse& from); + void CopyFrom(const ExecutePipelineRequest& from); using ::google::protobuf::Message::MergeFrom; - void MergeFrom( const BatchGetDocumentsResponse& from) { - BatchGetDocumentsResponse::MergeImpl(*this, from); + void MergeFrom( const ExecutePipelineRequest& from) { + ExecutePipelineRequest::MergeImpl(*this, from); } private: static void MergeImpl(::google::protobuf::Message& to_msg, const ::google::protobuf::Message& from_msg); @@ -4539,16 +4538,16 @@ class BatchGetDocumentsResponse final : ::google::protobuf::internal::CachedSize* AccessCachedSize() const final; void SharedCtor(::google::protobuf::Arena* arena); void SharedDtor(); - void InternalSwap(BatchGetDocumentsResponse* other); + void InternalSwap(ExecutePipelineRequest* other); private: friend class ::google::protobuf::internal::AnyMetadata; static ::absl::string_view FullMessageName() { - return "google.firestore.v1.BatchGetDocumentsResponse"; + return "google.firestore.v1.ExecutePipelineRequest"; } protected: - explicit BatchGetDocumentsResponse(::google::protobuf::Arena* arena); - BatchGetDocumentsResponse(::google::protobuf::Arena* arena, const BatchGetDocumentsResponse& from); + explicit ExecutePipelineRequest(::google::protobuf::Arena* arena); + ExecutePipelineRequest(::google::protobuf::Arena* arena, const ExecutePipelineRequest& from); public: static const ClassData _class_data_; @@ -4561,12 +4560,49 @@ class BatchGetDocumentsResponse final : // accessors ------------------------------------------------------- enum : int { - kTransactionFieldNumber = 3, - kReadTimeFieldNumber = 4, - kFoundFieldNumber = 1, - kMissingFieldNumber = 2, + kDatabaseFieldNumber = 1, + kStructuredPipelineFieldNumber = 2, + kTransactionFieldNumber = 5, + kNewTransactionFieldNumber = 6, + kReadTimeFieldNumber = 7, }; - // bytes transaction = 3; + // string database = 1 [(.google.api.field_behavior) = REQUIRED]; + void clear_database() ; + const std::string& database() const; + template + void set_database(Arg_&& arg, Args_... args); + std::string* mutable_database(); + PROTOBUF_NODISCARD std::string* release_database(); + void set_allocated_database(std::string* value); + + private: + const std::string& _internal_database() const; + inline PROTOBUF_ALWAYS_INLINE void _internal_set_database( + const std::string& value); + std::string* _internal_mutable_database(); + + public: + // .google.firestore.v1.StructuredPipeline structured_pipeline = 2; + bool has_structured_pipeline() const; + private: + bool _internal_has_structured_pipeline() const; + + public: + void clear_structured_pipeline() ; + const ::google::firestore::v1::StructuredPipeline& structured_pipeline() const; + PROTOBUF_NODISCARD ::google::firestore::v1::StructuredPipeline* release_structured_pipeline(); + ::google::firestore::v1::StructuredPipeline* mutable_structured_pipeline(); + void set_allocated_structured_pipeline(::google::firestore::v1::StructuredPipeline* value); + void unsafe_arena_set_allocated_structured_pipeline(::google::firestore::v1::StructuredPipeline* value); + ::google::firestore::v1::StructuredPipeline* unsafe_arena_release_structured_pipeline(); + + private: + const ::google::firestore::v1::StructuredPipeline& _internal_structured_pipeline() const; + ::google::firestore::v1::StructuredPipeline* _internal_mutable_structured_pipeline(); + + public: + // bytes transaction = 5; + bool has_transaction() const; void clear_transaction() ; const std::string& transaction() const; template @@ -4582,8 +4618,31 @@ class BatchGetDocumentsResponse final : std::string* _internal_mutable_transaction(); public: - // .google.protobuf.Timestamp read_time = 4; + // .google.firestore.v1.TransactionOptions new_transaction = 6; + bool has_new_transaction() const; + private: + bool _internal_has_new_transaction() const; + + public: + void clear_new_transaction() ; + const ::google::firestore::v1::TransactionOptions& new_transaction() const; + PROTOBUF_NODISCARD ::google::firestore::v1::TransactionOptions* release_new_transaction(); + ::google::firestore::v1::TransactionOptions* mutable_new_transaction(); + void set_allocated_new_transaction(::google::firestore::v1::TransactionOptions* value); + void unsafe_arena_set_allocated_new_transaction(::google::firestore::v1::TransactionOptions* value); + ::google::firestore::v1::TransactionOptions* unsafe_arena_release_new_transaction(); + + private: + const ::google::firestore::v1::TransactionOptions& _internal_new_transaction() const; + ::google::firestore::v1::TransactionOptions* _internal_mutable_new_transaction(); + + public: + // .google.protobuf.Timestamp read_time = 7; bool has_read_time() const; + private: + bool _internal_has_read_time() const; + + public: void clear_read_time() ; const ::google::protobuf::Timestamp& read_time() const; PROTOBUF_NODISCARD ::google::protobuf::Timestamp* release_read_time(); @@ -4597,57 +4656,28 @@ class BatchGetDocumentsResponse final : ::google::protobuf::Timestamp* _internal_mutable_read_time(); public: - // .google.firestore.v1.Document found = 1; - bool has_found() const; - private: - bool _internal_has_found() const; + void clear_pipeline_type(); + PipelineTypeCase pipeline_type_case() const; + void clear_consistency_selector(); + ConsistencySelectorCase consistency_selector_case() const; + // @@protoc_insertion_point(class_scope:google.firestore.v1.ExecutePipelineRequest) + private: + class _Internal; + void set_has_structured_pipeline(); + void set_has_transaction(); + void set_has_new_transaction(); + void set_has_read_time(); - public: - void clear_found() ; - const ::google::firestore::v1::Document& found() const; - PROTOBUF_NODISCARD ::google::firestore::v1::Document* release_found(); - ::google::firestore::v1::Document* mutable_found(); - void set_allocated_found(::google::firestore::v1::Document* value); - void unsafe_arena_set_allocated_found(::google::firestore::v1::Document* value); - ::google::firestore::v1::Document* unsafe_arena_release_found(); + inline bool has_pipeline_type() const; + inline void clear_has_pipeline_type(); - private: - const ::google::firestore::v1::Document& _internal_found() const; - ::google::firestore::v1::Document* _internal_mutable_found(); - - public: - // string missing = 2; - bool has_missing() const; - void clear_missing() ; - const std::string& missing() const; - template - void set_missing(Arg_&& arg, Args_... args); - std::string* mutable_missing(); - PROTOBUF_NODISCARD std::string* release_missing(); - void set_allocated_missing(std::string* value); - - private: - const std::string& _internal_missing() const; - inline PROTOBUF_ALWAYS_INLINE void _internal_set_missing( - const std::string& value); - std::string* _internal_mutable_missing(); - - public: - void clear_result(); - ResultCase result_case() const; - // @@protoc_insertion_point(class_scope:google.firestore.v1.BatchGetDocumentsResponse) - private: - class _Internal; - void set_has_found(); - void set_has_missing(); - - inline bool has_result() const; - inline void clear_has_result(); + inline bool has_consistency_selector() const; + inline void clear_has_consistency_selector(); friend class ::google::protobuf::internal::TcParser; static const ::google::protobuf::internal::TcParseTable< - 1, 4, 2, - 61, 2> + 0, 5, 3, + 59, 2> _table_; friend class ::google::protobuf::MessageLite; friend class ::google::protobuf::Arena; @@ -4663,17 +4693,21 @@ class BatchGetDocumentsResponse final : ::google::protobuf::Arena* arena); inline explicit Impl_(::google::protobuf::internal::InternalVisibility visibility, ::google::protobuf::Arena* arena, const Impl_& from); - ::google::protobuf::internal::HasBits<1> _has_bits_; - mutable ::google::protobuf::internal::CachedSize _cached_size_; - ::google::protobuf::internal::ArenaStringPtr transaction_; - ::google::protobuf::Timestamp* read_time_; - union ResultUnion { - constexpr ResultUnion() : _constinit_{} {} + ::google::protobuf::internal::ArenaStringPtr database_; + union PipelineTypeUnion { + constexpr PipelineTypeUnion() : _constinit_{} {} ::google::protobuf::internal::ConstantInitialized _constinit_; - ::google::firestore::v1::Document* found_; - ::google::protobuf::internal::ArenaStringPtr missing_; - } result_; - ::uint32_t _oneof_case_[1]; + ::google::firestore::v1::StructuredPipeline* structured_pipeline_; + } pipeline_type_; + union ConsistencySelectorUnion { + constexpr ConsistencySelectorUnion() : _constinit_{} {} + ::google::protobuf::internal::ConstantInitialized _constinit_; + ::google::protobuf::internal::ArenaStringPtr transaction_; + ::google::firestore::v1::TransactionOptions* new_transaction_; + ::google::protobuf::Timestamp* read_time_; + } consistency_selector_; + mutable ::google::protobuf::internal::CachedSize _cached_size_; + ::uint32_t _oneof_case_[2]; PROTOBUF_TSAN_DECLARE_MEMBER }; @@ -4681,26 +4715,26 @@ class BatchGetDocumentsResponse final : friend struct ::TableStruct_google_2ffirestore_2fv1_2ffirestore_2eproto; };// ------------------------------------------------------------------- -class WriteRequest final : - public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:google.firestore.v1.WriteRequest) */ { +class CreateDocumentRequest final : + public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:google.firestore.v1.CreateDocumentRequest) */ { public: - inline WriteRequest() : WriteRequest(nullptr) {} - ~WriteRequest() override; + inline CreateDocumentRequest() : CreateDocumentRequest(nullptr) {} + ~CreateDocumentRequest() override; template - explicit PROTOBUF_CONSTEXPR WriteRequest(::google::protobuf::internal::ConstantInitialized); + explicit PROTOBUF_CONSTEXPR CreateDocumentRequest(::google::protobuf::internal::ConstantInitialized); - inline WriteRequest(const WriteRequest& from) - : WriteRequest(nullptr, from) {} - WriteRequest(WriteRequest&& from) noexcept - : WriteRequest() { + inline CreateDocumentRequest(const CreateDocumentRequest& from) + : CreateDocumentRequest(nullptr, from) {} + CreateDocumentRequest(CreateDocumentRequest&& from) noexcept + : CreateDocumentRequest() { *this = ::std::move(from); } - inline WriteRequest& operator=(const WriteRequest& from) { + inline CreateDocumentRequest& operator=(const CreateDocumentRequest& from) { CopyFrom(from); return *this; } - inline WriteRequest& operator=(WriteRequest&& from) noexcept { + inline CreateDocumentRequest& operator=(CreateDocumentRequest&& from) noexcept { if (this == &from) return *this; if (GetArena() == from.GetArena() #ifdef PROTOBUF_FORCE_COPY_IN_MOVE @@ -4732,20 +4766,20 @@ class WriteRequest final : static const ::google::protobuf::Reflection* GetReflection() { return default_instance().GetMetadata().reflection; } - static const WriteRequest& default_instance() { + static const CreateDocumentRequest& default_instance() { return *internal_default_instance(); } - static inline const WriteRequest* internal_default_instance() { - return reinterpret_cast( - &_WriteRequest_default_instance_); + static inline const CreateDocumentRequest* internal_default_instance() { + return reinterpret_cast( + &_CreateDocumentRequest_default_instance_); } static constexpr int kIndexInFileMessages = - 18; + 3; - friend void swap(WriteRequest& a, WriteRequest& b) { + friend void swap(CreateDocumentRequest& a, CreateDocumentRequest& b) { a.Swap(&b); } - inline void Swap(WriteRequest* other) { + inline void Swap(CreateDocumentRequest* other) { if (other == this) return; #ifdef PROTOBUF_FORCE_COPY_IN_SWAP if (GetArena() != nullptr && @@ -4758,7 +4792,7 @@ class WriteRequest final : ::google::protobuf::internal::GenericSwap(this, other); } } - void UnsafeArenaSwap(WriteRequest* other) { + void UnsafeArenaSwap(CreateDocumentRequest* other) { if (other == this) return; ABSL_DCHECK(GetArena() == other->GetArena()); InternalSwap(other); @@ -4766,14 +4800,14 @@ class WriteRequest final : // implements Message ---------------------------------------------- - WriteRequest* New(::google::protobuf::Arena* arena = nullptr) const final { - return CreateMaybeMessage(arena); + CreateDocumentRequest* New(::google::protobuf::Arena* arena = nullptr) const final { + return CreateMaybeMessage(arena); } using ::google::protobuf::Message::CopyFrom; - void CopyFrom(const WriteRequest& from); + void CopyFrom(const CreateDocumentRequest& from); using ::google::protobuf::Message::MergeFrom; - void MergeFrom( const WriteRequest& from) { - WriteRequest::MergeImpl(*this, from); + void MergeFrom( const CreateDocumentRequest& from) { + CreateDocumentRequest::MergeImpl(*this, from); } private: static void MergeImpl(::google::protobuf::Message& to_msg, const ::google::protobuf::Message& from_msg); @@ -4791,16 +4825,16 @@ class WriteRequest final : ::google::protobuf::internal::CachedSize* AccessCachedSize() const final; void SharedCtor(::google::protobuf::Arena* arena); void SharedDtor(); - void InternalSwap(WriteRequest* other); + void InternalSwap(CreateDocumentRequest* other); private: friend class ::google::protobuf::internal::AnyMetadata; static ::absl::string_view FullMessageName() { - return "google.firestore.v1.WriteRequest"; + return "google.firestore.v1.CreateDocumentRequest"; } protected: - explicit WriteRequest(::google::protobuf::Arena* arena); - WriteRequest(::google::protobuf::Arena* arena, const WriteRequest& from); + explicit CreateDocumentRequest(::google::protobuf::Arena* arena); + CreateDocumentRequest(::google::protobuf::Arena* arena, const CreateDocumentRequest& from); public: static const ClassData _class_data_; @@ -4810,105 +4844,101 @@ class WriteRequest final : // nested types ---------------------------------------------------- - // accessors ------------------------------------------------------- enum : int { - kWritesFieldNumber = 3, - kLabelsFieldNumber = 5, - kDatabaseFieldNumber = 1, - kStreamIdFieldNumber = 2, - kStreamTokenFieldNumber = 4, + kParentFieldNumber = 1, + kCollectionIdFieldNumber = 2, + kDocumentIdFieldNumber = 3, + kDocumentFieldNumber = 4, + kMaskFieldNumber = 5, }; - // repeated .google.firestore.v1.Write writes = 3; - int writes_size() const; - private: - int _internal_writes_size() const; + // string parent = 1; + void clear_parent() ; + const std::string& parent() const; + template + void set_parent(Arg_&& arg, Args_... args); + std::string* mutable_parent(); + PROTOBUF_NODISCARD std::string* release_parent(); + void set_allocated_parent(std::string* value); - public: - void clear_writes() ; - ::google::firestore::v1::Write* mutable_writes(int index); - ::google::protobuf::RepeatedPtrField< ::google::firestore::v1::Write >* - mutable_writes(); - private: - const ::google::protobuf::RepeatedPtrField<::google::firestore::v1::Write>& _internal_writes() const; - ::google::protobuf::RepeatedPtrField<::google::firestore::v1::Write>* _internal_mutable_writes(); - public: - const ::google::firestore::v1::Write& writes(int index) const; - ::google::firestore::v1::Write* add_writes(); - const ::google::protobuf::RepeatedPtrField< ::google::firestore::v1::Write >& - writes() const; - // map labels = 5; - int labels_size() const; private: - int _internal_labels_size() const; + const std::string& _internal_parent() const; + inline PROTOBUF_ALWAYS_INLINE void _internal_set_parent( + const std::string& value); + std::string* _internal_mutable_parent(); public: - void clear_labels() ; - const ::google::protobuf::Map& labels() const; - ::google::protobuf::Map* mutable_labels(); + // string collection_id = 2; + void clear_collection_id() ; + const std::string& collection_id() const; + template + void set_collection_id(Arg_&& arg, Args_... args); + std::string* mutable_collection_id(); + PROTOBUF_NODISCARD std::string* release_collection_id(); + void set_allocated_collection_id(std::string* value); private: - const ::google::protobuf::Map& _internal_labels() const; - ::google::protobuf::Map* _internal_mutable_labels(); + const std::string& _internal_collection_id() const; + inline PROTOBUF_ALWAYS_INLINE void _internal_set_collection_id( + const std::string& value); + std::string* _internal_mutable_collection_id(); public: - // string database = 1; - void clear_database() ; - const std::string& database() const; + // string document_id = 3; + void clear_document_id() ; + const std::string& document_id() const; template - void set_database(Arg_&& arg, Args_... args); - std::string* mutable_database(); - PROTOBUF_NODISCARD std::string* release_database(); - void set_allocated_database(std::string* value); + void set_document_id(Arg_&& arg, Args_... args); + std::string* mutable_document_id(); + PROTOBUF_NODISCARD std::string* release_document_id(); + void set_allocated_document_id(std::string* value); private: - const std::string& _internal_database() const; - inline PROTOBUF_ALWAYS_INLINE void _internal_set_database( + const std::string& _internal_document_id() const; + inline PROTOBUF_ALWAYS_INLINE void _internal_set_document_id( const std::string& value); - std::string* _internal_mutable_database(); + std::string* _internal_mutable_document_id(); public: - // string stream_id = 2; - void clear_stream_id() ; - const std::string& stream_id() const; - template - void set_stream_id(Arg_&& arg, Args_... args); - std::string* mutable_stream_id(); - PROTOBUF_NODISCARD std::string* release_stream_id(); - void set_allocated_stream_id(std::string* value); + // .google.firestore.v1.Document document = 4; + bool has_document() const; + void clear_document() ; + const ::google::firestore::v1::Document& document() const; + PROTOBUF_NODISCARD ::google::firestore::v1::Document* release_document(); + ::google::firestore::v1::Document* mutable_document(); + void set_allocated_document(::google::firestore::v1::Document* value); + void unsafe_arena_set_allocated_document(::google::firestore::v1::Document* value); + ::google::firestore::v1::Document* unsafe_arena_release_document(); private: - const std::string& _internal_stream_id() const; - inline PROTOBUF_ALWAYS_INLINE void _internal_set_stream_id( - const std::string& value); - std::string* _internal_mutable_stream_id(); + const ::google::firestore::v1::Document& _internal_document() const; + ::google::firestore::v1::Document* _internal_mutable_document(); public: - // bytes stream_token = 4; - void clear_stream_token() ; - const std::string& stream_token() const; - template - void set_stream_token(Arg_&& arg, Args_... args); - std::string* mutable_stream_token(); - PROTOBUF_NODISCARD std::string* release_stream_token(); - void set_allocated_stream_token(std::string* value); + // .google.firestore.v1.DocumentMask mask = 5; + bool has_mask() const; + void clear_mask() ; + const ::google::firestore::v1::DocumentMask& mask() const; + PROTOBUF_NODISCARD ::google::firestore::v1::DocumentMask* release_mask(); + ::google::firestore::v1::DocumentMask* mutable_mask(); + void set_allocated_mask(::google::firestore::v1::DocumentMask* value); + void unsafe_arena_set_allocated_mask(::google::firestore::v1::DocumentMask* value); + ::google::firestore::v1::DocumentMask* unsafe_arena_release_mask(); private: - const std::string& _internal_stream_token() const; - inline PROTOBUF_ALWAYS_INLINE void _internal_set_stream_token( - const std::string& value); - std::string* _internal_mutable_stream_token(); + const ::google::firestore::v1::DocumentMask& _internal_mask() const; + ::google::firestore::v1::DocumentMask* _internal_mutable_mask(); public: - // @@protoc_insertion_point(class_scope:google.firestore.v1.WriteRequest) + // @@protoc_insertion_point(class_scope:google.firestore.v1.CreateDocumentRequest) private: class _Internal; friend class ::google::protobuf::internal::TcParser; static const ::google::protobuf::internal::TcParseTable< - 2, 5, 2, - 64, 2> + 3, 5, 2, + 80, 2> _table_; friend class ::google::protobuf::MessageLite; friend class ::google::protobuf::Arena; @@ -4924,41 +4954,39 @@ class WriteRequest final : ::google::protobuf::Arena* arena); inline explicit Impl_(::google::protobuf::internal::InternalVisibility visibility, ::google::protobuf::Arena* arena, const Impl_& from); - ::google::protobuf::RepeatedPtrField< ::google::firestore::v1::Write > writes_; - ::google::protobuf::internal::MapField - labels_; - ::google::protobuf::internal::ArenaStringPtr database_; - ::google::protobuf::internal::ArenaStringPtr stream_id_; - ::google::protobuf::internal::ArenaStringPtr stream_token_; + ::google::protobuf::internal::HasBits<1> _has_bits_; mutable ::google::protobuf::internal::CachedSize _cached_size_; + ::google::protobuf::internal::ArenaStringPtr parent_; + ::google::protobuf::internal::ArenaStringPtr collection_id_; + ::google::protobuf::internal::ArenaStringPtr document_id_; + ::google::firestore::v1::Document* document_; + ::google::firestore::v1::DocumentMask* mask_; PROTOBUF_TSAN_DECLARE_MEMBER }; union { Impl_ _impl_; }; friend struct ::TableStruct_google_2ffirestore_2fv1_2ffirestore_2eproto; };// ------------------------------------------------------------------- -class Target_QueryTarget final : - public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:google.firestore.v1.Target.QueryTarget) */ { +class BatchGetDocumentsResponse final : + public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:google.firestore.v1.BatchGetDocumentsResponse) */ { public: - inline Target_QueryTarget() : Target_QueryTarget(nullptr) {} - ~Target_QueryTarget() override; + inline BatchGetDocumentsResponse() : BatchGetDocumentsResponse(nullptr) {} + ~BatchGetDocumentsResponse() override; template - explicit PROTOBUF_CONSTEXPR Target_QueryTarget(::google::protobuf::internal::ConstantInitialized); + explicit PROTOBUF_CONSTEXPR BatchGetDocumentsResponse(::google::protobuf::internal::ConstantInitialized); - inline Target_QueryTarget(const Target_QueryTarget& from) - : Target_QueryTarget(nullptr, from) {} - Target_QueryTarget(Target_QueryTarget&& from) noexcept - : Target_QueryTarget() { + inline BatchGetDocumentsResponse(const BatchGetDocumentsResponse& from) + : BatchGetDocumentsResponse(nullptr, from) {} + BatchGetDocumentsResponse(BatchGetDocumentsResponse&& from) noexcept + : BatchGetDocumentsResponse() { *this = ::std::move(from); } - inline Target_QueryTarget& operator=(const Target_QueryTarget& from) { + inline BatchGetDocumentsResponse& operator=(const BatchGetDocumentsResponse& from) { CopyFrom(from); return *this; } - inline Target_QueryTarget& operator=(Target_QueryTarget&& from) noexcept { + inline BatchGetDocumentsResponse& operator=(BatchGetDocumentsResponse&& from) noexcept { if (this == &from) return *this; if (GetArena() == from.GetArena() #ifdef PROTOBUF_FORCE_COPY_IN_MOVE @@ -4990,25 +5018,26 @@ class Target_QueryTarget final : static const ::google::protobuf::Reflection* GetReflection() { return default_instance().GetMetadata().reflection; } - static const Target_QueryTarget& default_instance() { + static const BatchGetDocumentsResponse& default_instance() { return *internal_default_instance(); } - enum QueryTypeCase { - kStructuredQuery = 2, - QUERY_TYPE_NOT_SET = 0, + enum ResultCase { + kFound = 1, + kMissing = 2, + RESULT_NOT_SET = 0, }; - static inline const Target_QueryTarget* internal_default_instance() { - return reinterpret_cast( - &_Target_QueryTarget_default_instance_); + static inline const BatchGetDocumentsResponse* internal_default_instance() { + return reinterpret_cast( + &_BatchGetDocumentsResponse_default_instance_); } static constexpr int kIndexInFileMessages = - 24; + 7; - friend void swap(Target_QueryTarget& a, Target_QueryTarget& b) { + friend void swap(BatchGetDocumentsResponse& a, BatchGetDocumentsResponse& b) { a.Swap(&b); } - inline void Swap(Target_QueryTarget* other) { + inline void Swap(BatchGetDocumentsResponse* other) { if (other == this) return; #ifdef PROTOBUF_FORCE_COPY_IN_SWAP if (GetArena() != nullptr && @@ -5021,7 +5050,7 @@ class Target_QueryTarget final : ::google::protobuf::internal::GenericSwap(this, other); } } - void UnsafeArenaSwap(Target_QueryTarget* other) { + void UnsafeArenaSwap(BatchGetDocumentsResponse* other) { if (other == this) return; ABSL_DCHECK(GetArena() == other->GetArena()); InternalSwap(other); @@ -5029,14 +5058,14 @@ class Target_QueryTarget final : // implements Message ---------------------------------------------- - Target_QueryTarget* New(::google::protobuf::Arena* arena = nullptr) const final { - return CreateMaybeMessage(arena); + BatchGetDocumentsResponse* New(::google::protobuf::Arena* arena = nullptr) const final { + return CreateMaybeMessage(arena); } using ::google::protobuf::Message::CopyFrom; - void CopyFrom(const Target_QueryTarget& from); + void CopyFrom(const BatchGetDocumentsResponse& from); using ::google::protobuf::Message::MergeFrom; - void MergeFrom( const Target_QueryTarget& from) { - Target_QueryTarget::MergeImpl(*this, from); + void MergeFrom( const BatchGetDocumentsResponse& from) { + BatchGetDocumentsResponse::MergeImpl(*this, from); } private: static void MergeImpl(::google::protobuf::Message& to_msg, const ::google::protobuf::Message& from_msg); @@ -5054,16 +5083,16 @@ class Target_QueryTarget final : ::google::protobuf::internal::CachedSize* AccessCachedSize() const final; void SharedCtor(::google::protobuf::Arena* arena); void SharedDtor(); - void InternalSwap(Target_QueryTarget* other); + void InternalSwap(BatchGetDocumentsResponse* other); private: friend class ::google::protobuf::internal::AnyMetadata; static ::absl::string_view FullMessageName() { - return "google.firestore.v1.Target.QueryTarget"; + return "google.firestore.v1.BatchGetDocumentsResponse"; } protected: - explicit Target_QueryTarget(::google::protobuf::Arena* arena); - Target_QueryTarget(::google::protobuf::Arena* arena, const Target_QueryTarget& from); + explicit BatchGetDocumentsResponse(::google::protobuf::Arena* arena); + BatchGetDocumentsResponse(::google::protobuf::Arena* arena, const BatchGetDocumentsResponse& from); public: static const ClassData _class_data_; @@ -5076,58 +5105,93 @@ class Target_QueryTarget final : // accessors ------------------------------------------------------- enum : int { - kParentFieldNumber = 1, - kStructuredQueryFieldNumber = 2, + kTransactionFieldNumber = 3, + kReadTimeFieldNumber = 4, + kFoundFieldNumber = 1, + kMissingFieldNumber = 2, }; - // string parent = 1; - void clear_parent() ; - const std::string& parent() const; + // bytes transaction = 3; + void clear_transaction() ; + const std::string& transaction() const; template - void set_parent(Arg_&& arg, Args_... args); - std::string* mutable_parent(); - PROTOBUF_NODISCARD std::string* release_parent(); - void set_allocated_parent(std::string* value); + void set_transaction(Arg_&& arg, Args_... args); + std::string* mutable_transaction(); + PROTOBUF_NODISCARD std::string* release_transaction(); + void set_allocated_transaction(std::string* value); private: - const std::string& _internal_parent() const; - inline PROTOBUF_ALWAYS_INLINE void _internal_set_parent( + const std::string& _internal_transaction() const; + inline PROTOBUF_ALWAYS_INLINE void _internal_set_transaction( const std::string& value); - std::string* _internal_mutable_parent(); + std::string* _internal_mutable_transaction(); public: - // .google.firestore.v1.StructuredQuery structured_query = 2; - bool has_structured_query() const; + // .google.protobuf.Timestamp read_time = 4; + bool has_read_time() const; + void clear_read_time() ; + const ::google::protobuf::Timestamp& read_time() const; + PROTOBUF_NODISCARD ::google::protobuf::Timestamp* release_read_time(); + ::google::protobuf::Timestamp* mutable_read_time(); + void set_allocated_read_time(::google::protobuf::Timestamp* value); + void unsafe_arena_set_allocated_read_time(::google::protobuf::Timestamp* value); + ::google::protobuf::Timestamp* unsafe_arena_release_read_time(); + private: - bool _internal_has_structured_query() const; + const ::google::protobuf::Timestamp& _internal_read_time() const; + ::google::protobuf::Timestamp* _internal_mutable_read_time(); public: - void clear_structured_query() ; - const ::google::firestore::v1::StructuredQuery& structured_query() const; - PROTOBUF_NODISCARD ::google::firestore::v1::StructuredQuery* release_structured_query(); - ::google::firestore::v1::StructuredQuery* mutable_structured_query(); - void set_allocated_structured_query(::google::firestore::v1::StructuredQuery* value); - void unsafe_arena_set_allocated_structured_query(::google::firestore::v1::StructuredQuery* value); - ::google::firestore::v1::StructuredQuery* unsafe_arena_release_structured_query(); + // .google.firestore.v1.Document found = 1; + bool has_found() const; + private: + bool _internal_has_found() const; + + public: + void clear_found() ; + const ::google::firestore::v1::Document& found() const; + PROTOBUF_NODISCARD ::google::firestore::v1::Document* release_found(); + ::google::firestore::v1::Document* mutable_found(); + void set_allocated_found(::google::firestore::v1::Document* value); + void unsafe_arena_set_allocated_found(::google::firestore::v1::Document* value); + ::google::firestore::v1::Document* unsafe_arena_release_found(); private: - const ::google::firestore::v1::StructuredQuery& _internal_structured_query() const; - ::google::firestore::v1::StructuredQuery* _internal_mutable_structured_query(); + const ::google::firestore::v1::Document& _internal_found() const; + ::google::firestore::v1::Document* _internal_mutable_found(); public: - void clear_query_type(); - QueryTypeCase query_type_case() const; - // @@protoc_insertion_point(class_scope:google.firestore.v1.Target.QueryTarget) + // string missing = 2; + bool has_missing() const; + void clear_missing() ; + const std::string& missing() const; + template + void set_missing(Arg_&& arg, Args_... args); + std::string* mutable_missing(); + PROTOBUF_NODISCARD std::string* release_missing(); + void set_allocated_missing(std::string* value); + + private: + const std::string& _internal_missing() const; + inline PROTOBUF_ALWAYS_INLINE void _internal_set_missing( + const std::string& value); + std::string* _internal_mutable_missing(); + + public: + void clear_result(); + ResultCase result_case() const; + // @@protoc_insertion_point(class_scope:google.firestore.v1.BatchGetDocumentsResponse) private: class _Internal; - void set_has_structured_query(); + void set_has_found(); + void set_has_missing(); - inline bool has_query_type() const; - inline void clear_has_query_type(); + inline bool has_result() const; + inline void clear_has_result(); friend class ::google::protobuf::internal::TcParser; static const ::google::protobuf::internal::TcParseTable< - 0, 2, 1, - 53, 2> + 1, 4, 2, + 61, 2> _table_; friend class ::google::protobuf::MessageLite; friend class ::google::protobuf::Arena; @@ -5143,13 +5207,16 @@ class Target_QueryTarget final : ::google::protobuf::Arena* arena); inline explicit Impl_(::google::protobuf::internal::InternalVisibility visibility, ::google::protobuf::Arena* arena, const Impl_& from); - ::google::protobuf::internal::ArenaStringPtr parent_; - union QueryTypeUnion { - constexpr QueryTypeUnion() : _constinit_{} {} - ::google::protobuf::internal::ConstantInitialized _constinit_; - ::google::firestore::v1::StructuredQuery* structured_query_; - } query_type_; + ::google::protobuf::internal::HasBits<1> _has_bits_; mutable ::google::protobuf::internal::CachedSize _cached_size_; + ::google::protobuf::internal::ArenaStringPtr transaction_; + ::google::protobuf::Timestamp* read_time_; + union ResultUnion { + constexpr ResultUnion() : _constinit_{} {} + ::google::protobuf::internal::ConstantInitialized _constinit_; + ::google::firestore::v1::Document* found_; + ::google::protobuf::internal::ArenaStringPtr missing_; + } result_; ::uint32_t _oneof_case_[1]; PROTOBUF_TSAN_DECLARE_MEMBER @@ -5158,26 +5225,26 @@ class Target_QueryTarget final : friend struct ::TableStruct_google_2ffirestore_2fv1_2ffirestore_2eproto; };// ------------------------------------------------------------------- -class RunQueryRequest final : - public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:google.firestore.v1.RunQueryRequest) */ { +class WriteRequest final : + public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:google.firestore.v1.WriteRequest) */ { public: - inline RunQueryRequest() : RunQueryRequest(nullptr) {} - ~RunQueryRequest() override; + inline WriteRequest() : WriteRequest(nullptr) {} + ~WriteRequest() override; template - explicit PROTOBUF_CONSTEXPR RunQueryRequest(::google::protobuf::internal::ConstantInitialized); + explicit PROTOBUF_CONSTEXPR WriteRequest(::google::protobuf::internal::ConstantInitialized); - inline RunQueryRequest(const RunQueryRequest& from) - : RunQueryRequest(nullptr, from) {} - RunQueryRequest(RunQueryRequest&& from) noexcept - : RunQueryRequest() { + inline WriteRequest(const WriteRequest& from) + : WriteRequest(nullptr, from) {} + WriteRequest(WriteRequest&& from) noexcept + : WriteRequest() { *this = ::std::move(from); } - inline RunQueryRequest& operator=(const RunQueryRequest& from) { + inline WriteRequest& operator=(const WriteRequest& from) { CopyFrom(from); return *this; } - inline RunQueryRequest& operator=(RunQueryRequest&& from) noexcept { + inline WriteRequest& operator=(WriteRequest&& from) noexcept { if (this == &from) return *this; if (GetArena() == from.GetArena() #ifdef PROTOBUF_FORCE_COPY_IN_MOVE @@ -5209,32 +5276,20 @@ class RunQueryRequest final : static const ::google::protobuf::Reflection* GetReflection() { return default_instance().GetMetadata().reflection; } - static const RunQueryRequest& default_instance() { + static const WriteRequest& default_instance() { return *internal_default_instance(); } - enum QueryTypeCase { - kStructuredQuery = 2, - QUERY_TYPE_NOT_SET = 0, - }; - - enum ConsistencySelectorCase { - kTransaction = 5, - kNewTransaction = 6, - kReadTime = 7, - CONSISTENCY_SELECTOR_NOT_SET = 0, - }; - - static inline const RunQueryRequest* internal_default_instance() { - return reinterpret_cast( - &_RunQueryRequest_default_instance_); + static inline const WriteRequest* internal_default_instance() { + return reinterpret_cast( + &_WriteRequest_default_instance_); } static constexpr int kIndexInFileMessages = - 13; + 20; - friend void swap(RunQueryRequest& a, RunQueryRequest& b) { + friend void swap(WriteRequest& a, WriteRequest& b) { a.Swap(&b); } - inline void Swap(RunQueryRequest* other) { + inline void Swap(WriteRequest* other) { if (other == this) return; #ifdef PROTOBUF_FORCE_COPY_IN_SWAP if (GetArena() != nullptr && @@ -5247,7 +5302,7 @@ class RunQueryRequest final : ::google::protobuf::internal::GenericSwap(this, other); } } - void UnsafeArenaSwap(RunQueryRequest* other) { + void UnsafeArenaSwap(WriteRequest* other) { if (other == this) return; ABSL_DCHECK(GetArena() == other->GetArena()); InternalSwap(other); @@ -5255,14 +5310,14 @@ class RunQueryRequest final : // implements Message ---------------------------------------------- - RunQueryRequest* New(::google::protobuf::Arena* arena = nullptr) const final { - return CreateMaybeMessage(arena); + WriteRequest* New(::google::protobuf::Arena* arena = nullptr) const final { + return CreateMaybeMessage(arena); } using ::google::protobuf::Message::CopyFrom; - void CopyFrom(const RunQueryRequest& from); + void CopyFrom(const WriteRequest& from); using ::google::protobuf::Message::MergeFrom; - void MergeFrom( const RunQueryRequest& from) { - RunQueryRequest::MergeImpl(*this, from); + void MergeFrom( const WriteRequest& from) { + WriteRequest::MergeImpl(*this, from); } private: static void MergeImpl(::google::protobuf::Message& to_msg, const ::google::protobuf::Message& from_msg); @@ -5280,16 +5335,16 @@ class RunQueryRequest final : ::google::protobuf::internal::CachedSize* AccessCachedSize() const final; void SharedCtor(::google::protobuf::Arena* arena); void SharedDtor(); - void InternalSwap(RunQueryRequest* other); + void InternalSwap(WriteRequest* other); private: friend class ::google::protobuf::internal::AnyMetadata; static ::absl::string_view FullMessageName() { - return "google.firestore.v1.RunQueryRequest"; + return "google.firestore.v1.WriteRequest"; } protected: - explicit RunQueryRequest(::google::protobuf::Arena* arena); - RunQueryRequest(::google::protobuf::Arena* arena, const RunQueryRequest& from); + explicit WriteRequest(::google::protobuf::Arena* arena); + WriteRequest(::google::protobuf::Arena* arena, const WriteRequest& from); public: static const ClassData _class_data_; @@ -5299,127 +5354,105 @@ class RunQueryRequest final : // nested types ---------------------------------------------------- + // accessors ------------------------------------------------------- enum : int { - kParentFieldNumber = 1, - kStructuredQueryFieldNumber = 2, - kTransactionFieldNumber = 5, - kNewTransactionFieldNumber = 6, - kReadTimeFieldNumber = 7, + kWritesFieldNumber = 3, + kLabelsFieldNumber = 5, + kDatabaseFieldNumber = 1, + kStreamIdFieldNumber = 2, + kStreamTokenFieldNumber = 4, }; - // string parent = 1; - void clear_parent() ; - const std::string& parent() const; - template - void set_parent(Arg_&& arg, Args_... args); - std::string* mutable_parent(); - PROTOBUF_NODISCARD std::string* release_parent(); - void set_allocated_parent(std::string* value); - + // repeated .google.firestore.v1.Write writes = 3; + int writes_size() const; private: - const std::string& _internal_parent() const; - inline PROTOBUF_ALWAYS_INLINE void _internal_set_parent( - const std::string& value); - std::string* _internal_mutable_parent(); + int _internal_writes_size() const; public: - // .google.firestore.v1.StructuredQuery structured_query = 2; - bool has_structured_query() const; + void clear_writes() ; + ::google::firestore::v1::Write* mutable_writes(int index); + ::google::protobuf::RepeatedPtrField< ::google::firestore::v1::Write >* + mutable_writes(); private: - bool _internal_has_structured_query() const; + const ::google::protobuf::RepeatedPtrField<::google::firestore::v1::Write>& _internal_writes() const; + ::google::protobuf::RepeatedPtrField<::google::firestore::v1::Write>* _internal_mutable_writes(); + public: + const ::google::firestore::v1::Write& writes(int index) const; + ::google::firestore::v1::Write* add_writes(); + const ::google::protobuf::RepeatedPtrField< ::google::firestore::v1::Write >& + writes() const; + // map labels = 5; + int labels_size() const; + private: + int _internal_labels_size() const; public: - void clear_structured_query() ; - const ::google::firestore::v1::StructuredQuery& structured_query() const; - PROTOBUF_NODISCARD ::google::firestore::v1::StructuredQuery* release_structured_query(); - ::google::firestore::v1::StructuredQuery* mutable_structured_query(); - void set_allocated_structured_query(::google::firestore::v1::StructuredQuery* value); - void unsafe_arena_set_allocated_structured_query(::google::firestore::v1::StructuredQuery* value); - ::google::firestore::v1::StructuredQuery* unsafe_arena_release_structured_query(); + void clear_labels() ; + const ::google::protobuf::Map& labels() const; + ::google::protobuf::Map* mutable_labels(); private: - const ::google::firestore::v1::StructuredQuery& _internal_structured_query() const; - ::google::firestore::v1::StructuredQuery* _internal_mutable_structured_query(); + const ::google::protobuf::Map& _internal_labels() const; + ::google::protobuf::Map* _internal_mutable_labels(); public: - // bytes transaction = 5; - bool has_transaction() const; - void clear_transaction() ; - const std::string& transaction() const; + // string database = 1; + void clear_database() ; + const std::string& database() const; template - void set_transaction(Arg_&& arg, Args_... args); - std::string* mutable_transaction(); - PROTOBUF_NODISCARD std::string* release_transaction(); - void set_allocated_transaction(std::string* value); + void set_database(Arg_&& arg, Args_... args); + std::string* mutable_database(); + PROTOBUF_NODISCARD std::string* release_database(); + void set_allocated_database(std::string* value); private: - const std::string& _internal_transaction() const; - inline PROTOBUF_ALWAYS_INLINE void _internal_set_transaction( + const std::string& _internal_database() const; + inline PROTOBUF_ALWAYS_INLINE void _internal_set_database( const std::string& value); - std::string* _internal_mutable_transaction(); - - public: - // .google.firestore.v1.TransactionOptions new_transaction = 6; - bool has_new_transaction() const; - private: - bool _internal_has_new_transaction() const; + std::string* _internal_mutable_database(); public: - void clear_new_transaction() ; - const ::google::firestore::v1::TransactionOptions& new_transaction() const; - PROTOBUF_NODISCARD ::google::firestore::v1::TransactionOptions* release_new_transaction(); - ::google::firestore::v1::TransactionOptions* mutable_new_transaction(); - void set_allocated_new_transaction(::google::firestore::v1::TransactionOptions* value); - void unsafe_arena_set_allocated_new_transaction(::google::firestore::v1::TransactionOptions* value); - ::google::firestore::v1::TransactionOptions* unsafe_arena_release_new_transaction(); - - private: - const ::google::firestore::v1::TransactionOptions& _internal_new_transaction() const; - ::google::firestore::v1::TransactionOptions* _internal_mutable_new_transaction(); + // string stream_id = 2; + void clear_stream_id() ; + const std::string& stream_id() const; + template + void set_stream_id(Arg_&& arg, Args_... args); + std::string* mutable_stream_id(); + PROTOBUF_NODISCARD std::string* release_stream_id(); + void set_allocated_stream_id(std::string* value); - public: - // .google.protobuf.Timestamp read_time = 7; - bool has_read_time() const; private: - bool _internal_has_read_time() const; + const std::string& _internal_stream_id() const; + inline PROTOBUF_ALWAYS_INLINE void _internal_set_stream_id( + const std::string& value); + std::string* _internal_mutable_stream_id(); public: - void clear_read_time() ; - const ::google::protobuf::Timestamp& read_time() const; - PROTOBUF_NODISCARD ::google::protobuf::Timestamp* release_read_time(); - ::google::protobuf::Timestamp* mutable_read_time(); - void set_allocated_read_time(::google::protobuf::Timestamp* value); - void unsafe_arena_set_allocated_read_time(::google::protobuf::Timestamp* value); - ::google::protobuf::Timestamp* unsafe_arena_release_read_time(); + // bytes stream_token = 4; + void clear_stream_token() ; + const std::string& stream_token() const; + template + void set_stream_token(Arg_&& arg, Args_... args); + std::string* mutable_stream_token(); + PROTOBUF_NODISCARD std::string* release_stream_token(); + void set_allocated_stream_token(std::string* value); private: - const ::google::protobuf::Timestamp& _internal_read_time() const; - ::google::protobuf::Timestamp* _internal_mutable_read_time(); + const std::string& _internal_stream_token() const; + inline PROTOBUF_ALWAYS_INLINE void _internal_set_stream_token( + const std::string& value); + std::string* _internal_mutable_stream_token(); public: - void clear_query_type(); - QueryTypeCase query_type_case() const; - void clear_consistency_selector(); - ConsistencySelectorCase consistency_selector_case() const; - // @@protoc_insertion_point(class_scope:google.firestore.v1.RunQueryRequest) + // @@protoc_insertion_point(class_scope:google.firestore.v1.WriteRequest) private: class _Internal; - void set_has_structured_query(); - void set_has_transaction(); - void set_has_new_transaction(); - void set_has_read_time(); - - inline bool has_query_type() const; - inline void clear_has_query_type(); - - inline bool has_consistency_selector() const; - inline void clear_has_consistency_selector(); friend class ::google::protobuf::internal::TcParser; static const ::google::protobuf::internal::TcParseTable< - 0, 5, 3, - 50, 2> + 2, 5, 2, + 64, 2> _table_; friend class ::google::protobuf::MessageLite; friend class ::google::protobuf::Arena; @@ -5435,48 +5468,41 @@ class RunQueryRequest final : ::google::protobuf::Arena* arena); inline explicit Impl_(::google::protobuf::internal::InternalVisibility visibility, ::google::protobuf::Arena* arena, const Impl_& from); - ::google::protobuf::internal::ArenaStringPtr parent_; - union QueryTypeUnion { - constexpr QueryTypeUnion() : _constinit_{} {} - ::google::protobuf::internal::ConstantInitialized _constinit_; - ::google::firestore::v1::StructuredQuery* structured_query_; - } query_type_; - union ConsistencySelectorUnion { - constexpr ConsistencySelectorUnion() : _constinit_{} {} - ::google::protobuf::internal::ConstantInitialized _constinit_; - ::google::protobuf::internal::ArenaStringPtr transaction_; - ::google::firestore::v1::TransactionOptions* new_transaction_; - ::google::protobuf::Timestamp* read_time_; - } consistency_selector_; + ::google::protobuf::RepeatedPtrField< ::google::firestore::v1::Write > writes_; + ::google::protobuf::internal::MapField + labels_; + ::google::protobuf::internal::ArenaStringPtr database_; + ::google::protobuf::internal::ArenaStringPtr stream_id_; + ::google::protobuf::internal::ArenaStringPtr stream_token_; mutable ::google::protobuf::internal::CachedSize _cached_size_; - ::uint32_t _oneof_case_[2]; - PROTOBUF_TSAN_DECLARE_MEMBER }; union { Impl_ _impl_; }; friend struct ::TableStruct_google_2ffirestore_2fv1_2ffirestore_2eproto; };// ------------------------------------------------------------------- -class ListenResponse final : - public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:google.firestore.v1.ListenResponse) */ { +class Target_QueryTarget final : + public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:google.firestore.v1.Target.QueryTarget) */ { public: - inline ListenResponse() : ListenResponse(nullptr) {} - ~ListenResponse() override; + inline Target_QueryTarget() : Target_QueryTarget(nullptr) {} + ~Target_QueryTarget() override; template - explicit PROTOBUF_CONSTEXPR ListenResponse(::google::protobuf::internal::ConstantInitialized); + explicit PROTOBUF_CONSTEXPR Target_QueryTarget(::google::protobuf::internal::ConstantInitialized); - inline ListenResponse(const ListenResponse& from) - : ListenResponse(nullptr, from) {} - ListenResponse(ListenResponse&& from) noexcept - : ListenResponse() { + inline Target_QueryTarget(const Target_QueryTarget& from) + : Target_QueryTarget(nullptr, from) {} + Target_QueryTarget(Target_QueryTarget&& from) noexcept + : Target_QueryTarget() { *this = ::std::move(from); } - inline ListenResponse& operator=(const ListenResponse& from) { + inline Target_QueryTarget& operator=(const Target_QueryTarget& from) { CopyFrom(from); return *this; } - inline ListenResponse& operator=(ListenResponse&& from) noexcept { + inline Target_QueryTarget& operator=(Target_QueryTarget&& from) noexcept { if (this == &from) return *this; if (GetArena() == from.GetArena() #ifdef PROTOBUF_FORCE_COPY_IN_MOVE @@ -5508,29 +5534,25 @@ class ListenResponse final : static const ::google::protobuf::Reflection* GetReflection() { return default_instance().GetMetadata().reflection; } - static const ListenResponse& default_instance() { + static const Target_QueryTarget& default_instance() { return *internal_default_instance(); } - enum ResponseTypeCase { - kTargetChange = 2, - kDocumentChange = 3, - kDocumentDelete = 4, - kDocumentRemove = 6, - kFilter = 5, - RESPONSE_TYPE_NOT_SET = 0, + enum QueryTypeCase { + kStructuredQuery = 2, + QUERY_TYPE_NOT_SET = 0, }; - static inline const ListenResponse* internal_default_instance() { - return reinterpret_cast( - &_ListenResponse_default_instance_); + static inline const Target_QueryTarget* internal_default_instance() { + return reinterpret_cast( + &_Target_QueryTarget_default_instance_); } static constexpr int kIndexInFileMessages = - 22; + 26; - friend void swap(ListenResponse& a, ListenResponse& b) { + friend void swap(Target_QueryTarget& a, Target_QueryTarget& b) { a.Swap(&b); } - inline void Swap(ListenResponse* other) { + inline void Swap(Target_QueryTarget* other) { if (other == this) return; #ifdef PROTOBUF_FORCE_COPY_IN_SWAP if (GetArena() != nullptr && @@ -5543,7 +5565,7 @@ class ListenResponse final : ::google::protobuf::internal::GenericSwap(this, other); } } - void UnsafeArenaSwap(ListenResponse* other) { + void UnsafeArenaSwap(Target_QueryTarget* other) { if (other == this) return; ABSL_DCHECK(GetArena() == other->GetArena()); InternalSwap(other); @@ -5551,14 +5573,14 @@ class ListenResponse final : // implements Message ---------------------------------------------- - ListenResponse* New(::google::protobuf::Arena* arena = nullptr) const final { - return CreateMaybeMessage(arena); + Target_QueryTarget* New(::google::protobuf::Arena* arena = nullptr) const final { + return CreateMaybeMessage(arena); } using ::google::protobuf::Message::CopyFrom; - void CopyFrom(const ListenResponse& from); + void CopyFrom(const Target_QueryTarget& from); using ::google::protobuf::Message::MergeFrom; - void MergeFrom( const ListenResponse& from) { - ListenResponse::MergeImpl(*this, from); + void MergeFrom( const Target_QueryTarget& from) { + Target_QueryTarget::MergeImpl(*this, from); } private: static void MergeImpl(::google::protobuf::Message& to_msg, const ::google::protobuf::Message& from_msg); @@ -5576,16 +5598,16 @@ class ListenResponse final : ::google::protobuf::internal::CachedSize* AccessCachedSize() const final; void SharedCtor(::google::protobuf::Arena* arena); void SharedDtor(); - void InternalSwap(ListenResponse* other); + void InternalSwap(Target_QueryTarget* other); private: friend class ::google::protobuf::internal::AnyMetadata; static ::absl::string_view FullMessageName() { - return "google.firestore.v1.ListenResponse"; + return "google.firestore.v1.Target.QueryTarget"; } protected: - explicit ListenResponse(::google::protobuf::Arena* arena); - ListenResponse(::google::protobuf::Arena* arena, const ListenResponse& from); + explicit Target_QueryTarget(::google::protobuf::Arena* arena); + Target_QueryTarget(::google::protobuf::Arena* arena, const Target_QueryTarget& from); public: static const ClassData _class_data_; @@ -5598,125 +5620,58 @@ class ListenResponse final : // accessors ------------------------------------------------------- enum : int { - kTargetChangeFieldNumber = 2, - kDocumentChangeFieldNumber = 3, - kDocumentDeleteFieldNumber = 4, - kDocumentRemoveFieldNumber = 6, - kFilterFieldNumber = 5, + kParentFieldNumber = 1, + kStructuredQueryFieldNumber = 2, }; - // .google.firestore.v1.TargetChange target_change = 2; - bool has_target_change() const; + // string parent = 1; + void clear_parent() ; + const std::string& parent() const; + template + void set_parent(Arg_&& arg, Args_... args); + std::string* mutable_parent(); + PROTOBUF_NODISCARD std::string* release_parent(); + void set_allocated_parent(std::string* value); + private: - bool _internal_has_target_change() const; + const std::string& _internal_parent() const; + inline PROTOBUF_ALWAYS_INLINE void _internal_set_parent( + const std::string& value); + std::string* _internal_mutable_parent(); public: - void clear_target_change() ; - const ::google::firestore::v1::TargetChange& target_change() const; - PROTOBUF_NODISCARD ::google::firestore::v1::TargetChange* release_target_change(); - ::google::firestore::v1::TargetChange* mutable_target_change(); - void set_allocated_target_change(::google::firestore::v1::TargetChange* value); - void unsafe_arena_set_allocated_target_change(::google::firestore::v1::TargetChange* value); - ::google::firestore::v1::TargetChange* unsafe_arena_release_target_change(); - + // .google.firestore.v1.StructuredQuery structured_query = 2; + bool has_structured_query() const; private: - const ::google::firestore::v1::TargetChange& _internal_target_change() const; - ::google::firestore::v1::TargetChange* _internal_mutable_target_change(); + bool _internal_has_structured_query() const; public: - // .google.firestore.v1.DocumentChange document_change = 3; - bool has_document_change() const; - private: - bool _internal_has_document_change() const; - - public: - void clear_document_change() ; - const ::google::firestore::v1::DocumentChange& document_change() const; - PROTOBUF_NODISCARD ::google::firestore::v1::DocumentChange* release_document_change(); - ::google::firestore::v1::DocumentChange* mutable_document_change(); - void set_allocated_document_change(::google::firestore::v1::DocumentChange* value); - void unsafe_arena_set_allocated_document_change(::google::firestore::v1::DocumentChange* value); - ::google::firestore::v1::DocumentChange* unsafe_arena_release_document_change(); - - private: - const ::google::firestore::v1::DocumentChange& _internal_document_change() const; - ::google::firestore::v1::DocumentChange* _internal_mutable_document_change(); - - public: - // .google.firestore.v1.DocumentDelete document_delete = 4; - bool has_document_delete() const; - private: - bool _internal_has_document_delete() const; - - public: - void clear_document_delete() ; - const ::google::firestore::v1::DocumentDelete& document_delete() const; - PROTOBUF_NODISCARD ::google::firestore::v1::DocumentDelete* release_document_delete(); - ::google::firestore::v1::DocumentDelete* mutable_document_delete(); - void set_allocated_document_delete(::google::firestore::v1::DocumentDelete* value); - void unsafe_arena_set_allocated_document_delete(::google::firestore::v1::DocumentDelete* value); - ::google::firestore::v1::DocumentDelete* unsafe_arena_release_document_delete(); - - private: - const ::google::firestore::v1::DocumentDelete& _internal_document_delete() const; - ::google::firestore::v1::DocumentDelete* _internal_mutable_document_delete(); - - public: - // .google.firestore.v1.DocumentRemove document_remove = 6; - bool has_document_remove() const; - private: - bool _internal_has_document_remove() const; - - public: - void clear_document_remove() ; - const ::google::firestore::v1::DocumentRemove& document_remove() const; - PROTOBUF_NODISCARD ::google::firestore::v1::DocumentRemove* release_document_remove(); - ::google::firestore::v1::DocumentRemove* mutable_document_remove(); - void set_allocated_document_remove(::google::firestore::v1::DocumentRemove* value); - void unsafe_arena_set_allocated_document_remove(::google::firestore::v1::DocumentRemove* value); - ::google::firestore::v1::DocumentRemove* unsafe_arena_release_document_remove(); - - private: - const ::google::firestore::v1::DocumentRemove& _internal_document_remove() const; - ::google::firestore::v1::DocumentRemove* _internal_mutable_document_remove(); - - public: - // .google.firestore.v1.ExistenceFilter filter = 5; - bool has_filter() const; - private: - bool _internal_has_filter() const; - - public: - void clear_filter() ; - const ::google::firestore::v1::ExistenceFilter& filter() const; - PROTOBUF_NODISCARD ::google::firestore::v1::ExistenceFilter* release_filter(); - ::google::firestore::v1::ExistenceFilter* mutable_filter(); - void set_allocated_filter(::google::firestore::v1::ExistenceFilter* value); - void unsafe_arena_set_allocated_filter(::google::firestore::v1::ExistenceFilter* value); - ::google::firestore::v1::ExistenceFilter* unsafe_arena_release_filter(); + void clear_structured_query() ; + const ::google::firestore::v1::StructuredQuery& structured_query() const; + PROTOBUF_NODISCARD ::google::firestore::v1::StructuredQuery* release_structured_query(); + ::google::firestore::v1::StructuredQuery* mutable_structured_query(); + void set_allocated_structured_query(::google::firestore::v1::StructuredQuery* value); + void unsafe_arena_set_allocated_structured_query(::google::firestore::v1::StructuredQuery* value); + ::google::firestore::v1::StructuredQuery* unsafe_arena_release_structured_query(); private: - const ::google::firestore::v1::ExistenceFilter& _internal_filter() const; - ::google::firestore::v1::ExistenceFilter* _internal_mutable_filter(); + const ::google::firestore::v1::StructuredQuery& _internal_structured_query() const; + ::google::firestore::v1::StructuredQuery* _internal_mutable_structured_query(); public: - void clear_response_type(); - ResponseTypeCase response_type_case() const; - // @@protoc_insertion_point(class_scope:google.firestore.v1.ListenResponse) + void clear_query_type(); + QueryTypeCase query_type_case() const; + // @@protoc_insertion_point(class_scope:google.firestore.v1.Target.QueryTarget) private: class _Internal; - void set_has_target_change(); - void set_has_document_change(); - void set_has_document_delete(); - void set_has_document_remove(); - void set_has_filter(); + void set_has_structured_query(); - inline bool has_response_type() const; - inline void clear_has_response_type(); + inline bool has_query_type() const; + inline void clear_has_query_type(); friend class ::google::protobuf::internal::TcParser; static const ::google::protobuf::internal::TcParseTable< - 0, 5, 5, - 0, 2> + 0, 2, 1, + 53, 2> _table_; friend class ::google::protobuf::MessageLite; friend class ::google::protobuf::Arena; @@ -5732,15 +5687,12 @@ class ListenResponse final : ::google::protobuf::Arena* arena); inline explicit Impl_(::google::protobuf::internal::InternalVisibility visibility, ::google::protobuf::Arena* arena, const Impl_& from); - union ResponseTypeUnion { - constexpr ResponseTypeUnion() : _constinit_{} {} + ::google::protobuf::internal::ArenaStringPtr parent_; + union QueryTypeUnion { + constexpr QueryTypeUnion() : _constinit_{} {} ::google::protobuf::internal::ConstantInitialized _constinit_; - ::google::firestore::v1::TargetChange* target_change_; - ::google::firestore::v1::DocumentChange* document_change_; - ::google::firestore::v1::DocumentDelete* document_delete_; - ::google::firestore::v1::DocumentRemove* document_remove_; - ::google::firestore::v1::ExistenceFilter* filter_; - } response_type_; + ::google::firestore::v1::StructuredQuery* structured_query_; + } query_type_; mutable ::google::protobuf::internal::CachedSize _cached_size_; ::uint32_t _oneof_case_[1]; @@ -5750,26 +5702,26 @@ class ListenResponse final : friend struct ::TableStruct_google_2ffirestore_2fv1_2ffirestore_2eproto; };// ------------------------------------------------------------------- -class CommitRequest final : - public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:google.firestore.v1.CommitRequest) */ { +class RunQueryRequest final : + public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:google.firestore.v1.RunQueryRequest) */ { public: - inline CommitRequest() : CommitRequest(nullptr) {} - ~CommitRequest() override; + inline RunQueryRequest() : RunQueryRequest(nullptr) {} + ~RunQueryRequest() override; template - explicit PROTOBUF_CONSTEXPR CommitRequest(::google::protobuf::internal::ConstantInitialized); + explicit PROTOBUF_CONSTEXPR RunQueryRequest(::google::protobuf::internal::ConstantInitialized); - inline CommitRequest(const CommitRequest& from) - : CommitRequest(nullptr, from) {} - CommitRequest(CommitRequest&& from) noexcept - : CommitRequest() { + inline RunQueryRequest(const RunQueryRequest& from) + : RunQueryRequest(nullptr, from) {} + RunQueryRequest(RunQueryRequest&& from) noexcept + : RunQueryRequest() { *this = ::std::move(from); } - inline CommitRequest& operator=(const CommitRequest& from) { + inline RunQueryRequest& operator=(const RunQueryRequest& from) { CopyFrom(from); return *this; } - inline CommitRequest& operator=(CommitRequest&& from) noexcept { + inline RunQueryRequest& operator=(RunQueryRequest&& from) noexcept { if (this == &from) return *this; if (GetArena() == from.GetArena() #ifdef PROTOBUF_FORCE_COPY_IN_MOVE @@ -5801,20 +5753,32 @@ class CommitRequest final : static const ::google::protobuf::Reflection* GetReflection() { return default_instance().GetMetadata().reflection; } - static const CommitRequest& default_instance() { + static const RunQueryRequest& default_instance() { return *internal_default_instance(); } - static inline const CommitRequest* internal_default_instance() { - return reinterpret_cast( - &_CommitRequest_default_instance_); + enum QueryTypeCase { + kStructuredQuery = 2, + QUERY_TYPE_NOT_SET = 0, + }; + + enum ConsistencySelectorCase { + kTransaction = 5, + kNewTransaction = 6, + kReadTime = 7, + CONSISTENCY_SELECTOR_NOT_SET = 0, + }; + + static inline const RunQueryRequest* internal_default_instance() { + return reinterpret_cast( + &_RunQueryRequest_default_instance_); } static constexpr int kIndexInFileMessages = - 10; + 13; - friend void swap(CommitRequest& a, CommitRequest& b) { + friend void swap(RunQueryRequest& a, RunQueryRequest& b) { a.Swap(&b); } - inline void Swap(CommitRequest* other) { + inline void Swap(RunQueryRequest* other) { if (other == this) return; #ifdef PROTOBUF_FORCE_COPY_IN_SWAP if (GetArena() != nullptr && @@ -5827,7 +5791,7 @@ class CommitRequest final : ::google::protobuf::internal::GenericSwap(this, other); } } - void UnsafeArenaSwap(CommitRequest* other) { + void UnsafeArenaSwap(RunQueryRequest* other) { if (other == this) return; ABSL_DCHECK(GetArena() == other->GetArena()); InternalSwap(other); @@ -5835,14 +5799,14 @@ class CommitRequest final : // implements Message ---------------------------------------------- - CommitRequest* New(::google::protobuf::Arena* arena = nullptr) const final { - return CreateMaybeMessage(arena); + RunQueryRequest* New(::google::protobuf::Arena* arena = nullptr) const final { + return CreateMaybeMessage(arena); } using ::google::protobuf::Message::CopyFrom; - void CopyFrom(const CommitRequest& from); + void CopyFrom(const RunQueryRequest& from); using ::google::protobuf::Message::MergeFrom; - void MergeFrom( const CommitRequest& from) { - CommitRequest::MergeImpl(*this, from); + void MergeFrom( const RunQueryRequest& from) { + RunQueryRequest::MergeImpl(*this, from); } private: static void MergeImpl(::google::protobuf::Message& to_msg, const ::google::protobuf::Message& from_msg); @@ -5860,16 +5824,16 @@ class CommitRequest final : ::google::protobuf::internal::CachedSize* AccessCachedSize() const final; void SharedCtor(::google::protobuf::Arena* arena); void SharedDtor(); - void InternalSwap(CommitRequest* other); + void InternalSwap(RunQueryRequest* other); private: friend class ::google::protobuf::internal::AnyMetadata; static ::absl::string_view FullMessageName() { - return "google.firestore.v1.CommitRequest"; + return "google.firestore.v1.RunQueryRequest"; } protected: - explicit CommitRequest(::google::protobuf::Arena* arena); - CommitRequest(::google::protobuf::Arena* arena, const CommitRequest& from); + explicit RunQueryRequest(::google::protobuf::Arena* arena); + RunQueryRequest(::google::protobuf::Arena* arena, const RunQueryRequest& from); public: static const ClassData _class_data_; @@ -5882,45 +5846,49 @@ class CommitRequest final : // accessors ------------------------------------------------------- enum : int { - kWritesFieldNumber = 2, - kDatabaseFieldNumber = 1, - kTransactionFieldNumber = 3, + kParentFieldNumber = 1, + kStructuredQueryFieldNumber = 2, + kTransactionFieldNumber = 5, + kNewTransactionFieldNumber = 6, + kReadTimeFieldNumber = 7, }; - // repeated .google.firestore.v1.Write writes = 2; - int writes_size() const; + // string parent = 1; + void clear_parent() ; + const std::string& parent() const; + template + void set_parent(Arg_&& arg, Args_... args); + std::string* mutable_parent(); + PROTOBUF_NODISCARD std::string* release_parent(); + void set_allocated_parent(std::string* value); + private: - int _internal_writes_size() const; + const std::string& _internal_parent() const; + inline PROTOBUF_ALWAYS_INLINE void _internal_set_parent( + const std::string& value); + std::string* _internal_mutable_parent(); public: - void clear_writes() ; - ::google::firestore::v1::Write* mutable_writes(int index); - ::google::protobuf::RepeatedPtrField< ::google::firestore::v1::Write >* - mutable_writes(); + // .google.firestore.v1.StructuredQuery structured_query = 2; + bool has_structured_query() const; private: - const ::google::protobuf::RepeatedPtrField<::google::firestore::v1::Write>& _internal_writes() const; - ::google::protobuf::RepeatedPtrField<::google::firestore::v1::Write>* _internal_mutable_writes(); + bool _internal_has_structured_query() const; + public: - const ::google::firestore::v1::Write& writes(int index) const; - ::google::firestore::v1::Write* add_writes(); - const ::google::protobuf::RepeatedPtrField< ::google::firestore::v1::Write >& - writes() const; - // string database = 1; - void clear_database() ; - const std::string& database() const; - template - void set_database(Arg_&& arg, Args_... args); - std::string* mutable_database(); - PROTOBUF_NODISCARD std::string* release_database(); - void set_allocated_database(std::string* value); + void clear_structured_query() ; + const ::google::firestore::v1::StructuredQuery& structured_query() const; + PROTOBUF_NODISCARD ::google::firestore::v1::StructuredQuery* release_structured_query(); + ::google::firestore::v1::StructuredQuery* mutable_structured_query(); + void set_allocated_structured_query(::google::firestore::v1::StructuredQuery* value); + void unsafe_arena_set_allocated_structured_query(::google::firestore::v1::StructuredQuery* value); + ::google::firestore::v1::StructuredQuery* unsafe_arena_release_structured_query(); private: - const std::string& _internal_database() const; - inline PROTOBUF_ALWAYS_INLINE void _internal_set_database( - const std::string& value); - std::string* _internal_mutable_database(); + const ::google::firestore::v1::StructuredQuery& _internal_structured_query() const; + ::google::firestore::v1::StructuredQuery* _internal_mutable_structured_query(); public: - // bytes transaction = 3; + // bytes transaction = 5; + bool has_transaction() const; void clear_transaction() ; const std::string& transaction() const; template @@ -5936,16 +5904,68 @@ class CommitRequest final : std::string* _internal_mutable_transaction(); public: - // @@protoc_insertion_point(class_scope:google.firestore.v1.CommitRequest) - private: - class _Internal; + // .google.firestore.v1.TransactionOptions new_transaction = 6; + bool has_new_transaction() const; + private: + bool _internal_has_new_transaction() const; - friend class ::google::protobuf::internal::TcParser; - static const ::google::protobuf::internal::TcParseTable< - 2, 3, 1, - 50, 2> - _table_; - friend class ::google::protobuf::MessageLite; + public: + void clear_new_transaction() ; + const ::google::firestore::v1::TransactionOptions& new_transaction() const; + PROTOBUF_NODISCARD ::google::firestore::v1::TransactionOptions* release_new_transaction(); + ::google::firestore::v1::TransactionOptions* mutable_new_transaction(); + void set_allocated_new_transaction(::google::firestore::v1::TransactionOptions* value); + void unsafe_arena_set_allocated_new_transaction(::google::firestore::v1::TransactionOptions* value); + ::google::firestore::v1::TransactionOptions* unsafe_arena_release_new_transaction(); + + private: + const ::google::firestore::v1::TransactionOptions& _internal_new_transaction() const; + ::google::firestore::v1::TransactionOptions* _internal_mutable_new_transaction(); + + public: + // .google.protobuf.Timestamp read_time = 7; + bool has_read_time() const; + private: + bool _internal_has_read_time() const; + + public: + void clear_read_time() ; + const ::google::protobuf::Timestamp& read_time() const; + PROTOBUF_NODISCARD ::google::protobuf::Timestamp* release_read_time(); + ::google::protobuf::Timestamp* mutable_read_time(); + void set_allocated_read_time(::google::protobuf::Timestamp* value); + void unsafe_arena_set_allocated_read_time(::google::protobuf::Timestamp* value); + ::google::protobuf::Timestamp* unsafe_arena_release_read_time(); + + private: + const ::google::protobuf::Timestamp& _internal_read_time() const; + ::google::protobuf::Timestamp* _internal_mutable_read_time(); + + public: + void clear_query_type(); + QueryTypeCase query_type_case() const; + void clear_consistency_selector(); + ConsistencySelectorCase consistency_selector_case() const; + // @@protoc_insertion_point(class_scope:google.firestore.v1.RunQueryRequest) + private: + class _Internal; + void set_has_structured_query(); + void set_has_transaction(); + void set_has_new_transaction(); + void set_has_read_time(); + + inline bool has_query_type() const; + inline void clear_has_query_type(); + + inline bool has_consistency_selector() const; + inline void clear_has_consistency_selector(); + + friend class ::google::protobuf::internal::TcParser; + static const ::google::protobuf::internal::TcParseTable< + 0, 5, 3, + 50, 2> + _table_; + friend class ::google::protobuf::MessageLite; friend class ::google::protobuf::Arena; template friend class ::google::protobuf::Arena::InternalHelper; @@ -5959,36 +5979,48 @@ class CommitRequest final : ::google::protobuf::Arena* arena); inline explicit Impl_(::google::protobuf::internal::InternalVisibility visibility, ::google::protobuf::Arena* arena, const Impl_& from); - ::google::protobuf::RepeatedPtrField< ::google::firestore::v1::Write > writes_; - ::google::protobuf::internal::ArenaStringPtr database_; - ::google::protobuf::internal::ArenaStringPtr transaction_; + ::google::protobuf::internal::ArenaStringPtr parent_; + union QueryTypeUnion { + constexpr QueryTypeUnion() : _constinit_{} {} + ::google::protobuf::internal::ConstantInitialized _constinit_; + ::google::firestore::v1::StructuredQuery* structured_query_; + } query_type_; + union ConsistencySelectorUnion { + constexpr ConsistencySelectorUnion() : _constinit_{} {} + ::google::protobuf::internal::ConstantInitialized _constinit_; + ::google::protobuf::internal::ArenaStringPtr transaction_; + ::google::firestore::v1::TransactionOptions* new_transaction_; + ::google::protobuf::Timestamp* read_time_; + } consistency_selector_; mutable ::google::protobuf::internal::CachedSize _cached_size_; + ::uint32_t _oneof_case_[2]; + PROTOBUF_TSAN_DECLARE_MEMBER }; union { Impl_ _impl_; }; friend struct ::TableStruct_google_2ffirestore_2fv1_2ffirestore_2eproto; };// ------------------------------------------------------------------- -class Target final : - public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:google.firestore.v1.Target) */ { +class ListenResponse final : + public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:google.firestore.v1.ListenResponse) */ { public: - inline Target() : Target(nullptr) {} - ~Target() override; + inline ListenResponse() : ListenResponse(nullptr) {} + ~ListenResponse() override; template - explicit PROTOBUF_CONSTEXPR Target(::google::protobuf::internal::ConstantInitialized); + explicit PROTOBUF_CONSTEXPR ListenResponse(::google::protobuf::internal::ConstantInitialized); - inline Target(const Target& from) - : Target(nullptr, from) {} - Target(Target&& from) noexcept - : Target() { + inline ListenResponse(const ListenResponse& from) + : ListenResponse(nullptr, from) {} + ListenResponse(ListenResponse&& from) noexcept + : ListenResponse() { *this = ::std::move(from); } - inline Target& operator=(const Target& from) { + inline ListenResponse& operator=(const ListenResponse& from) { CopyFrom(from); return *this; } - inline Target& operator=(Target&& from) noexcept { + inline ListenResponse& operator=(ListenResponse&& from) noexcept { if (this == &from) return *this; if (GetArena() == from.GetArena() #ifdef PROTOBUF_FORCE_COPY_IN_MOVE @@ -6020,32 +6052,29 @@ class Target final : static const ::google::protobuf::Reflection* GetReflection() { return default_instance().GetMetadata().reflection; } - static const Target& default_instance() { + static const ListenResponse& default_instance() { return *internal_default_instance(); } - enum TargetTypeCase { - kQuery = 2, - kDocuments = 3, - TARGET_TYPE_NOT_SET = 0, - }; - - enum ResumeTypeCase { - kResumeToken = 4, - kReadTime = 11, - RESUME_TYPE_NOT_SET = 0, + enum ResponseTypeCase { + kTargetChange = 2, + kDocumentChange = 3, + kDocumentDelete = 4, + kDocumentRemove = 6, + kFilter = 5, + RESPONSE_TYPE_NOT_SET = 0, }; - static inline const Target* internal_default_instance() { - return reinterpret_cast( - &_Target_default_instance_); + static inline const ListenResponse* internal_default_instance() { + return reinterpret_cast( + &_ListenResponse_default_instance_); } static constexpr int kIndexInFileMessages = - 25; + 24; - friend void swap(Target& a, Target& b) { + friend void swap(ListenResponse& a, ListenResponse& b) { a.Swap(&b); } - inline void Swap(Target* other) { + inline void Swap(ListenResponse* other) { if (other == this) return; #ifdef PROTOBUF_FORCE_COPY_IN_SWAP if (GetArena() != nullptr && @@ -6058,7 +6087,7 @@ class Target final : ::google::protobuf::internal::GenericSwap(this, other); } } - void UnsafeArenaSwap(Target* other) { + void UnsafeArenaSwap(ListenResponse* other) { if (other == this) return; ABSL_DCHECK(GetArena() == other->GetArena()); InternalSwap(other); @@ -6066,14 +6095,14 @@ class Target final : // implements Message ---------------------------------------------- - Target* New(::google::protobuf::Arena* arena = nullptr) const final { - return CreateMaybeMessage(arena); + ListenResponse* New(::google::protobuf::Arena* arena = nullptr) const final { + return CreateMaybeMessage(arena); } using ::google::protobuf::Message::CopyFrom; - void CopyFrom(const Target& from); + void CopyFrom(const ListenResponse& from); using ::google::protobuf::Message::MergeFrom; - void MergeFrom( const Target& from) { - Target::MergeImpl(*this, from); + void MergeFrom( const ListenResponse& from) { + ListenResponse::MergeImpl(*this, from); } private: static void MergeImpl(::google::protobuf::Message& to_msg, const ::google::protobuf::Message& from_msg); @@ -6091,16 +6120,16 @@ class Target final : ::google::protobuf::internal::CachedSize* AccessCachedSize() const final; void SharedCtor(::google::protobuf::Arena* arena); void SharedDtor(); - void InternalSwap(Target* other); + void InternalSwap(ListenResponse* other); private: friend class ::google::protobuf::internal::AnyMetadata; static ::absl::string_view FullMessageName() { - return "google.firestore.v1.Target"; + return "google.firestore.v1.ListenResponse"; } protected: - explicit Target(::google::protobuf::Arena* arena); - Target(::google::protobuf::Arena* arena, const Target& from); + explicit ListenResponse(::google::protobuf::Arena* arena); + ListenResponse(::google::protobuf::Arena* arena, const ListenResponse& from); public: static const ClassData _class_data_; @@ -6110,150 +6139,127 @@ class Target final : // nested types ---------------------------------------------------- - using DocumentsTarget = Target_DocumentsTarget; - using QueryTarget = Target_QueryTarget; - // accessors ------------------------------------------------------- enum : int { - kExpectedCountFieldNumber = 12, - kTargetIdFieldNumber = 5, - kOnceFieldNumber = 6, - kQueryFieldNumber = 2, - kDocumentsFieldNumber = 3, - kResumeTokenFieldNumber = 4, - kReadTimeFieldNumber = 11, + kTargetChangeFieldNumber = 2, + kDocumentChangeFieldNumber = 3, + kDocumentDeleteFieldNumber = 4, + kDocumentRemoveFieldNumber = 6, + kFilterFieldNumber = 5, }; - // .google.protobuf.Int32Value expected_count = 12; - bool has_expected_count() const; - void clear_expected_count() ; - const ::google::protobuf::Int32Value& expected_count() const; - PROTOBUF_NODISCARD ::google::protobuf::Int32Value* release_expected_count(); - ::google::protobuf::Int32Value* mutable_expected_count(); - void set_allocated_expected_count(::google::protobuf::Int32Value* value); - void unsafe_arena_set_allocated_expected_count(::google::protobuf::Int32Value* value); - ::google::protobuf::Int32Value* unsafe_arena_release_expected_count(); - + // .google.firestore.v1.TargetChange target_change = 2; + bool has_target_change() const; private: - const ::google::protobuf::Int32Value& _internal_expected_count() const; - ::google::protobuf::Int32Value* _internal_mutable_expected_count(); + bool _internal_has_target_change() const; public: - // int32 target_id = 5; - void clear_target_id() ; - ::int32_t target_id() const; - void set_target_id(::int32_t value); + void clear_target_change() ; + const ::google::firestore::v1::TargetChange& target_change() const; + PROTOBUF_NODISCARD ::google::firestore::v1::TargetChange* release_target_change(); + ::google::firestore::v1::TargetChange* mutable_target_change(); + void set_allocated_target_change(::google::firestore::v1::TargetChange* value); + void unsafe_arena_set_allocated_target_change(::google::firestore::v1::TargetChange* value); + ::google::firestore::v1::TargetChange* unsafe_arena_release_target_change(); private: - ::int32_t _internal_target_id() const; - void _internal_set_target_id(::int32_t value); + const ::google::firestore::v1::TargetChange& _internal_target_change() const; + ::google::firestore::v1::TargetChange* _internal_mutable_target_change(); public: - // bool once = 6; - void clear_once() ; - bool once() const; - void set_once(bool value); - + // .google.firestore.v1.DocumentChange document_change = 3; + bool has_document_change() const; private: - bool _internal_once() const; - void _internal_set_once(bool value); + bool _internal_has_document_change() const; public: - // .google.firestore.v1.Target.QueryTarget query = 2; - bool has_query() const; + void clear_document_change() ; + const ::google::firestore::v1::DocumentChange& document_change() const; + PROTOBUF_NODISCARD ::google::firestore::v1::DocumentChange* release_document_change(); + ::google::firestore::v1::DocumentChange* mutable_document_change(); + void set_allocated_document_change(::google::firestore::v1::DocumentChange* value); + void unsafe_arena_set_allocated_document_change(::google::firestore::v1::DocumentChange* value); + ::google::firestore::v1::DocumentChange* unsafe_arena_release_document_change(); + private: - bool _internal_has_query() const; + const ::google::firestore::v1::DocumentChange& _internal_document_change() const; + ::google::firestore::v1::DocumentChange* _internal_mutable_document_change(); public: - void clear_query() ; - const ::google::firestore::v1::Target_QueryTarget& query() const; - PROTOBUF_NODISCARD ::google::firestore::v1::Target_QueryTarget* release_query(); - ::google::firestore::v1::Target_QueryTarget* mutable_query(); - void set_allocated_query(::google::firestore::v1::Target_QueryTarget* value); - void unsafe_arena_set_allocated_query(::google::firestore::v1::Target_QueryTarget* value); - ::google::firestore::v1::Target_QueryTarget* unsafe_arena_release_query(); - + // .google.firestore.v1.DocumentDelete document_delete = 4; + bool has_document_delete() const; private: - const ::google::firestore::v1::Target_QueryTarget& _internal_query() const; - ::google::firestore::v1::Target_QueryTarget* _internal_mutable_query(); + bool _internal_has_document_delete() const; public: - // .google.firestore.v1.Target.DocumentsTarget documents = 3; - bool has_documents() const; + void clear_document_delete() ; + const ::google::firestore::v1::DocumentDelete& document_delete() const; + PROTOBUF_NODISCARD ::google::firestore::v1::DocumentDelete* release_document_delete(); + ::google::firestore::v1::DocumentDelete* mutable_document_delete(); + void set_allocated_document_delete(::google::firestore::v1::DocumentDelete* value); + void unsafe_arena_set_allocated_document_delete(::google::firestore::v1::DocumentDelete* value); + ::google::firestore::v1::DocumentDelete* unsafe_arena_release_document_delete(); + private: - bool _internal_has_documents() const; + const ::google::firestore::v1::DocumentDelete& _internal_document_delete() const; + ::google::firestore::v1::DocumentDelete* _internal_mutable_document_delete(); public: - void clear_documents() ; - const ::google::firestore::v1::Target_DocumentsTarget& documents() const; - PROTOBUF_NODISCARD ::google::firestore::v1::Target_DocumentsTarget* release_documents(); - ::google::firestore::v1::Target_DocumentsTarget* mutable_documents(); - void set_allocated_documents(::google::firestore::v1::Target_DocumentsTarget* value); - void unsafe_arena_set_allocated_documents(::google::firestore::v1::Target_DocumentsTarget* value); - ::google::firestore::v1::Target_DocumentsTarget* unsafe_arena_release_documents(); - + // .google.firestore.v1.DocumentRemove document_remove = 6; + bool has_document_remove() const; private: - const ::google::firestore::v1::Target_DocumentsTarget& _internal_documents() const; - ::google::firestore::v1::Target_DocumentsTarget* _internal_mutable_documents(); + bool _internal_has_document_remove() const; public: - // bytes resume_token = 4; - bool has_resume_token() const; - void clear_resume_token() ; - const std::string& resume_token() const; - template - void set_resume_token(Arg_&& arg, Args_... args); - std::string* mutable_resume_token(); - PROTOBUF_NODISCARD std::string* release_resume_token(); - void set_allocated_resume_token(std::string* value); + void clear_document_remove() ; + const ::google::firestore::v1::DocumentRemove& document_remove() const; + PROTOBUF_NODISCARD ::google::firestore::v1::DocumentRemove* release_document_remove(); + ::google::firestore::v1::DocumentRemove* mutable_document_remove(); + void set_allocated_document_remove(::google::firestore::v1::DocumentRemove* value); + void unsafe_arena_set_allocated_document_remove(::google::firestore::v1::DocumentRemove* value); + ::google::firestore::v1::DocumentRemove* unsafe_arena_release_document_remove(); private: - const std::string& _internal_resume_token() const; - inline PROTOBUF_ALWAYS_INLINE void _internal_set_resume_token( - const std::string& value); - std::string* _internal_mutable_resume_token(); + const ::google::firestore::v1::DocumentRemove& _internal_document_remove() const; + ::google::firestore::v1::DocumentRemove* _internal_mutable_document_remove(); public: - // .google.protobuf.Timestamp read_time = 11; - bool has_read_time() const; + // .google.firestore.v1.ExistenceFilter filter = 5; + bool has_filter() const; private: - bool _internal_has_read_time() const; + bool _internal_has_filter() const; public: - void clear_read_time() ; - const ::google::protobuf::Timestamp& read_time() const; - PROTOBUF_NODISCARD ::google::protobuf::Timestamp* release_read_time(); - ::google::protobuf::Timestamp* mutable_read_time(); - void set_allocated_read_time(::google::protobuf::Timestamp* value); - void unsafe_arena_set_allocated_read_time(::google::protobuf::Timestamp* value); - ::google::protobuf::Timestamp* unsafe_arena_release_read_time(); + void clear_filter() ; + const ::google::firestore::v1::ExistenceFilter& filter() const; + PROTOBUF_NODISCARD ::google::firestore::v1::ExistenceFilter* release_filter(); + ::google::firestore::v1::ExistenceFilter* mutable_filter(); + void set_allocated_filter(::google::firestore::v1::ExistenceFilter* value); + void unsafe_arena_set_allocated_filter(::google::firestore::v1::ExistenceFilter* value); + ::google::firestore::v1::ExistenceFilter* unsafe_arena_release_filter(); private: - const ::google::protobuf::Timestamp& _internal_read_time() const; - ::google::protobuf::Timestamp* _internal_mutable_read_time(); + const ::google::firestore::v1::ExistenceFilter& _internal_filter() const; + ::google::firestore::v1::ExistenceFilter* _internal_mutable_filter(); public: - void clear_target_type(); - TargetTypeCase target_type_case() const; - void clear_resume_type(); - ResumeTypeCase resume_type_case() const; - // @@protoc_insertion_point(class_scope:google.firestore.v1.Target) + void clear_response_type(); + ResponseTypeCase response_type_case() const; + // @@protoc_insertion_point(class_scope:google.firestore.v1.ListenResponse) private: class _Internal; - void set_has_query(); - void set_has_documents(); - void set_has_resume_token(); - void set_has_read_time(); - - inline bool has_target_type() const; - inline void clear_has_target_type(); + void set_has_target_change(); + void set_has_document_change(); + void set_has_document_delete(); + void set_has_document_remove(); + void set_has_filter(); - inline bool has_resume_type() const; - inline void clear_has_resume_type(); + inline bool has_response_type() const; + inline void clear_has_response_type(); friend class ::google::protobuf::internal::TcParser; static const ::google::protobuf::internal::TcParseTable< - 2, 7, 4, + 0, 5, 5, 0, 2> _table_; friend class ::google::protobuf::MessageLite; @@ -6270,24 +6276,17 @@ class Target final : ::google::protobuf::Arena* arena); inline explicit Impl_(::google::protobuf::internal::InternalVisibility visibility, ::google::protobuf::Arena* arena, const Impl_& from); - ::google::protobuf::internal::HasBits<1> _has_bits_; - mutable ::google::protobuf::internal::CachedSize _cached_size_; - ::google::protobuf::Int32Value* expected_count_; - ::int32_t target_id_; - bool once_; - union TargetTypeUnion { - constexpr TargetTypeUnion() : _constinit_{} {} - ::google::protobuf::internal::ConstantInitialized _constinit_; - ::google::firestore::v1::Target_QueryTarget* query_; - ::google::firestore::v1::Target_DocumentsTarget* documents_; - } target_type_; - union ResumeTypeUnion { - constexpr ResumeTypeUnion() : _constinit_{} {} + union ResponseTypeUnion { + constexpr ResponseTypeUnion() : _constinit_{} {} ::google::protobuf::internal::ConstantInitialized _constinit_; - ::google::protobuf::internal::ArenaStringPtr resume_token_; - ::google::protobuf::Timestamp* read_time_; - } resume_type_; - ::uint32_t _oneof_case_[2]; + ::google::firestore::v1::TargetChange* target_change_; + ::google::firestore::v1::DocumentChange* document_change_; + ::google::firestore::v1::DocumentDelete* document_delete_; + ::google::firestore::v1::DocumentRemove* document_remove_; + ::google::firestore::v1::ExistenceFilter* filter_; + } response_type_; + mutable ::google::protobuf::internal::CachedSize _cached_size_; + ::uint32_t _oneof_case_[1]; PROTOBUF_TSAN_DECLARE_MEMBER }; @@ -6295,26 +6294,26 @@ class Target final : friend struct ::TableStruct_google_2ffirestore_2fv1_2ffirestore_2eproto; };// ------------------------------------------------------------------- -class RunAggregationQueryRequest final : - public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:google.firestore.v1.RunAggregationQueryRequest) */ { +class CommitRequest final : + public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:google.firestore.v1.CommitRequest) */ { public: - inline RunAggregationQueryRequest() : RunAggregationQueryRequest(nullptr) {} - ~RunAggregationQueryRequest() override; + inline CommitRequest() : CommitRequest(nullptr) {} + ~CommitRequest() override; template - explicit PROTOBUF_CONSTEXPR RunAggregationQueryRequest(::google::protobuf::internal::ConstantInitialized); + explicit PROTOBUF_CONSTEXPR CommitRequest(::google::protobuf::internal::ConstantInitialized); - inline RunAggregationQueryRequest(const RunAggregationQueryRequest& from) - : RunAggregationQueryRequest(nullptr, from) {} - RunAggregationQueryRequest(RunAggregationQueryRequest&& from) noexcept - : RunAggregationQueryRequest() { + inline CommitRequest(const CommitRequest& from) + : CommitRequest(nullptr, from) {} + CommitRequest(CommitRequest&& from) noexcept + : CommitRequest() { *this = ::std::move(from); } - inline RunAggregationQueryRequest& operator=(const RunAggregationQueryRequest& from) { + inline CommitRequest& operator=(const CommitRequest& from) { CopyFrom(from); return *this; } - inline RunAggregationQueryRequest& operator=(RunAggregationQueryRequest&& from) noexcept { + inline CommitRequest& operator=(CommitRequest&& from) noexcept { if (this == &from) return *this; if (GetArena() == from.GetArena() #ifdef PROTOBUF_FORCE_COPY_IN_MOVE @@ -6346,32 +6345,20 @@ class RunAggregationQueryRequest final : static const ::google::protobuf::Reflection* GetReflection() { return default_instance().GetMetadata().reflection; } - static const RunAggregationQueryRequest& default_instance() { + static const CommitRequest& default_instance() { return *internal_default_instance(); } - enum QueryTypeCase { - kStructuredAggregationQuery = 2, - QUERY_TYPE_NOT_SET = 0, - }; - - enum ConsistencySelectorCase { - kTransaction = 4, - kNewTransaction = 5, - kReadTime = 6, - CONSISTENCY_SELECTOR_NOT_SET = 0, - }; - - static inline const RunAggregationQueryRequest* internal_default_instance() { - return reinterpret_cast( - &_RunAggregationQueryRequest_default_instance_); + static inline const CommitRequest* internal_default_instance() { + return reinterpret_cast( + &_CommitRequest_default_instance_); } static constexpr int kIndexInFileMessages = - 15; + 10; - friend void swap(RunAggregationQueryRequest& a, RunAggregationQueryRequest& b) { + friend void swap(CommitRequest& a, CommitRequest& b) { a.Swap(&b); } - inline void Swap(RunAggregationQueryRequest* other) { + inline void Swap(CommitRequest* other) { if (other == this) return; #ifdef PROTOBUF_FORCE_COPY_IN_SWAP if (GetArena() != nullptr && @@ -6384,7 +6371,7 @@ class RunAggregationQueryRequest final : ::google::protobuf::internal::GenericSwap(this, other); } } - void UnsafeArenaSwap(RunAggregationQueryRequest* other) { + void UnsafeArenaSwap(CommitRequest* other) { if (other == this) return; ABSL_DCHECK(GetArena() == other->GetArena()); InternalSwap(other); @@ -6392,14 +6379,14 @@ class RunAggregationQueryRequest final : // implements Message ---------------------------------------------- - RunAggregationQueryRequest* New(::google::protobuf::Arena* arena = nullptr) const final { - return CreateMaybeMessage(arena); + CommitRequest* New(::google::protobuf::Arena* arena = nullptr) const final { + return CreateMaybeMessage(arena); } using ::google::protobuf::Message::CopyFrom; - void CopyFrom(const RunAggregationQueryRequest& from); + void CopyFrom(const CommitRequest& from); using ::google::protobuf::Message::MergeFrom; - void MergeFrom( const RunAggregationQueryRequest& from) { - RunAggregationQueryRequest::MergeImpl(*this, from); + void MergeFrom( const CommitRequest& from) { + CommitRequest::MergeImpl(*this, from); } private: static void MergeImpl(::google::protobuf::Message& to_msg, const ::google::protobuf::Message& from_msg); @@ -6417,16 +6404,16 @@ class RunAggregationQueryRequest final : ::google::protobuf::internal::CachedSize* AccessCachedSize() const final; void SharedCtor(::google::protobuf::Arena* arena); void SharedDtor(); - void InternalSwap(RunAggregationQueryRequest* other); + void InternalSwap(CommitRequest* other); private: friend class ::google::protobuf::internal::AnyMetadata; static ::absl::string_view FullMessageName() { - return "google.firestore.v1.RunAggregationQueryRequest"; + return "google.firestore.v1.CommitRequest"; } protected: - explicit RunAggregationQueryRequest(::google::protobuf::Arena* arena); - RunAggregationQueryRequest(::google::protobuf::Arena* arena, const RunAggregationQueryRequest& from); + explicit CommitRequest(::google::protobuf::Arena* arena); + CommitRequest(::google::protobuf::Arena* arena, const CommitRequest& from); public: static const ClassData _class_data_; @@ -6439,49 +6426,45 @@ class RunAggregationQueryRequest final : // accessors ------------------------------------------------------- enum : int { - kParentFieldNumber = 1, - kStructuredAggregationQueryFieldNumber = 2, - kTransactionFieldNumber = 4, - kNewTransactionFieldNumber = 5, - kReadTimeFieldNumber = 6, + kWritesFieldNumber = 2, + kDatabaseFieldNumber = 1, + kTransactionFieldNumber = 3, }; - // string parent = 1; - void clear_parent() ; - const std::string& parent() const; - template - void set_parent(Arg_&& arg, Args_... args); - std::string* mutable_parent(); - PROTOBUF_NODISCARD std::string* release_parent(); - void set_allocated_parent(std::string* value); - + // repeated .google.firestore.v1.Write writes = 2; + int writes_size() const; private: - const std::string& _internal_parent() const; - inline PROTOBUF_ALWAYS_INLINE void _internal_set_parent( - const std::string& value); - std::string* _internal_mutable_parent(); + int _internal_writes_size() const; public: - // .google.firestore.v1.StructuredAggregationQuery structured_aggregation_query = 2; - bool has_structured_aggregation_query() const; + void clear_writes() ; + ::google::firestore::v1::Write* mutable_writes(int index); + ::google::protobuf::RepeatedPtrField< ::google::firestore::v1::Write >* + mutable_writes(); private: - bool _internal_has_structured_aggregation_query() const; - + const ::google::protobuf::RepeatedPtrField<::google::firestore::v1::Write>& _internal_writes() const; + ::google::protobuf::RepeatedPtrField<::google::firestore::v1::Write>* _internal_mutable_writes(); public: - void clear_structured_aggregation_query() ; - const ::google::firestore::v1::StructuredAggregationQuery& structured_aggregation_query() const; - PROTOBUF_NODISCARD ::google::firestore::v1::StructuredAggregationQuery* release_structured_aggregation_query(); - ::google::firestore::v1::StructuredAggregationQuery* mutable_structured_aggregation_query(); - void set_allocated_structured_aggregation_query(::google::firestore::v1::StructuredAggregationQuery* value); - void unsafe_arena_set_allocated_structured_aggregation_query(::google::firestore::v1::StructuredAggregationQuery* value); - ::google::firestore::v1::StructuredAggregationQuery* unsafe_arena_release_structured_aggregation_query(); + const ::google::firestore::v1::Write& writes(int index) const; + ::google::firestore::v1::Write* add_writes(); + const ::google::protobuf::RepeatedPtrField< ::google::firestore::v1::Write >& + writes() const; + // string database = 1; + void clear_database() ; + const std::string& database() const; + template + void set_database(Arg_&& arg, Args_... args); + std::string* mutable_database(); + PROTOBUF_NODISCARD std::string* release_database(); + void set_allocated_database(std::string* value); private: - const ::google::firestore::v1::StructuredAggregationQuery& _internal_structured_aggregation_query() const; - ::google::firestore::v1::StructuredAggregationQuery* _internal_mutable_structured_aggregation_query(); + const std::string& _internal_database() const; + inline PROTOBUF_ALWAYS_INLINE void _internal_set_database( + const std::string& value); + std::string* _internal_mutable_database(); public: - // bytes transaction = 4; - bool has_transaction() const; + // bytes transaction = 3; void clear_transaction() ; const std::string& transaction() const; template @@ -6497,74 +6480,22 @@ class RunAggregationQueryRequest final : std::string* _internal_mutable_transaction(); public: - // .google.firestore.v1.TransactionOptions new_transaction = 5; - bool has_new_transaction() const; - private: - bool _internal_has_new_transaction() const; + // @@protoc_insertion_point(class_scope:google.firestore.v1.CommitRequest) + private: + class _Internal; - public: - void clear_new_transaction() ; - const ::google::firestore::v1::TransactionOptions& new_transaction() const; - PROTOBUF_NODISCARD ::google::firestore::v1::TransactionOptions* release_new_transaction(); - ::google::firestore::v1::TransactionOptions* mutable_new_transaction(); - void set_allocated_new_transaction(::google::firestore::v1::TransactionOptions* value); - void unsafe_arena_set_allocated_new_transaction(::google::firestore::v1::TransactionOptions* value); - ::google::firestore::v1::TransactionOptions* unsafe_arena_release_new_transaction(); - - private: - const ::google::firestore::v1::TransactionOptions& _internal_new_transaction() const; - ::google::firestore::v1::TransactionOptions* _internal_mutable_new_transaction(); - - public: - // .google.protobuf.Timestamp read_time = 6; - bool has_read_time() const; - private: - bool _internal_has_read_time() const; - - public: - void clear_read_time() ; - const ::google::protobuf::Timestamp& read_time() const; - PROTOBUF_NODISCARD ::google::protobuf::Timestamp* release_read_time(); - ::google::protobuf::Timestamp* mutable_read_time(); - void set_allocated_read_time(::google::protobuf::Timestamp* value); - void unsafe_arena_set_allocated_read_time(::google::protobuf::Timestamp* value); - ::google::protobuf::Timestamp* unsafe_arena_release_read_time(); - - private: - const ::google::protobuf::Timestamp& _internal_read_time() const; - ::google::protobuf::Timestamp* _internal_mutable_read_time(); - - public: - void clear_query_type(); - QueryTypeCase query_type_case() const; - void clear_consistency_selector(); - ConsistencySelectorCase consistency_selector_case() const; - // @@protoc_insertion_point(class_scope:google.firestore.v1.RunAggregationQueryRequest) - private: - class _Internal; - void set_has_structured_aggregation_query(); - void set_has_transaction(); - void set_has_new_transaction(); - void set_has_read_time(); - - inline bool has_query_type() const; - inline void clear_has_query_type(); - - inline bool has_consistency_selector() const; - inline void clear_has_consistency_selector(); - - friend class ::google::protobuf::internal::TcParser; - static const ::google::protobuf::internal::TcParseTable< - 0, 5, 3, - 61, 2> - _table_; - friend class ::google::protobuf::MessageLite; - friend class ::google::protobuf::Arena; - template - friend class ::google::protobuf::Arena::InternalHelper; - using InternalArenaConstructable_ = void; - using DestructorSkippable_ = void; - struct Impl_ { + friend class ::google::protobuf::internal::TcParser; + static const ::google::protobuf::internal::TcParseTable< + 2, 3, 1, + 50, 2> + _table_; + friend class ::google::protobuf::MessageLite; + friend class ::google::protobuf::Arena; + template + friend class ::google::protobuf::Arena::InternalHelper; + using InternalArenaConstructable_ = void; + using DestructorSkippable_ = void; + struct Impl_ { inline explicit constexpr Impl_( ::google::protobuf::internal::ConstantInitialized) noexcept; @@ -6572,48 +6503,36 @@ class RunAggregationQueryRequest final : ::google::protobuf::Arena* arena); inline explicit Impl_(::google::protobuf::internal::InternalVisibility visibility, ::google::protobuf::Arena* arena, const Impl_& from); - ::google::protobuf::internal::ArenaStringPtr parent_; - union QueryTypeUnion { - constexpr QueryTypeUnion() : _constinit_{} {} - ::google::protobuf::internal::ConstantInitialized _constinit_; - ::google::firestore::v1::StructuredAggregationQuery* structured_aggregation_query_; - } query_type_; - union ConsistencySelectorUnion { - constexpr ConsistencySelectorUnion() : _constinit_{} {} - ::google::protobuf::internal::ConstantInitialized _constinit_; - ::google::protobuf::internal::ArenaStringPtr transaction_; - ::google::firestore::v1::TransactionOptions* new_transaction_; - ::google::protobuf::Timestamp* read_time_; - } consistency_selector_; + ::google::protobuf::RepeatedPtrField< ::google::firestore::v1::Write > writes_; + ::google::protobuf::internal::ArenaStringPtr database_; + ::google::protobuf::internal::ArenaStringPtr transaction_; mutable ::google::protobuf::internal::CachedSize _cached_size_; - ::uint32_t _oneof_case_[2]; - PROTOBUF_TSAN_DECLARE_MEMBER }; union { Impl_ _impl_; }; friend struct ::TableStruct_google_2ffirestore_2fv1_2ffirestore_2eproto; };// ------------------------------------------------------------------- -class ListenRequest final : - public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:google.firestore.v1.ListenRequest) */ { +class Target final : + public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:google.firestore.v1.Target) */ { public: - inline ListenRequest() : ListenRequest(nullptr) {} - ~ListenRequest() override; + inline Target() : Target(nullptr) {} + ~Target() override; template - explicit PROTOBUF_CONSTEXPR ListenRequest(::google::protobuf::internal::ConstantInitialized); + explicit PROTOBUF_CONSTEXPR Target(::google::protobuf::internal::ConstantInitialized); - inline ListenRequest(const ListenRequest& from) - : ListenRequest(nullptr, from) {} - ListenRequest(ListenRequest&& from) noexcept - : ListenRequest() { + inline Target(const Target& from) + : Target(nullptr, from) {} + Target(Target&& from) noexcept + : Target() { *this = ::std::move(from); } - inline ListenRequest& operator=(const ListenRequest& from) { + inline Target& operator=(const Target& from) { CopyFrom(from); return *this; } - inline ListenRequest& operator=(ListenRequest&& from) noexcept { + inline Target& operator=(Target&& from) noexcept { if (this == &from) return *this; if (GetArena() == from.GetArena() #ifdef PROTOBUF_FORCE_COPY_IN_MOVE @@ -6645,26 +6564,32 @@ class ListenRequest final : static const ::google::protobuf::Reflection* GetReflection() { return default_instance().GetMetadata().reflection; } - static const ListenRequest& default_instance() { + static const Target& default_instance() { return *internal_default_instance(); } - enum TargetChangeCase { - kAddTarget = 2, - kRemoveTarget = 3, - TARGET_CHANGE_NOT_SET = 0, + enum TargetTypeCase { + kQuery = 2, + kDocuments = 3, + TARGET_TYPE_NOT_SET = 0, }; - static inline const ListenRequest* internal_default_instance() { - return reinterpret_cast( - &_ListenRequest_default_instance_); + enum ResumeTypeCase { + kResumeToken = 4, + kReadTime = 11, + RESUME_TYPE_NOT_SET = 0, + }; + + static inline const Target* internal_default_instance() { + return reinterpret_cast( + &_Target_default_instance_); } static constexpr int kIndexInFileMessages = - 21; + 27; - friend void swap(ListenRequest& a, ListenRequest& b) { + friend void swap(Target& a, Target& b) { a.Swap(&b); } - inline void Swap(ListenRequest* other) { + inline void Swap(Target* other) { if (other == this) return; #ifdef PROTOBUF_FORCE_COPY_IN_SWAP if (GetArena() != nullptr && @@ -6677,7 +6602,7 @@ class ListenRequest final : ::google::protobuf::internal::GenericSwap(this, other); } } - void UnsafeArenaSwap(ListenRequest* other) { + void UnsafeArenaSwap(Target* other) { if (other == this) return; ABSL_DCHECK(GetArena() == other->GetArena()); InternalSwap(other); @@ -6685,14 +6610,14 @@ class ListenRequest final : // implements Message ---------------------------------------------- - ListenRequest* New(::google::protobuf::Arena* arena = nullptr) const final { - return CreateMaybeMessage(arena); + Target* New(::google::protobuf::Arena* arena = nullptr) const final { + return CreateMaybeMessage(arena); } using ::google::protobuf::Message::CopyFrom; - void CopyFrom(const ListenRequest& from); + void CopyFrom(const Target& from); using ::google::protobuf::Message::MergeFrom; - void MergeFrom( const ListenRequest& from) { - ListenRequest::MergeImpl(*this, from); + void MergeFrom( const Target& from) { + Target::MergeImpl(*this, from); } private: static void MergeImpl(::google::protobuf::Message& to_msg, const ::google::protobuf::Message& from_msg); @@ -6710,16 +6635,16 @@ class ListenRequest final : ::google::protobuf::internal::CachedSize* AccessCachedSize() const final; void SharedCtor(::google::protobuf::Arena* arena); void SharedDtor(); - void InternalSwap(ListenRequest* other); + void InternalSwap(Target* other); private: friend class ::google::protobuf::internal::AnyMetadata; static ::absl::string_view FullMessageName() { - return "google.firestore.v1.ListenRequest"; + return "google.firestore.v1.Target"; } protected: - explicit ListenRequest(::google::protobuf::Arena* arena); - ListenRequest(::google::protobuf::Arena* arena, const ListenRequest& from); + explicit Target(::google::protobuf::Arena* arena); + Target(::google::protobuf::Arena* arena, const Target& from); public: static const ClassData _class_data_; @@ -6729,90 +6654,709 @@ class ListenRequest final : // nested types ---------------------------------------------------- + using DocumentsTarget = Target_DocumentsTarget; + using QueryTarget = Target_QueryTarget; // accessors ------------------------------------------------------- enum : int { - kLabelsFieldNumber = 4, - kDatabaseFieldNumber = 1, - kAddTargetFieldNumber = 2, - kRemoveTargetFieldNumber = 3, + kExpectedCountFieldNumber = 12, + kTargetIdFieldNumber = 5, + kOnceFieldNumber = 6, + kQueryFieldNumber = 2, + kDocumentsFieldNumber = 3, + kResumeTokenFieldNumber = 4, + kReadTimeFieldNumber = 11, }; - // map labels = 4; - int labels_size() const; + // .google.protobuf.Int32Value expected_count = 12; + bool has_expected_count() const; + void clear_expected_count() ; + const ::google::protobuf::Int32Value& expected_count() const; + PROTOBUF_NODISCARD ::google::protobuf::Int32Value* release_expected_count(); + ::google::protobuf::Int32Value* mutable_expected_count(); + void set_allocated_expected_count(::google::protobuf::Int32Value* value); + void unsafe_arena_set_allocated_expected_count(::google::protobuf::Int32Value* value); + ::google::protobuf::Int32Value* unsafe_arena_release_expected_count(); + private: - int _internal_labels_size() const; + const ::google::protobuf::Int32Value& _internal_expected_count() const; + ::google::protobuf::Int32Value* _internal_mutable_expected_count(); public: - void clear_labels() ; - const ::google::protobuf::Map& labels() const; - ::google::protobuf::Map* mutable_labels(); + // int32 target_id = 5; + void clear_target_id() ; + ::int32_t target_id() const; + void set_target_id(::int32_t value); private: - const ::google::protobuf::Map& _internal_labels() const; - ::google::protobuf::Map* _internal_mutable_labels(); + ::int32_t _internal_target_id() const; + void _internal_set_target_id(::int32_t value); public: - // string database = 1; - void clear_database() ; - const std::string& database() const; - template - void set_database(Arg_&& arg, Args_... args); - std::string* mutable_database(); - PROTOBUF_NODISCARD std::string* release_database(); - void set_allocated_database(std::string* value); + // bool once = 6; + void clear_once() ; + bool once() const; + void set_once(bool value); private: - const std::string& _internal_database() const; - inline PROTOBUF_ALWAYS_INLINE void _internal_set_database( - const std::string& value); - std::string* _internal_mutable_database(); + bool _internal_once() const; + void _internal_set_once(bool value); public: - // .google.firestore.v1.Target add_target = 2; - bool has_add_target() const; + // .google.firestore.v1.Target.QueryTarget query = 2; + bool has_query() const; private: - bool _internal_has_add_target() const; + bool _internal_has_query() const; public: - void clear_add_target() ; - const ::google::firestore::v1::Target& add_target() const; - PROTOBUF_NODISCARD ::google::firestore::v1::Target* release_add_target(); - ::google::firestore::v1::Target* mutable_add_target(); - void set_allocated_add_target(::google::firestore::v1::Target* value); - void unsafe_arena_set_allocated_add_target(::google::firestore::v1::Target* value); - ::google::firestore::v1::Target* unsafe_arena_release_add_target(); + void clear_query() ; + const ::google::firestore::v1::Target_QueryTarget& query() const; + PROTOBUF_NODISCARD ::google::firestore::v1::Target_QueryTarget* release_query(); + ::google::firestore::v1::Target_QueryTarget* mutable_query(); + void set_allocated_query(::google::firestore::v1::Target_QueryTarget* value); + void unsafe_arena_set_allocated_query(::google::firestore::v1::Target_QueryTarget* value); + ::google::firestore::v1::Target_QueryTarget* unsafe_arena_release_query(); private: - const ::google::firestore::v1::Target& _internal_add_target() const; - ::google::firestore::v1::Target* _internal_mutable_add_target(); + const ::google::firestore::v1::Target_QueryTarget& _internal_query() const; + ::google::firestore::v1::Target_QueryTarget* _internal_mutable_query(); public: - // int32 remove_target = 3; - bool has_remove_target() const; - void clear_remove_target() ; - ::int32_t remove_target() const; - void set_remove_target(::int32_t value); - + // .google.firestore.v1.Target.DocumentsTarget documents = 3; + bool has_documents() const; private: - ::int32_t _internal_remove_target() const; - void _internal_set_remove_target(::int32_t value); + bool _internal_has_documents() const; public: - void clear_target_change(); - TargetChangeCase target_change_case() const; - // @@protoc_insertion_point(class_scope:google.firestore.v1.ListenRequest) - private: - class _Internal; - void set_has_add_target(); - void set_has_remove_target(); + void clear_documents() ; + const ::google::firestore::v1::Target_DocumentsTarget& documents() const; + PROTOBUF_NODISCARD ::google::firestore::v1::Target_DocumentsTarget* release_documents(); + ::google::firestore::v1::Target_DocumentsTarget* mutable_documents(); + void set_allocated_documents(::google::firestore::v1::Target_DocumentsTarget* value); + void unsafe_arena_set_allocated_documents(::google::firestore::v1::Target_DocumentsTarget* value); + ::google::firestore::v1::Target_DocumentsTarget* unsafe_arena_release_documents(); - inline bool has_target_change() const; - inline void clear_has_target_change(); + private: + const ::google::firestore::v1::Target_DocumentsTarget& _internal_documents() const; + ::google::firestore::v1::Target_DocumentsTarget* _internal_mutable_documents(); - friend class ::google::protobuf::internal::TcParser; - static const ::google::protobuf::internal::TcParseTable< - 0, 4, 2, + public: + // bytes resume_token = 4; + bool has_resume_token() const; + void clear_resume_token() ; + const std::string& resume_token() const; + template + void set_resume_token(Arg_&& arg, Args_... args); + std::string* mutable_resume_token(); + PROTOBUF_NODISCARD std::string* release_resume_token(); + void set_allocated_resume_token(std::string* value); + + private: + const std::string& _internal_resume_token() const; + inline PROTOBUF_ALWAYS_INLINE void _internal_set_resume_token( + const std::string& value); + std::string* _internal_mutable_resume_token(); + + public: + // .google.protobuf.Timestamp read_time = 11; + bool has_read_time() const; + private: + bool _internal_has_read_time() const; + + public: + void clear_read_time() ; + const ::google::protobuf::Timestamp& read_time() const; + PROTOBUF_NODISCARD ::google::protobuf::Timestamp* release_read_time(); + ::google::protobuf::Timestamp* mutable_read_time(); + void set_allocated_read_time(::google::protobuf::Timestamp* value); + void unsafe_arena_set_allocated_read_time(::google::protobuf::Timestamp* value); + ::google::protobuf::Timestamp* unsafe_arena_release_read_time(); + + private: + const ::google::protobuf::Timestamp& _internal_read_time() const; + ::google::protobuf::Timestamp* _internal_mutable_read_time(); + + public: + void clear_target_type(); + TargetTypeCase target_type_case() const; + void clear_resume_type(); + ResumeTypeCase resume_type_case() const; + // @@protoc_insertion_point(class_scope:google.firestore.v1.Target) + private: + class _Internal; + void set_has_query(); + void set_has_documents(); + void set_has_resume_token(); + void set_has_read_time(); + + inline bool has_target_type() const; + inline void clear_has_target_type(); + + inline bool has_resume_type() const; + inline void clear_has_resume_type(); + + friend class ::google::protobuf::internal::TcParser; + static const ::google::protobuf::internal::TcParseTable< + 2, 7, 4, + 0, 2> + _table_; + friend class ::google::protobuf::MessageLite; + friend class ::google::protobuf::Arena; + template + friend class ::google::protobuf::Arena::InternalHelper; + using InternalArenaConstructable_ = void; + using DestructorSkippable_ = void; + struct Impl_ { + + inline explicit constexpr Impl_( + ::google::protobuf::internal::ConstantInitialized) noexcept; + inline explicit Impl_(::google::protobuf::internal::InternalVisibility visibility, + ::google::protobuf::Arena* arena); + inline explicit Impl_(::google::protobuf::internal::InternalVisibility visibility, + ::google::protobuf::Arena* arena, const Impl_& from); + ::google::protobuf::internal::HasBits<1> _has_bits_; + mutable ::google::protobuf::internal::CachedSize _cached_size_; + ::google::protobuf::Int32Value* expected_count_; + ::int32_t target_id_; + bool once_; + union TargetTypeUnion { + constexpr TargetTypeUnion() : _constinit_{} {} + ::google::protobuf::internal::ConstantInitialized _constinit_; + ::google::firestore::v1::Target_QueryTarget* query_; + ::google::firestore::v1::Target_DocumentsTarget* documents_; + } target_type_; + union ResumeTypeUnion { + constexpr ResumeTypeUnion() : _constinit_{} {} + ::google::protobuf::internal::ConstantInitialized _constinit_; + ::google::protobuf::internal::ArenaStringPtr resume_token_; + ::google::protobuf::Timestamp* read_time_; + } resume_type_; + ::uint32_t _oneof_case_[2]; + + PROTOBUF_TSAN_DECLARE_MEMBER + }; + union { Impl_ _impl_; }; + friend struct ::TableStruct_google_2ffirestore_2fv1_2ffirestore_2eproto; +};// ------------------------------------------------------------------- + +class RunAggregationQueryRequest final : + public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:google.firestore.v1.RunAggregationQueryRequest) */ { + public: + inline RunAggregationQueryRequest() : RunAggregationQueryRequest(nullptr) {} + ~RunAggregationQueryRequest() override; + template + explicit PROTOBUF_CONSTEXPR RunAggregationQueryRequest(::google::protobuf::internal::ConstantInitialized); + + inline RunAggregationQueryRequest(const RunAggregationQueryRequest& from) + : RunAggregationQueryRequest(nullptr, from) {} + RunAggregationQueryRequest(RunAggregationQueryRequest&& from) noexcept + : RunAggregationQueryRequest() { + *this = ::std::move(from); + } + + inline RunAggregationQueryRequest& operator=(const RunAggregationQueryRequest& from) { + CopyFrom(from); + return *this; + } + inline RunAggregationQueryRequest& operator=(RunAggregationQueryRequest&& from) noexcept { + if (this == &from) return *this; + if (GetArena() == from.GetArena() + #ifdef PROTOBUF_FORCE_COPY_IN_MOVE + && GetArena() != nullptr + #endif // !PROTOBUF_FORCE_COPY_IN_MOVE + ) { + InternalSwap(&from); + } else { + CopyFrom(from); + } + return *this; + } + + inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const + ABSL_ATTRIBUTE_LIFETIME_BOUND { + return _internal_metadata_.unknown_fields<::google::protobuf::UnknownFieldSet>(::google::protobuf::UnknownFieldSet::default_instance); + } + inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() + ABSL_ATTRIBUTE_LIFETIME_BOUND { + return _internal_metadata_.mutable_unknown_fields<::google::protobuf::UnknownFieldSet>(); + } + + static const ::google::protobuf::Descriptor* descriptor() { + return GetDescriptor(); + } + static const ::google::protobuf::Descriptor* GetDescriptor() { + return default_instance().GetMetadata().descriptor; + } + static const ::google::protobuf::Reflection* GetReflection() { + return default_instance().GetMetadata().reflection; + } + static const RunAggregationQueryRequest& default_instance() { + return *internal_default_instance(); + } + enum QueryTypeCase { + kStructuredAggregationQuery = 2, + QUERY_TYPE_NOT_SET = 0, + }; + + enum ConsistencySelectorCase { + kTransaction = 4, + kNewTransaction = 5, + kReadTime = 6, + CONSISTENCY_SELECTOR_NOT_SET = 0, + }; + + static inline const RunAggregationQueryRequest* internal_default_instance() { + return reinterpret_cast( + &_RunAggregationQueryRequest_default_instance_); + } + static constexpr int kIndexInFileMessages = + 17; + + friend void swap(RunAggregationQueryRequest& a, RunAggregationQueryRequest& b) { + a.Swap(&b); + } + inline void Swap(RunAggregationQueryRequest* other) { + if (other == this) return; + #ifdef PROTOBUF_FORCE_COPY_IN_SWAP + if (GetArena() != nullptr && + GetArena() == other->GetArena()) { + #else // PROTOBUF_FORCE_COPY_IN_SWAP + if (GetArena() == other->GetArena()) { + #endif // !PROTOBUF_FORCE_COPY_IN_SWAP + InternalSwap(other); + } else { + ::google::protobuf::internal::GenericSwap(this, other); + } + } + void UnsafeArenaSwap(RunAggregationQueryRequest* other) { + if (other == this) return; + ABSL_DCHECK(GetArena() == other->GetArena()); + InternalSwap(other); + } + + // implements Message ---------------------------------------------- + + RunAggregationQueryRequest* New(::google::protobuf::Arena* arena = nullptr) const final { + return CreateMaybeMessage(arena); + } + using ::google::protobuf::Message::CopyFrom; + void CopyFrom(const RunAggregationQueryRequest& from); + using ::google::protobuf::Message::MergeFrom; + void MergeFrom( const RunAggregationQueryRequest& from) { + RunAggregationQueryRequest::MergeImpl(*this, from); + } + private: + static void MergeImpl(::google::protobuf::Message& to_msg, const ::google::protobuf::Message& from_msg); + public: + PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final; + bool IsInitialized() const final; + + ::size_t ByteSizeLong() const final; + const char* _InternalParse(const char* ptr, ::google::protobuf::internal::ParseContext* ctx) final; + ::uint8_t* _InternalSerialize( + ::uint8_t* target, ::google::protobuf::io::EpsCopyOutputStream* stream) const final; + int GetCachedSize() const { return _impl_._cached_size_.Get(); } + + private: + ::google::protobuf::internal::CachedSize* AccessCachedSize() const final; + void SharedCtor(::google::protobuf::Arena* arena); + void SharedDtor(); + void InternalSwap(RunAggregationQueryRequest* other); + + private: + friend class ::google::protobuf::internal::AnyMetadata; + static ::absl::string_view FullMessageName() { + return "google.firestore.v1.RunAggregationQueryRequest"; + } + protected: + explicit RunAggregationQueryRequest(::google::protobuf::Arena* arena); + RunAggregationQueryRequest(::google::protobuf::Arena* arena, const RunAggregationQueryRequest& from); + public: + + static const ClassData _class_data_; + const ::google::protobuf::Message::ClassData*GetClassData() const final; + + ::google::protobuf::Metadata GetMetadata() const final; + + // nested types ---------------------------------------------------- + + // accessors ------------------------------------------------------- + + enum : int { + kParentFieldNumber = 1, + kStructuredAggregationQueryFieldNumber = 2, + kTransactionFieldNumber = 4, + kNewTransactionFieldNumber = 5, + kReadTimeFieldNumber = 6, + }; + // string parent = 1; + void clear_parent() ; + const std::string& parent() const; + template + void set_parent(Arg_&& arg, Args_... args); + std::string* mutable_parent(); + PROTOBUF_NODISCARD std::string* release_parent(); + void set_allocated_parent(std::string* value); + + private: + const std::string& _internal_parent() const; + inline PROTOBUF_ALWAYS_INLINE void _internal_set_parent( + const std::string& value); + std::string* _internal_mutable_parent(); + + public: + // .google.firestore.v1.StructuredAggregationQuery structured_aggregation_query = 2; + bool has_structured_aggregation_query() const; + private: + bool _internal_has_structured_aggregation_query() const; + + public: + void clear_structured_aggregation_query() ; + const ::google::firestore::v1::StructuredAggregationQuery& structured_aggregation_query() const; + PROTOBUF_NODISCARD ::google::firestore::v1::StructuredAggregationQuery* release_structured_aggregation_query(); + ::google::firestore::v1::StructuredAggregationQuery* mutable_structured_aggregation_query(); + void set_allocated_structured_aggregation_query(::google::firestore::v1::StructuredAggregationQuery* value); + void unsafe_arena_set_allocated_structured_aggregation_query(::google::firestore::v1::StructuredAggregationQuery* value); + ::google::firestore::v1::StructuredAggregationQuery* unsafe_arena_release_structured_aggregation_query(); + + private: + const ::google::firestore::v1::StructuredAggregationQuery& _internal_structured_aggregation_query() const; + ::google::firestore::v1::StructuredAggregationQuery* _internal_mutable_structured_aggregation_query(); + + public: + // bytes transaction = 4; + bool has_transaction() const; + void clear_transaction() ; + const std::string& transaction() const; + template + void set_transaction(Arg_&& arg, Args_... args); + std::string* mutable_transaction(); + PROTOBUF_NODISCARD std::string* release_transaction(); + void set_allocated_transaction(std::string* value); + + private: + const std::string& _internal_transaction() const; + inline PROTOBUF_ALWAYS_INLINE void _internal_set_transaction( + const std::string& value); + std::string* _internal_mutable_transaction(); + + public: + // .google.firestore.v1.TransactionOptions new_transaction = 5; + bool has_new_transaction() const; + private: + bool _internal_has_new_transaction() const; + + public: + void clear_new_transaction() ; + const ::google::firestore::v1::TransactionOptions& new_transaction() const; + PROTOBUF_NODISCARD ::google::firestore::v1::TransactionOptions* release_new_transaction(); + ::google::firestore::v1::TransactionOptions* mutable_new_transaction(); + void set_allocated_new_transaction(::google::firestore::v1::TransactionOptions* value); + void unsafe_arena_set_allocated_new_transaction(::google::firestore::v1::TransactionOptions* value); + ::google::firestore::v1::TransactionOptions* unsafe_arena_release_new_transaction(); + + private: + const ::google::firestore::v1::TransactionOptions& _internal_new_transaction() const; + ::google::firestore::v1::TransactionOptions* _internal_mutable_new_transaction(); + + public: + // .google.protobuf.Timestamp read_time = 6; + bool has_read_time() const; + private: + bool _internal_has_read_time() const; + + public: + void clear_read_time() ; + const ::google::protobuf::Timestamp& read_time() const; + PROTOBUF_NODISCARD ::google::protobuf::Timestamp* release_read_time(); + ::google::protobuf::Timestamp* mutable_read_time(); + void set_allocated_read_time(::google::protobuf::Timestamp* value); + void unsafe_arena_set_allocated_read_time(::google::protobuf::Timestamp* value); + ::google::protobuf::Timestamp* unsafe_arena_release_read_time(); + + private: + const ::google::protobuf::Timestamp& _internal_read_time() const; + ::google::protobuf::Timestamp* _internal_mutable_read_time(); + + public: + void clear_query_type(); + QueryTypeCase query_type_case() const; + void clear_consistency_selector(); + ConsistencySelectorCase consistency_selector_case() const; + // @@protoc_insertion_point(class_scope:google.firestore.v1.RunAggregationQueryRequest) + private: + class _Internal; + void set_has_structured_aggregation_query(); + void set_has_transaction(); + void set_has_new_transaction(); + void set_has_read_time(); + + inline bool has_query_type() const; + inline void clear_has_query_type(); + + inline bool has_consistency_selector() const; + inline void clear_has_consistency_selector(); + + friend class ::google::protobuf::internal::TcParser; + static const ::google::protobuf::internal::TcParseTable< + 0, 5, 3, + 61, 2> + _table_; + friend class ::google::protobuf::MessageLite; + friend class ::google::protobuf::Arena; + template + friend class ::google::protobuf::Arena::InternalHelper; + using InternalArenaConstructable_ = void; + using DestructorSkippable_ = void; + struct Impl_ { + + inline explicit constexpr Impl_( + ::google::protobuf::internal::ConstantInitialized) noexcept; + inline explicit Impl_(::google::protobuf::internal::InternalVisibility visibility, + ::google::protobuf::Arena* arena); + inline explicit Impl_(::google::protobuf::internal::InternalVisibility visibility, + ::google::protobuf::Arena* arena, const Impl_& from); + ::google::protobuf::internal::ArenaStringPtr parent_; + union QueryTypeUnion { + constexpr QueryTypeUnion() : _constinit_{} {} + ::google::protobuf::internal::ConstantInitialized _constinit_; + ::google::firestore::v1::StructuredAggregationQuery* structured_aggregation_query_; + } query_type_; + union ConsistencySelectorUnion { + constexpr ConsistencySelectorUnion() : _constinit_{} {} + ::google::protobuf::internal::ConstantInitialized _constinit_; + ::google::protobuf::internal::ArenaStringPtr transaction_; + ::google::firestore::v1::TransactionOptions* new_transaction_; + ::google::protobuf::Timestamp* read_time_; + } consistency_selector_; + mutable ::google::protobuf::internal::CachedSize _cached_size_; + ::uint32_t _oneof_case_[2]; + + PROTOBUF_TSAN_DECLARE_MEMBER + }; + union { Impl_ _impl_; }; + friend struct ::TableStruct_google_2ffirestore_2fv1_2ffirestore_2eproto; +};// ------------------------------------------------------------------- + +class ListenRequest final : + public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:google.firestore.v1.ListenRequest) */ { + public: + inline ListenRequest() : ListenRequest(nullptr) {} + ~ListenRequest() override; + template + explicit PROTOBUF_CONSTEXPR ListenRequest(::google::protobuf::internal::ConstantInitialized); + + inline ListenRequest(const ListenRequest& from) + : ListenRequest(nullptr, from) {} + ListenRequest(ListenRequest&& from) noexcept + : ListenRequest() { + *this = ::std::move(from); + } + + inline ListenRequest& operator=(const ListenRequest& from) { + CopyFrom(from); + return *this; + } + inline ListenRequest& operator=(ListenRequest&& from) noexcept { + if (this == &from) return *this; + if (GetArena() == from.GetArena() + #ifdef PROTOBUF_FORCE_COPY_IN_MOVE + && GetArena() != nullptr + #endif // !PROTOBUF_FORCE_COPY_IN_MOVE + ) { + InternalSwap(&from); + } else { + CopyFrom(from); + } + return *this; + } + + inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const + ABSL_ATTRIBUTE_LIFETIME_BOUND { + return _internal_metadata_.unknown_fields<::google::protobuf::UnknownFieldSet>(::google::protobuf::UnknownFieldSet::default_instance); + } + inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() + ABSL_ATTRIBUTE_LIFETIME_BOUND { + return _internal_metadata_.mutable_unknown_fields<::google::protobuf::UnknownFieldSet>(); + } + + static const ::google::protobuf::Descriptor* descriptor() { + return GetDescriptor(); + } + static const ::google::protobuf::Descriptor* GetDescriptor() { + return default_instance().GetMetadata().descriptor; + } + static const ::google::protobuf::Reflection* GetReflection() { + return default_instance().GetMetadata().reflection; + } + static const ListenRequest& default_instance() { + return *internal_default_instance(); + } + enum TargetChangeCase { + kAddTarget = 2, + kRemoveTarget = 3, + TARGET_CHANGE_NOT_SET = 0, + }; + + static inline const ListenRequest* internal_default_instance() { + return reinterpret_cast( + &_ListenRequest_default_instance_); + } + static constexpr int kIndexInFileMessages = + 23; + + friend void swap(ListenRequest& a, ListenRequest& b) { + a.Swap(&b); + } + inline void Swap(ListenRequest* other) { + if (other == this) return; + #ifdef PROTOBUF_FORCE_COPY_IN_SWAP + if (GetArena() != nullptr && + GetArena() == other->GetArena()) { + #else // PROTOBUF_FORCE_COPY_IN_SWAP + if (GetArena() == other->GetArena()) { + #endif // !PROTOBUF_FORCE_COPY_IN_SWAP + InternalSwap(other); + } else { + ::google::protobuf::internal::GenericSwap(this, other); + } + } + void UnsafeArenaSwap(ListenRequest* other) { + if (other == this) return; + ABSL_DCHECK(GetArena() == other->GetArena()); + InternalSwap(other); + } + + // implements Message ---------------------------------------------- + + ListenRequest* New(::google::protobuf::Arena* arena = nullptr) const final { + return CreateMaybeMessage(arena); + } + using ::google::protobuf::Message::CopyFrom; + void CopyFrom(const ListenRequest& from); + using ::google::protobuf::Message::MergeFrom; + void MergeFrom( const ListenRequest& from) { + ListenRequest::MergeImpl(*this, from); + } + private: + static void MergeImpl(::google::protobuf::Message& to_msg, const ::google::protobuf::Message& from_msg); + public: + PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final; + bool IsInitialized() const final; + + ::size_t ByteSizeLong() const final; + const char* _InternalParse(const char* ptr, ::google::protobuf::internal::ParseContext* ctx) final; + ::uint8_t* _InternalSerialize( + ::uint8_t* target, ::google::protobuf::io::EpsCopyOutputStream* stream) const final; + int GetCachedSize() const { return _impl_._cached_size_.Get(); } + + private: + ::google::protobuf::internal::CachedSize* AccessCachedSize() const final; + void SharedCtor(::google::protobuf::Arena* arena); + void SharedDtor(); + void InternalSwap(ListenRequest* other); + + private: + friend class ::google::protobuf::internal::AnyMetadata; + static ::absl::string_view FullMessageName() { + return "google.firestore.v1.ListenRequest"; + } + protected: + explicit ListenRequest(::google::protobuf::Arena* arena); + ListenRequest(::google::protobuf::Arena* arena, const ListenRequest& from); + public: + + static const ClassData _class_data_; + const ::google::protobuf::Message::ClassData*GetClassData() const final; + + ::google::protobuf::Metadata GetMetadata() const final; + + // nested types ---------------------------------------------------- + + + // accessors ------------------------------------------------------- + + enum : int { + kLabelsFieldNumber = 4, + kDatabaseFieldNumber = 1, + kAddTargetFieldNumber = 2, + kRemoveTargetFieldNumber = 3, + }; + // map labels = 4; + int labels_size() const; + private: + int _internal_labels_size() const; + + public: + void clear_labels() ; + const ::google::protobuf::Map& labels() const; + ::google::protobuf::Map* mutable_labels(); + + private: + const ::google::protobuf::Map& _internal_labels() const; + ::google::protobuf::Map* _internal_mutable_labels(); + + public: + // string database = 1; + void clear_database() ; + const std::string& database() const; + template + void set_database(Arg_&& arg, Args_... args); + std::string* mutable_database(); + PROTOBUF_NODISCARD std::string* release_database(); + void set_allocated_database(std::string* value); + + private: + const std::string& _internal_database() const; + inline PROTOBUF_ALWAYS_INLINE void _internal_set_database( + const std::string& value); + std::string* _internal_mutable_database(); + + public: + // .google.firestore.v1.Target add_target = 2; + bool has_add_target() const; + private: + bool _internal_has_add_target() const; + + public: + void clear_add_target() ; + const ::google::firestore::v1::Target& add_target() const; + PROTOBUF_NODISCARD ::google::firestore::v1::Target* release_add_target(); + ::google::firestore::v1::Target* mutable_add_target(); + void set_allocated_add_target(::google::firestore::v1::Target* value); + void unsafe_arena_set_allocated_add_target(::google::firestore::v1::Target* value); + ::google::firestore::v1::Target* unsafe_arena_release_add_target(); + + private: + const ::google::firestore::v1::Target& _internal_add_target() const; + ::google::firestore::v1::Target* _internal_mutable_add_target(); + + public: + // int32 remove_target = 3; + bool has_remove_target() const; + void clear_remove_target() ; + ::int32_t remove_target() const; + void set_remove_target(::int32_t value); + + private: + ::int32_t _internal_remove_target() const; + void _internal_set_remove_target(::int32_t value); + + public: + void clear_target_change(); + TargetChangeCase target_change_case() const; + // @@protoc_insertion_point(class_scope:google.firestore.v1.ListenRequest) + private: + class _Internal; + void set_has_add_target(); + void set_has_remove_target(); + + inline bool has_target_change() const; + inline void clear_has_target_change(); + + friend class ::google::protobuf::internal::TcParser; + static const ::google::protobuf::internal::TcParseTable< + 0, 4, 2, 56, 2> _table_; friend class ::google::protobuf::MessageLite; @@ -7669,320 +8213,779 @@ inline bool ListDocumentsRequest::_internal_show_missing() const { PROTOBUF_TSAN_READ(&_impl_._tsan_detect_race); return _impl_.show_missing_; } -inline void ListDocumentsRequest::_internal_set_show_missing(bool value) { +inline void ListDocumentsRequest::_internal_set_show_missing(bool value) { + PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); + ; + _impl_.show_missing_ = value; +} + +inline bool ListDocumentsRequest::has_consistency_selector() const { + return consistency_selector_case() != CONSISTENCY_SELECTOR_NOT_SET; +} +inline void ListDocumentsRequest::clear_has_consistency_selector() { + _impl_._oneof_case_[0] = CONSISTENCY_SELECTOR_NOT_SET; +} +inline ListDocumentsRequest::ConsistencySelectorCase ListDocumentsRequest::consistency_selector_case() const { + return ListDocumentsRequest::ConsistencySelectorCase(_impl_._oneof_case_[0]); +} +// ------------------------------------------------------------------- + +// ListDocumentsResponse + +// repeated .google.firestore.v1.Document documents = 1; +inline int ListDocumentsResponse::_internal_documents_size() const { + return _internal_documents().size(); +} +inline int ListDocumentsResponse::documents_size() const { + return _internal_documents_size(); +} +inline ::google::firestore::v1::Document* ListDocumentsResponse::mutable_documents(int index) + ABSL_ATTRIBUTE_LIFETIME_BOUND { + // @@protoc_insertion_point(field_mutable:google.firestore.v1.ListDocumentsResponse.documents) + return _internal_mutable_documents()->Mutable(index); +} +inline ::google::protobuf::RepeatedPtrField<::google::firestore::v1::Document>* ListDocumentsResponse::mutable_documents() + ABSL_ATTRIBUTE_LIFETIME_BOUND { + // @@protoc_insertion_point(field_mutable_list:google.firestore.v1.ListDocumentsResponse.documents) + PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); + return _internal_mutable_documents(); +} +inline const ::google::firestore::v1::Document& ListDocumentsResponse::documents(int index) const + ABSL_ATTRIBUTE_LIFETIME_BOUND { + // @@protoc_insertion_point(field_get:google.firestore.v1.ListDocumentsResponse.documents) + return _internal_documents().Get(index); +} +inline ::google::firestore::v1::Document* ListDocumentsResponse::add_documents() ABSL_ATTRIBUTE_LIFETIME_BOUND { + PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); + ::google::firestore::v1::Document* _add = _internal_mutable_documents()->Add(); + // @@protoc_insertion_point(field_add:google.firestore.v1.ListDocumentsResponse.documents) + return _add; +} +inline const ::google::protobuf::RepeatedPtrField<::google::firestore::v1::Document>& ListDocumentsResponse::documents() const + ABSL_ATTRIBUTE_LIFETIME_BOUND { + // @@protoc_insertion_point(field_list:google.firestore.v1.ListDocumentsResponse.documents) + return _internal_documents(); +} +inline const ::google::protobuf::RepeatedPtrField<::google::firestore::v1::Document>& +ListDocumentsResponse::_internal_documents() const { + PROTOBUF_TSAN_READ(&_impl_._tsan_detect_race); + return _impl_.documents_; +} +inline ::google::protobuf::RepeatedPtrField<::google::firestore::v1::Document>* +ListDocumentsResponse::_internal_mutable_documents() { + PROTOBUF_TSAN_READ(&_impl_._tsan_detect_race); + return &_impl_.documents_; +} + +// string next_page_token = 2; +inline void ListDocumentsResponse::clear_next_page_token() { + PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); + _impl_.next_page_token_.ClearToEmpty(); +} +inline const std::string& ListDocumentsResponse::next_page_token() const + ABSL_ATTRIBUTE_LIFETIME_BOUND { + // @@protoc_insertion_point(field_get:google.firestore.v1.ListDocumentsResponse.next_page_token) + return _internal_next_page_token(); +} +template +inline PROTOBUF_ALWAYS_INLINE void ListDocumentsResponse::set_next_page_token(Arg_&& arg, + Args_... args) { + PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); + ; + _impl_.next_page_token_.Set(static_cast(arg), args..., GetArena()); + // @@protoc_insertion_point(field_set:google.firestore.v1.ListDocumentsResponse.next_page_token) +} +inline std::string* ListDocumentsResponse::mutable_next_page_token() ABSL_ATTRIBUTE_LIFETIME_BOUND { + std::string* _s = _internal_mutable_next_page_token(); + // @@protoc_insertion_point(field_mutable:google.firestore.v1.ListDocumentsResponse.next_page_token) + return _s; +} +inline const std::string& ListDocumentsResponse::_internal_next_page_token() const { + PROTOBUF_TSAN_READ(&_impl_._tsan_detect_race); + return _impl_.next_page_token_.Get(); +} +inline void ListDocumentsResponse::_internal_set_next_page_token(const std::string& value) { + PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); + ; + _impl_.next_page_token_.Set(value, GetArena()); +} +inline std::string* ListDocumentsResponse::_internal_mutable_next_page_token() { + PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); + ; + return _impl_.next_page_token_.Mutable( GetArena()); +} +inline std::string* ListDocumentsResponse::release_next_page_token() { + PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); + // @@protoc_insertion_point(field_release:google.firestore.v1.ListDocumentsResponse.next_page_token) + return _impl_.next_page_token_.Release(); +} +inline void ListDocumentsResponse::set_allocated_next_page_token(std::string* value) { + PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); + _impl_.next_page_token_.SetAllocated(value, GetArena()); + #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING + if (_impl_.next_page_token_.IsDefault()) { + _impl_.next_page_token_.Set("", GetArena()); + } + #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING + // @@protoc_insertion_point(field_set_allocated:google.firestore.v1.ListDocumentsResponse.next_page_token) +} + +// ------------------------------------------------------------------- + +// CreateDocumentRequest + +// string parent = 1; +inline void CreateDocumentRequest::clear_parent() { + PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); + _impl_.parent_.ClearToEmpty(); +} +inline const std::string& CreateDocumentRequest::parent() const + ABSL_ATTRIBUTE_LIFETIME_BOUND { + // @@protoc_insertion_point(field_get:google.firestore.v1.CreateDocumentRequest.parent) + return _internal_parent(); +} +template +inline PROTOBUF_ALWAYS_INLINE void CreateDocumentRequest::set_parent(Arg_&& arg, + Args_... args) { + PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); + ; + _impl_.parent_.Set(static_cast(arg), args..., GetArena()); + // @@protoc_insertion_point(field_set:google.firestore.v1.CreateDocumentRequest.parent) +} +inline std::string* CreateDocumentRequest::mutable_parent() ABSL_ATTRIBUTE_LIFETIME_BOUND { + std::string* _s = _internal_mutable_parent(); + // @@protoc_insertion_point(field_mutable:google.firestore.v1.CreateDocumentRequest.parent) + return _s; +} +inline const std::string& CreateDocumentRequest::_internal_parent() const { + PROTOBUF_TSAN_READ(&_impl_._tsan_detect_race); + return _impl_.parent_.Get(); +} +inline void CreateDocumentRequest::_internal_set_parent(const std::string& value) { + PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); + ; + _impl_.parent_.Set(value, GetArena()); +} +inline std::string* CreateDocumentRequest::_internal_mutable_parent() { + PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); + ; + return _impl_.parent_.Mutable( GetArena()); +} +inline std::string* CreateDocumentRequest::release_parent() { + PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); + // @@protoc_insertion_point(field_release:google.firestore.v1.CreateDocumentRequest.parent) + return _impl_.parent_.Release(); +} +inline void CreateDocumentRequest::set_allocated_parent(std::string* value) { + PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); + _impl_.parent_.SetAllocated(value, GetArena()); + #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING + if (_impl_.parent_.IsDefault()) { + _impl_.parent_.Set("", GetArena()); + } + #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING + // @@protoc_insertion_point(field_set_allocated:google.firestore.v1.CreateDocumentRequest.parent) +} + +// string collection_id = 2; +inline void CreateDocumentRequest::clear_collection_id() { + PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); + _impl_.collection_id_.ClearToEmpty(); +} +inline const std::string& CreateDocumentRequest::collection_id() const + ABSL_ATTRIBUTE_LIFETIME_BOUND { + // @@protoc_insertion_point(field_get:google.firestore.v1.CreateDocumentRequest.collection_id) + return _internal_collection_id(); +} +template +inline PROTOBUF_ALWAYS_INLINE void CreateDocumentRequest::set_collection_id(Arg_&& arg, + Args_... args) { + PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); + ; + _impl_.collection_id_.Set(static_cast(arg), args..., GetArena()); + // @@protoc_insertion_point(field_set:google.firestore.v1.CreateDocumentRequest.collection_id) +} +inline std::string* CreateDocumentRequest::mutable_collection_id() ABSL_ATTRIBUTE_LIFETIME_BOUND { + std::string* _s = _internal_mutable_collection_id(); + // @@protoc_insertion_point(field_mutable:google.firestore.v1.CreateDocumentRequest.collection_id) + return _s; +} +inline const std::string& CreateDocumentRequest::_internal_collection_id() const { + PROTOBUF_TSAN_READ(&_impl_._tsan_detect_race); + return _impl_.collection_id_.Get(); +} +inline void CreateDocumentRequest::_internal_set_collection_id(const std::string& value) { + PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); + ; + _impl_.collection_id_.Set(value, GetArena()); +} +inline std::string* CreateDocumentRequest::_internal_mutable_collection_id() { + PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); + ; + return _impl_.collection_id_.Mutable( GetArena()); +} +inline std::string* CreateDocumentRequest::release_collection_id() { + PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); + // @@protoc_insertion_point(field_release:google.firestore.v1.CreateDocumentRequest.collection_id) + return _impl_.collection_id_.Release(); +} +inline void CreateDocumentRequest::set_allocated_collection_id(std::string* value) { + PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); + _impl_.collection_id_.SetAllocated(value, GetArena()); + #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING + if (_impl_.collection_id_.IsDefault()) { + _impl_.collection_id_.Set("", GetArena()); + } + #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING + // @@protoc_insertion_point(field_set_allocated:google.firestore.v1.CreateDocumentRequest.collection_id) +} + +// string document_id = 3; +inline void CreateDocumentRequest::clear_document_id() { + PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); + _impl_.document_id_.ClearToEmpty(); +} +inline const std::string& CreateDocumentRequest::document_id() const + ABSL_ATTRIBUTE_LIFETIME_BOUND { + // @@protoc_insertion_point(field_get:google.firestore.v1.CreateDocumentRequest.document_id) + return _internal_document_id(); +} +template +inline PROTOBUF_ALWAYS_INLINE void CreateDocumentRequest::set_document_id(Arg_&& arg, + Args_... args) { + PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); + ; + _impl_.document_id_.Set(static_cast(arg), args..., GetArena()); + // @@protoc_insertion_point(field_set:google.firestore.v1.CreateDocumentRequest.document_id) +} +inline std::string* CreateDocumentRequest::mutable_document_id() ABSL_ATTRIBUTE_LIFETIME_BOUND { + std::string* _s = _internal_mutable_document_id(); + // @@protoc_insertion_point(field_mutable:google.firestore.v1.CreateDocumentRequest.document_id) + return _s; +} +inline const std::string& CreateDocumentRequest::_internal_document_id() const { + PROTOBUF_TSAN_READ(&_impl_._tsan_detect_race); + return _impl_.document_id_.Get(); +} +inline void CreateDocumentRequest::_internal_set_document_id(const std::string& value) { PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); ; - _impl_.show_missing_ = value; + _impl_.document_id_.Set(value, GetArena()); } - -inline bool ListDocumentsRequest::has_consistency_selector() const { - return consistency_selector_case() != CONSISTENCY_SELECTOR_NOT_SET; +inline std::string* CreateDocumentRequest::_internal_mutable_document_id() { + PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); + ; + return _impl_.document_id_.Mutable( GetArena()); } -inline void ListDocumentsRequest::clear_has_consistency_selector() { - _impl_._oneof_case_[0] = CONSISTENCY_SELECTOR_NOT_SET; +inline std::string* CreateDocumentRequest::release_document_id() { + PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); + // @@protoc_insertion_point(field_release:google.firestore.v1.CreateDocumentRequest.document_id) + return _impl_.document_id_.Release(); } -inline ListDocumentsRequest::ConsistencySelectorCase ListDocumentsRequest::consistency_selector_case() const { - return ListDocumentsRequest::ConsistencySelectorCase(_impl_._oneof_case_[0]); +inline void CreateDocumentRequest::set_allocated_document_id(std::string* value) { + PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); + _impl_.document_id_.SetAllocated(value, GetArena()); + #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING + if (_impl_.document_id_.IsDefault()) { + _impl_.document_id_.Set("", GetArena()); + } + #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING + // @@protoc_insertion_point(field_set_allocated:google.firestore.v1.CreateDocumentRequest.document_id) } -// ------------------------------------------------------------------- - -// ListDocumentsResponse -// repeated .google.firestore.v1.Document documents = 1; -inline int ListDocumentsResponse::_internal_documents_size() const { - return _internal_documents().size(); +// .google.firestore.v1.Document document = 4; +inline bool CreateDocumentRequest::has_document() const { + bool value = (_impl_._has_bits_[0] & 0x00000001u) != 0; + PROTOBUF_ASSUME(!value || _impl_.document_ != nullptr); + return value; } -inline int ListDocumentsResponse::documents_size() const { - return _internal_documents_size(); +inline const ::google::firestore::v1::Document& CreateDocumentRequest::_internal_document() const { + PROTOBUF_TSAN_READ(&_impl_._tsan_detect_race); + const ::google::firestore::v1::Document* p = _impl_.document_; + return p != nullptr ? *p : reinterpret_cast(::google::firestore::v1::_Document_default_instance_); } -inline ::google::firestore::v1::Document* ListDocumentsResponse::mutable_documents(int index) - ABSL_ATTRIBUTE_LIFETIME_BOUND { - // @@protoc_insertion_point(field_mutable:google.firestore.v1.ListDocumentsResponse.documents) - return _internal_mutable_documents()->Mutable(index); +inline const ::google::firestore::v1::Document& CreateDocumentRequest::document() const ABSL_ATTRIBUTE_LIFETIME_BOUND { + // @@protoc_insertion_point(field_get:google.firestore.v1.CreateDocumentRequest.document) + return _internal_document(); } -inline ::google::protobuf::RepeatedPtrField<::google::firestore::v1::Document>* ListDocumentsResponse::mutable_documents() - ABSL_ATTRIBUTE_LIFETIME_BOUND { - // @@protoc_insertion_point(field_mutable_list:google.firestore.v1.ListDocumentsResponse.documents) +inline void CreateDocumentRequest::unsafe_arena_set_allocated_document(::google::firestore::v1::Document* value) { PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); - return _internal_mutable_documents(); -} -inline const ::google::firestore::v1::Document& ListDocumentsResponse::documents(int index) const - ABSL_ATTRIBUTE_LIFETIME_BOUND { - // @@protoc_insertion_point(field_get:google.firestore.v1.ListDocumentsResponse.documents) - return _internal_documents().Get(index); + if (GetArena() == nullptr) { + delete reinterpret_cast<::google::protobuf::MessageLite*>(_impl_.document_); + } + _impl_.document_ = reinterpret_cast<::google::firestore::v1::Document*>(value); + if (value != nullptr) { + _impl_._has_bits_[0] |= 0x00000001u; + } else { + _impl_._has_bits_[0] &= ~0x00000001u; + } + // @@protoc_insertion_point(field_unsafe_arena_set_allocated:google.firestore.v1.CreateDocumentRequest.document) } -inline ::google::firestore::v1::Document* ListDocumentsResponse::add_documents() ABSL_ATTRIBUTE_LIFETIME_BOUND { +inline ::google::firestore::v1::Document* CreateDocumentRequest::release_document() { PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); - ::google::firestore::v1::Document* _add = _internal_mutable_documents()->Add(); - // @@protoc_insertion_point(field_add:google.firestore.v1.ListDocumentsResponse.documents) - return _add; -} -inline const ::google::protobuf::RepeatedPtrField<::google::firestore::v1::Document>& ListDocumentsResponse::documents() const - ABSL_ATTRIBUTE_LIFETIME_BOUND { - // @@protoc_insertion_point(field_list:google.firestore.v1.ListDocumentsResponse.documents) - return _internal_documents(); -} -inline const ::google::protobuf::RepeatedPtrField<::google::firestore::v1::Document>& -ListDocumentsResponse::_internal_documents() const { - PROTOBUF_TSAN_READ(&_impl_._tsan_detect_race); - return _impl_.documents_; -} -inline ::google::protobuf::RepeatedPtrField<::google::firestore::v1::Document>* -ListDocumentsResponse::_internal_mutable_documents() { - PROTOBUF_TSAN_READ(&_impl_._tsan_detect_race); - return &_impl_.documents_; + + _impl_._has_bits_[0] &= ~0x00000001u; + ::google::firestore::v1::Document* released = _impl_.document_; + _impl_.document_ = nullptr; +#ifdef PROTOBUF_FORCE_COPY_IN_RELEASE + auto* old = reinterpret_cast<::google::protobuf::MessageLite*>(released); + released = ::google::protobuf::internal::DuplicateIfNonNull(released); + if (GetArena() == nullptr) { + delete old; + } +#else // PROTOBUF_FORCE_COPY_IN_RELEASE + if (GetArena() != nullptr) { + released = ::google::protobuf::internal::DuplicateIfNonNull(released); + } +#endif // !PROTOBUF_FORCE_COPY_IN_RELEASE + return released; } +inline ::google::firestore::v1::Document* CreateDocumentRequest::unsafe_arena_release_document() { + PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); + // @@protoc_insertion_point(field_release:google.firestore.v1.CreateDocumentRequest.document) -// string next_page_token = 2; -inline void ListDocumentsResponse::clear_next_page_token() { + _impl_._has_bits_[0] &= ~0x00000001u; + ::google::firestore::v1::Document* temp = _impl_.document_; + _impl_.document_ = nullptr; + return temp; +} +inline ::google::firestore::v1::Document* CreateDocumentRequest::_internal_mutable_document() { PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); - _impl_.next_page_token_.ClearToEmpty(); + _impl_._has_bits_[0] |= 0x00000001u; + if (_impl_.document_ == nullptr) { + auto* p = CreateMaybeMessage<::google::firestore::v1::Document>(GetArena()); + _impl_.document_ = reinterpret_cast<::google::firestore::v1::Document*>(p); + } + return _impl_.document_; } -inline const std::string& ListDocumentsResponse::next_page_token() const - ABSL_ATTRIBUTE_LIFETIME_BOUND { - // @@protoc_insertion_point(field_get:google.firestore.v1.ListDocumentsResponse.next_page_token) - return _internal_next_page_token(); +inline ::google::firestore::v1::Document* CreateDocumentRequest::mutable_document() ABSL_ATTRIBUTE_LIFETIME_BOUND { + ::google::firestore::v1::Document* _msg = _internal_mutable_document(); + // @@protoc_insertion_point(field_mutable:google.firestore.v1.CreateDocumentRequest.document) + return _msg; } -template -inline PROTOBUF_ALWAYS_INLINE void ListDocumentsResponse::set_next_page_token(Arg_&& arg, - Args_... args) { +inline void CreateDocumentRequest::set_allocated_document(::google::firestore::v1::Document* value) { + ::google::protobuf::Arena* message_arena = GetArena(); PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); - ; - _impl_.next_page_token_.Set(static_cast(arg), args..., GetArena()); - // @@protoc_insertion_point(field_set:google.firestore.v1.ListDocumentsResponse.next_page_token) + if (message_arena == nullptr) { + delete reinterpret_cast<::google::protobuf::MessageLite*>(_impl_.document_); + } + + if (value != nullptr) { + ::google::protobuf::Arena* submessage_arena = reinterpret_cast<::google::protobuf::MessageLite*>(value)->GetArena(); + if (message_arena != submessage_arena) { + value = ::google::protobuf::internal::GetOwnedMessage(message_arena, value, submessage_arena); + } + _impl_._has_bits_[0] |= 0x00000001u; + } else { + _impl_._has_bits_[0] &= ~0x00000001u; + } + + _impl_.document_ = reinterpret_cast<::google::firestore::v1::Document*>(value); + // @@protoc_insertion_point(field_set_allocated:google.firestore.v1.CreateDocumentRequest.document) } -inline std::string* ListDocumentsResponse::mutable_next_page_token() ABSL_ATTRIBUTE_LIFETIME_BOUND { - std::string* _s = _internal_mutable_next_page_token(); - // @@protoc_insertion_point(field_mutable:google.firestore.v1.ListDocumentsResponse.next_page_token) - return _s; + +// .google.firestore.v1.DocumentMask mask = 5; +inline bool CreateDocumentRequest::has_mask() const { + bool value = (_impl_._has_bits_[0] & 0x00000002u) != 0; + PROTOBUF_ASSUME(!value || _impl_.mask_ != nullptr); + return value; } -inline const std::string& ListDocumentsResponse::_internal_next_page_token() const { +inline const ::google::firestore::v1::DocumentMask& CreateDocumentRequest::_internal_mask() const { PROTOBUF_TSAN_READ(&_impl_._tsan_detect_race); - return _impl_.next_page_token_.Get(); + const ::google::firestore::v1::DocumentMask* p = _impl_.mask_; + return p != nullptr ? *p : reinterpret_cast(::google::firestore::v1::_DocumentMask_default_instance_); } -inline void ListDocumentsResponse::_internal_set_next_page_token(const std::string& value) { +inline const ::google::firestore::v1::DocumentMask& CreateDocumentRequest::mask() const ABSL_ATTRIBUTE_LIFETIME_BOUND { + // @@protoc_insertion_point(field_get:google.firestore.v1.CreateDocumentRequest.mask) + return _internal_mask(); +} +inline void CreateDocumentRequest::unsafe_arena_set_allocated_mask(::google::firestore::v1::DocumentMask* value) { PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); - ; - _impl_.next_page_token_.Set(value, GetArena()); + if (GetArena() == nullptr) { + delete reinterpret_cast<::google::protobuf::MessageLite*>(_impl_.mask_); + } + _impl_.mask_ = reinterpret_cast<::google::firestore::v1::DocumentMask*>(value); + if (value != nullptr) { + _impl_._has_bits_[0] |= 0x00000002u; + } else { + _impl_._has_bits_[0] &= ~0x00000002u; + } + // @@protoc_insertion_point(field_unsafe_arena_set_allocated:google.firestore.v1.CreateDocumentRequest.mask) } -inline std::string* ListDocumentsResponse::_internal_mutable_next_page_token() { +inline ::google::firestore::v1::DocumentMask* CreateDocumentRequest::release_mask() { PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); - ; - return _impl_.next_page_token_.Mutable( GetArena()); + + _impl_._has_bits_[0] &= ~0x00000002u; + ::google::firestore::v1::DocumentMask* released = _impl_.mask_; + _impl_.mask_ = nullptr; +#ifdef PROTOBUF_FORCE_COPY_IN_RELEASE + auto* old = reinterpret_cast<::google::protobuf::MessageLite*>(released); + released = ::google::protobuf::internal::DuplicateIfNonNull(released); + if (GetArena() == nullptr) { + delete old; + } +#else // PROTOBUF_FORCE_COPY_IN_RELEASE + if (GetArena() != nullptr) { + released = ::google::protobuf::internal::DuplicateIfNonNull(released); + } +#endif // !PROTOBUF_FORCE_COPY_IN_RELEASE + return released; } -inline std::string* ListDocumentsResponse::release_next_page_token() { +inline ::google::firestore::v1::DocumentMask* CreateDocumentRequest::unsafe_arena_release_mask() { PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); - // @@protoc_insertion_point(field_release:google.firestore.v1.ListDocumentsResponse.next_page_token) - return _impl_.next_page_token_.Release(); + // @@protoc_insertion_point(field_release:google.firestore.v1.CreateDocumentRequest.mask) + + _impl_._has_bits_[0] &= ~0x00000002u; + ::google::firestore::v1::DocumentMask* temp = _impl_.mask_; + _impl_.mask_ = nullptr; + return temp; } -inline void ListDocumentsResponse::set_allocated_next_page_token(std::string* value) { +inline ::google::firestore::v1::DocumentMask* CreateDocumentRequest::_internal_mutable_mask() { PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); - _impl_.next_page_token_.SetAllocated(value, GetArena()); - #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING - if (_impl_.next_page_token_.IsDefault()) { - _impl_.next_page_token_.Set("", GetArena()); - } - #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING - // @@protoc_insertion_point(field_set_allocated:google.firestore.v1.ListDocumentsResponse.next_page_token) + _impl_._has_bits_[0] |= 0x00000002u; + if (_impl_.mask_ == nullptr) { + auto* p = CreateMaybeMessage<::google::firestore::v1::DocumentMask>(GetArena()); + _impl_.mask_ = reinterpret_cast<::google::firestore::v1::DocumentMask*>(p); + } + return _impl_.mask_; +} +inline ::google::firestore::v1::DocumentMask* CreateDocumentRequest::mutable_mask() ABSL_ATTRIBUTE_LIFETIME_BOUND { + ::google::firestore::v1::DocumentMask* _msg = _internal_mutable_mask(); + // @@protoc_insertion_point(field_mutable:google.firestore.v1.CreateDocumentRequest.mask) + return _msg; +} +inline void CreateDocumentRequest::set_allocated_mask(::google::firestore::v1::DocumentMask* value) { + ::google::protobuf::Arena* message_arena = GetArena(); + PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); + if (message_arena == nullptr) { + delete reinterpret_cast<::google::protobuf::MessageLite*>(_impl_.mask_); + } + + if (value != nullptr) { + ::google::protobuf::Arena* submessage_arena = reinterpret_cast<::google::protobuf::MessageLite*>(value)->GetArena(); + if (message_arena != submessage_arena) { + value = ::google::protobuf::internal::GetOwnedMessage(message_arena, value, submessage_arena); + } + _impl_._has_bits_[0] |= 0x00000002u; + } else { + _impl_._has_bits_[0] &= ~0x00000002u; + } + + _impl_.mask_ = reinterpret_cast<::google::firestore::v1::DocumentMask*>(value); + // @@protoc_insertion_point(field_set_allocated:google.firestore.v1.CreateDocumentRequest.mask) } // ------------------------------------------------------------------- -// CreateDocumentRequest +// UpdateDocumentRequest -// string parent = 1; -inline void CreateDocumentRequest::clear_parent() { - PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); - _impl_.parent_.ClearToEmpty(); -} -inline const std::string& CreateDocumentRequest::parent() const - ABSL_ATTRIBUTE_LIFETIME_BOUND { - // @@protoc_insertion_point(field_get:google.firestore.v1.CreateDocumentRequest.parent) - return _internal_parent(); -} -template -inline PROTOBUF_ALWAYS_INLINE void CreateDocumentRequest::set_parent(Arg_&& arg, - Args_... args) { - PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); - ; - _impl_.parent_.Set(static_cast(arg), args..., GetArena()); - // @@protoc_insertion_point(field_set:google.firestore.v1.CreateDocumentRequest.parent) -} -inline std::string* CreateDocumentRequest::mutable_parent() ABSL_ATTRIBUTE_LIFETIME_BOUND { - std::string* _s = _internal_mutable_parent(); - // @@protoc_insertion_point(field_mutable:google.firestore.v1.CreateDocumentRequest.parent) - return _s; +// .google.firestore.v1.Document document = 1; +inline bool UpdateDocumentRequest::has_document() const { + bool value = (_impl_._has_bits_[0] & 0x00000001u) != 0; + PROTOBUF_ASSUME(!value || _impl_.document_ != nullptr); + return value; } -inline const std::string& CreateDocumentRequest::_internal_parent() const { +inline const ::google::firestore::v1::Document& UpdateDocumentRequest::_internal_document() const { PROTOBUF_TSAN_READ(&_impl_._tsan_detect_race); - return _impl_.parent_.Get(); + const ::google::firestore::v1::Document* p = _impl_.document_; + return p != nullptr ? *p : reinterpret_cast(::google::firestore::v1::_Document_default_instance_); } -inline void CreateDocumentRequest::_internal_set_parent(const std::string& value) { - PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); - ; - _impl_.parent_.Set(value, GetArena()); +inline const ::google::firestore::v1::Document& UpdateDocumentRequest::document() const ABSL_ATTRIBUTE_LIFETIME_BOUND { + // @@protoc_insertion_point(field_get:google.firestore.v1.UpdateDocumentRequest.document) + return _internal_document(); } -inline std::string* CreateDocumentRequest::_internal_mutable_parent() { +inline void UpdateDocumentRequest::unsafe_arena_set_allocated_document(::google::firestore::v1::Document* value) { PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); - ; - return _impl_.parent_.Mutable( GetArena()); + if (GetArena() == nullptr) { + delete reinterpret_cast<::google::protobuf::MessageLite*>(_impl_.document_); + } + _impl_.document_ = reinterpret_cast<::google::firestore::v1::Document*>(value); + if (value != nullptr) { + _impl_._has_bits_[0] |= 0x00000001u; + } else { + _impl_._has_bits_[0] &= ~0x00000001u; + } + // @@protoc_insertion_point(field_unsafe_arena_set_allocated:google.firestore.v1.UpdateDocumentRequest.document) } -inline std::string* CreateDocumentRequest::release_parent() { +inline ::google::firestore::v1::Document* UpdateDocumentRequest::release_document() { PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); - // @@protoc_insertion_point(field_release:google.firestore.v1.CreateDocumentRequest.parent) - return _impl_.parent_.Release(); + + _impl_._has_bits_[0] &= ~0x00000001u; + ::google::firestore::v1::Document* released = _impl_.document_; + _impl_.document_ = nullptr; +#ifdef PROTOBUF_FORCE_COPY_IN_RELEASE + auto* old = reinterpret_cast<::google::protobuf::MessageLite*>(released); + released = ::google::protobuf::internal::DuplicateIfNonNull(released); + if (GetArena() == nullptr) { + delete old; + } +#else // PROTOBUF_FORCE_COPY_IN_RELEASE + if (GetArena() != nullptr) { + released = ::google::protobuf::internal::DuplicateIfNonNull(released); + } +#endif // !PROTOBUF_FORCE_COPY_IN_RELEASE + return released; } -inline void CreateDocumentRequest::set_allocated_parent(std::string* value) { +inline ::google::firestore::v1::Document* UpdateDocumentRequest::unsafe_arena_release_document() { PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); - _impl_.parent_.SetAllocated(value, GetArena()); - #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING - if (_impl_.parent_.IsDefault()) { - _impl_.parent_.Set("", GetArena()); - } - #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING - // @@protoc_insertion_point(field_set_allocated:google.firestore.v1.CreateDocumentRequest.parent) -} + // @@protoc_insertion_point(field_release:google.firestore.v1.UpdateDocumentRequest.document) -// string collection_id = 2; -inline void CreateDocumentRequest::clear_collection_id() { + _impl_._has_bits_[0] &= ~0x00000001u; + ::google::firestore::v1::Document* temp = _impl_.document_; + _impl_.document_ = nullptr; + return temp; +} +inline ::google::firestore::v1::Document* UpdateDocumentRequest::_internal_mutable_document() { PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); - _impl_.collection_id_.ClearToEmpty(); + _impl_._has_bits_[0] |= 0x00000001u; + if (_impl_.document_ == nullptr) { + auto* p = CreateMaybeMessage<::google::firestore::v1::Document>(GetArena()); + _impl_.document_ = reinterpret_cast<::google::firestore::v1::Document*>(p); + } + return _impl_.document_; } -inline const std::string& CreateDocumentRequest::collection_id() const - ABSL_ATTRIBUTE_LIFETIME_BOUND { - // @@protoc_insertion_point(field_get:google.firestore.v1.CreateDocumentRequest.collection_id) - return _internal_collection_id(); +inline ::google::firestore::v1::Document* UpdateDocumentRequest::mutable_document() ABSL_ATTRIBUTE_LIFETIME_BOUND { + ::google::firestore::v1::Document* _msg = _internal_mutable_document(); + // @@protoc_insertion_point(field_mutable:google.firestore.v1.UpdateDocumentRequest.document) + return _msg; } -template -inline PROTOBUF_ALWAYS_INLINE void CreateDocumentRequest::set_collection_id(Arg_&& arg, - Args_... args) { +inline void UpdateDocumentRequest::set_allocated_document(::google::firestore::v1::Document* value) { + ::google::protobuf::Arena* message_arena = GetArena(); PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); - ; - _impl_.collection_id_.Set(static_cast(arg), args..., GetArena()); - // @@protoc_insertion_point(field_set:google.firestore.v1.CreateDocumentRequest.collection_id) + if (message_arena == nullptr) { + delete reinterpret_cast<::google::protobuf::MessageLite*>(_impl_.document_); + } + + if (value != nullptr) { + ::google::protobuf::Arena* submessage_arena = reinterpret_cast<::google::protobuf::MessageLite*>(value)->GetArena(); + if (message_arena != submessage_arena) { + value = ::google::protobuf::internal::GetOwnedMessage(message_arena, value, submessage_arena); + } + _impl_._has_bits_[0] |= 0x00000001u; + } else { + _impl_._has_bits_[0] &= ~0x00000001u; + } + + _impl_.document_ = reinterpret_cast<::google::firestore::v1::Document*>(value); + // @@protoc_insertion_point(field_set_allocated:google.firestore.v1.UpdateDocumentRequest.document) } -inline std::string* CreateDocumentRequest::mutable_collection_id() ABSL_ATTRIBUTE_LIFETIME_BOUND { - std::string* _s = _internal_mutable_collection_id(); - // @@protoc_insertion_point(field_mutable:google.firestore.v1.CreateDocumentRequest.collection_id) - return _s; + +// .google.firestore.v1.DocumentMask update_mask = 2; +inline bool UpdateDocumentRequest::has_update_mask() const { + bool value = (_impl_._has_bits_[0] & 0x00000002u) != 0; + PROTOBUF_ASSUME(!value || _impl_.update_mask_ != nullptr); + return value; } -inline const std::string& CreateDocumentRequest::_internal_collection_id() const { +inline const ::google::firestore::v1::DocumentMask& UpdateDocumentRequest::_internal_update_mask() const { PROTOBUF_TSAN_READ(&_impl_._tsan_detect_race); - return _impl_.collection_id_.Get(); + const ::google::firestore::v1::DocumentMask* p = _impl_.update_mask_; + return p != nullptr ? *p : reinterpret_cast(::google::firestore::v1::_DocumentMask_default_instance_); } -inline void CreateDocumentRequest::_internal_set_collection_id(const std::string& value) { - PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); - ; - _impl_.collection_id_.Set(value, GetArena()); +inline const ::google::firestore::v1::DocumentMask& UpdateDocumentRequest::update_mask() const ABSL_ATTRIBUTE_LIFETIME_BOUND { + // @@protoc_insertion_point(field_get:google.firestore.v1.UpdateDocumentRequest.update_mask) + return _internal_update_mask(); } -inline std::string* CreateDocumentRequest::_internal_mutable_collection_id() { +inline void UpdateDocumentRequest::unsafe_arena_set_allocated_update_mask(::google::firestore::v1::DocumentMask* value) { PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); - ; - return _impl_.collection_id_.Mutable( GetArena()); + if (GetArena() == nullptr) { + delete reinterpret_cast<::google::protobuf::MessageLite*>(_impl_.update_mask_); + } + _impl_.update_mask_ = reinterpret_cast<::google::firestore::v1::DocumentMask*>(value); + if (value != nullptr) { + _impl_._has_bits_[0] |= 0x00000002u; + } else { + _impl_._has_bits_[0] &= ~0x00000002u; + } + // @@protoc_insertion_point(field_unsafe_arena_set_allocated:google.firestore.v1.UpdateDocumentRequest.update_mask) } -inline std::string* CreateDocumentRequest::release_collection_id() { +inline ::google::firestore::v1::DocumentMask* UpdateDocumentRequest::release_update_mask() { PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); - // @@protoc_insertion_point(field_release:google.firestore.v1.CreateDocumentRequest.collection_id) - return _impl_.collection_id_.Release(); + + _impl_._has_bits_[0] &= ~0x00000002u; + ::google::firestore::v1::DocumentMask* released = _impl_.update_mask_; + _impl_.update_mask_ = nullptr; +#ifdef PROTOBUF_FORCE_COPY_IN_RELEASE + auto* old = reinterpret_cast<::google::protobuf::MessageLite*>(released); + released = ::google::protobuf::internal::DuplicateIfNonNull(released); + if (GetArena() == nullptr) { + delete old; + } +#else // PROTOBUF_FORCE_COPY_IN_RELEASE + if (GetArena() != nullptr) { + released = ::google::protobuf::internal::DuplicateIfNonNull(released); + } +#endif // !PROTOBUF_FORCE_COPY_IN_RELEASE + return released; } -inline void CreateDocumentRequest::set_allocated_collection_id(std::string* value) { +inline ::google::firestore::v1::DocumentMask* UpdateDocumentRequest::unsafe_arena_release_update_mask() { PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); - _impl_.collection_id_.SetAllocated(value, GetArena()); - #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING - if (_impl_.collection_id_.IsDefault()) { - _impl_.collection_id_.Set("", GetArena()); - } - #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING - // @@protoc_insertion_point(field_set_allocated:google.firestore.v1.CreateDocumentRequest.collection_id) -} + // @@protoc_insertion_point(field_release:google.firestore.v1.UpdateDocumentRequest.update_mask) -// string document_id = 3; -inline void CreateDocumentRequest::clear_document_id() { + _impl_._has_bits_[0] &= ~0x00000002u; + ::google::firestore::v1::DocumentMask* temp = _impl_.update_mask_; + _impl_.update_mask_ = nullptr; + return temp; +} +inline ::google::firestore::v1::DocumentMask* UpdateDocumentRequest::_internal_mutable_update_mask() { PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); - _impl_.document_id_.ClearToEmpty(); + _impl_._has_bits_[0] |= 0x00000002u; + if (_impl_.update_mask_ == nullptr) { + auto* p = CreateMaybeMessage<::google::firestore::v1::DocumentMask>(GetArena()); + _impl_.update_mask_ = reinterpret_cast<::google::firestore::v1::DocumentMask*>(p); + } + return _impl_.update_mask_; } -inline const std::string& CreateDocumentRequest::document_id() const - ABSL_ATTRIBUTE_LIFETIME_BOUND { - // @@protoc_insertion_point(field_get:google.firestore.v1.CreateDocumentRequest.document_id) - return _internal_document_id(); +inline ::google::firestore::v1::DocumentMask* UpdateDocumentRequest::mutable_update_mask() ABSL_ATTRIBUTE_LIFETIME_BOUND { + ::google::firestore::v1::DocumentMask* _msg = _internal_mutable_update_mask(); + // @@protoc_insertion_point(field_mutable:google.firestore.v1.UpdateDocumentRequest.update_mask) + return _msg; } -template -inline PROTOBUF_ALWAYS_INLINE void CreateDocumentRequest::set_document_id(Arg_&& arg, - Args_... args) { +inline void UpdateDocumentRequest::set_allocated_update_mask(::google::firestore::v1::DocumentMask* value) { + ::google::protobuf::Arena* message_arena = GetArena(); PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); - ; - _impl_.document_id_.Set(static_cast(arg), args..., GetArena()); - // @@protoc_insertion_point(field_set:google.firestore.v1.CreateDocumentRequest.document_id) -} -inline std::string* CreateDocumentRequest::mutable_document_id() ABSL_ATTRIBUTE_LIFETIME_BOUND { - std::string* _s = _internal_mutable_document_id(); - // @@protoc_insertion_point(field_mutable:google.firestore.v1.CreateDocumentRequest.document_id) - return _s; + if (message_arena == nullptr) { + delete reinterpret_cast<::google::protobuf::MessageLite*>(_impl_.update_mask_); + } + + if (value != nullptr) { + ::google::protobuf::Arena* submessage_arena = reinterpret_cast<::google::protobuf::MessageLite*>(value)->GetArena(); + if (message_arena != submessage_arena) { + value = ::google::protobuf::internal::GetOwnedMessage(message_arena, value, submessage_arena); + } + _impl_._has_bits_[0] |= 0x00000002u; + } else { + _impl_._has_bits_[0] &= ~0x00000002u; + } + + _impl_.update_mask_ = reinterpret_cast<::google::firestore::v1::DocumentMask*>(value); + // @@protoc_insertion_point(field_set_allocated:google.firestore.v1.UpdateDocumentRequest.update_mask) } -inline const std::string& CreateDocumentRequest::_internal_document_id() const { + +// .google.firestore.v1.DocumentMask mask = 3; +inline bool UpdateDocumentRequest::has_mask() const { + bool value = (_impl_._has_bits_[0] & 0x00000004u) != 0; + PROTOBUF_ASSUME(!value || _impl_.mask_ != nullptr); + return value; +} +inline const ::google::firestore::v1::DocumentMask& UpdateDocumentRequest::_internal_mask() const { PROTOBUF_TSAN_READ(&_impl_._tsan_detect_race); - return _impl_.document_id_.Get(); + const ::google::firestore::v1::DocumentMask* p = _impl_.mask_; + return p != nullptr ? *p : reinterpret_cast(::google::firestore::v1::_DocumentMask_default_instance_); } -inline void CreateDocumentRequest::_internal_set_document_id(const std::string& value) { +inline const ::google::firestore::v1::DocumentMask& UpdateDocumentRequest::mask() const ABSL_ATTRIBUTE_LIFETIME_BOUND { + // @@protoc_insertion_point(field_get:google.firestore.v1.UpdateDocumentRequest.mask) + return _internal_mask(); +} +inline void UpdateDocumentRequest::unsafe_arena_set_allocated_mask(::google::firestore::v1::DocumentMask* value) { PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); - ; - _impl_.document_id_.Set(value, GetArena()); + if (GetArena() == nullptr) { + delete reinterpret_cast<::google::protobuf::MessageLite*>(_impl_.mask_); + } + _impl_.mask_ = reinterpret_cast<::google::firestore::v1::DocumentMask*>(value); + if (value != nullptr) { + _impl_._has_bits_[0] |= 0x00000004u; + } else { + _impl_._has_bits_[0] &= ~0x00000004u; + } + // @@protoc_insertion_point(field_unsafe_arena_set_allocated:google.firestore.v1.UpdateDocumentRequest.mask) } -inline std::string* CreateDocumentRequest::_internal_mutable_document_id() { +inline ::google::firestore::v1::DocumentMask* UpdateDocumentRequest::release_mask() { PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); - ; - return _impl_.document_id_.Mutable( GetArena()); + + _impl_._has_bits_[0] &= ~0x00000004u; + ::google::firestore::v1::DocumentMask* released = _impl_.mask_; + _impl_.mask_ = nullptr; +#ifdef PROTOBUF_FORCE_COPY_IN_RELEASE + auto* old = reinterpret_cast<::google::protobuf::MessageLite*>(released); + released = ::google::protobuf::internal::DuplicateIfNonNull(released); + if (GetArena() == nullptr) { + delete old; + } +#else // PROTOBUF_FORCE_COPY_IN_RELEASE + if (GetArena() != nullptr) { + released = ::google::protobuf::internal::DuplicateIfNonNull(released); + } +#endif // !PROTOBUF_FORCE_COPY_IN_RELEASE + return released; } -inline std::string* CreateDocumentRequest::release_document_id() { +inline ::google::firestore::v1::DocumentMask* UpdateDocumentRequest::unsafe_arena_release_mask() { PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); - // @@protoc_insertion_point(field_release:google.firestore.v1.CreateDocumentRequest.document_id) - return _impl_.document_id_.Release(); + // @@protoc_insertion_point(field_release:google.firestore.v1.UpdateDocumentRequest.mask) + + _impl_._has_bits_[0] &= ~0x00000004u; + ::google::firestore::v1::DocumentMask* temp = _impl_.mask_; + _impl_.mask_ = nullptr; + return temp; } -inline void CreateDocumentRequest::set_allocated_document_id(std::string* value) { +inline ::google::firestore::v1::DocumentMask* UpdateDocumentRequest::_internal_mutable_mask() { PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); - _impl_.document_id_.SetAllocated(value, GetArena()); - #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING - if (_impl_.document_id_.IsDefault()) { - _impl_.document_id_.Set("", GetArena()); - } - #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING - // @@protoc_insertion_point(field_set_allocated:google.firestore.v1.CreateDocumentRequest.document_id) + _impl_._has_bits_[0] |= 0x00000004u; + if (_impl_.mask_ == nullptr) { + auto* p = CreateMaybeMessage<::google::firestore::v1::DocumentMask>(GetArena()); + _impl_.mask_ = reinterpret_cast<::google::firestore::v1::DocumentMask*>(p); + } + return _impl_.mask_; +} +inline ::google::firestore::v1::DocumentMask* UpdateDocumentRequest::mutable_mask() ABSL_ATTRIBUTE_LIFETIME_BOUND { + ::google::firestore::v1::DocumentMask* _msg = _internal_mutable_mask(); + // @@protoc_insertion_point(field_mutable:google.firestore.v1.UpdateDocumentRequest.mask) + return _msg; } +inline void UpdateDocumentRequest::set_allocated_mask(::google::firestore::v1::DocumentMask* value) { + ::google::protobuf::Arena* message_arena = GetArena(); + PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); + if (message_arena == nullptr) { + delete reinterpret_cast<::google::protobuf::MessageLite*>(_impl_.mask_); + } -// .google.firestore.v1.Document document = 4; -inline bool CreateDocumentRequest::has_document() const { - bool value = (_impl_._has_bits_[0] & 0x00000001u) != 0; - PROTOBUF_ASSUME(!value || _impl_.document_ != nullptr); + if (value != nullptr) { + ::google::protobuf::Arena* submessage_arena = reinterpret_cast<::google::protobuf::MessageLite*>(value)->GetArena(); + if (message_arena != submessage_arena) { + value = ::google::protobuf::internal::GetOwnedMessage(message_arena, value, submessage_arena); + } + _impl_._has_bits_[0] |= 0x00000004u; + } else { + _impl_._has_bits_[0] &= ~0x00000004u; + } + + _impl_.mask_ = reinterpret_cast<::google::firestore::v1::DocumentMask*>(value); + // @@protoc_insertion_point(field_set_allocated:google.firestore.v1.UpdateDocumentRequest.mask) +} + +// .google.firestore.v1.Precondition current_document = 4; +inline bool UpdateDocumentRequest::has_current_document() const { + bool value = (_impl_._has_bits_[0] & 0x00000008u) != 0; + PROTOBUF_ASSUME(!value || _impl_.current_document_ != nullptr); return value; } -inline const ::google::firestore::v1::Document& CreateDocumentRequest::_internal_document() const { +inline const ::google::firestore::v1::Precondition& UpdateDocumentRequest::_internal_current_document() const { PROTOBUF_TSAN_READ(&_impl_._tsan_detect_race); - const ::google::firestore::v1::Document* p = _impl_.document_; - return p != nullptr ? *p : reinterpret_cast(::google::firestore::v1::_Document_default_instance_); + const ::google::firestore::v1::Precondition* p = _impl_.current_document_; + return p != nullptr ? *p : reinterpret_cast(::google::firestore::v1::_Precondition_default_instance_); } -inline const ::google::firestore::v1::Document& CreateDocumentRequest::document() const ABSL_ATTRIBUTE_LIFETIME_BOUND { - // @@protoc_insertion_point(field_get:google.firestore.v1.CreateDocumentRequest.document) - return _internal_document(); +inline const ::google::firestore::v1::Precondition& UpdateDocumentRequest::current_document() const ABSL_ATTRIBUTE_LIFETIME_BOUND { + // @@protoc_insertion_point(field_get:google.firestore.v1.UpdateDocumentRequest.current_document) + return _internal_current_document(); } -inline void CreateDocumentRequest::unsafe_arena_set_allocated_document(::google::firestore::v1::Document* value) { +inline void UpdateDocumentRequest::unsafe_arena_set_allocated_current_document(::google::firestore::v1::Precondition* value) { PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); if (GetArena() == nullptr) { - delete reinterpret_cast<::google::protobuf::MessageLite*>(_impl_.document_); + delete reinterpret_cast<::google::protobuf::MessageLite*>(_impl_.current_document_); } - _impl_.document_ = reinterpret_cast<::google::firestore::v1::Document*>(value); + _impl_.current_document_ = reinterpret_cast<::google::firestore::v1::Precondition*>(value); if (value != nullptr) { - _impl_._has_bits_[0] |= 0x00000001u; + _impl_._has_bits_[0] |= 0x00000008u; } else { - _impl_._has_bits_[0] &= ~0x00000001u; + _impl_._has_bits_[0] &= ~0x00000008u; } - // @@protoc_insertion_point(field_unsafe_arena_set_allocated:google.firestore.v1.CreateDocumentRequest.document) + // @@protoc_insertion_point(field_unsafe_arena_set_allocated:google.firestore.v1.UpdateDocumentRequest.current_document) } -inline ::google::firestore::v1::Document* CreateDocumentRequest::release_document() { +inline ::google::firestore::v1::Precondition* UpdateDocumentRequest::release_current_document() { PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); - _impl_._has_bits_[0] &= ~0x00000001u; - ::google::firestore::v1::Document* released = _impl_.document_; - _impl_.document_ = nullptr; + _impl_._has_bits_[0] &= ~0x00000008u; + ::google::firestore::v1::Precondition* released = _impl_.current_document_; + _impl_.current_document_ = nullptr; #ifdef PROTOBUF_FORCE_COPY_IN_RELEASE auto* old = reinterpret_cast<::google::protobuf::MessageLite*>(released); released = ::google::protobuf::internal::DuplicateIfNonNull(released); @@ -7996,34 +8999,34 @@ inline ::google::firestore::v1::Document* CreateDocumentRequest::release_documen #endif // !PROTOBUF_FORCE_COPY_IN_RELEASE return released; } -inline ::google::firestore::v1::Document* CreateDocumentRequest::unsafe_arena_release_document() { +inline ::google::firestore::v1::Precondition* UpdateDocumentRequest::unsafe_arena_release_current_document() { PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); - // @@protoc_insertion_point(field_release:google.firestore.v1.CreateDocumentRequest.document) + // @@protoc_insertion_point(field_release:google.firestore.v1.UpdateDocumentRequest.current_document) - _impl_._has_bits_[0] &= ~0x00000001u; - ::google::firestore::v1::Document* temp = _impl_.document_; - _impl_.document_ = nullptr; + _impl_._has_bits_[0] &= ~0x00000008u; + ::google::firestore::v1::Precondition* temp = _impl_.current_document_; + _impl_.current_document_ = nullptr; return temp; } -inline ::google::firestore::v1::Document* CreateDocumentRequest::_internal_mutable_document() { +inline ::google::firestore::v1::Precondition* UpdateDocumentRequest::_internal_mutable_current_document() { PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); - _impl_._has_bits_[0] |= 0x00000001u; - if (_impl_.document_ == nullptr) { - auto* p = CreateMaybeMessage<::google::firestore::v1::Document>(GetArena()); - _impl_.document_ = reinterpret_cast<::google::firestore::v1::Document*>(p); + _impl_._has_bits_[0] |= 0x00000008u; + if (_impl_.current_document_ == nullptr) { + auto* p = CreateMaybeMessage<::google::firestore::v1::Precondition>(GetArena()); + _impl_.current_document_ = reinterpret_cast<::google::firestore::v1::Precondition*>(p); } - return _impl_.document_; + return _impl_.current_document_; } -inline ::google::firestore::v1::Document* CreateDocumentRequest::mutable_document() ABSL_ATTRIBUTE_LIFETIME_BOUND { - ::google::firestore::v1::Document* _msg = _internal_mutable_document(); - // @@protoc_insertion_point(field_mutable:google.firestore.v1.CreateDocumentRequest.document) +inline ::google::firestore::v1::Precondition* UpdateDocumentRequest::mutable_current_document() ABSL_ATTRIBUTE_LIFETIME_BOUND { + ::google::firestore::v1::Precondition* _msg = _internal_mutable_current_document(); + // @@protoc_insertion_point(field_mutable:google.firestore.v1.UpdateDocumentRequest.current_document) return _msg; } -inline void CreateDocumentRequest::set_allocated_document(::google::firestore::v1::Document* value) { +inline void UpdateDocumentRequest::set_allocated_current_document(::google::firestore::v1::Precondition* value) { ::google::protobuf::Arena* message_arena = GetArena(); PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); if (message_arena == nullptr) { - delete reinterpret_cast<::google::protobuf::MessageLite*>(_impl_.document_); + delete reinterpret_cast<::google::protobuf::MessageLite*>(_impl_.current_document_); } if (value != nullptr) { @@ -8031,49 +9034,106 @@ inline void CreateDocumentRequest::set_allocated_document(::google::firestore::v if (message_arena != submessage_arena) { value = ::google::protobuf::internal::GetOwnedMessage(message_arena, value, submessage_arena); } - _impl_._has_bits_[0] |= 0x00000001u; + _impl_._has_bits_[0] |= 0x00000008u; } else { - _impl_._has_bits_[0] &= ~0x00000001u; + _impl_._has_bits_[0] &= ~0x00000008u; } - _impl_.document_ = reinterpret_cast<::google::firestore::v1::Document*>(value); - // @@protoc_insertion_point(field_set_allocated:google.firestore.v1.CreateDocumentRequest.document) + _impl_.current_document_ = reinterpret_cast<::google::firestore::v1::Precondition*>(value); + // @@protoc_insertion_point(field_set_allocated:google.firestore.v1.UpdateDocumentRequest.current_document) } -// .google.firestore.v1.DocumentMask mask = 5; -inline bool CreateDocumentRequest::has_mask() const { - bool value = (_impl_._has_bits_[0] & 0x00000002u) != 0; - PROTOBUF_ASSUME(!value || _impl_.mask_ != nullptr); - return value; +// ------------------------------------------------------------------- + +// DeleteDocumentRequest + +// string name = 1; +inline void DeleteDocumentRequest::clear_name() { + PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); + _impl_.name_.ClearToEmpty(); } -inline const ::google::firestore::v1::DocumentMask& CreateDocumentRequest::_internal_mask() const { +inline const std::string& DeleteDocumentRequest::name() const + ABSL_ATTRIBUTE_LIFETIME_BOUND { + // @@protoc_insertion_point(field_get:google.firestore.v1.DeleteDocumentRequest.name) + return _internal_name(); +} +template +inline PROTOBUF_ALWAYS_INLINE void DeleteDocumentRequest::set_name(Arg_&& arg, + Args_... args) { + PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); + ; + _impl_.name_.Set(static_cast(arg), args..., GetArena()); + // @@protoc_insertion_point(field_set:google.firestore.v1.DeleteDocumentRequest.name) +} +inline std::string* DeleteDocumentRequest::mutable_name() ABSL_ATTRIBUTE_LIFETIME_BOUND { + std::string* _s = _internal_mutable_name(); + // @@protoc_insertion_point(field_mutable:google.firestore.v1.DeleteDocumentRequest.name) + return _s; +} +inline const std::string& DeleteDocumentRequest::_internal_name() const { PROTOBUF_TSAN_READ(&_impl_._tsan_detect_race); - const ::google::firestore::v1::DocumentMask* p = _impl_.mask_; - return p != nullptr ? *p : reinterpret_cast(::google::firestore::v1::_DocumentMask_default_instance_); + return _impl_.name_.Get(); } -inline const ::google::firestore::v1::DocumentMask& CreateDocumentRequest::mask() const ABSL_ATTRIBUTE_LIFETIME_BOUND { - // @@protoc_insertion_point(field_get:google.firestore.v1.CreateDocumentRequest.mask) - return _internal_mask(); +inline void DeleteDocumentRequest::_internal_set_name(const std::string& value) { + PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); + ; + _impl_.name_.Set(value, GetArena()); +} +inline std::string* DeleteDocumentRequest::_internal_mutable_name() { + PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); + ; + return _impl_.name_.Mutable( GetArena()); +} +inline std::string* DeleteDocumentRequest::release_name() { + PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); + // @@protoc_insertion_point(field_release:google.firestore.v1.DeleteDocumentRequest.name) + return _impl_.name_.Release(); +} +inline void DeleteDocumentRequest::set_allocated_name(std::string* value) { + PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); + _impl_.name_.SetAllocated(value, GetArena()); + #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING + if (_impl_.name_.IsDefault()) { + _impl_.name_.Set("", GetArena()); + } + #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING + // @@protoc_insertion_point(field_set_allocated:google.firestore.v1.DeleteDocumentRequest.name) +} + +// .google.firestore.v1.Precondition current_document = 2; +inline bool DeleteDocumentRequest::has_current_document() const { + bool value = (_impl_._has_bits_[0] & 0x00000001u) != 0; + PROTOBUF_ASSUME(!value || _impl_.current_document_ != nullptr); + return value; +} +inline const ::google::firestore::v1::Precondition& DeleteDocumentRequest::_internal_current_document() const { + PROTOBUF_TSAN_READ(&_impl_._tsan_detect_race); + const ::google::firestore::v1::Precondition* p = _impl_.current_document_; + return p != nullptr ? *p : reinterpret_cast(::google::firestore::v1::_Precondition_default_instance_); } -inline void CreateDocumentRequest::unsafe_arena_set_allocated_mask(::google::firestore::v1::DocumentMask* value) { +inline const ::google::firestore::v1::Precondition& DeleteDocumentRequest::current_document() const ABSL_ATTRIBUTE_LIFETIME_BOUND { + // @@protoc_insertion_point(field_get:google.firestore.v1.DeleteDocumentRequest.current_document) + return _internal_current_document(); +} +inline void DeleteDocumentRequest::unsafe_arena_set_allocated_current_document(::google::firestore::v1::Precondition* value) { PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); if (GetArena() == nullptr) { - delete reinterpret_cast<::google::protobuf::MessageLite*>(_impl_.mask_); + delete reinterpret_cast<::google::protobuf::MessageLite*>(_impl_.current_document_); } - _impl_.mask_ = reinterpret_cast<::google::firestore::v1::DocumentMask*>(value); + _impl_.current_document_ = reinterpret_cast<::google::firestore::v1::Precondition*>(value); if (value != nullptr) { - _impl_._has_bits_[0] |= 0x00000002u; + _impl_._has_bits_[0] |= 0x00000001u; } else { - _impl_._has_bits_[0] &= ~0x00000002u; + _impl_._has_bits_[0] &= ~0x00000001u; } - // @@protoc_insertion_point(field_unsafe_arena_set_allocated:google.firestore.v1.CreateDocumentRequest.mask) + // @@protoc_insertion_point(field_unsafe_arena_set_allocated:google.firestore.v1.DeleteDocumentRequest.current_document) } -inline ::google::firestore::v1::DocumentMask* CreateDocumentRequest::release_mask() { +inline ::google::firestore::v1::Precondition* DeleteDocumentRequest::release_current_document() { PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); - _impl_._has_bits_[0] &= ~0x00000002u; - ::google::firestore::v1::DocumentMask* released = _impl_.mask_; - _impl_.mask_ = nullptr; + _impl_._has_bits_[0] &= ~0x00000001u; + ::google::firestore::v1::Precondition* released = _impl_.current_document_; + _impl_.current_document_ = nullptr; #ifdef PROTOBUF_FORCE_COPY_IN_RELEASE auto* old = reinterpret_cast<::google::protobuf::MessageLite*>(released); released = ::google::protobuf::internal::DuplicateIfNonNull(released); @@ -8087,34 +9147,34 @@ inline ::google::firestore::v1::DocumentMask* CreateDocumentRequest::release_mas #endif // !PROTOBUF_FORCE_COPY_IN_RELEASE return released; } -inline ::google::firestore::v1::DocumentMask* CreateDocumentRequest::unsafe_arena_release_mask() { +inline ::google::firestore::v1::Precondition* DeleteDocumentRequest::unsafe_arena_release_current_document() { PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); - // @@protoc_insertion_point(field_release:google.firestore.v1.CreateDocumentRequest.mask) + // @@protoc_insertion_point(field_release:google.firestore.v1.DeleteDocumentRequest.current_document) - _impl_._has_bits_[0] &= ~0x00000002u; - ::google::firestore::v1::DocumentMask* temp = _impl_.mask_; - _impl_.mask_ = nullptr; + _impl_._has_bits_[0] &= ~0x00000001u; + ::google::firestore::v1::Precondition* temp = _impl_.current_document_; + _impl_.current_document_ = nullptr; return temp; } -inline ::google::firestore::v1::DocumentMask* CreateDocumentRequest::_internal_mutable_mask() { +inline ::google::firestore::v1::Precondition* DeleteDocumentRequest::_internal_mutable_current_document() { PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); - _impl_._has_bits_[0] |= 0x00000002u; - if (_impl_.mask_ == nullptr) { - auto* p = CreateMaybeMessage<::google::firestore::v1::DocumentMask>(GetArena()); - _impl_.mask_ = reinterpret_cast<::google::firestore::v1::DocumentMask*>(p); + _impl_._has_bits_[0] |= 0x00000001u; + if (_impl_.current_document_ == nullptr) { + auto* p = CreateMaybeMessage<::google::firestore::v1::Precondition>(GetArena()); + _impl_.current_document_ = reinterpret_cast<::google::firestore::v1::Precondition*>(p); } - return _impl_.mask_; + return _impl_.current_document_; } -inline ::google::firestore::v1::DocumentMask* CreateDocumentRequest::mutable_mask() ABSL_ATTRIBUTE_LIFETIME_BOUND { - ::google::firestore::v1::DocumentMask* _msg = _internal_mutable_mask(); - // @@protoc_insertion_point(field_mutable:google.firestore.v1.CreateDocumentRequest.mask) +inline ::google::firestore::v1::Precondition* DeleteDocumentRequest::mutable_current_document() ABSL_ATTRIBUTE_LIFETIME_BOUND { + ::google::firestore::v1::Precondition* _msg = _internal_mutable_current_document(); + // @@protoc_insertion_point(field_mutable:google.firestore.v1.DeleteDocumentRequest.current_document) return _msg; } -inline void CreateDocumentRequest::set_allocated_mask(::google::firestore::v1::DocumentMask* value) { +inline void DeleteDocumentRequest::set_allocated_current_document(::google::firestore::v1::Precondition* value) { ::google::protobuf::Arena* message_arena = GetArena(); PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); if (message_arena == nullptr) { - delete reinterpret_cast<::google::protobuf::MessageLite*>(_impl_.mask_); + delete reinterpret_cast<::google::protobuf::MessageLite*>(_impl_.current_document_); } if (value != nullptr) { @@ -8122,53 +9182,207 @@ inline void CreateDocumentRequest::set_allocated_mask(::google::firestore::v1::D if (message_arena != submessage_arena) { value = ::google::protobuf::internal::GetOwnedMessage(message_arena, value, submessage_arena); } - _impl_._has_bits_[0] |= 0x00000002u; + _impl_._has_bits_[0] |= 0x00000001u; } else { - _impl_._has_bits_[0] &= ~0x00000002u; + _impl_._has_bits_[0] &= ~0x00000001u; } - _impl_.mask_ = reinterpret_cast<::google::firestore::v1::DocumentMask*>(value); - // @@protoc_insertion_point(field_set_allocated:google.firestore.v1.CreateDocumentRequest.mask) + _impl_.current_document_ = reinterpret_cast<::google::firestore::v1::Precondition*>(value); + // @@protoc_insertion_point(field_set_allocated:google.firestore.v1.DeleteDocumentRequest.current_document) } // ------------------------------------------------------------------- -// UpdateDocumentRequest +// BatchGetDocumentsRequest -// .google.firestore.v1.Document document = 1; -inline bool UpdateDocumentRequest::has_document() const { +// string database = 1; +inline void BatchGetDocumentsRequest::clear_database() { + PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); + _impl_.database_.ClearToEmpty(); +} +inline const std::string& BatchGetDocumentsRequest::database() const + ABSL_ATTRIBUTE_LIFETIME_BOUND { + // @@protoc_insertion_point(field_get:google.firestore.v1.BatchGetDocumentsRequest.database) + return _internal_database(); +} +template +inline PROTOBUF_ALWAYS_INLINE void BatchGetDocumentsRequest::set_database(Arg_&& arg, + Args_... args) { + PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); + ; + _impl_.database_.Set(static_cast(arg), args..., GetArena()); + // @@protoc_insertion_point(field_set:google.firestore.v1.BatchGetDocumentsRequest.database) +} +inline std::string* BatchGetDocumentsRequest::mutable_database() ABSL_ATTRIBUTE_LIFETIME_BOUND { + std::string* _s = _internal_mutable_database(); + // @@protoc_insertion_point(field_mutable:google.firestore.v1.BatchGetDocumentsRequest.database) + return _s; +} +inline const std::string& BatchGetDocumentsRequest::_internal_database() const { + PROTOBUF_TSAN_READ(&_impl_._tsan_detect_race); + return _impl_.database_.Get(); +} +inline void BatchGetDocumentsRequest::_internal_set_database(const std::string& value) { + PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); + ; + _impl_.database_.Set(value, GetArena()); +} +inline std::string* BatchGetDocumentsRequest::_internal_mutable_database() { + PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); + ; + return _impl_.database_.Mutable( GetArena()); +} +inline std::string* BatchGetDocumentsRequest::release_database() { + PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); + // @@protoc_insertion_point(field_release:google.firestore.v1.BatchGetDocumentsRequest.database) + return _impl_.database_.Release(); +} +inline void BatchGetDocumentsRequest::set_allocated_database(std::string* value) { + PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); + _impl_.database_.SetAllocated(value, GetArena()); + #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING + if (_impl_.database_.IsDefault()) { + _impl_.database_.Set("", GetArena()); + } + #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING + // @@protoc_insertion_point(field_set_allocated:google.firestore.v1.BatchGetDocumentsRequest.database) +} + +// repeated string documents = 2; +inline int BatchGetDocumentsRequest::_internal_documents_size() const { + return _internal_documents().size(); +} +inline int BatchGetDocumentsRequest::documents_size() const { + return _internal_documents_size(); +} +inline void BatchGetDocumentsRequest::clear_documents() { + PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); + _impl_.documents_.Clear(); +} +inline std::string* BatchGetDocumentsRequest::add_documents() + ABSL_ATTRIBUTE_LIFETIME_BOUND { + PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); + std::string* _s = _internal_mutable_documents()->Add(); + // @@protoc_insertion_point(field_add_mutable:google.firestore.v1.BatchGetDocumentsRequest.documents) + return _s; +} +inline const std::string& BatchGetDocumentsRequest::documents(int index) const + ABSL_ATTRIBUTE_LIFETIME_BOUND { + // @@protoc_insertion_point(field_get:google.firestore.v1.BatchGetDocumentsRequest.documents) + return _internal_documents().Get(index); +} +inline std::string* BatchGetDocumentsRequest::mutable_documents(int index) + ABSL_ATTRIBUTE_LIFETIME_BOUND { + // @@protoc_insertion_point(field_mutable:google.firestore.v1.BatchGetDocumentsRequest.documents) + return _internal_mutable_documents()->Mutable(index); +} +inline void BatchGetDocumentsRequest::set_documents(int index, const std::string& value) { + _internal_mutable_documents()->Mutable(index)->assign(value); + // @@protoc_insertion_point(field_set:google.firestore.v1.BatchGetDocumentsRequest.documents) +} +inline void BatchGetDocumentsRequest::set_documents(int index, std::string&& value) { + _internal_mutable_documents()->Mutable(index)->assign(std::move(value)); + // @@protoc_insertion_point(field_set:google.firestore.v1.BatchGetDocumentsRequest.documents) +} +inline void BatchGetDocumentsRequest::set_documents(int index, const char* value) { + ABSL_DCHECK(value != nullptr); + _internal_mutable_documents()->Mutable(index)->assign(value); + // @@protoc_insertion_point(field_set_char:google.firestore.v1.BatchGetDocumentsRequest.documents) +} +inline void BatchGetDocumentsRequest::set_documents(int index, const char* value, + std::size_t size) { + _internal_mutable_documents()->Mutable(index)->assign( + reinterpret_cast(value), size); + // @@protoc_insertion_point(field_set_pointer:google.firestore.v1.BatchGetDocumentsRequest.documents) +} +inline void BatchGetDocumentsRequest::set_documents(int index, absl::string_view value) { + _internal_mutable_documents()->Mutable(index)->assign(value.data(), + value.size()); + // @@protoc_insertion_point(field_set_string_piece:google.firestore.v1.BatchGetDocumentsRequest.documents) +} +inline void BatchGetDocumentsRequest::add_documents(const std::string& value) { + PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); + _internal_mutable_documents()->Add()->assign(value); + // @@protoc_insertion_point(field_add:google.firestore.v1.BatchGetDocumentsRequest.documents) +} +inline void BatchGetDocumentsRequest::add_documents(std::string&& value) { + PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); + _internal_mutable_documents()->Add(std::move(value)); + // @@protoc_insertion_point(field_add:google.firestore.v1.BatchGetDocumentsRequest.documents) +} +inline void BatchGetDocumentsRequest::add_documents(const char* value) { + ABSL_DCHECK(value != nullptr); + PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); + _internal_mutable_documents()->Add()->assign(value); + // @@protoc_insertion_point(field_add_char:google.firestore.v1.BatchGetDocumentsRequest.documents) +} +inline void BatchGetDocumentsRequest::add_documents(const char* value, std::size_t size) { + PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); + _internal_mutable_documents()->Add()->assign( + reinterpret_cast(value), size); + // @@protoc_insertion_point(field_add_pointer:google.firestore.v1.BatchGetDocumentsRequest.documents) +} +inline void BatchGetDocumentsRequest::add_documents(absl::string_view value) { + PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); + _internal_mutable_documents()->Add()->assign(value.data(), value.size()); + // @@protoc_insertion_point(field_add_string_piece:google.firestore.v1.BatchGetDocumentsRequest.documents) +} +inline const ::google::protobuf::RepeatedPtrField& +BatchGetDocumentsRequest::documents() const ABSL_ATTRIBUTE_LIFETIME_BOUND { + // @@protoc_insertion_point(field_list:google.firestore.v1.BatchGetDocumentsRequest.documents) + return _internal_documents(); +} +inline ::google::protobuf::RepeatedPtrField* +BatchGetDocumentsRequest::mutable_documents() ABSL_ATTRIBUTE_LIFETIME_BOUND { + // @@protoc_insertion_point(field_mutable_list:google.firestore.v1.BatchGetDocumentsRequest.documents) + PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); + return _internal_mutable_documents(); +} +inline const ::google::protobuf::RepeatedPtrField& +BatchGetDocumentsRequest::_internal_documents() const { + PROTOBUF_TSAN_READ(&_impl_._tsan_detect_race); + return _impl_.documents_; +} +inline ::google::protobuf::RepeatedPtrField* +BatchGetDocumentsRequest::_internal_mutable_documents() { + PROTOBUF_TSAN_READ(&_impl_._tsan_detect_race); + return &_impl_.documents_; +} + +// .google.firestore.v1.DocumentMask mask = 3; +inline bool BatchGetDocumentsRequest::has_mask() const { bool value = (_impl_._has_bits_[0] & 0x00000001u) != 0; - PROTOBUF_ASSUME(!value || _impl_.document_ != nullptr); + PROTOBUF_ASSUME(!value || _impl_.mask_ != nullptr); return value; } -inline const ::google::firestore::v1::Document& UpdateDocumentRequest::_internal_document() const { +inline const ::google::firestore::v1::DocumentMask& BatchGetDocumentsRequest::_internal_mask() const { PROTOBUF_TSAN_READ(&_impl_._tsan_detect_race); - const ::google::firestore::v1::Document* p = _impl_.document_; - return p != nullptr ? *p : reinterpret_cast(::google::firestore::v1::_Document_default_instance_); + const ::google::firestore::v1::DocumentMask* p = _impl_.mask_; + return p != nullptr ? *p : reinterpret_cast(::google::firestore::v1::_DocumentMask_default_instance_); } -inline const ::google::firestore::v1::Document& UpdateDocumentRequest::document() const ABSL_ATTRIBUTE_LIFETIME_BOUND { - // @@protoc_insertion_point(field_get:google.firestore.v1.UpdateDocumentRequest.document) - return _internal_document(); +inline const ::google::firestore::v1::DocumentMask& BatchGetDocumentsRequest::mask() const ABSL_ATTRIBUTE_LIFETIME_BOUND { + // @@protoc_insertion_point(field_get:google.firestore.v1.BatchGetDocumentsRequest.mask) + return _internal_mask(); } -inline void UpdateDocumentRequest::unsafe_arena_set_allocated_document(::google::firestore::v1::Document* value) { +inline void BatchGetDocumentsRequest::unsafe_arena_set_allocated_mask(::google::firestore::v1::DocumentMask* value) { PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); if (GetArena() == nullptr) { - delete reinterpret_cast<::google::protobuf::MessageLite*>(_impl_.document_); + delete reinterpret_cast<::google::protobuf::MessageLite*>(_impl_.mask_); } - _impl_.document_ = reinterpret_cast<::google::firestore::v1::Document*>(value); + _impl_.mask_ = reinterpret_cast<::google::firestore::v1::DocumentMask*>(value); if (value != nullptr) { _impl_._has_bits_[0] |= 0x00000001u; } else { _impl_._has_bits_[0] &= ~0x00000001u; } - // @@protoc_insertion_point(field_unsafe_arena_set_allocated:google.firestore.v1.UpdateDocumentRequest.document) + // @@protoc_insertion_point(field_unsafe_arena_set_allocated:google.firestore.v1.BatchGetDocumentsRequest.mask) } -inline ::google::firestore::v1::Document* UpdateDocumentRequest::release_document() { +inline ::google::firestore::v1::DocumentMask* BatchGetDocumentsRequest::release_mask() { PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); _impl_._has_bits_[0] &= ~0x00000001u; - ::google::firestore::v1::Document* released = _impl_.document_; - _impl_.document_ = nullptr; + ::google::firestore::v1::DocumentMask* released = _impl_.mask_; + _impl_.mask_ = nullptr; #ifdef PROTOBUF_FORCE_COPY_IN_RELEASE auto* old = reinterpret_cast<::google::protobuf::MessageLite*>(released); released = ::google::protobuf::internal::DuplicateIfNonNull(released); @@ -8182,34 +9396,34 @@ inline ::google::firestore::v1::Document* UpdateDocumentRequest::release_documen #endif // !PROTOBUF_FORCE_COPY_IN_RELEASE return released; } -inline ::google::firestore::v1::Document* UpdateDocumentRequest::unsafe_arena_release_document() { +inline ::google::firestore::v1::DocumentMask* BatchGetDocumentsRequest::unsafe_arena_release_mask() { PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); - // @@protoc_insertion_point(field_release:google.firestore.v1.UpdateDocumentRequest.document) + // @@protoc_insertion_point(field_release:google.firestore.v1.BatchGetDocumentsRequest.mask) _impl_._has_bits_[0] &= ~0x00000001u; - ::google::firestore::v1::Document* temp = _impl_.document_; - _impl_.document_ = nullptr; + ::google::firestore::v1::DocumentMask* temp = _impl_.mask_; + _impl_.mask_ = nullptr; return temp; } -inline ::google::firestore::v1::Document* UpdateDocumentRequest::_internal_mutable_document() { +inline ::google::firestore::v1::DocumentMask* BatchGetDocumentsRequest::_internal_mutable_mask() { PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); _impl_._has_bits_[0] |= 0x00000001u; - if (_impl_.document_ == nullptr) { - auto* p = CreateMaybeMessage<::google::firestore::v1::Document>(GetArena()); - _impl_.document_ = reinterpret_cast<::google::firestore::v1::Document*>(p); + if (_impl_.mask_ == nullptr) { + auto* p = CreateMaybeMessage<::google::firestore::v1::DocumentMask>(GetArena()); + _impl_.mask_ = reinterpret_cast<::google::firestore::v1::DocumentMask*>(p); } - return _impl_.document_; + return _impl_.mask_; } -inline ::google::firestore::v1::Document* UpdateDocumentRequest::mutable_document() ABSL_ATTRIBUTE_LIFETIME_BOUND { - ::google::firestore::v1::Document* _msg = _internal_mutable_document(); - // @@protoc_insertion_point(field_mutable:google.firestore.v1.UpdateDocumentRequest.document) +inline ::google::firestore::v1::DocumentMask* BatchGetDocumentsRequest::mutable_mask() ABSL_ATTRIBUTE_LIFETIME_BOUND { + ::google::firestore::v1::DocumentMask* _msg = _internal_mutable_mask(); + // @@protoc_insertion_point(field_mutable:google.firestore.v1.BatchGetDocumentsRequest.mask) return _msg; } -inline void UpdateDocumentRequest::set_allocated_document(::google::firestore::v1::Document* value) { +inline void BatchGetDocumentsRequest::set_allocated_mask(::google::firestore::v1::DocumentMask* value) { ::google::protobuf::Arena* message_arena = GetArena(); PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); if (message_arena == nullptr) { - delete reinterpret_cast<::google::protobuf::MessageLite*>(_impl_.document_); + delete reinterpret_cast<::google::protobuf::MessageLite*>(_impl_.mask_); } if (value != nullptr) { @@ -8222,374 +9436,481 @@ inline void UpdateDocumentRequest::set_allocated_document(::google::firestore::v _impl_._has_bits_[0] &= ~0x00000001u; } - _impl_.document_ = reinterpret_cast<::google::firestore::v1::Document*>(value); - // @@protoc_insertion_point(field_set_allocated:google.firestore.v1.UpdateDocumentRequest.document) + _impl_.mask_ = reinterpret_cast<::google::firestore::v1::DocumentMask*>(value); + // @@protoc_insertion_point(field_set_allocated:google.firestore.v1.BatchGetDocumentsRequest.mask) } -// .google.firestore.v1.DocumentMask update_mask = 2; -inline bool UpdateDocumentRequest::has_update_mask() const { - bool value = (_impl_._has_bits_[0] & 0x00000002u) != 0; - PROTOBUF_ASSUME(!value || _impl_.update_mask_ != nullptr); - return value; +// bytes transaction = 4; +inline bool BatchGetDocumentsRequest::has_transaction() const { + return consistency_selector_case() == kTransaction; } -inline const ::google::firestore::v1::DocumentMask& UpdateDocumentRequest::_internal_update_mask() const { +inline void BatchGetDocumentsRequest::set_has_transaction() { + _impl_._oneof_case_[0] = kTransaction; +} +inline void BatchGetDocumentsRequest::clear_transaction() { + PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); + if (consistency_selector_case() == kTransaction) { + _impl_.consistency_selector_.transaction_.Destroy(); + clear_has_consistency_selector(); + } +} +inline const std::string& BatchGetDocumentsRequest::transaction() const + ABSL_ATTRIBUTE_LIFETIME_BOUND { + // @@protoc_insertion_point(field_get:google.firestore.v1.BatchGetDocumentsRequest.transaction) + return _internal_transaction(); +} +template +inline PROTOBUF_ALWAYS_INLINE void BatchGetDocumentsRequest::set_transaction(Arg_&& arg, + Args_... args) { + PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); + if (consistency_selector_case() != kTransaction) { + clear_consistency_selector(); + + set_has_transaction(); + _impl_.consistency_selector_.transaction_.InitDefault(); + } + _impl_.consistency_selector_.transaction_.SetBytes(static_cast(arg), args..., GetArena()); + // @@protoc_insertion_point(field_set:google.firestore.v1.BatchGetDocumentsRequest.transaction) +} +inline std::string* BatchGetDocumentsRequest::mutable_transaction() ABSL_ATTRIBUTE_LIFETIME_BOUND { + std::string* _s = _internal_mutable_transaction(); + // @@protoc_insertion_point(field_mutable:google.firestore.v1.BatchGetDocumentsRequest.transaction) + return _s; +} +inline const std::string& BatchGetDocumentsRequest::_internal_transaction() const { PROTOBUF_TSAN_READ(&_impl_._tsan_detect_race); - const ::google::firestore::v1::DocumentMask* p = _impl_.update_mask_; - return p != nullptr ? *p : reinterpret_cast(::google::firestore::v1::_DocumentMask_default_instance_); + if (consistency_selector_case() != kTransaction) { + return ::google::protobuf::internal::GetEmptyStringAlreadyInited(); + } + return _impl_.consistency_selector_.transaction_.Get(); } -inline const ::google::firestore::v1::DocumentMask& UpdateDocumentRequest::update_mask() const ABSL_ATTRIBUTE_LIFETIME_BOUND { - // @@protoc_insertion_point(field_get:google.firestore.v1.UpdateDocumentRequest.update_mask) - return _internal_update_mask(); +inline void BatchGetDocumentsRequest::_internal_set_transaction(const std::string& value) { + PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); + if (consistency_selector_case() != kTransaction) { + clear_consistency_selector(); + + set_has_transaction(); + _impl_.consistency_selector_.transaction_.InitDefault(); + } + _impl_.consistency_selector_.transaction_.Set(value, GetArena()); } -inline void UpdateDocumentRequest::unsafe_arena_set_allocated_update_mask(::google::firestore::v1::DocumentMask* value) { +inline std::string* BatchGetDocumentsRequest::_internal_mutable_transaction() { PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); - if (GetArena() == nullptr) { - delete reinterpret_cast<::google::protobuf::MessageLite*>(_impl_.update_mask_); + if (consistency_selector_case() != kTransaction) { + clear_consistency_selector(); + + set_has_transaction(); + _impl_.consistency_selector_.transaction_.InitDefault(); + } + return _impl_.consistency_selector_.transaction_.Mutable( GetArena()); +} +inline std::string* BatchGetDocumentsRequest::release_transaction() { + PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); + // @@protoc_insertion_point(field_release:google.firestore.v1.BatchGetDocumentsRequest.transaction) + if (consistency_selector_case() != kTransaction) { + return nullptr; + } + clear_has_consistency_selector(); + return _impl_.consistency_selector_.transaction_.Release(); +} +inline void BatchGetDocumentsRequest::set_allocated_transaction(std::string* value) { + PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); + if (has_consistency_selector()) { + clear_consistency_selector(); } - _impl_.update_mask_ = reinterpret_cast<::google::firestore::v1::DocumentMask*>(value); if (value != nullptr) { - _impl_._has_bits_[0] |= 0x00000002u; + set_has_transaction(); + _impl_.consistency_selector_.transaction_.InitAllocated(value, GetArena()); + } + // @@protoc_insertion_point(field_set_allocated:google.firestore.v1.BatchGetDocumentsRequest.transaction) +} + +// .google.firestore.v1.TransactionOptions new_transaction = 5; +inline bool BatchGetDocumentsRequest::has_new_transaction() const { + return consistency_selector_case() == kNewTransaction; +} +inline bool BatchGetDocumentsRequest::_internal_has_new_transaction() const { + return consistency_selector_case() == kNewTransaction; +} +inline void BatchGetDocumentsRequest::set_has_new_transaction() { + _impl_._oneof_case_[0] = kNewTransaction; +} +inline ::google::firestore::v1::TransactionOptions* BatchGetDocumentsRequest::release_new_transaction() { + // @@protoc_insertion_point(field_release:google.firestore.v1.BatchGetDocumentsRequest.new_transaction) + if (consistency_selector_case() == kNewTransaction) { + clear_has_consistency_selector(); + auto* temp = _impl_.consistency_selector_.new_transaction_; + if (GetArena() != nullptr) { + temp = ::google::protobuf::internal::DuplicateIfNonNull(temp); + } + _impl_.consistency_selector_.new_transaction_ = nullptr; + return temp; } else { - _impl_._has_bits_[0] &= ~0x00000002u; + return nullptr; } - // @@protoc_insertion_point(field_unsafe_arena_set_allocated:google.firestore.v1.UpdateDocumentRequest.update_mask) } -inline ::google::firestore::v1::DocumentMask* UpdateDocumentRequest::release_update_mask() { - PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); +inline const ::google::firestore::v1::TransactionOptions& BatchGetDocumentsRequest::_internal_new_transaction() const { + return consistency_selector_case() == kNewTransaction ? *_impl_.consistency_selector_.new_transaction_ : reinterpret_cast<::google::firestore::v1::TransactionOptions&>(::google::firestore::v1::_TransactionOptions_default_instance_); +} +inline const ::google::firestore::v1::TransactionOptions& BatchGetDocumentsRequest::new_transaction() const ABSL_ATTRIBUTE_LIFETIME_BOUND { + // @@protoc_insertion_point(field_get:google.firestore.v1.BatchGetDocumentsRequest.new_transaction) + return _internal_new_transaction(); +} +inline ::google::firestore::v1::TransactionOptions* BatchGetDocumentsRequest::unsafe_arena_release_new_transaction() { + // @@protoc_insertion_point(field_unsafe_arena_release:google.firestore.v1.BatchGetDocumentsRequest.new_transaction) + if (consistency_selector_case() == kNewTransaction) { + clear_has_consistency_selector(); + auto* temp = _impl_.consistency_selector_.new_transaction_; + _impl_.consistency_selector_.new_transaction_ = nullptr; + return temp; + } else { + return nullptr; + } +} +inline void BatchGetDocumentsRequest::unsafe_arena_set_allocated_new_transaction(::google::firestore::v1::TransactionOptions* value) { + // We rely on the oneof clear method to free the earlier contents + // of this oneof. We can directly use the pointer we're given to + // set the new value. + clear_consistency_selector(); + if (value) { + set_has_new_transaction(); + _impl_.consistency_selector_.new_transaction_ = value; + } + // @@protoc_insertion_point(field_unsafe_arena_set_allocated:google.firestore.v1.BatchGetDocumentsRequest.new_transaction) +} +inline ::google::firestore::v1::TransactionOptions* BatchGetDocumentsRequest::_internal_mutable_new_transaction() { + if (consistency_selector_case() != kNewTransaction) { + clear_consistency_selector(); + set_has_new_transaction(); + _impl_.consistency_selector_.new_transaction_ = CreateMaybeMessage<::google::firestore::v1::TransactionOptions>(GetArena()); + } + return _impl_.consistency_selector_.new_transaction_; +} +inline ::google::firestore::v1::TransactionOptions* BatchGetDocumentsRequest::mutable_new_transaction() ABSL_ATTRIBUTE_LIFETIME_BOUND { + ::google::firestore::v1::TransactionOptions* _msg = _internal_mutable_new_transaction(); + // @@protoc_insertion_point(field_mutable:google.firestore.v1.BatchGetDocumentsRequest.new_transaction) + return _msg; +} - _impl_._has_bits_[0] &= ~0x00000002u; - ::google::firestore::v1::DocumentMask* released = _impl_.update_mask_; - _impl_.update_mask_ = nullptr; -#ifdef PROTOBUF_FORCE_COPY_IN_RELEASE - auto* old = reinterpret_cast<::google::protobuf::MessageLite*>(released); - released = ::google::protobuf::internal::DuplicateIfNonNull(released); - if (GetArena() == nullptr) { - delete old; +// .google.protobuf.Timestamp read_time = 7; +inline bool BatchGetDocumentsRequest::has_read_time() const { + return consistency_selector_case() == kReadTime; +} +inline bool BatchGetDocumentsRequest::_internal_has_read_time() const { + return consistency_selector_case() == kReadTime; +} +inline void BatchGetDocumentsRequest::set_has_read_time() { + _impl_._oneof_case_[0] = kReadTime; +} +inline ::google::protobuf::Timestamp* BatchGetDocumentsRequest::release_read_time() { + // @@protoc_insertion_point(field_release:google.firestore.v1.BatchGetDocumentsRequest.read_time) + if (consistency_selector_case() == kReadTime) { + clear_has_consistency_selector(); + auto* temp = _impl_.consistency_selector_.read_time_; + if (GetArena() != nullptr) { + temp = ::google::protobuf::internal::DuplicateIfNonNull(temp); + } + _impl_.consistency_selector_.read_time_ = nullptr; + return temp; + } else { + return nullptr; } -#else // PROTOBUF_FORCE_COPY_IN_RELEASE - if (GetArena() != nullptr) { - released = ::google::protobuf::internal::DuplicateIfNonNull(released); +} +inline const ::google::protobuf::Timestamp& BatchGetDocumentsRequest::_internal_read_time() const { + return consistency_selector_case() == kReadTime ? *_impl_.consistency_selector_.read_time_ : reinterpret_cast<::google::protobuf::Timestamp&>(::google::protobuf::_Timestamp_default_instance_); +} +inline const ::google::protobuf::Timestamp& BatchGetDocumentsRequest::read_time() const ABSL_ATTRIBUTE_LIFETIME_BOUND { + // @@protoc_insertion_point(field_get:google.firestore.v1.BatchGetDocumentsRequest.read_time) + return _internal_read_time(); +} +inline ::google::protobuf::Timestamp* BatchGetDocumentsRequest::unsafe_arena_release_read_time() { + // @@protoc_insertion_point(field_unsafe_arena_release:google.firestore.v1.BatchGetDocumentsRequest.read_time) + if (consistency_selector_case() == kReadTime) { + clear_has_consistency_selector(); + auto* temp = _impl_.consistency_selector_.read_time_; + _impl_.consistency_selector_.read_time_ = nullptr; + return temp; + } else { + return nullptr; + } +} +inline void BatchGetDocumentsRequest::unsafe_arena_set_allocated_read_time(::google::protobuf::Timestamp* value) { + // We rely on the oneof clear method to free the earlier contents + // of this oneof. We can directly use the pointer we're given to + // set the new value. + clear_consistency_selector(); + if (value) { + set_has_read_time(); + _impl_.consistency_selector_.read_time_ = value; + } + // @@protoc_insertion_point(field_unsafe_arena_set_allocated:google.firestore.v1.BatchGetDocumentsRequest.read_time) +} +inline ::google::protobuf::Timestamp* BatchGetDocumentsRequest::_internal_mutable_read_time() { + if (consistency_selector_case() != kReadTime) { + clear_consistency_selector(); + set_has_read_time(); + _impl_.consistency_selector_.read_time_ = CreateMaybeMessage<::google::protobuf::Timestamp>(GetArena()); } -#endif // !PROTOBUF_FORCE_COPY_IN_RELEASE - return released; + return _impl_.consistency_selector_.read_time_; +} +inline ::google::protobuf::Timestamp* BatchGetDocumentsRequest::mutable_read_time() ABSL_ATTRIBUTE_LIFETIME_BOUND { + ::google::protobuf::Timestamp* _msg = _internal_mutable_read_time(); + // @@protoc_insertion_point(field_mutable:google.firestore.v1.BatchGetDocumentsRequest.read_time) + return _msg; } -inline ::google::firestore::v1::DocumentMask* UpdateDocumentRequest::unsafe_arena_release_update_mask() { - PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); - // @@protoc_insertion_point(field_release:google.firestore.v1.UpdateDocumentRequest.update_mask) - _impl_._has_bits_[0] &= ~0x00000002u; - ::google::firestore::v1::DocumentMask* temp = _impl_.update_mask_; - _impl_.update_mask_ = nullptr; - return temp; +inline bool BatchGetDocumentsRequest::has_consistency_selector() const { + return consistency_selector_case() != CONSISTENCY_SELECTOR_NOT_SET; } -inline ::google::firestore::v1::DocumentMask* UpdateDocumentRequest::_internal_mutable_update_mask() { - PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); - _impl_._has_bits_[0] |= 0x00000002u; - if (_impl_.update_mask_ == nullptr) { - auto* p = CreateMaybeMessage<::google::firestore::v1::DocumentMask>(GetArena()); - _impl_.update_mask_ = reinterpret_cast<::google::firestore::v1::DocumentMask*>(p); - } - return _impl_.update_mask_; +inline void BatchGetDocumentsRequest::clear_has_consistency_selector() { + _impl_._oneof_case_[0] = CONSISTENCY_SELECTOR_NOT_SET; } -inline ::google::firestore::v1::DocumentMask* UpdateDocumentRequest::mutable_update_mask() ABSL_ATTRIBUTE_LIFETIME_BOUND { - ::google::firestore::v1::DocumentMask* _msg = _internal_mutable_update_mask(); - // @@protoc_insertion_point(field_mutable:google.firestore.v1.UpdateDocumentRequest.update_mask) - return _msg; +inline BatchGetDocumentsRequest::ConsistencySelectorCase BatchGetDocumentsRequest::consistency_selector_case() const { + return BatchGetDocumentsRequest::ConsistencySelectorCase(_impl_._oneof_case_[0]); } -inline void UpdateDocumentRequest::set_allocated_update_mask(::google::firestore::v1::DocumentMask* value) { - ::google::protobuf::Arena* message_arena = GetArena(); - PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); - if (message_arena == nullptr) { - delete reinterpret_cast<::google::protobuf::MessageLite*>(_impl_.update_mask_); - } +// ------------------------------------------------------------------- - if (value != nullptr) { - ::google::protobuf::Arena* submessage_arena = reinterpret_cast<::google::protobuf::MessageLite*>(value)->GetArena(); - if (message_arena != submessage_arena) { - value = ::google::protobuf::internal::GetOwnedMessage(message_arena, value, submessage_arena); +// BatchGetDocumentsResponse + +// .google.firestore.v1.Document found = 1; +inline bool BatchGetDocumentsResponse::has_found() const { + return result_case() == kFound; +} +inline bool BatchGetDocumentsResponse::_internal_has_found() const { + return result_case() == kFound; +} +inline void BatchGetDocumentsResponse::set_has_found() { + _impl_._oneof_case_[0] = kFound; +} +inline ::google::firestore::v1::Document* BatchGetDocumentsResponse::release_found() { + // @@protoc_insertion_point(field_release:google.firestore.v1.BatchGetDocumentsResponse.found) + if (result_case() == kFound) { + clear_has_result(); + auto* temp = _impl_.result_.found_; + if (GetArena() != nullptr) { + temp = ::google::protobuf::internal::DuplicateIfNonNull(temp); } - _impl_._has_bits_[0] |= 0x00000002u; + _impl_.result_.found_ = nullptr; + return temp; } else { - _impl_._has_bits_[0] &= ~0x00000002u; + return nullptr; } - - _impl_.update_mask_ = reinterpret_cast<::google::firestore::v1::DocumentMask*>(value); - // @@protoc_insertion_point(field_set_allocated:google.firestore.v1.UpdateDocumentRequest.update_mask) } - -// .google.firestore.v1.DocumentMask mask = 3; -inline bool UpdateDocumentRequest::has_mask() const { - bool value = (_impl_._has_bits_[0] & 0x00000004u) != 0; - PROTOBUF_ASSUME(!value || _impl_.mask_ != nullptr); - return value; -} -inline const ::google::firestore::v1::DocumentMask& UpdateDocumentRequest::_internal_mask() const { - PROTOBUF_TSAN_READ(&_impl_._tsan_detect_race); - const ::google::firestore::v1::DocumentMask* p = _impl_.mask_; - return p != nullptr ? *p : reinterpret_cast(::google::firestore::v1::_DocumentMask_default_instance_); +inline const ::google::firestore::v1::Document& BatchGetDocumentsResponse::_internal_found() const { + return result_case() == kFound ? *_impl_.result_.found_ : reinterpret_cast<::google::firestore::v1::Document&>(::google::firestore::v1::_Document_default_instance_); } -inline const ::google::firestore::v1::DocumentMask& UpdateDocumentRequest::mask() const ABSL_ATTRIBUTE_LIFETIME_BOUND { - // @@protoc_insertion_point(field_get:google.firestore.v1.UpdateDocumentRequest.mask) - return _internal_mask(); +inline const ::google::firestore::v1::Document& BatchGetDocumentsResponse::found() const ABSL_ATTRIBUTE_LIFETIME_BOUND { + // @@protoc_insertion_point(field_get:google.firestore.v1.BatchGetDocumentsResponse.found) + return _internal_found(); } -inline void UpdateDocumentRequest::unsafe_arena_set_allocated_mask(::google::firestore::v1::DocumentMask* value) { - PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); - if (GetArena() == nullptr) { - delete reinterpret_cast<::google::protobuf::MessageLite*>(_impl_.mask_); - } - _impl_.mask_ = reinterpret_cast<::google::firestore::v1::DocumentMask*>(value); - if (value != nullptr) { - _impl_._has_bits_[0] |= 0x00000004u; +inline ::google::firestore::v1::Document* BatchGetDocumentsResponse::unsafe_arena_release_found() { + // @@protoc_insertion_point(field_unsafe_arena_release:google.firestore.v1.BatchGetDocumentsResponse.found) + if (result_case() == kFound) { + clear_has_result(); + auto* temp = _impl_.result_.found_; + _impl_.result_.found_ = nullptr; + return temp; } else { - _impl_._has_bits_[0] &= ~0x00000004u; + return nullptr; } - // @@protoc_insertion_point(field_unsafe_arena_set_allocated:google.firestore.v1.UpdateDocumentRequest.mask) } -inline ::google::firestore::v1::DocumentMask* UpdateDocumentRequest::release_mask() { - PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); - - _impl_._has_bits_[0] &= ~0x00000004u; - ::google::firestore::v1::DocumentMask* released = _impl_.mask_; - _impl_.mask_ = nullptr; -#ifdef PROTOBUF_FORCE_COPY_IN_RELEASE - auto* old = reinterpret_cast<::google::protobuf::MessageLite*>(released); - released = ::google::protobuf::internal::DuplicateIfNonNull(released); - if (GetArena() == nullptr) { - delete old; +inline void BatchGetDocumentsResponse::unsafe_arena_set_allocated_found(::google::firestore::v1::Document* value) { + // We rely on the oneof clear method to free the earlier contents + // of this oneof. We can directly use the pointer we're given to + // set the new value. + clear_result(); + if (value) { + set_has_found(); + _impl_.result_.found_ = value; } -#else // PROTOBUF_FORCE_COPY_IN_RELEASE - if (GetArena() != nullptr) { - released = ::google::protobuf::internal::DuplicateIfNonNull(released); + // @@protoc_insertion_point(field_unsafe_arena_set_allocated:google.firestore.v1.BatchGetDocumentsResponse.found) +} +inline ::google::firestore::v1::Document* BatchGetDocumentsResponse::_internal_mutable_found() { + if (result_case() != kFound) { + clear_result(); + set_has_found(); + _impl_.result_.found_ = CreateMaybeMessage<::google::firestore::v1::Document>(GetArena()); } -#endif // !PROTOBUF_FORCE_COPY_IN_RELEASE - return released; + return _impl_.result_.found_; +} +inline ::google::firestore::v1::Document* BatchGetDocumentsResponse::mutable_found() ABSL_ATTRIBUTE_LIFETIME_BOUND { + ::google::firestore::v1::Document* _msg = _internal_mutable_found(); + // @@protoc_insertion_point(field_mutable:google.firestore.v1.BatchGetDocumentsResponse.found) + return _msg; } -inline ::google::firestore::v1::DocumentMask* UpdateDocumentRequest::unsafe_arena_release_mask() { - PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); - // @@protoc_insertion_point(field_release:google.firestore.v1.UpdateDocumentRequest.mask) - _impl_._has_bits_[0] &= ~0x00000004u; - ::google::firestore::v1::DocumentMask* temp = _impl_.mask_; - _impl_.mask_ = nullptr; - return temp; +// string missing = 2; +inline bool BatchGetDocumentsResponse::has_missing() const { + return result_case() == kMissing; } -inline ::google::firestore::v1::DocumentMask* UpdateDocumentRequest::_internal_mutable_mask() { +inline void BatchGetDocumentsResponse::set_has_missing() { + _impl_._oneof_case_[0] = kMissing; +} +inline void BatchGetDocumentsResponse::clear_missing() { PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); - _impl_._has_bits_[0] |= 0x00000004u; - if (_impl_.mask_ == nullptr) { - auto* p = CreateMaybeMessage<::google::firestore::v1::DocumentMask>(GetArena()); - _impl_.mask_ = reinterpret_cast<::google::firestore::v1::DocumentMask*>(p); + if (result_case() == kMissing) { + _impl_.result_.missing_.Destroy(); + clear_has_result(); } - return _impl_.mask_; } -inline ::google::firestore::v1::DocumentMask* UpdateDocumentRequest::mutable_mask() ABSL_ATTRIBUTE_LIFETIME_BOUND { - ::google::firestore::v1::DocumentMask* _msg = _internal_mutable_mask(); - // @@protoc_insertion_point(field_mutable:google.firestore.v1.UpdateDocumentRequest.mask) - return _msg; +inline const std::string& BatchGetDocumentsResponse::missing() const + ABSL_ATTRIBUTE_LIFETIME_BOUND { + // @@protoc_insertion_point(field_get:google.firestore.v1.BatchGetDocumentsResponse.missing) + return _internal_missing(); } -inline void UpdateDocumentRequest::set_allocated_mask(::google::firestore::v1::DocumentMask* value) { - ::google::protobuf::Arena* message_arena = GetArena(); +template +inline PROTOBUF_ALWAYS_INLINE void BatchGetDocumentsResponse::set_missing(Arg_&& arg, + Args_... args) { PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); - if (message_arena == nullptr) { - delete reinterpret_cast<::google::protobuf::MessageLite*>(_impl_.mask_); - } + if (result_case() != kMissing) { + clear_result(); - if (value != nullptr) { - ::google::protobuf::Arena* submessage_arena = reinterpret_cast<::google::protobuf::MessageLite*>(value)->GetArena(); - if (message_arena != submessage_arena) { - value = ::google::protobuf::internal::GetOwnedMessage(message_arena, value, submessage_arena); - } - _impl_._has_bits_[0] |= 0x00000004u; - } else { - _impl_._has_bits_[0] &= ~0x00000004u; + set_has_missing(); + _impl_.result_.missing_.InitDefault(); } - - _impl_.mask_ = reinterpret_cast<::google::firestore::v1::DocumentMask*>(value); - // @@protoc_insertion_point(field_set_allocated:google.firestore.v1.UpdateDocumentRequest.mask) + _impl_.result_.missing_.Set(static_cast(arg), args..., GetArena()); + // @@protoc_insertion_point(field_set:google.firestore.v1.BatchGetDocumentsResponse.missing) } - -// .google.firestore.v1.Precondition current_document = 4; -inline bool UpdateDocumentRequest::has_current_document() const { - bool value = (_impl_._has_bits_[0] & 0x00000008u) != 0; - PROTOBUF_ASSUME(!value || _impl_.current_document_ != nullptr); - return value; +inline std::string* BatchGetDocumentsResponse::mutable_missing() ABSL_ATTRIBUTE_LIFETIME_BOUND { + std::string* _s = _internal_mutable_missing(); + // @@protoc_insertion_point(field_mutable:google.firestore.v1.BatchGetDocumentsResponse.missing) + return _s; } -inline const ::google::firestore::v1::Precondition& UpdateDocumentRequest::_internal_current_document() const { +inline const std::string& BatchGetDocumentsResponse::_internal_missing() const { PROTOBUF_TSAN_READ(&_impl_._tsan_detect_race); - const ::google::firestore::v1::Precondition* p = _impl_.current_document_; - return p != nullptr ? *p : reinterpret_cast(::google::firestore::v1::_Precondition_default_instance_); -} -inline const ::google::firestore::v1::Precondition& UpdateDocumentRequest::current_document() const ABSL_ATTRIBUTE_LIFETIME_BOUND { - // @@protoc_insertion_point(field_get:google.firestore.v1.UpdateDocumentRequest.current_document) - return _internal_current_document(); -} -inline void UpdateDocumentRequest::unsafe_arena_set_allocated_current_document(::google::firestore::v1::Precondition* value) { - PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); - if (GetArena() == nullptr) { - delete reinterpret_cast<::google::protobuf::MessageLite*>(_impl_.current_document_); - } - _impl_.current_document_ = reinterpret_cast<::google::firestore::v1::Precondition*>(value); - if (value != nullptr) { - _impl_._has_bits_[0] |= 0x00000008u; - } else { - _impl_._has_bits_[0] &= ~0x00000008u; + if (result_case() != kMissing) { + return ::google::protobuf::internal::GetEmptyStringAlreadyInited(); } - // @@protoc_insertion_point(field_unsafe_arena_set_allocated:google.firestore.v1.UpdateDocumentRequest.current_document) + return _impl_.result_.missing_.Get(); } -inline ::google::firestore::v1::Precondition* UpdateDocumentRequest::release_current_document() { +inline void BatchGetDocumentsResponse::_internal_set_missing(const std::string& value) { PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); + if (result_case() != kMissing) { + clear_result(); - _impl_._has_bits_[0] &= ~0x00000008u; - ::google::firestore::v1::Precondition* released = _impl_.current_document_; - _impl_.current_document_ = nullptr; -#ifdef PROTOBUF_FORCE_COPY_IN_RELEASE - auto* old = reinterpret_cast<::google::protobuf::MessageLite*>(released); - released = ::google::protobuf::internal::DuplicateIfNonNull(released); - if (GetArena() == nullptr) { - delete old; - } -#else // PROTOBUF_FORCE_COPY_IN_RELEASE - if (GetArena() != nullptr) { - released = ::google::protobuf::internal::DuplicateIfNonNull(released); + set_has_missing(); + _impl_.result_.missing_.InitDefault(); } -#endif // !PROTOBUF_FORCE_COPY_IN_RELEASE - return released; + _impl_.result_.missing_.Set(value, GetArena()); } -inline ::google::firestore::v1::Precondition* UpdateDocumentRequest::unsafe_arena_release_current_document() { +inline std::string* BatchGetDocumentsResponse::_internal_mutable_missing() { PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); - // @@protoc_insertion_point(field_release:google.firestore.v1.UpdateDocumentRequest.current_document) + if (result_case() != kMissing) { + clear_result(); - _impl_._has_bits_[0] &= ~0x00000008u; - ::google::firestore::v1::Precondition* temp = _impl_.current_document_; - _impl_.current_document_ = nullptr; - return temp; + set_has_missing(); + _impl_.result_.missing_.InitDefault(); + } + return _impl_.result_.missing_.Mutable( GetArena()); } -inline ::google::firestore::v1::Precondition* UpdateDocumentRequest::_internal_mutable_current_document() { +inline std::string* BatchGetDocumentsResponse::release_missing() { PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); - _impl_._has_bits_[0] |= 0x00000008u; - if (_impl_.current_document_ == nullptr) { - auto* p = CreateMaybeMessage<::google::firestore::v1::Precondition>(GetArena()); - _impl_.current_document_ = reinterpret_cast<::google::firestore::v1::Precondition*>(p); + // @@protoc_insertion_point(field_release:google.firestore.v1.BatchGetDocumentsResponse.missing) + if (result_case() != kMissing) { + return nullptr; } - return _impl_.current_document_; -} -inline ::google::firestore::v1::Precondition* UpdateDocumentRequest::mutable_current_document() ABSL_ATTRIBUTE_LIFETIME_BOUND { - ::google::firestore::v1::Precondition* _msg = _internal_mutable_current_document(); - // @@protoc_insertion_point(field_mutable:google.firestore.v1.UpdateDocumentRequest.current_document) - return _msg; + clear_has_result(); + return _impl_.result_.missing_.Release(); } -inline void UpdateDocumentRequest::set_allocated_current_document(::google::firestore::v1::Precondition* value) { - ::google::protobuf::Arena* message_arena = GetArena(); +inline void BatchGetDocumentsResponse::set_allocated_missing(std::string* value) { PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); - if (message_arena == nullptr) { - delete reinterpret_cast<::google::protobuf::MessageLite*>(_impl_.current_document_); + if (has_result()) { + clear_result(); } - if (value != nullptr) { - ::google::protobuf::Arena* submessage_arena = reinterpret_cast<::google::protobuf::MessageLite*>(value)->GetArena(); - if (message_arena != submessage_arena) { - value = ::google::protobuf::internal::GetOwnedMessage(message_arena, value, submessage_arena); - } - _impl_._has_bits_[0] |= 0x00000008u; - } else { - _impl_._has_bits_[0] &= ~0x00000008u; + set_has_missing(); + _impl_.result_.missing_.InitAllocated(value, GetArena()); } - - _impl_.current_document_ = reinterpret_cast<::google::firestore::v1::Precondition*>(value); - // @@protoc_insertion_point(field_set_allocated:google.firestore.v1.UpdateDocumentRequest.current_document) + // @@protoc_insertion_point(field_set_allocated:google.firestore.v1.BatchGetDocumentsResponse.missing) } -// ------------------------------------------------------------------- - -// DeleteDocumentRequest - -// string name = 1; -inline void DeleteDocumentRequest::clear_name() { +// bytes transaction = 3; +inline void BatchGetDocumentsResponse::clear_transaction() { PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); - _impl_.name_.ClearToEmpty(); + _impl_.transaction_.ClearToEmpty(); } -inline const std::string& DeleteDocumentRequest::name() const +inline const std::string& BatchGetDocumentsResponse::transaction() const ABSL_ATTRIBUTE_LIFETIME_BOUND { - // @@protoc_insertion_point(field_get:google.firestore.v1.DeleteDocumentRequest.name) - return _internal_name(); + // @@protoc_insertion_point(field_get:google.firestore.v1.BatchGetDocumentsResponse.transaction) + return _internal_transaction(); } template -inline PROTOBUF_ALWAYS_INLINE void DeleteDocumentRequest::set_name(Arg_&& arg, +inline PROTOBUF_ALWAYS_INLINE void BatchGetDocumentsResponse::set_transaction(Arg_&& arg, Args_... args) { PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); ; - _impl_.name_.Set(static_cast(arg), args..., GetArena()); - // @@protoc_insertion_point(field_set:google.firestore.v1.DeleteDocumentRequest.name) + _impl_.transaction_.SetBytes(static_cast(arg), args..., GetArena()); + // @@protoc_insertion_point(field_set:google.firestore.v1.BatchGetDocumentsResponse.transaction) } -inline std::string* DeleteDocumentRequest::mutable_name() ABSL_ATTRIBUTE_LIFETIME_BOUND { - std::string* _s = _internal_mutable_name(); - // @@protoc_insertion_point(field_mutable:google.firestore.v1.DeleteDocumentRequest.name) +inline std::string* BatchGetDocumentsResponse::mutable_transaction() ABSL_ATTRIBUTE_LIFETIME_BOUND { + std::string* _s = _internal_mutable_transaction(); + // @@protoc_insertion_point(field_mutable:google.firestore.v1.BatchGetDocumentsResponse.transaction) return _s; } -inline const std::string& DeleteDocumentRequest::_internal_name() const { +inline const std::string& BatchGetDocumentsResponse::_internal_transaction() const { PROTOBUF_TSAN_READ(&_impl_._tsan_detect_race); - return _impl_.name_.Get(); + return _impl_.transaction_.Get(); } -inline void DeleteDocumentRequest::_internal_set_name(const std::string& value) { +inline void BatchGetDocumentsResponse::_internal_set_transaction(const std::string& value) { PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); ; - _impl_.name_.Set(value, GetArena()); + _impl_.transaction_.Set(value, GetArena()); } -inline std::string* DeleteDocumentRequest::_internal_mutable_name() { +inline std::string* BatchGetDocumentsResponse::_internal_mutable_transaction() { PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); ; - return _impl_.name_.Mutable( GetArena()); + return _impl_.transaction_.Mutable( GetArena()); } -inline std::string* DeleteDocumentRequest::release_name() { +inline std::string* BatchGetDocumentsResponse::release_transaction() { PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); - // @@protoc_insertion_point(field_release:google.firestore.v1.DeleteDocumentRequest.name) - return _impl_.name_.Release(); + // @@protoc_insertion_point(field_release:google.firestore.v1.BatchGetDocumentsResponse.transaction) + return _impl_.transaction_.Release(); } -inline void DeleteDocumentRequest::set_allocated_name(std::string* value) { +inline void BatchGetDocumentsResponse::set_allocated_transaction(std::string* value) { PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); - _impl_.name_.SetAllocated(value, GetArena()); + _impl_.transaction_.SetAllocated(value, GetArena()); #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING - if (_impl_.name_.IsDefault()) { - _impl_.name_.Set("", GetArena()); + if (_impl_.transaction_.IsDefault()) { + _impl_.transaction_.Set("", GetArena()); } #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING - // @@protoc_insertion_point(field_set_allocated:google.firestore.v1.DeleteDocumentRequest.name) + // @@protoc_insertion_point(field_set_allocated:google.firestore.v1.BatchGetDocumentsResponse.transaction) } -// .google.firestore.v1.Precondition current_document = 2; -inline bool DeleteDocumentRequest::has_current_document() const { +// .google.protobuf.Timestamp read_time = 4; +inline bool BatchGetDocumentsResponse::has_read_time() const { bool value = (_impl_._has_bits_[0] & 0x00000001u) != 0; - PROTOBUF_ASSUME(!value || _impl_.current_document_ != nullptr); + PROTOBUF_ASSUME(!value || _impl_.read_time_ != nullptr); return value; } -inline const ::google::firestore::v1::Precondition& DeleteDocumentRequest::_internal_current_document() const { +inline const ::google::protobuf::Timestamp& BatchGetDocumentsResponse::_internal_read_time() const { PROTOBUF_TSAN_READ(&_impl_._tsan_detect_race); - const ::google::firestore::v1::Precondition* p = _impl_.current_document_; - return p != nullptr ? *p : reinterpret_cast(::google::firestore::v1::_Precondition_default_instance_); + const ::google::protobuf::Timestamp* p = _impl_.read_time_; + return p != nullptr ? *p : reinterpret_cast(::google::protobuf::_Timestamp_default_instance_); } -inline const ::google::firestore::v1::Precondition& DeleteDocumentRequest::current_document() const ABSL_ATTRIBUTE_LIFETIME_BOUND { - // @@protoc_insertion_point(field_get:google.firestore.v1.DeleteDocumentRequest.current_document) - return _internal_current_document(); +inline const ::google::protobuf::Timestamp& BatchGetDocumentsResponse::read_time() const ABSL_ATTRIBUTE_LIFETIME_BOUND { + // @@protoc_insertion_point(field_get:google.firestore.v1.BatchGetDocumentsResponse.read_time) + return _internal_read_time(); } -inline void DeleteDocumentRequest::unsafe_arena_set_allocated_current_document(::google::firestore::v1::Precondition* value) { +inline void BatchGetDocumentsResponse::unsafe_arena_set_allocated_read_time(::google::protobuf::Timestamp* value) { PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); if (GetArena() == nullptr) { - delete reinterpret_cast<::google::protobuf::MessageLite*>(_impl_.current_document_); + delete reinterpret_cast<::google::protobuf::MessageLite*>(_impl_.read_time_); } - _impl_.current_document_ = reinterpret_cast<::google::firestore::v1::Precondition*>(value); + _impl_.read_time_ = reinterpret_cast<::google::protobuf::Timestamp*>(value); if (value != nullptr) { _impl_._has_bits_[0] |= 0x00000001u; } else { _impl_._has_bits_[0] &= ~0x00000001u; } - // @@protoc_insertion_point(field_unsafe_arena_set_allocated:google.firestore.v1.DeleteDocumentRequest.current_document) + // @@protoc_insertion_point(field_unsafe_arena_set_allocated:google.firestore.v1.BatchGetDocumentsResponse.read_time) } -inline ::google::firestore::v1::Precondition* DeleteDocumentRequest::release_current_document() { +inline ::google::protobuf::Timestamp* BatchGetDocumentsResponse::release_read_time() { PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); _impl_._has_bits_[0] &= ~0x00000001u; - ::google::firestore::v1::Precondition* released = _impl_.current_document_; - _impl_.current_document_ = nullptr; + ::google::protobuf::Timestamp* released = _impl_.read_time_; + _impl_.read_time_ = nullptr; #ifdef PROTOBUF_FORCE_COPY_IN_RELEASE auto* old = reinterpret_cast<::google::protobuf::MessageLite*>(released); released = ::google::protobuf::internal::DuplicateIfNonNull(released); @@ -8603,34 +9924,34 @@ inline ::google::firestore::v1::Precondition* DeleteDocumentRequest::release_cur #endif // !PROTOBUF_FORCE_COPY_IN_RELEASE return released; } -inline ::google::firestore::v1::Precondition* DeleteDocumentRequest::unsafe_arena_release_current_document() { +inline ::google::protobuf::Timestamp* BatchGetDocumentsResponse::unsafe_arena_release_read_time() { PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); - // @@protoc_insertion_point(field_release:google.firestore.v1.DeleteDocumentRequest.current_document) + // @@protoc_insertion_point(field_release:google.firestore.v1.BatchGetDocumentsResponse.read_time) _impl_._has_bits_[0] &= ~0x00000001u; - ::google::firestore::v1::Precondition* temp = _impl_.current_document_; - _impl_.current_document_ = nullptr; + ::google::protobuf::Timestamp* temp = _impl_.read_time_; + _impl_.read_time_ = nullptr; return temp; } -inline ::google::firestore::v1::Precondition* DeleteDocumentRequest::_internal_mutable_current_document() { +inline ::google::protobuf::Timestamp* BatchGetDocumentsResponse::_internal_mutable_read_time() { PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); _impl_._has_bits_[0] |= 0x00000001u; - if (_impl_.current_document_ == nullptr) { - auto* p = CreateMaybeMessage<::google::firestore::v1::Precondition>(GetArena()); - _impl_.current_document_ = reinterpret_cast<::google::firestore::v1::Precondition*>(p); + if (_impl_.read_time_ == nullptr) { + auto* p = CreateMaybeMessage<::google::protobuf::Timestamp>(GetArena()); + _impl_.read_time_ = reinterpret_cast<::google::protobuf::Timestamp*>(p); } - return _impl_.current_document_; + return _impl_.read_time_; } -inline ::google::firestore::v1::Precondition* DeleteDocumentRequest::mutable_current_document() ABSL_ATTRIBUTE_LIFETIME_BOUND { - ::google::firestore::v1::Precondition* _msg = _internal_mutable_current_document(); - // @@protoc_insertion_point(field_mutable:google.firestore.v1.DeleteDocumentRequest.current_document) +inline ::google::protobuf::Timestamp* BatchGetDocumentsResponse::mutable_read_time() ABSL_ATTRIBUTE_LIFETIME_BOUND { + ::google::protobuf::Timestamp* _msg = _internal_mutable_read_time(); + // @@protoc_insertion_point(field_mutable:google.firestore.v1.BatchGetDocumentsResponse.read_time) return _msg; } -inline void DeleteDocumentRequest::set_allocated_current_document(::google::firestore::v1::Precondition* value) { +inline void BatchGetDocumentsResponse::set_allocated_read_time(::google::protobuf::Timestamp* value) { ::google::protobuf::Arena* message_arena = GetArena(); PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); if (message_arena == nullptr) { - delete reinterpret_cast<::google::protobuf::MessageLite*>(_impl_.current_document_); + delete reinterpret_cast<::google::protobuf::MessageLite*>(_impl_.read_time_); } if (value != nullptr) { @@ -8642,203 +9963,111 @@ inline void DeleteDocumentRequest::set_allocated_current_document(::google::fire } else { _impl_._has_bits_[0] &= ~0x00000001u; } - - _impl_.current_document_ = reinterpret_cast<::google::firestore::v1::Precondition*>(value); - // @@protoc_insertion_point(field_set_allocated:google.firestore.v1.DeleteDocumentRequest.current_document) -} - -// ------------------------------------------------------------------- - -// BatchGetDocumentsRequest - -// string database = 1; -inline void BatchGetDocumentsRequest::clear_database() { - PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); - _impl_.database_.ClearToEmpty(); -} -inline const std::string& BatchGetDocumentsRequest::database() const - ABSL_ATTRIBUTE_LIFETIME_BOUND { - // @@protoc_insertion_point(field_get:google.firestore.v1.BatchGetDocumentsRequest.database) - return _internal_database(); -} -template -inline PROTOBUF_ALWAYS_INLINE void BatchGetDocumentsRequest::set_database(Arg_&& arg, - Args_... args) { - PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); - ; - _impl_.database_.Set(static_cast(arg), args..., GetArena()); - // @@protoc_insertion_point(field_set:google.firestore.v1.BatchGetDocumentsRequest.database) -} -inline std::string* BatchGetDocumentsRequest::mutable_database() ABSL_ATTRIBUTE_LIFETIME_BOUND { - std::string* _s = _internal_mutable_database(); - // @@protoc_insertion_point(field_mutable:google.firestore.v1.BatchGetDocumentsRequest.database) - return _s; -} -inline const std::string& BatchGetDocumentsRequest::_internal_database() const { - PROTOBUF_TSAN_READ(&_impl_._tsan_detect_race); - return _impl_.database_.Get(); -} -inline void BatchGetDocumentsRequest::_internal_set_database(const std::string& value) { - PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); - ; - _impl_.database_.Set(value, GetArena()); -} -inline std::string* BatchGetDocumentsRequest::_internal_mutable_database() { - PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); - ; - return _impl_.database_.Mutable( GetArena()); -} -inline std::string* BatchGetDocumentsRequest::release_database() { - PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); - // @@protoc_insertion_point(field_release:google.firestore.v1.BatchGetDocumentsRequest.database) - return _impl_.database_.Release(); -} -inline void BatchGetDocumentsRequest::set_allocated_database(std::string* value) { - PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); - _impl_.database_.SetAllocated(value, GetArena()); - #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING - if (_impl_.database_.IsDefault()) { - _impl_.database_.Set("", GetArena()); - } - #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING - // @@protoc_insertion_point(field_set_allocated:google.firestore.v1.BatchGetDocumentsRequest.database) -} - -// repeated string documents = 2; -inline int BatchGetDocumentsRequest::_internal_documents_size() const { - return _internal_documents().size(); -} -inline int BatchGetDocumentsRequest::documents_size() const { - return _internal_documents_size(); -} -inline void BatchGetDocumentsRequest::clear_documents() { - PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); - _impl_.documents_.Clear(); -} -inline std::string* BatchGetDocumentsRequest::add_documents() - ABSL_ATTRIBUTE_LIFETIME_BOUND { - PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); - std::string* _s = _internal_mutable_documents()->Add(); - // @@protoc_insertion_point(field_add_mutable:google.firestore.v1.BatchGetDocumentsRequest.documents) - return _s; -} -inline const std::string& BatchGetDocumentsRequest::documents(int index) const - ABSL_ATTRIBUTE_LIFETIME_BOUND { - // @@protoc_insertion_point(field_get:google.firestore.v1.BatchGetDocumentsRequest.documents) - return _internal_documents().Get(index); -} -inline std::string* BatchGetDocumentsRequest::mutable_documents(int index) - ABSL_ATTRIBUTE_LIFETIME_BOUND { - // @@protoc_insertion_point(field_mutable:google.firestore.v1.BatchGetDocumentsRequest.documents) - return _internal_mutable_documents()->Mutable(index); + + _impl_.read_time_ = reinterpret_cast<::google::protobuf::Timestamp*>(value); + // @@protoc_insertion_point(field_set_allocated:google.firestore.v1.BatchGetDocumentsResponse.read_time) } -inline void BatchGetDocumentsRequest::set_documents(int index, const std::string& value) { - _internal_mutable_documents()->Mutable(index)->assign(value); - // @@protoc_insertion_point(field_set:google.firestore.v1.BatchGetDocumentsRequest.documents) + +inline bool BatchGetDocumentsResponse::has_result() const { + return result_case() != RESULT_NOT_SET; } -inline void BatchGetDocumentsRequest::set_documents(int index, std::string&& value) { - _internal_mutable_documents()->Mutable(index)->assign(std::move(value)); - // @@protoc_insertion_point(field_set:google.firestore.v1.BatchGetDocumentsRequest.documents) +inline void BatchGetDocumentsResponse::clear_has_result() { + _impl_._oneof_case_[0] = RESULT_NOT_SET; } -inline void BatchGetDocumentsRequest::set_documents(int index, const char* value) { - ABSL_DCHECK(value != nullptr); - _internal_mutable_documents()->Mutable(index)->assign(value); - // @@protoc_insertion_point(field_set_char:google.firestore.v1.BatchGetDocumentsRequest.documents) +inline BatchGetDocumentsResponse::ResultCase BatchGetDocumentsResponse::result_case() const { + return BatchGetDocumentsResponse::ResultCase(_impl_._oneof_case_[0]); } -inline void BatchGetDocumentsRequest::set_documents(int index, const char* value, - std::size_t size) { - _internal_mutable_documents()->Mutable(index)->assign( - reinterpret_cast(value), size); - // @@protoc_insertion_point(field_set_pointer:google.firestore.v1.BatchGetDocumentsRequest.documents) +// ------------------------------------------------------------------- + +// BeginTransactionRequest + +// string database = 1; +inline void BeginTransactionRequest::clear_database() { + PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); + _impl_.database_.ClearToEmpty(); } -inline void BatchGetDocumentsRequest::set_documents(int index, absl::string_view value) { - _internal_mutable_documents()->Mutable(index)->assign(value.data(), - value.size()); - // @@protoc_insertion_point(field_set_string_piece:google.firestore.v1.BatchGetDocumentsRequest.documents) +inline const std::string& BeginTransactionRequest::database() const + ABSL_ATTRIBUTE_LIFETIME_BOUND { + // @@protoc_insertion_point(field_get:google.firestore.v1.BeginTransactionRequest.database) + return _internal_database(); } -inline void BatchGetDocumentsRequest::add_documents(const std::string& value) { +template +inline PROTOBUF_ALWAYS_INLINE void BeginTransactionRequest::set_database(Arg_&& arg, + Args_... args) { PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); - _internal_mutable_documents()->Add()->assign(value); - // @@protoc_insertion_point(field_add:google.firestore.v1.BatchGetDocumentsRequest.documents) + ; + _impl_.database_.Set(static_cast(arg), args..., GetArena()); + // @@protoc_insertion_point(field_set:google.firestore.v1.BeginTransactionRequest.database) } -inline void BatchGetDocumentsRequest::add_documents(std::string&& value) { - PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); - _internal_mutable_documents()->Add(std::move(value)); - // @@protoc_insertion_point(field_add:google.firestore.v1.BatchGetDocumentsRequest.documents) +inline std::string* BeginTransactionRequest::mutable_database() ABSL_ATTRIBUTE_LIFETIME_BOUND { + std::string* _s = _internal_mutable_database(); + // @@protoc_insertion_point(field_mutable:google.firestore.v1.BeginTransactionRequest.database) + return _s; } -inline void BatchGetDocumentsRequest::add_documents(const char* value) { - ABSL_DCHECK(value != nullptr); - PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); - _internal_mutable_documents()->Add()->assign(value); - // @@protoc_insertion_point(field_add_char:google.firestore.v1.BatchGetDocumentsRequest.documents) +inline const std::string& BeginTransactionRequest::_internal_database() const { + PROTOBUF_TSAN_READ(&_impl_._tsan_detect_race); + return _impl_.database_.Get(); } -inline void BatchGetDocumentsRequest::add_documents(const char* value, std::size_t size) { +inline void BeginTransactionRequest::_internal_set_database(const std::string& value) { PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); - _internal_mutable_documents()->Add()->assign( - reinterpret_cast(value), size); - // @@protoc_insertion_point(field_add_pointer:google.firestore.v1.BatchGetDocumentsRequest.documents) + ; + _impl_.database_.Set(value, GetArena()); } -inline void BatchGetDocumentsRequest::add_documents(absl::string_view value) { +inline std::string* BeginTransactionRequest::_internal_mutable_database() { PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); - _internal_mutable_documents()->Add()->assign(value.data(), value.size()); - // @@protoc_insertion_point(field_add_string_piece:google.firestore.v1.BatchGetDocumentsRequest.documents) -} -inline const ::google::protobuf::RepeatedPtrField& -BatchGetDocumentsRequest::documents() const ABSL_ATTRIBUTE_LIFETIME_BOUND { - // @@protoc_insertion_point(field_list:google.firestore.v1.BatchGetDocumentsRequest.documents) - return _internal_documents(); + ; + return _impl_.database_.Mutable( GetArena()); } -inline ::google::protobuf::RepeatedPtrField* -BatchGetDocumentsRequest::mutable_documents() ABSL_ATTRIBUTE_LIFETIME_BOUND { - // @@protoc_insertion_point(field_mutable_list:google.firestore.v1.BatchGetDocumentsRequest.documents) +inline std::string* BeginTransactionRequest::release_database() { PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); - return _internal_mutable_documents(); -} -inline const ::google::protobuf::RepeatedPtrField& -BatchGetDocumentsRequest::_internal_documents() const { - PROTOBUF_TSAN_READ(&_impl_._tsan_detect_race); - return _impl_.documents_; + // @@protoc_insertion_point(field_release:google.firestore.v1.BeginTransactionRequest.database) + return _impl_.database_.Release(); } -inline ::google::protobuf::RepeatedPtrField* -BatchGetDocumentsRequest::_internal_mutable_documents() { - PROTOBUF_TSAN_READ(&_impl_._tsan_detect_race); - return &_impl_.documents_; +inline void BeginTransactionRequest::set_allocated_database(std::string* value) { + PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); + _impl_.database_.SetAllocated(value, GetArena()); + #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING + if (_impl_.database_.IsDefault()) { + _impl_.database_.Set("", GetArena()); + } + #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING + // @@protoc_insertion_point(field_set_allocated:google.firestore.v1.BeginTransactionRequest.database) } -// .google.firestore.v1.DocumentMask mask = 3; -inline bool BatchGetDocumentsRequest::has_mask() const { +// .google.firestore.v1.TransactionOptions options = 2; +inline bool BeginTransactionRequest::has_options() const { bool value = (_impl_._has_bits_[0] & 0x00000001u) != 0; - PROTOBUF_ASSUME(!value || _impl_.mask_ != nullptr); + PROTOBUF_ASSUME(!value || _impl_.options_ != nullptr); return value; } -inline const ::google::firestore::v1::DocumentMask& BatchGetDocumentsRequest::_internal_mask() const { +inline const ::google::firestore::v1::TransactionOptions& BeginTransactionRequest::_internal_options() const { PROTOBUF_TSAN_READ(&_impl_._tsan_detect_race); - const ::google::firestore::v1::DocumentMask* p = _impl_.mask_; - return p != nullptr ? *p : reinterpret_cast(::google::firestore::v1::_DocumentMask_default_instance_); + const ::google::firestore::v1::TransactionOptions* p = _impl_.options_; + return p != nullptr ? *p : reinterpret_cast(::google::firestore::v1::_TransactionOptions_default_instance_); } -inline const ::google::firestore::v1::DocumentMask& BatchGetDocumentsRequest::mask() const ABSL_ATTRIBUTE_LIFETIME_BOUND { - // @@protoc_insertion_point(field_get:google.firestore.v1.BatchGetDocumentsRequest.mask) - return _internal_mask(); +inline const ::google::firestore::v1::TransactionOptions& BeginTransactionRequest::options() const ABSL_ATTRIBUTE_LIFETIME_BOUND { + // @@protoc_insertion_point(field_get:google.firestore.v1.BeginTransactionRequest.options) + return _internal_options(); } -inline void BatchGetDocumentsRequest::unsafe_arena_set_allocated_mask(::google::firestore::v1::DocumentMask* value) { +inline void BeginTransactionRequest::unsafe_arena_set_allocated_options(::google::firestore::v1::TransactionOptions* value) { PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); if (GetArena() == nullptr) { - delete reinterpret_cast<::google::protobuf::MessageLite*>(_impl_.mask_); + delete reinterpret_cast<::google::protobuf::MessageLite*>(_impl_.options_); } - _impl_.mask_ = reinterpret_cast<::google::firestore::v1::DocumentMask*>(value); + _impl_.options_ = reinterpret_cast<::google::firestore::v1::TransactionOptions*>(value); if (value != nullptr) { _impl_._has_bits_[0] |= 0x00000001u; } else { _impl_._has_bits_[0] &= ~0x00000001u; } - // @@protoc_insertion_point(field_unsafe_arena_set_allocated:google.firestore.v1.BatchGetDocumentsRequest.mask) + // @@protoc_insertion_point(field_unsafe_arena_set_allocated:google.firestore.v1.BeginTransactionRequest.options) } -inline ::google::firestore::v1::DocumentMask* BatchGetDocumentsRequest::release_mask() { +inline ::google::firestore::v1::TransactionOptions* BeginTransactionRequest::release_options() { PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); _impl_._has_bits_[0] &= ~0x00000001u; - ::google::firestore::v1::DocumentMask* released = _impl_.mask_; - _impl_.mask_ = nullptr; + ::google::firestore::v1::TransactionOptions* released = _impl_.options_; + _impl_.options_ = nullptr; #ifdef PROTOBUF_FORCE_COPY_IN_RELEASE auto* old = reinterpret_cast<::google::protobuf::MessageLite*>(released); released = ::google::protobuf::internal::DuplicateIfNonNull(released); @@ -8852,34 +10081,34 @@ inline ::google::firestore::v1::DocumentMask* BatchGetDocumentsRequest::release_ #endif // !PROTOBUF_FORCE_COPY_IN_RELEASE return released; } -inline ::google::firestore::v1::DocumentMask* BatchGetDocumentsRequest::unsafe_arena_release_mask() { +inline ::google::firestore::v1::TransactionOptions* BeginTransactionRequest::unsafe_arena_release_options() { PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); - // @@protoc_insertion_point(field_release:google.firestore.v1.BatchGetDocumentsRequest.mask) + // @@protoc_insertion_point(field_release:google.firestore.v1.BeginTransactionRequest.options) _impl_._has_bits_[0] &= ~0x00000001u; - ::google::firestore::v1::DocumentMask* temp = _impl_.mask_; - _impl_.mask_ = nullptr; + ::google::firestore::v1::TransactionOptions* temp = _impl_.options_; + _impl_.options_ = nullptr; return temp; } -inline ::google::firestore::v1::DocumentMask* BatchGetDocumentsRequest::_internal_mutable_mask() { +inline ::google::firestore::v1::TransactionOptions* BeginTransactionRequest::_internal_mutable_options() { PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); _impl_._has_bits_[0] |= 0x00000001u; - if (_impl_.mask_ == nullptr) { - auto* p = CreateMaybeMessage<::google::firestore::v1::DocumentMask>(GetArena()); - _impl_.mask_ = reinterpret_cast<::google::firestore::v1::DocumentMask*>(p); + if (_impl_.options_ == nullptr) { + auto* p = CreateMaybeMessage<::google::firestore::v1::TransactionOptions>(GetArena()); + _impl_.options_ = reinterpret_cast<::google::firestore::v1::TransactionOptions*>(p); } - return _impl_.mask_; + return _impl_.options_; } -inline ::google::firestore::v1::DocumentMask* BatchGetDocumentsRequest::mutable_mask() ABSL_ATTRIBUTE_LIFETIME_BOUND { - ::google::firestore::v1::DocumentMask* _msg = _internal_mutable_mask(); - // @@protoc_insertion_point(field_mutable:google.firestore.v1.BatchGetDocumentsRequest.mask) +inline ::google::firestore::v1::TransactionOptions* BeginTransactionRequest::mutable_options() ABSL_ATTRIBUTE_LIFETIME_BOUND { + ::google::firestore::v1::TransactionOptions* _msg = _internal_mutable_options(); + // @@protoc_insertion_point(field_mutable:google.firestore.v1.BeginTransactionRequest.options) return _msg; } -inline void BatchGetDocumentsRequest::set_allocated_mask(::google::firestore::v1::DocumentMask* value) { +inline void BeginTransactionRequest::set_allocated_options(::google::firestore::v1::TransactionOptions* value) { ::google::protobuf::Arena* message_arena = GetArena(); PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); if (message_arena == nullptr) { - delete reinterpret_cast<::google::protobuf::MessageLite*>(_impl_.mask_); + delete reinterpret_cast<::google::protobuf::MessageLite*>(_impl_.options_); } if (value != nullptr) { @@ -8892,437 +10121,462 @@ inline void BatchGetDocumentsRequest::set_allocated_mask(::google::firestore::v1 _impl_._has_bits_[0] &= ~0x00000001u; } - _impl_.mask_ = reinterpret_cast<::google::firestore::v1::DocumentMask*>(value); - // @@protoc_insertion_point(field_set_allocated:google.firestore.v1.BatchGetDocumentsRequest.mask) + _impl_.options_ = reinterpret_cast<::google::firestore::v1::TransactionOptions*>(value); + // @@protoc_insertion_point(field_set_allocated:google.firestore.v1.BeginTransactionRequest.options) } -// bytes transaction = 4; -inline bool BatchGetDocumentsRequest::has_transaction() const { - return consistency_selector_case() == kTransaction; -} -inline void BatchGetDocumentsRequest::set_has_transaction() { - _impl_._oneof_case_[0] = kTransaction; -} -inline void BatchGetDocumentsRequest::clear_transaction() { +// ------------------------------------------------------------------- + +// BeginTransactionResponse + +// bytes transaction = 1; +inline void BeginTransactionResponse::clear_transaction() { PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); - if (consistency_selector_case() == kTransaction) { - _impl_.consistency_selector_.transaction_.Destroy(); - clear_has_consistency_selector(); - } + _impl_.transaction_.ClearToEmpty(); } -inline const std::string& BatchGetDocumentsRequest::transaction() const +inline const std::string& BeginTransactionResponse::transaction() const ABSL_ATTRIBUTE_LIFETIME_BOUND { - // @@protoc_insertion_point(field_get:google.firestore.v1.BatchGetDocumentsRequest.transaction) + // @@protoc_insertion_point(field_get:google.firestore.v1.BeginTransactionResponse.transaction) return _internal_transaction(); } template -inline PROTOBUF_ALWAYS_INLINE void BatchGetDocumentsRequest::set_transaction(Arg_&& arg, +inline PROTOBUF_ALWAYS_INLINE void BeginTransactionResponse::set_transaction(Arg_&& arg, Args_... args) { PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); - if (consistency_selector_case() != kTransaction) { - clear_consistency_selector(); + ; + _impl_.transaction_.SetBytes(static_cast(arg), args..., GetArena()); + // @@protoc_insertion_point(field_set:google.firestore.v1.BeginTransactionResponse.transaction) +} +inline std::string* BeginTransactionResponse::mutable_transaction() ABSL_ATTRIBUTE_LIFETIME_BOUND { + std::string* _s = _internal_mutable_transaction(); + // @@protoc_insertion_point(field_mutable:google.firestore.v1.BeginTransactionResponse.transaction) + return _s; +} +inline const std::string& BeginTransactionResponse::_internal_transaction() const { + PROTOBUF_TSAN_READ(&_impl_._tsan_detect_race); + return _impl_.transaction_.Get(); +} +inline void BeginTransactionResponse::_internal_set_transaction(const std::string& value) { + PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); + ; + _impl_.transaction_.Set(value, GetArena()); +} +inline std::string* BeginTransactionResponse::_internal_mutable_transaction() { + PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); + ; + return _impl_.transaction_.Mutable( GetArena()); +} +inline std::string* BeginTransactionResponse::release_transaction() { + PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); + // @@protoc_insertion_point(field_release:google.firestore.v1.BeginTransactionResponse.transaction) + return _impl_.transaction_.Release(); +} +inline void BeginTransactionResponse::set_allocated_transaction(std::string* value) { + PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); + _impl_.transaction_.SetAllocated(value, GetArena()); + #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING + if (_impl_.transaction_.IsDefault()) { + _impl_.transaction_.Set("", GetArena()); + } + #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING + // @@protoc_insertion_point(field_set_allocated:google.firestore.v1.BeginTransactionResponse.transaction) +} - set_has_transaction(); - _impl_.consistency_selector_.transaction_.InitDefault(); - } - _impl_.consistency_selector_.transaction_.SetBytes(static_cast(arg), args..., GetArena()); - // @@protoc_insertion_point(field_set:google.firestore.v1.BatchGetDocumentsRequest.transaction) +// ------------------------------------------------------------------- + +// CommitRequest + +// string database = 1; +inline void CommitRequest::clear_database() { + PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); + _impl_.database_.ClearToEmpty(); +} +inline const std::string& CommitRequest::database() const + ABSL_ATTRIBUTE_LIFETIME_BOUND { + // @@protoc_insertion_point(field_get:google.firestore.v1.CommitRequest.database) + return _internal_database(); } -inline std::string* BatchGetDocumentsRequest::mutable_transaction() ABSL_ATTRIBUTE_LIFETIME_BOUND { - std::string* _s = _internal_mutable_transaction(); - // @@protoc_insertion_point(field_mutable:google.firestore.v1.BatchGetDocumentsRequest.transaction) +template +inline PROTOBUF_ALWAYS_INLINE void CommitRequest::set_database(Arg_&& arg, + Args_... args) { + PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); + ; + _impl_.database_.Set(static_cast(arg), args..., GetArena()); + // @@protoc_insertion_point(field_set:google.firestore.v1.CommitRequest.database) +} +inline std::string* CommitRequest::mutable_database() ABSL_ATTRIBUTE_LIFETIME_BOUND { + std::string* _s = _internal_mutable_database(); + // @@protoc_insertion_point(field_mutable:google.firestore.v1.CommitRequest.database) return _s; } -inline const std::string& BatchGetDocumentsRequest::_internal_transaction() const { +inline const std::string& CommitRequest::_internal_database() const { PROTOBUF_TSAN_READ(&_impl_._tsan_detect_race); - if (consistency_selector_case() != kTransaction) { - return ::google::protobuf::internal::GetEmptyStringAlreadyInited(); - } - return _impl_.consistency_selector_.transaction_.Get(); + return _impl_.database_.Get(); } -inline void BatchGetDocumentsRequest::_internal_set_transaction(const std::string& value) { +inline void CommitRequest::_internal_set_database(const std::string& value) { PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); - if (consistency_selector_case() != kTransaction) { - clear_consistency_selector(); - - set_has_transaction(); - _impl_.consistency_selector_.transaction_.InitDefault(); - } - _impl_.consistency_selector_.transaction_.Set(value, GetArena()); + ; + _impl_.database_.Set(value, GetArena()); } -inline std::string* BatchGetDocumentsRequest::_internal_mutable_transaction() { +inline std::string* CommitRequest::_internal_mutable_database() { PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); - if (consistency_selector_case() != kTransaction) { - clear_consistency_selector(); - - set_has_transaction(); - _impl_.consistency_selector_.transaction_.InitDefault(); - } - return _impl_.consistency_selector_.transaction_.Mutable( GetArena()); + ; + return _impl_.database_.Mutable( GetArena()); } -inline std::string* BatchGetDocumentsRequest::release_transaction() { +inline std::string* CommitRequest::release_database() { PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); - // @@protoc_insertion_point(field_release:google.firestore.v1.BatchGetDocumentsRequest.transaction) - if (consistency_selector_case() != kTransaction) { - return nullptr; - } - clear_has_consistency_selector(); - return _impl_.consistency_selector_.transaction_.Release(); + // @@protoc_insertion_point(field_release:google.firestore.v1.CommitRequest.database) + return _impl_.database_.Release(); } -inline void BatchGetDocumentsRequest::set_allocated_transaction(std::string* value) { +inline void CommitRequest::set_allocated_database(std::string* value) { PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); - if (has_consistency_selector()) { - clear_consistency_selector(); - } - if (value != nullptr) { - set_has_transaction(); - _impl_.consistency_selector_.transaction_.InitAllocated(value, GetArena()); - } - // @@protoc_insertion_point(field_set_allocated:google.firestore.v1.BatchGetDocumentsRequest.transaction) + _impl_.database_.SetAllocated(value, GetArena()); + #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING + if (_impl_.database_.IsDefault()) { + _impl_.database_.Set("", GetArena()); + } + #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING + // @@protoc_insertion_point(field_set_allocated:google.firestore.v1.CommitRequest.database) } -// .google.firestore.v1.TransactionOptions new_transaction = 5; -inline bool BatchGetDocumentsRequest::has_new_transaction() const { - return consistency_selector_case() == kNewTransaction; -} -inline bool BatchGetDocumentsRequest::_internal_has_new_transaction() const { - return consistency_selector_case() == kNewTransaction; +// repeated .google.firestore.v1.Write writes = 2; +inline int CommitRequest::_internal_writes_size() const { + return _internal_writes().size(); } -inline void BatchGetDocumentsRequest::set_has_new_transaction() { - _impl_._oneof_case_[0] = kNewTransaction; +inline int CommitRequest::writes_size() const { + return _internal_writes_size(); } -inline ::google::firestore::v1::TransactionOptions* BatchGetDocumentsRequest::release_new_transaction() { - // @@protoc_insertion_point(field_release:google.firestore.v1.BatchGetDocumentsRequest.new_transaction) - if (consistency_selector_case() == kNewTransaction) { - clear_has_consistency_selector(); - auto* temp = _impl_.consistency_selector_.new_transaction_; - if (GetArena() != nullptr) { - temp = ::google::protobuf::internal::DuplicateIfNonNull(temp); - } - _impl_.consistency_selector_.new_transaction_ = nullptr; - return temp; - } else { - return nullptr; - } +inline ::google::firestore::v1::Write* CommitRequest::mutable_writes(int index) + ABSL_ATTRIBUTE_LIFETIME_BOUND { + // @@protoc_insertion_point(field_mutable:google.firestore.v1.CommitRequest.writes) + return _internal_mutable_writes()->Mutable(index); } -inline const ::google::firestore::v1::TransactionOptions& BatchGetDocumentsRequest::_internal_new_transaction() const { - return consistency_selector_case() == kNewTransaction ? *_impl_.consistency_selector_.new_transaction_ : reinterpret_cast<::google::firestore::v1::TransactionOptions&>(::google::firestore::v1::_TransactionOptions_default_instance_); +inline ::google::protobuf::RepeatedPtrField<::google::firestore::v1::Write>* CommitRequest::mutable_writes() + ABSL_ATTRIBUTE_LIFETIME_BOUND { + // @@protoc_insertion_point(field_mutable_list:google.firestore.v1.CommitRequest.writes) + PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); + return _internal_mutable_writes(); } -inline const ::google::firestore::v1::TransactionOptions& BatchGetDocumentsRequest::new_transaction() const ABSL_ATTRIBUTE_LIFETIME_BOUND { - // @@protoc_insertion_point(field_get:google.firestore.v1.BatchGetDocumentsRequest.new_transaction) - return _internal_new_transaction(); +inline const ::google::firestore::v1::Write& CommitRequest::writes(int index) const + ABSL_ATTRIBUTE_LIFETIME_BOUND { + // @@protoc_insertion_point(field_get:google.firestore.v1.CommitRequest.writes) + return _internal_writes().Get(index); } -inline ::google::firestore::v1::TransactionOptions* BatchGetDocumentsRequest::unsafe_arena_release_new_transaction() { - // @@protoc_insertion_point(field_unsafe_arena_release:google.firestore.v1.BatchGetDocumentsRequest.new_transaction) - if (consistency_selector_case() == kNewTransaction) { - clear_has_consistency_selector(); - auto* temp = _impl_.consistency_selector_.new_transaction_; - _impl_.consistency_selector_.new_transaction_ = nullptr; - return temp; - } else { - return nullptr; - } +inline ::google::firestore::v1::Write* CommitRequest::add_writes() ABSL_ATTRIBUTE_LIFETIME_BOUND { + PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); + ::google::firestore::v1::Write* _add = _internal_mutable_writes()->Add(); + // @@protoc_insertion_point(field_add:google.firestore.v1.CommitRequest.writes) + return _add; } -inline void BatchGetDocumentsRequest::unsafe_arena_set_allocated_new_transaction(::google::firestore::v1::TransactionOptions* value) { - // We rely on the oneof clear method to free the earlier contents - // of this oneof. We can directly use the pointer we're given to - // set the new value. - clear_consistency_selector(); - if (value) { - set_has_new_transaction(); - _impl_.consistency_selector_.new_transaction_ = value; - } - // @@protoc_insertion_point(field_unsafe_arena_set_allocated:google.firestore.v1.BatchGetDocumentsRequest.new_transaction) +inline const ::google::protobuf::RepeatedPtrField<::google::firestore::v1::Write>& CommitRequest::writes() const + ABSL_ATTRIBUTE_LIFETIME_BOUND { + // @@protoc_insertion_point(field_list:google.firestore.v1.CommitRequest.writes) + return _internal_writes(); } -inline ::google::firestore::v1::TransactionOptions* BatchGetDocumentsRequest::_internal_mutable_new_transaction() { - if (consistency_selector_case() != kNewTransaction) { - clear_consistency_selector(); - set_has_new_transaction(); - _impl_.consistency_selector_.new_transaction_ = CreateMaybeMessage<::google::firestore::v1::TransactionOptions>(GetArena()); - } - return _impl_.consistency_selector_.new_transaction_; +inline const ::google::protobuf::RepeatedPtrField<::google::firestore::v1::Write>& +CommitRequest::_internal_writes() const { + PROTOBUF_TSAN_READ(&_impl_._tsan_detect_race); + return _impl_.writes_; } -inline ::google::firestore::v1::TransactionOptions* BatchGetDocumentsRequest::mutable_new_transaction() ABSL_ATTRIBUTE_LIFETIME_BOUND { - ::google::firestore::v1::TransactionOptions* _msg = _internal_mutable_new_transaction(); - // @@protoc_insertion_point(field_mutable:google.firestore.v1.BatchGetDocumentsRequest.new_transaction) - return _msg; +inline ::google::protobuf::RepeatedPtrField<::google::firestore::v1::Write>* +CommitRequest::_internal_mutable_writes() { + PROTOBUF_TSAN_READ(&_impl_._tsan_detect_race); + return &_impl_.writes_; } -// .google.protobuf.Timestamp read_time = 7; -inline bool BatchGetDocumentsRequest::has_read_time() const { - return consistency_selector_case() == kReadTime; +// bytes transaction = 3; +inline void CommitRequest::clear_transaction() { + PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); + _impl_.transaction_.ClearToEmpty(); } -inline bool BatchGetDocumentsRequest::_internal_has_read_time() const { - return consistency_selector_case() == kReadTime; +inline const std::string& CommitRequest::transaction() const + ABSL_ATTRIBUTE_LIFETIME_BOUND { + // @@protoc_insertion_point(field_get:google.firestore.v1.CommitRequest.transaction) + return _internal_transaction(); } -inline void BatchGetDocumentsRequest::set_has_read_time() { - _impl_._oneof_case_[0] = kReadTime; +template +inline PROTOBUF_ALWAYS_INLINE void CommitRequest::set_transaction(Arg_&& arg, + Args_... args) { + PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); + ; + _impl_.transaction_.SetBytes(static_cast(arg), args..., GetArena()); + // @@protoc_insertion_point(field_set:google.firestore.v1.CommitRequest.transaction) } -inline ::google::protobuf::Timestamp* BatchGetDocumentsRequest::release_read_time() { - // @@protoc_insertion_point(field_release:google.firestore.v1.BatchGetDocumentsRequest.read_time) - if (consistency_selector_case() == kReadTime) { - clear_has_consistency_selector(); - auto* temp = _impl_.consistency_selector_.read_time_; - if (GetArena() != nullptr) { - temp = ::google::protobuf::internal::DuplicateIfNonNull(temp); - } - _impl_.consistency_selector_.read_time_ = nullptr; - return temp; - } else { - return nullptr; - } +inline std::string* CommitRequest::mutable_transaction() ABSL_ATTRIBUTE_LIFETIME_BOUND { + std::string* _s = _internal_mutable_transaction(); + // @@protoc_insertion_point(field_mutable:google.firestore.v1.CommitRequest.transaction) + return _s; } -inline const ::google::protobuf::Timestamp& BatchGetDocumentsRequest::_internal_read_time() const { - return consistency_selector_case() == kReadTime ? *_impl_.consistency_selector_.read_time_ : reinterpret_cast<::google::protobuf::Timestamp&>(::google::protobuf::_Timestamp_default_instance_); +inline const std::string& CommitRequest::_internal_transaction() const { + PROTOBUF_TSAN_READ(&_impl_._tsan_detect_race); + return _impl_.transaction_.Get(); } -inline const ::google::protobuf::Timestamp& BatchGetDocumentsRequest::read_time() const ABSL_ATTRIBUTE_LIFETIME_BOUND { - // @@protoc_insertion_point(field_get:google.firestore.v1.BatchGetDocumentsRequest.read_time) - return _internal_read_time(); +inline void CommitRequest::_internal_set_transaction(const std::string& value) { + PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); + ; + _impl_.transaction_.Set(value, GetArena()); } -inline ::google::protobuf::Timestamp* BatchGetDocumentsRequest::unsafe_arena_release_read_time() { - // @@protoc_insertion_point(field_unsafe_arena_release:google.firestore.v1.BatchGetDocumentsRequest.read_time) - if (consistency_selector_case() == kReadTime) { - clear_has_consistency_selector(); - auto* temp = _impl_.consistency_selector_.read_time_; - _impl_.consistency_selector_.read_time_ = nullptr; - return temp; - } else { - return nullptr; - } +inline std::string* CommitRequest::_internal_mutable_transaction() { + PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); + ; + return _impl_.transaction_.Mutable( GetArena()); } -inline void BatchGetDocumentsRequest::unsafe_arena_set_allocated_read_time(::google::protobuf::Timestamp* value) { - // We rely on the oneof clear method to free the earlier contents - // of this oneof. We can directly use the pointer we're given to - // set the new value. - clear_consistency_selector(); - if (value) { - set_has_read_time(); - _impl_.consistency_selector_.read_time_ = value; - } - // @@protoc_insertion_point(field_unsafe_arena_set_allocated:google.firestore.v1.BatchGetDocumentsRequest.read_time) +inline std::string* CommitRequest::release_transaction() { + PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); + // @@protoc_insertion_point(field_release:google.firestore.v1.CommitRequest.transaction) + return _impl_.transaction_.Release(); +} +inline void CommitRequest::set_allocated_transaction(std::string* value) { + PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); + _impl_.transaction_.SetAllocated(value, GetArena()); + #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING + if (_impl_.transaction_.IsDefault()) { + _impl_.transaction_.Set("", GetArena()); + } + #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING + // @@protoc_insertion_point(field_set_allocated:google.firestore.v1.CommitRequest.transaction) +} + +// ------------------------------------------------------------------- + +// CommitResponse + +// repeated .google.firestore.v1.WriteResult write_results = 1; +inline int CommitResponse::_internal_write_results_size() const { + return _internal_write_results().size(); } -inline ::google::protobuf::Timestamp* BatchGetDocumentsRequest::_internal_mutable_read_time() { - if (consistency_selector_case() != kReadTime) { - clear_consistency_selector(); - set_has_read_time(); - _impl_.consistency_selector_.read_time_ = CreateMaybeMessage<::google::protobuf::Timestamp>(GetArena()); - } - return _impl_.consistency_selector_.read_time_; +inline int CommitResponse::write_results_size() const { + return _internal_write_results_size(); } -inline ::google::protobuf::Timestamp* BatchGetDocumentsRequest::mutable_read_time() ABSL_ATTRIBUTE_LIFETIME_BOUND { - ::google::protobuf::Timestamp* _msg = _internal_mutable_read_time(); - // @@protoc_insertion_point(field_mutable:google.firestore.v1.BatchGetDocumentsRequest.read_time) - return _msg; +inline ::google::firestore::v1::WriteResult* CommitResponse::mutable_write_results(int index) + ABSL_ATTRIBUTE_LIFETIME_BOUND { + // @@protoc_insertion_point(field_mutable:google.firestore.v1.CommitResponse.write_results) + return _internal_mutable_write_results()->Mutable(index); } - -inline bool BatchGetDocumentsRequest::has_consistency_selector() const { - return consistency_selector_case() != CONSISTENCY_SELECTOR_NOT_SET; +inline ::google::protobuf::RepeatedPtrField<::google::firestore::v1::WriteResult>* CommitResponse::mutable_write_results() + ABSL_ATTRIBUTE_LIFETIME_BOUND { + // @@protoc_insertion_point(field_mutable_list:google.firestore.v1.CommitResponse.write_results) + PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); + return _internal_mutable_write_results(); } -inline void BatchGetDocumentsRequest::clear_has_consistency_selector() { - _impl_._oneof_case_[0] = CONSISTENCY_SELECTOR_NOT_SET; +inline const ::google::firestore::v1::WriteResult& CommitResponse::write_results(int index) const + ABSL_ATTRIBUTE_LIFETIME_BOUND { + // @@protoc_insertion_point(field_get:google.firestore.v1.CommitResponse.write_results) + return _internal_write_results().Get(index); } -inline BatchGetDocumentsRequest::ConsistencySelectorCase BatchGetDocumentsRequest::consistency_selector_case() const { - return BatchGetDocumentsRequest::ConsistencySelectorCase(_impl_._oneof_case_[0]); +inline ::google::firestore::v1::WriteResult* CommitResponse::add_write_results() ABSL_ATTRIBUTE_LIFETIME_BOUND { + PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); + ::google::firestore::v1::WriteResult* _add = _internal_mutable_write_results()->Add(); + // @@protoc_insertion_point(field_add:google.firestore.v1.CommitResponse.write_results) + return _add; } -// ------------------------------------------------------------------- - -// BatchGetDocumentsResponse - -// .google.firestore.v1.Document found = 1; -inline bool BatchGetDocumentsResponse::has_found() const { - return result_case() == kFound; +inline const ::google::protobuf::RepeatedPtrField<::google::firestore::v1::WriteResult>& CommitResponse::write_results() const + ABSL_ATTRIBUTE_LIFETIME_BOUND { + // @@protoc_insertion_point(field_list:google.firestore.v1.CommitResponse.write_results) + return _internal_write_results(); } -inline bool BatchGetDocumentsResponse::_internal_has_found() const { - return result_case() == kFound; +inline const ::google::protobuf::RepeatedPtrField<::google::firestore::v1::WriteResult>& +CommitResponse::_internal_write_results() const { + PROTOBUF_TSAN_READ(&_impl_._tsan_detect_race); + return _impl_.write_results_; } -inline void BatchGetDocumentsResponse::set_has_found() { - _impl_._oneof_case_[0] = kFound; +inline ::google::protobuf::RepeatedPtrField<::google::firestore::v1::WriteResult>* +CommitResponse::_internal_mutable_write_results() { + PROTOBUF_TSAN_READ(&_impl_._tsan_detect_race); + return &_impl_.write_results_; } -inline ::google::firestore::v1::Document* BatchGetDocumentsResponse::release_found() { - // @@protoc_insertion_point(field_release:google.firestore.v1.BatchGetDocumentsResponse.found) - if (result_case() == kFound) { - clear_has_result(); - auto* temp = _impl_.result_.found_; - if (GetArena() != nullptr) { - temp = ::google::protobuf::internal::DuplicateIfNonNull(temp); - } - _impl_.result_.found_ = nullptr; - return temp; - } else { - return nullptr; - } + +// .google.protobuf.Timestamp commit_time = 2; +inline bool CommitResponse::has_commit_time() const { + bool value = (_impl_._has_bits_[0] & 0x00000001u) != 0; + PROTOBUF_ASSUME(!value || _impl_.commit_time_ != nullptr); + return value; } -inline const ::google::firestore::v1::Document& BatchGetDocumentsResponse::_internal_found() const { - return result_case() == kFound ? *_impl_.result_.found_ : reinterpret_cast<::google::firestore::v1::Document&>(::google::firestore::v1::_Document_default_instance_); +inline const ::google::protobuf::Timestamp& CommitResponse::_internal_commit_time() const { + PROTOBUF_TSAN_READ(&_impl_._tsan_detect_race); + const ::google::protobuf::Timestamp* p = _impl_.commit_time_; + return p != nullptr ? *p : reinterpret_cast(::google::protobuf::_Timestamp_default_instance_); } -inline const ::google::firestore::v1::Document& BatchGetDocumentsResponse::found() const ABSL_ATTRIBUTE_LIFETIME_BOUND { - // @@protoc_insertion_point(field_get:google.firestore.v1.BatchGetDocumentsResponse.found) - return _internal_found(); +inline const ::google::protobuf::Timestamp& CommitResponse::commit_time() const ABSL_ATTRIBUTE_LIFETIME_BOUND { + // @@protoc_insertion_point(field_get:google.firestore.v1.CommitResponse.commit_time) + return _internal_commit_time(); } -inline ::google::firestore::v1::Document* BatchGetDocumentsResponse::unsafe_arena_release_found() { - // @@protoc_insertion_point(field_unsafe_arena_release:google.firestore.v1.BatchGetDocumentsResponse.found) - if (result_case() == kFound) { - clear_has_result(); - auto* temp = _impl_.result_.found_; - _impl_.result_.found_ = nullptr; - return temp; +inline void CommitResponse::unsafe_arena_set_allocated_commit_time(::google::protobuf::Timestamp* value) { + PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); + if (GetArena() == nullptr) { + delete reinterpret_cast<::google::protobuf::MessageLite*>(_impl_.commit_time_); + } + _impl_.commit_time_ = reinterpret_cast<::google::protobuf::Timestamp*>(value); + if (value != nullptr) { + _impl_._has_bits_[0] |= 0x00000001u; } else { - return nullptr; + _impl_._has_bits_[0] &= ~0x00000001u; } + // @@protoc_insertion_point(field_unsafe_arena_set_allocated:google.firestore.v1.CommitResponse.commit_time) } -inline void BatchGetDocumentsResponse::unsafe_arena_set_allocated_found(::google::firestore::v1::Document* value) { - // We rely on the oneof clear method to free the earlier contents - // of this oneof. We can directly use the pointer we're given to - // set the new value. - clear_result(); - if (value) { - set_has_found(); - _impl_.result_.found_ = value; +inline ::google::protobuf::Timestamp* CommitResponse::release_commit_time() { + PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); + + _impl_._has_bits_[0] &= ~0x00000001u; + ::google::protobuf::Timestamp* released = _impl_.commit_time_; + _impl_.commit_time_ = nullptr; +#ifdef PROTOBUF_FORCE_COPY_IN_RELEASE + auto* old = reinterpret_cast<::google::protobuf::MessageLite*>(released); + released = ::google::protobuf::internal::DuplicateIfNonNull(released); + if (GetArena() == nullptr) { + delete old; } - // @@protoc_insertion_point(field_unsafe_arena_set_allocated:google.firestore.v1.BatchGetDocumentsResponse.found) +#else // PROTOBUF_FORCE_COPY_IN_RELEASE + if (GetArena() != nullptr) { + released = ::google::protobuf::internal::DuplicateIfNonNull(released); + } +#endif // !PROTOBUF_FORCE_COPY_IN_RELEASE + return released; } -inline ::google::firestore::v1::Document* BatchGetDocumentsResponse::_internal_mutable_found() { - if (result_case() != kFound) { - clear_result(); - set_has_found(); - _impl_.result_.found_ = CreateMaybeMessage<::google::firestore::v1::Document>(GetArena()); +inline ::google::protobuf::Timestamp* CommitResponse::unsafe_arena_release_commit_time() { + PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); + // @@protoc_insertion_point(field_release:google.firestore.v1.CommitResponse.commit_time) + + _impl_._has_bits_[0] &= ~0x00000001u; + ::google::protobuf::Timestamp* temp = _impl_.commit_time_; + _impl_.commit_time_ = nullptr; + return temp; +} +inline ::google::protobuf::Timestamp* CommitResponse::_internal_mutable_commit_time() { + PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); + _impl_._has_bits_[0] |= 0x00000001u; + if (_impl_.commit_time_ == nullptr) { + auto* p = CreateMaybeMessage<::google::protobuf::Timestamp>(GetArena()); + _impl_.commit_time_ = reinterpret_cast<::google::protobuf::Timestamp*>(p); } - return _impl_.result_.found_; + return _impl_.commit_time_; } -inline ::google::firestore::v1::Document* BatchGetDocumentsResponse::mutable_found() ABSL_ATTRIBUTE_LIFETIME_BOUND { - ::google::firestore::v1::Document* _msg = _internal_mutable_found(); - // @@protoc_insertion_point(field_mutable:google.firestore.v1.BatchGetDocumentsResponse.found) +inline ::google::protobuf::Timestamp* CommitResponse::mutable_commit_time() ABSL_ATTRIBUTE_LIFETIME_BOUND { + ::google::protobuf::Timestamp* _msg = _internal_mutable_commit_time(); + // @@protoc_insertion_point(field_mutable:google.firestore.v1.CommitResponse.commit_time) return _msg; } +inline void CommitResponse::set_allocated_commit_time(::google::protobuf::Timestamp* value) { + ::google::protobuf::Arena* message_arena = GetArena(); + PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); + if (message_arena == nullptr) { + delete reinterpret_cast<::google::protobuf::MessageLite*>(_impl_.commit_time_); + } -// string missing = 2; -inline bool BatchGetDocumentsResponse::has_missing() const { - return result_case() == kMissing; -} -inline void BatchGetDocumentsResponse::set_has_missing() { - _impl_._oneof_case_[0] = kMissing; + if (value != nullptr) { + ::google::protobuf::Arena* submessage_arena = reinterpret_cast<::google::protobuf::MessageLite*>(value)->GetArena(); + if (message_arena != submessage_arena) { + value = ::google::protobuf::internal::GetOwnedMessage(message_arena, value, submessage_arena); + } + _impl_._has_bits_[0] |= 0x00000001u; + } else { + _impl_._has_bits_[0] &= ~0x00000001u; + } + + _impl_.commit_time_ = reinterpret_cast<::google::protobuf::Timestamp*>(value); + // @@protoc_insertion_point(field_set_allocated:google.firestore.v1.CommitResponse.commit_time) } -inline void BatchGetDocumentsResponse::clear_missing() { + +// ------------------------------------------------------------------- + +// RollbackRequest + +// string database = 1; +inline void RollbackRequest::clear_database() { PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); - if (result_case() == kMissing) { - _impl_.result_.missing_.Destroy(); - clear_has_result(); - } + _impl_.database_.ClearToEmpty(); } -inline const std::string& BatchGetDocumentsResponse::missing() const +inline const std::string& RollbackRequest::database() const ABSL_ATTRIBUTE_LIFETIME_BOUND { - // @@protoc_insertion_point(field_get:google.firestore.v1.BatchGetDocumentsResponse.missing) - return _internal_missing(); + // @@protoc_insertion_point(field_get:google.firestore.v1.RollbackRequest.database) + return _internal_database(); } template -inline PROTOBUF_ALWAYS_INLINE void BatchGetDocumentsResponse::set_missing(Arg_&& arg, +inline PROTOBUF_ALWAYS_INLINE void RollbackRequest::set_database(Arg_&& arg, Args_... args) { PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); - if (result_case() != kMissing) { - clear_result(); - - set_has_missing(); - _impl_.result_.missing_.InitDefault(); - } - _impl_.result_.missing_.Set(static_cast(arg), args..., GetArena()); - // @@protoc_insertion_point(field_set:google.firestore.v1.BatchGetDocumentsResponse.missing) + ; + _impl_.database_.Set(static_cast(arg), args..., GetArena()); + // @@protoc_insertion_point(field_set:google.firestore.v1.RollbackRequest.database) } -inline std::string* BatchGetDocumentsResponse::mutable_missing() ABSL_ATTRIBUTE_LIFETIME_BOUND { - std::string* _s = _internal_mutable_missing(); - // @@protoc_insertion_point(field_mutable:google.firestore.v1.BatchGetDocumentsResponse.missing) +inline std::string* RollbackRequest::mutable_database() ABSL_ATTRIBUTE_LIFETIME_BOUND { + std::string* _s = _internal_mutable_database(); + // @@protoc_insertion_point(field_mutable:google.firestore.v1.RollbackRequest.database) return _s; } -inline const std::string& BatchGetDocumentsResponse::_internal_missing() const { +inline const std::string& RollbackRequest::_internal_database() const { PROTOBUF_TSAN_READ(&_impl_._tsan_detect_race); - if (result_case() != kMissing) { - return ::google::protobuf::internal::GetEmptyStringAlreadyInited(); - } - return _impl_.result_.missing_.Get(); -} -inline void BatchGetDocumentsResponse::_internal_set_missing(const std::string& value) { - PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); - if (result_case() != kMissing) { - clear_result(); - - set_has_missing(); - _impl_.result_.missing_.InitDefault(); - } - _impl_.result_.missing_.Set(value, GetArena()); + return _impl_.database_.Get(); } -inline std::string* BatchGetDocumentsResponse::_internal_mutable_missing() { +inline void RollbackRequest::_internal_set_database(const std::string& value) { PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); - if (result_case() != kMissing) { - clear_result(); - - set_has_missing(); - _impl_.result_.missing_.InitDefault(); - } - return _impl_.result_.missing_.Mutable( GetArena()); + ; + _impl_.database_.Set(value, GetArena()); } -inline std::string* BatchGetDocumentsResponse::release_missing() { +inline std::string* RollbackRequest::_internal_mutable_database() { PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); - // @@protoc_insertion_point(field_release:google.firestore.v1.BatchGetDocumentsResponse.missing) - if (result_case() != kMissing) { - return nullptr; - } - clear_has_result(); - return _impl_.result_.missing_.Release(); + ; + return _impl_.database_.Mutable( GetArena()); } -inline void BatchGetDocumentsResponse::set_allocated_missing(std::string* value) { +inline std::string* RollbackRequest::release_database() { PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); - if (has_result()) { - clear_result(); - } - if (value != nullptr) { - set_has_missing(); - _impl_.result_.missing_.InitAllocated(value, GetArena()); - } - // @@protoc_insertion_point(field_set_allocated:google.firestore.v1.BatchGetDocumentsResponse.missing) + // @@protoc_insertion_point(field_release:google.firestore.v1.RollbackRequest.database) + return _impl_.database_.Release(); +} +inline void RollbackRequest::set_allocated_database(std::string* value) { + PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); + _impl_.database_.SetAllocated(value, GetArena()); + #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING + if (_impl_.database_.IsDefault()) { + _impl_.database_.Set("", GetArena()); + } + #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING + // @@protoc_insertion_point(field_set_allocated:google.firestore.v1.RollbackRequest.database) } -// bytes transaction = 3; -inline void BatchGetDocumentsResponse::clear_transaction() { +// bytes transaction = 2; +inline void RollbackRequest::clear_transaction() { PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); _impl_.transaction_.ClearToEmpty(); } -inline const std::string& BatchGetDocumentsResponse::transaction() const +inline const std::string& RollbackRequest::transaction() const ABSL_ATTRIBUTE_LIFETIME_BOUND { - // @@protoc_insertion_point(field_get:google.firestore.v1.BatchGetDocumentsResponse.transaction) + // @@protoc_insertion_point(field_get:google.firestore.v1.RollbackRequest.transaction) return _internal_transaction(); } template -inline PROTOBUF_ALWAYS_INLINE void BatchGetDocumentsResponse::set_transaction(Arg_&& arg, +inline PROTOBUF_ALWAYS_INLINE void RollbackRequest::set_transaction(Arg_&& arg, Args_... args) { PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); ; _impl_.transaction_.SetBytes(static_cast(arg), args..., GetArena()); - // @@protoc_insertion_point(field_set:google.firestore.v1.BatchGetDocumentsResponse.transaction) + // @@protoc_insertion_point(field_set:google.firestore.v1.RollbackRequest.transaction) } -inline std::string* BatchGetDocumentsResponse::mutable_transaction() ABSL_ATTRIBUTE_LIFETIME_BOUND { +inline std::string* RollbackRequest::mutable_transaction() ABSL_ATTRIBUTE_LIFETIME_BOUND { std::string* _s = _internal_mutable_transaction(); - // @@protoc_insertion_point(field_mutable:google.firestore.v1.BatchGetDocumentsResponse.transaction) + // @@protoc_insertion_point(field_mutable:google.firestore.v1.RollbackRequest.transaction) return _s; } -inline const std::string& BatchGetDocumentsResponse::_internal_transaction() const { +inline const std::string& RollbackRequest::_internal_transaction() const { PROTOBUF_TSAN_READ(&_impl_._tsan_detect_race); return _impl_.transaction_.Get(); } -inline void BatchGetDocumentsResponse::_internal_set_transaction(const std::string& value) { +inline void RollbackRequest::_internal_set_transaction(const std::string& value) { PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); ; _impl_.transaction_.Set(value, GetArena()); } -inline std::string* BatchGetDocumentsResponse::_internal_mutable_transaction() { +inline std::string* RollbackRequest::_internal_mutable_transaction() { PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); ; return _impl_.transaction_.Mutable( GetArena()); } -inline std::string* BatchGetDocumentsResponse::release_transaction() { +inline std::string* RollbackRequest::release_transaction() { PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); - // @@protoc_insertion_point(field_release:google.firestore.v1.BatchGetDocumentsResponse.transaction) + // @@protoc_insertion_point(field_release:google.firestore.v1.RollbackRequest.transaction) return _impl_.transaction_.Release(); } -inline void BatchGetDocumentsResponse::set_allocated_transaction(std::string* value) { +inline void RollbackRequest::set_allocated_transaction(std::string* value) { PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); _impl_.transaction_.SetAllocated(value, GetArena()); #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING @@ -9330,552 +10584,461 @@ inline void BatchGetDocumentsResponse::set_allocated_transaction(std::string* va _impl_.transaction_.Set("", GetArena()); } #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING - // @@protoc_insertion_point(field_set_allocated:google.firestore.v1.BatchGetDocumentsResponse.transaction) + // @@protoc_insertion_point(field_set_allocated:google.firestore.v1.RollbackRequest.transaction) } -// .google.protobuf.Timestamp read_time = 4; -inline bool BatchGetDocumentsResponse::has_read_time() const { - bool value = (_impl_._has_bits_[0] & 0x00000001u) != 0; - PROTOBUF_ASSUME(!value || _impl_.read_time_ != nullptr); - return value; +// ------------------------------------------------------------------- + +// RunQueryRequest + +// string parent = 1; +inline void RunQueryRequest::clear_parent() { + PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); + _impl_.parent_.ClearToEmpty(); } -inline const ::google::protobuf::Timestamp& BatchGetDocumentsResponse::_internal_read_time() const { +inline const std::string& RunQueryRequest::parent() const + ABSL_ATTRIBUTE_LIFETIME_BOUND { + // @@protoc_insertion_point(field_get:google.firestore.v1.RunQueryRequest.parent) + return _internal_parent(); +} +template +inline PROTOBUF_ALWAYS_INLINE void RunQueryRequest::set_parent(Arg_&& arg, + Args_... args) { + PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); + ; + _impl_.parent_.Set(static_cast(arg), args..., GetArena()); + // @@protoc_insertion_point(field_set:google.firestore.v1.RunQueryRequest.parent) +} +inline std::string* RunQueryRequest::mutable_parent() ABSL_ATTRIBUTE_LIFETIME_BOUND { + std::string* _s = _internal_mutable_parent(); + // @@protoc_insertion_point(field_mutable:google.firestore.v1.RunQueryRequest.parent) + return _s; +} +inline const std::string& RunQueryRequest::_internal_parent() const { PROTOBUF_TSAN_READ(&_impl_._tsan_detect_race); - const ::google::protobuf::Timestamp* p = _impl_.read_time_; - return p != nullptr ? *p : reinterpret_cast(::google::protobuf::_Timestamp_default_instance_); + return _impl_.parent_.Get(); } -inline const ::google::protobuf::Timestamp& BatchGetDocumentsResponse::read_time() const ABSL_ATTRIBUTE_LIFETIME_BOUND { - // @@protoc_insertion_point(field_get:google.firestore.v1.BatchGetDocumentsResponse.read_time) - return _internal_read_time(); +inline void RunQueryRequest::_internal_set_parent(const std::string& value) { + PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); + ; + _impl_.parent_.Set(value, GetArena()); } -inline void BatchGetDocumentsResponse::unsafe_arena_set_allocated_read_time(::google::protobuf::Timestamp* value) { +inline std::string* RunQueryRequest::_internal_mutable_parent() { PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); - if (GetArena() == nullptr) { - delete reinterpret_cast<::google::protobuf::MessageLite*>(_impl_.read_time_); - } - _impl_.read_time_ = reinterpret_cast<::google::protobuf::Timestamp*>(value); - if (value != nullptr) { - _impl_._has_bits_[0] |= 0x00000001u; - } else { - _impl_._has_bits_[0] &= ~0x00000001u; - } - // @@protoc_insertion_point(field_unsafe_arena_set_allocated:google.firestore.v1.BatchGetDocumentsResponse.read_time) + ; + return _impl_.parent_.Mutable( GetArena()); } -inline ::google::protobuf::Timestamp* BatchGetDocumentsResponse::release_read_time() { +inline std::string* RunQueryRequest::release_parent() { PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); - - _impl_._has_bits_[0] &= ~0x00000001u; - ::google::protobuf::Timestamp* released = _impl_.read_time_; - _impl_.read_time_ = nullptr; -#ifdef PROTOBUF_FORCE_COPY_IN_RELEASE - auto* old = reinterpret_cast<::google::protobuf::MessageLite*>(released); - released = ::google::protobuf::internal::DuplicateIfNonNull(released); - if (GetArena() == nullptr) { - delete old; - } -#else // PROTOBUF_FORCE_COPY_IN_RELEASE - if (GetArena() != nullptr) { - released = ::google::protobuf::internal::DuplicateIfNonNull(released); - } -#endif // !PROTOBUF_FORCE_COPY_IN_RELEASE - return released; + // @@protoc_insertion_point(field_release:google.firestore.v1.RunQueryRequest.parent) + return _impl_.parent_.Release(); } -inline ::google::protobuf::Timestamp* BatchGetDocumentsResponse::unsafe_arena_release_read_time() { +inline void RunQueryRequest::set_allocated_parent(std::string* value) { PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); - // @@protoc_insertion_point(field_release:google.firestore.v1.BatchGetDocumentsResponse.read_time) + _impl_.parent_.SetAllocated(value, GetArena()); + #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING + if (_impl_.parent_.IsDefault()) { + _impl_.parent_.Set("", GetArena()); + } + #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING + // @@protoc_insertion_point(field_set_allocated:google.firestore.v1.RunQueryRequest.parent) +} - _impl_._has_bits_[0] &= ~0x00000001u; - ::google::protobuf::Timestamp* temp = _impl_.read_time_; - _impl_.read_time_ = nullptr; - return temp; +// .google.firestore.v1.StructuredQuery structured_query = 2; +inline bool RunQueryRequest::has_structured_query() const { + return query_type_case() == kStructuredQuery; } -inline ::google::protobuf::Timestamp* BatchGetDocumentsResponse::_internal_mutable_read_time() { - PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); - _impl_._has_bits_[0] |= 0x00000001u; - if (_impl_.read_time_ == nullptr) { - auto* p = CreateMaybeMessage<::google::protobuf::Timestamp>(GetArena()); - _impl_.read_time_ = reinterpret_cast<::google::protobuf::Timestamp*>(p); - } - return _impl_.read_time_; +inline bool RunQueryRequest::_internal_has_structured_query() const { + return query_type_case() == kStructuredQuery; } -inline ::google::protobuf::Timestamp* BatchGetDocumentsResponse::mutable_read_time() ABSL_ATTRIBUTE_LIFETIME_BOUND { - ::google::protobuf::Timestamp* _msg = _internal_mutable_read_time(); - // @@protoc_insertion_point(field_mutable:google.firestore.v1.BatchGetDocumentsResponse.read_time) - return _msg; +inline void RunQueryRequest::set_has_structured_query() { + _impl_._oneof_case_[0] = kStructuredQuery; } -inline void BatchGetDocumentsResponse::set_allocated_read_time(::google::protobuf::Timestamp* value) { - ::google::protobuf::Arena* message_arena = GetArena(); - PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); - if (message_arena == nullptr) { - delete reinterpret_cast<::google::protobuf::MessageLite*>(_impl_.read_time_); - } - - if (value != nullptr) { - ::google::protobuf::Arena* submessage_arena = reinterpret_cast<::google::protobuf::MessageLite*>(value)->GetArena(); - if (message_arena != submessage_arena) { - value = ::google::protobuf::internal::GetOwnedMessage(message_arena, value, submessage_arena); +inline ::google::firestore::v1::StructuredQuery* RunQueryRequest::release_structured_query() { + // @@protoc_insertion_point(field_release:google.firestore.v1.RunQueryRequest.structured_query) + if (query_type_case() == kStructuredQuery) { + clear_has_query_type(); + auto* temp = _impl_.query_type_.structured_query_; + if (GetArena() != nullptr) { + temp = ::google::protobuf::internal::DuplicateIfNonNull(temp); } - _impl_._has_bits_[0] |= 0x00000001u; + _impl_.query_type_.structured_query_ = nullptr; + return temp; } else { - _impl_._has_bits_[0] &= ~0x00000001u; + return nullptr; } - - _impl_.read_time_ = reinterpret_cast<::google::protobuf::Timestamp*>(value); - // @@protoc_insertion_point(field_set_allocated:google.firestore.v1.BatchGetDocumentsResponse.read_time) -} - -inline bool BatchGetDocumentsResponse::has_result() const { - return result_case() != RESULT_NOT_SET; } -inline void BatchGetDocumentsResponse::clear_has_result() { - _impl_._oneof_case_[0] = RESULT_NOT_SET; +inline const ::google::firestore::v1::StructuredQuery& RunQueryRequest::_internal_structured_query() const { + return query_type_case() == kStructuredQuery ? *_impl_.query_type_.structured_query_ : reinterpret_cast<::google::firestore::v1::StructuredQuery&>(::google::firestore::v1::_StructuredQuery_default_instance_); } -inline BatchGetDocumentsResponse::ResultCase BatchGetDocumentsResponse::result_case() const { - return BatchGetDocumentsResponse::ResultCase(_impl_._oneof_case_[0]); +inline const ::google::firestore::v1::StructuredQuery& RunQueryRequest::structured_query() const ABSL_ATTRIBUTE_LIFETIME_BOUND { + // @@protoc_insertion_point(field_get:google.firestore.v1.RunQueryRequest.structured_query) + return _internal_structured_query(); } -// ------------------------------------------------------------------- - -// BeginTransactionRequest - -// string database = 1; -inline void BeginTransactionRequest::clear_database() { - PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); - _impl_.database_.ClearToEmpty(); +inline ::google::firestore::v1::StructuredQuery* RunQueryRequest::unsafe_arena_release_structured_query() { + // @@protoc_insertion_point(field_unsafe_arena_release:google.firestore.v1.RunQueryRequest.structured_query) + if (query_type_case() == kStructuredQuery) { + clear_has_query_type(); + auto* temp = _impl_.query_type_.structured_query_; + _impl_.query_type_.structured_query_ = nullptr; + return temp; + } else { + return nullptr; + } } -inline const std::string& BeginTransactionRequest::database() const - ABSL_ATTRIBUTE_LIFETIME_BOUND { - // @@protoc_insertion_point(field_get:google.firestore.v1.BeginTransactionRequest.database) - return _internal_database(); +inline void RunQueryRequest::unsafe_arena_set_allocated_structured_query(::google::firestore::v1::StructuredQuery* value) { + // We rely on the oneof clear method to free the earlier contents + // of this oneof. We can directly use the pointer we're given to + // set the new value. + clear_query_type(); + if (value) { + set_has_structured_query(); + _impl_.query_type_.structured_query_ = value; + } + // @@protoc_insertion_point(field_unsafe_arena_set_allocated:google.firestore.v1.RunQueryRequest.structured_query) } -template -inline PROTOBUF_ALWAYS_INLINE void BeginTransactionRequest::set_database(Arg_&& arg, - Args_... args) { - PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); - ; - _impl_.database_.Set(static_cast(arg), args..., GetArena()); - // @@protoc_insertion_point(field_set:google.firestore.v1.BeginTransactionRequest.database) +inline ::google::firestore::v1::StructuredQuery* RunQueryRequest::_internal_mutable_structured_query() { + if (query_type_case() != kStructuredQuery) { + clear_query_type(); + set_has_structured_query(); + _impl_.query_type_.structured_query_ = CreateMaybeMessage<::google::firestore::v1::StructuredQuery>(GetArena()); + } + return _impl_.query_type_.structured_query_; } -inline std::string* BeginTransactionRequest::mutable_database() ABSL_ATTRIBUTE_LIFETIME_BOUND { - std::string* _s = _internal_mutable_database(); - // @@protoc_insertion_point(field_mutable:google.firestore.v1.BeginTransactionRequest.database) - return _s; +inline ::google::firestore::v1::StructuredQuery* RunQueryRequest::mutable_structured_query() ABSL_ATTRIBUTE_LIFETIME_BOUND { + ::google::firestore::v1::StructuredQuery* _msg = _internal_mutable_structured_query(); + // @@protoc_insertion_point(field_mutable:google.firestore.v1.RunQueryRequest.structured_query) + return _msg; } -inline const std::string& BeginTransactionRequest::_internal_database() const { - PROTOBUF_TSAN_READ(&_impl_._tsan_detect_race); - return _impl_.database_.Get(); + +// bytes transaction = 5; +inline bool RunQueryRequest::has_transaction() const { + return consistency_selector_case() == kTransaction; } -inline void BeginTransactionRequest::_internal_set_database(const std::string& value) { - PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); - ; - _impl_.database_.Set(value, GetArena()); +inline void RunQueryRequest::set_has_transaction() { + _impl_._oneof_case_[1] = kTransaction; } -inline std::string* BeginTransactionRequest::_internal_mutable_database() { +inline void RunQueryRequest::clear_transaction() { PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); - ; - return _impl_.database_.Mutable( GetArena()); + if (consistency_selector_case() == kTransaction) { + _impl_.consistency_selector_.transaction_.Destroy(); + clear_has_consistency_selector(); + } } -inline std::string* BeginTransactionRequest::release_database() { - PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); - // @@protoc_insertion_point(field_release:google.firestore.v1.BeginTransactionRequest.database) - return _impl_.database_.Release(); +inline const std::string& RunQueryRequest::transaction() const + ABSL_ATTRIBUTE_LIFETIME_BOUND { + // @@protoc_insertion_point(field_get:google.firestore.v1.RunQueryRequest.transaction) + return _internal_transaction(); } -inline void BeginTransactionRequest::set_allocated_database(std::string* value) { +template +inline PROTOBUF_ALWAYS_INLINE void RunQueryRequest::set_transaction(Arg_&& arg, + Args_... args) { PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); - _impl_.database_.SetAllocated(value, GetArena()); - #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING - if (_impl_.database_.IsDefault()) { - _impl_.database_.Set("", GetArena()); - } - #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING - // @@protoc_insertion_point(field_set_allocated:google.firestore.v1.BeginTransactionRequest.database) -} + if (consistency_selector_case() != kTransaction) { + clear_consistency_selector(); -// .google.firestore.v1.TransactionOptions options = 2; -inline bool BeginTransactionRequest::has_options() const { - bool value = (_impl_._has_bits_[0] & 0x00000001u) != 0; - PROTOBUF_ASSUME(!value || _impl_.options_ != nullptr); - return value; -} -inline const ::google::firestore::v1::TransactionOptions& BeginTransactionRequest::_internal_options() const { - PROTOBUF_TSAN_READ(&_impl_._tsan_detect_race); - const ::google::firestore::v1::TransactionOptions* p = _impl_.options_; - return p != nullptr ? *p : reinterpret_cast(::google::firestore::v1::_TransactionOptions_default_instance_); + set_has_transaction(); + _impl_.consistency_selector_.transaction_.InitDefault(); + } + _impl_.consistency_selector_.transaction_.SetBytes(static_cast(arg), args..., GetArena()); + // @@protoc_insertion_point(field_set:google.firestore.v1.RunQueryRequest.transaction) } -inline const ::google::firestore::v1::TransactionOptions& BeginTransactionRequest::options() const ABSL_ATTRIBUTE_LIFETIME_BOUND { - // @@protoc_insertion_point(field_get:google.firestore.v1.BeginTransactionRequest.options) - return _internal_options(); +inline std::string* RunQueryRequest::mutable_transaction() ABSL_ATTRIBUTE_LIFETIME_BOUND { + std::string* _s = _internal_mutable_transaction(); + // @@protoc_insertion_point(field_mutable:google.firestore.v1.RunQueryRequest.transaction) + return _s; } -inline void BeginTransactionRequest::unsafe_arena_set_allocated_options(::google::firestore::v1::TransactionOptions* value) { - PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); - if (GetArena() == nullptr) { - delete reinterpret_cast<::google::protobuf::MessageLite*>(_impl_.options_); - } - _impl_.options_ = reinterpret_cast<::google::firestore::v1::TransactionOptions*>(value); - if (value != nullptr) { - _impl_._has_bits_[0] |= 0x00000001u; - } else { - _impl_._has_bits_[0] &= ~0x00000001u; +inline const std::string& RunQueryRequest::_internal_transaction() const { + PROTOBUF_TSAN_READ(&_impl_._tsan_detect_race); + if (consistency_selector_case() != kTransaction) { + return ::google::protobuf::internal::GetEmptyStringAlreadyInited(); } - // @@protoc_insertion_point(field_unsafe_arena_set_allocated:google.firestore.v1.BeginTransactionRequest.options) + return _impl_.consistency_selector_.transaction_.Get(); } -inline ::google::firestore::v1::TransactionOptions* BeginTransactionRequest::release_options() { +inline void RunQueryRequest::_internal_set_transaction(const std::string& value) { PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); + if (consistency_selector_case() != kTransaction) { + clear_consistency_selector(); - _impl_._has_bits_[0] &= ~0x00000001u; - ::google::firestore::v1::TransactionOptions* released = _impl_.options_; - _impl_.options_ = nullptr; -#ifdef PROTOBUF_FORCE_COPY_IN_RELEASE - auto* old = reinterpret_cast<::google::protobuf::MessageLite*>(released); - released = ::google::protobuf::internal::DuplicateIfNonNull(released); - if (GetArena() == nullptr) { - delete old; - } -#else // PROTOBUF_FORCE_COPY_IN_RELEASE - if (GetArena() != nullptr) { - released = ::google::protobuf::internal::DuplicateIfNonNull(released); + set_has_transaction(); + _impl_.consistency_selector_.transaction_.InitDefault(); } -#endif // !PROTOBUF_FORCE_COPY_IN_RELEASE - return released; + _impl_.consistency_selector_.transaction_.Set(value, GetArena()); } -inline ::google::firestore::v1::TransactionOptions* BeginTransactionRequest::unsafe_arena_release_options() { +inline std::string* RunQueryRequest::_internal_mutable_transaction() { PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); - // @@protoc_insertion_point(field_release:google.firestore.v1.BeginTransactionRequest.options) + if (consistency_selector_case() != kTransaction) { + clear_consistency_selector(); - _impl_._has_bits_[0] &= ~0x00000001u; - ::google::firestore::v1::TransactionOptions* temp = _impl_.options_; - _impl_.options_ = nullptr; - return temp; + set_has_transaction(); + _impl_.consistency_selector_.transaction_.InitDefault(); + } + return _impl_.consistency_selector_.transaction_.Mutable( GetArena()); } -inline ::google::firestore::v1::TransactionOptions* BeginTransactionRequest::_internal_mutable_options() { +inline std::string* RunQueryRequest::release_transaction() { PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); - _impl_._has_bits_[0] |= 0x00000001u; - if (_impl_.options_ == nullptr) { - auto* p = CreateMaybeMessage<::google::firestore::v1::TransactionOptions>(GetArena()); - _impl_.options_ = reinterpret_cast<::google::firestore::v1::TransactionOptions*>(p); + // @@protoc_insertion_point(field_release:google.firestore.v1.RunQueryRequest.transaction) + if (consistency_selector_case() != kTransaction) { + return nullptr; } - return _impl_.options_; -} -inline ::google::firestore::v1::TransactionOptions* BeginTransactionRequest::mutable_options() ABSL_ATTRIBUTE_LIFETIME_BOUND { - ::google::firestore::v1::TransactionOptions* _msg = _internal_mutable_options(); - // @@protoc_insertion_point(field_mutable:google.firestore.v1.BeginTransactionRequest.options) - return _msg; + clear_has_consistency_selector(); + return _impl_.consistency_selector_.transaction_.Release(); } -inline void BeginTransactionRequest::set_allocated_options(::google::firestore::v1::TransactionOptions* value) { - ::google::protobuf::Arena* message_arena = GetArena(); +inline void RunQueryRequest::set_allocated_transaction(std::string* value) { PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); - if (message_arena == nullptr) { - delete reinterpret_cast<::google::protobuf::MessageLite*>(_impl_.options_); + if (has_consistency_selector()) { + clear_consistency_selector(); } - if (value != nullptr) { - ::google::protobuf::Arena* submessage_arena = reinterpret_cast<::google::protobuf::MessageLite*>(value)->GetArena(); - if (message_arena != submessage_arena) { - value = ::google::protobuf::internal::GetOwnedMessage(message_arena, value, submessage_arena); - } - _impl_._has_bits_[0] |= 0x00000001u; - } else { - _impl_._has_bits_[0] &= ~0x00000001u; + set_has_transaction(); + _impl_.consistency_selector_.transaction_.InitAllocated(value, GetArena()); } - - _impl_.options_ = reinterpret_cast<::google::firestore::v1::TransactionOptions*>(value); - // @@protoc_insertion_point(field_set_allocated:google.firestore.v1.BeginTransactionRequest.options) + // @@protoc_insertion_point(field_set_allocated:google.firestore.v1.RunQueryRequest.transaction) } -// ------------------------------------------------------------------- - -// BeginTransactionResponse - -// bytes transaction = 1; -inline void BeginTransactionResponse::clear_transaction() { - PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); - _impl_.transaction_.ClearToEmpty(); -} -inline const std::string& BeginTransactionResponse::transaction() const - ABSL_ATTRIBUTE_LIFETIME_BOUND { - // @@protoc_insertion_point(field_get:google.firestore.v1.BeginTransactionResponse.transaction) - return _internal_transaction(); +// .google.firestore.v1.TransactionOptions new_transaction = 6; +inline bool RunQueryRequest::has_new_transaction() const { + return consistency_selector_case() == kNewTransaction; } -template -inline PROTOBUF_ALWAYS_INLINE void BeginTransactionResponse::set_transaction(Arg_&& arg, - Args_... args) { - PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); - ; - _impl_.transaction_.SetBytes(static_cast(arg), args..., GetArena()); - // @@protoc_insertion_point(field_set:google.firestore.v1.BeginTransactionResponse.transaction) +inline bool RunQueryRequest::_internal_has_new_transaction() const { + return consistency_selector_case() == kNewTransaction; } -inline std::string* BeginTransactionResponse::mutable_transaction() ABSL_ATTRIBUTE_LIFETIME_BOUND { - std::string* _s = _internal_mutable_transaction(); - // @@protoc_insertion_point(field_mutable:google.firestore.v1.BeginTransactionResponse.transaction) - return _s; +inline void RunQueryRequest::set_has_new_transaction() { + _impl_._oneof_case_[1] = kNewTransaction; } -inline const std::string& BeginTransactionResponse::_internal_transaction() const { - PROTOBUF_TSAN_READ(&_impl_._tsan_detect_race); - return _impl_.transaction_.Get(); +inline ::google::firestore::v1::TransactionOptions* RunQueryRequest::release_new_transaction() { + // @@protoc_insertion_point(field_release:google.firestore.v1.RunQueryRequest.new_transaction) + if (consistency_selector_case() == kNewTransaction) { + clear_has_consistency_selector(); + auto* temp = _impl_.consistency_selector_.new_transaction_; + if (GetArena() != nullptr) { + temp = ::google::protobuf::internal::DuplicateIfNonNull(temp); + } + _impl_.consistency_selector_.new_transaction_ = nullptr; + return temp; + } else { + return nullptr; + } } -inline void BeginTransactionResponse::_internal_set_transaction(const std::string& value) { - PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); - ; - _impl_.transaction_.Set(value, GetArena()); +inline const ::google::firestore::v1::TransactionOptions& RunQueryRequest::_internal_new_transaction() const { + return consistency_selector_case() == kNewTransaction ? *_impl_.consistency_selector_.new_transaction_ : reinterpret_cast<::google::firestore::v1::TransactionOptions&>(::google::firestore::v1::_TransactionOptions_default_instance_); } -inline std::string* BeginTransactionResponse::_internal_mutable_transaction() { - PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); - ; - return _impl_.transaction_.Mutable( GetArena()); +inline const ::google::firestore::v1::TransactionOptions& RunQueryRequest::new_transaction() const ABSL_ATTRIBUTE_LIFETIME_BOUND { + // @@protoc_insertion_point(field_get:google.firestore.v1.RunQueryRequest.new_transaction) + return _internal_new_transaction(); } -inline std::string* BeginTransactionResponse::release_transaction() { - PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); - // @@protoc_insertion_point(field_release:google.firestore.v1.BeginTransactionResponse.transaction) - return _impl_.transaction_.Release(); +inline ::google::firestore::v1::TransactionOptions* RunQueryRequest::unsafe_arena_release_new_transaction() { + // @@protoc_insertion_point(field_unsafe_arena_release:google.firestore.v1.RunQueryRequest.new_transaction) + if (consistency_selector_case() == kNewTransaction) { + clear_has_consistency_selector(); + auto* temp = _impl_.consistency_selector_.new_transaction_; + _impl_.consistency_selector_.new_transaction_ = nullptr; + return temp; + } else { + return nullptr; + } } -inline void BeginTransactionResponse::set_allocated_transaction(std::string* value) { - PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); - _impl_.transaction_.SetAllocated(value, GetArena()); - #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING - if (_impl_.transaction_.IsDefault()) { - _impl_.transaction_.Set("", GetArena()); - } - #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING - // @@protoc_insertion_point(field_set_allocated:google.firestore.v1.BeginTransactionResponse.transaction) +inline void RunQueryRequest::unsafe_arena_set_allocated_new_transaction(::google::firestore::v1::TransactionOptions* value) { + // We rely on the oneof clear method to free the earlier contents + // of this oneof. We can directly use the pointer we're given to + // set the new value. + clear_consistency_selector(); + if (value) { + set_has_new_transaction(); + _impl_.consistency_selector_.new_transaction_ = value; + } + // @@protoc_insertion_point(field_unsafe_arena_set_allocated:google.firestore.v1.RunQueryRequest.new_transaction) } - -// ------------------------------------------------------------------- - -// CommitRequest - -// string database = 1; -inline void CommitRequest::clear_database() { - PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); - _impl_.database_.ClearToEmpty(); +inline ::google::firestore::v1::TransactionOptions* RunQueryRequest::_internal_mutable_new_transaction() { + if (consistency_selector_case() != kNewTransaction) { + clear_consistency_selector(); + set_has_new_transaction(); + _impl_.consistency_selector_.new_transaction_ = CreateMaybeMessage<::google::firestore::v1::TransactionOptions>(GetArena()); + } + return _impl_.consistency_selector_.new_transaction_; } -inline const std::string& CommitRequest::database() const - ABSL_ATTRIBUTE_LIFETIME_BOUND { - // @@protoc_insertion_point(field_get:google.firestore.v1.CommitRequest.database) - return _internal_database(); +inline ::google::firestore::v1::TransactionOptions* RunQueryRequest::mutable_new_transaction() ABSL_ATTRIBUTE_LIFETIME_BOUND { + ::google::firestore::v1::TransactionOptions* _msg = _internal_mutable_new_transaction(); + // @@protoc_insertion_point(field_mutable:google.firestore.v1.RunQueryRequest.new_transaction) + return _msg; } -template -inline PROTOBUF_ALWAYS_INLINE void CommitRequest::set_database(Arg_&& arg, - Args_... args) { - PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); - ; - _impl_.database_.Set(static_cast(arg), args..., GetArena()); - // @@protoc_insertion_point(field_set:google.firestore.v1.CommitRequest.database) + +// .google.protobuf.Timestamp read_time = 7; +inline bool RunQueryRequest::has_read_time() const { + return consistency_selector_case() == kReadTime; } -inline std::string* CommitRequest::mutable_database() ABSL_ATTRIBUTE_LIFETIME_BOUND { - std::string* _s = _internal_mutable_database(); - // @@protoc_insertion_point(field_mutable:google.firestore.v1.CommitRequest.database) - return _s; +inline bool RunQueryRequest::_internal_has_read_time() const { + return consistency_selector_case() == kReadTime; } -inline const std::string& CommitRequest::_internal_database() const { - PROTOBUF_TSAN_READ(&_impl_._tsan_detect_race); - return _impl_.database_.Get(); +inline void RunQueryRequest::set_has_read_time() { + _impl_._oneof_case_[1] = kReadTime; } -inline void CommitRequest::_internal_set_database(const std::string& value) { - PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); - ; - _impl_.database_.Set(value, GetArena()); +inline ::google::protobuf::Timestamp* RunQueryRequest::release_read_time() { + // @@protoc_insertion_point(field_release:google.firestore.v1.RunQueryRequest.read_time) + if (consistency_selector_case() == kReadTime) { + clear_has_consistency_selector(); + auto* temp = _impl_.consistency_selector_.read_time_; + if (GetArena() != nullptr) { + temp = ::google::protobuf::internal::DuplicateIfNonNull(temp); + } + _impl_.consistency_selector_.read_time_ = nullptr; + return temp; + } else { + return nullptr; + } } -inline std::string* CommitRequest::_internal_mutable_database() { - PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); - ; - return _impl_.database_.Mutable( GetArena()); +inline const ::google::protobuf::Timestamp& RunQueryRequest::_internal_read_time() const { + return consistency_selector_case() == kReadTime ? *_impl_.consistency_selector_.read_time_ : reinterpret_cast<::google::protobuf::Timestamp&>(::google::protobuf::_Timestamp_default_instance_); } -inline std::string* CommitRequest::release_database() { - PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); - // @@protoc_insertion_point(field_release:google.firestore.v1.CommitRequest.database) - return _impl_.database_.Release(); +inline const ::google::protobuf::Timestamp& RunQueryRequest::read_time() const ABSL_ATTRIBUTE_LIFETIME_BOUND { + // @@protoc_insertion_point(field_get:google.firestore.v1.RunQueryRequest.read_time) + return _internal_read_time(); } -inline void CommitRequest::set_allocated_database(std::string* value) { - PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); - _impl_.database_.SetAllocated(value, GetArena()); - #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING - if (_impl_.database_.IsDefault()) { - _impl_.database_.Set("", GetArena()); - } - #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING - // @@protoc_insertion_point(field_set_allocated:google.firestore.v1.CommitRequest.database) +inline ::google::protobuf::Timestamp* RunQueryRequest::unsafe_arena_release_read_time() { + // @@protoc_insertion_point(field_unsafe_arena_release:google.firestore.v1.RunQueryRequest.read_time) + if (consistency_selector_case() == kReadTime) { + clear_has_consistency_selector(); + auto* temp = _impl_.consistency_selector_.read_time_; + _impl_.consistency_selector_.read_time_ = nullptr; + return temp; + } else { + return nullptr; + } } - -// repeated .google.firestore.v1.Write writes = 2; -inline int CommitRequest::_internal_writes_size() const { - return _internal_writes().size(); +inline void RunQueryRequest::unsafe_arena_set_allocated_read_time(::google::protobuf::Timestamp* value) { + // We rely on the oneof clear method to free the earlier contents + // of this oneof. We can directly use the pointer we're given to + // set the new value. + clear_consistency_selector(); + if (value) { + set_has_read_time(); + _impl_.consistency_selector_.read_time_ = value; + } + // @@protoc_insertion_point(field_unsafe_arena_set_allocated:google.firestore.v1.RunQueryRequest.read_time) } -inline int CommitRequest::writes_size() const { - return _internal_writes_size(); +inline ::google::protobuf::Timestamp* RunQueryRequest::_internal_mutable_read_time() { + if (consistency_selector_case() != kReadTime) { + clear_consistency_selector(); + set_has_read_time(); + _impl_.consistency_selector_.read_time_ = CreateMaybeMessage<::google::protobuf::Timestamp>(GetArena()); + } + return _impl_.consistency_selector_.read_time_; } -inline ::google::firestore::v1::Write* CommitRequest::mutable_writes(int index) - ABSL_ATTRIBUTE_LIFETIME_BOUND { - // @@protoc_insertion_point(field_mutable:google.firestore.v1.CommitRequest.writes) - return _internal_mutable_writes()->Mutable(index); +inline ::google::protobuf::Timestamp* RunQueryRequest::mutable_read_time() ABSL_ATTRIBUTE_LIFETIME_BOUND { + ::google::protobuf::Timestamp* _msg = _internal_mutable_read_time(); + // @@protoc_insertion_point(field_mutable:google.firestore.v1.RunQueryRequest.read_time) + return _msg; } -inline ::google::protobuf::RepeatedPtrField<::google::firestore::v1::Write>* CommitRequest::mutable_writes() - ABSL_ATTRIBUTE_LIFETIME_BOUND { - // @@protoc_insertion_point(field_mutable_list:google.firestore.v1.CommitRequest.writes) - PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); - return _internal_mutable_writes(); + +inline bool RunQueryRequest::has_query_type() const { + return query_type_case() != QUERY_TYPE_NOT_SET; } -inline const ::google::firestore::v1::Write& CommitRequest::writes(int index) const - ABSL_ATTRIBUTE_LIFETIME_BOUND { - // @@protoc_insertion_point(field_get:google.firestore.v1.CommitRequest.writes) - return _internal_writes().Get(index); +inline void RunQueryRequest::clear_has_query_type() { + _impl_._oneof_case_[0] = QUERY_TYPE_NOT_SET; } -inline ::google::firestore::v1::Write* CommitRequest::add_writes() ABSL_ATTRIBUTE_LIFETIME_BOUND { - PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); - ::google::firestore::v1::Write* _add = _internal_mutable_writes()->Add(); - // @@protoc_insertion_point(field_add:google.firestore.v1.CommitRequest.writes) - return _add; +inline bool RunQueryRequest::has_consistency_selector() const { + return consistency_selector_case() != CONSISTENCY_SELECTOR_NOT_SET; } -inline const ::google::protobuf::RepeatedPtrField<::google::firestore::v1::Write>& CommitRequest::writes() const - ABSL_ATTRIBUTE_LIFETIME_BOUND { - // @@protoc_insertion_point(field_list:google.firestore.v1.CommitRequest.writes) - return _internal_writes(); +inline void RunQueryRequest::clear_has_consistency_selector() { + _impl_._oneof_case_[1] = CONSISTENCY_SELECTOR_NOT_SET; } -inline const ::google::protobuf::RepeatedPtrField<::google::firestore::v1::Write>& -CommitRequest::_internal_writes() const { - PROTOBUF_TSAN_READ(&_impl_._tsan_detect_race); - return _impl_.writes_; +inline RunQueryRequest::QueryTypeCase RunQueryRequest::query_type_case() const { + return RunQueryRequest::QueryTypeCase(_impl_._oneof_case_[0]); } -inline ::google::protobuf::RepeatedPtrField<::google::firestore::v1::Write>* -CommitRequest::_internal_mutable_writes() { - PROTOBUF_TSAN_READ(&_impl_._tsan_detect_race); - return &_impl_.writes_; +inline RunQueryRequest::ConsistencySelectorCase RunQueryRequest::consistency_selector_case() const { + return RunQueryRequest::ConsistencySelectorCase(_impl_._oneof_case_[1]); } +// ------------------------------------------------------------------- -// bytes transaction = 3; -inline void CommitRequest::clear_transaction() { +// RunQueryResponse + +// bytes transaction = 2; +inline void RunQueryResponse::clear_transaction() { PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); _impl_.transaction_.ClearToEmpty(); } -inline const std::string& CommitRequest::transaction() const +inline const std::string& RunQueryResponse::transaction() const ABSL_ATTRIBUTE_LIFETIME_BOUND { - // @@protoc_insertion_point(field_get:google.firestore.v1.CommitRequest.transaction) + // @@protoc_insertion_point(field_get:google.firestore.v1.RunQueryResponse.transaction) return _internal_transaction(); } template -inline PROTOBUF_ALWAYS_INLINE void CommitRequest::set_transaction(Arg_&& arg, +inline PROTOBUF_ALWAYS_INLINE void RunQueryResponse::set_transaction(Arg_&& arg, Args_... args) { PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); ; _impl_.transaction_.SetBytes(static_cast(arg), args..., GetArena()); - // @@protoc_insertion_point(field_set:google.firestore.v1.CommitRequest.transaction) + // @@protoc_insertion_point(field_set:google.firestore.v1.RunQueryResponse.transaction) } -inline std::string* CommitRequest::mutable_transaction() ABSL_ATTRIBUTE_LIFETIME_BOUND { +inline std::string* RunQueryResponse::mutable_transaction() ABSL_ATTRIBUTE_LIFETIME_BOUND { std::string* _s = _internal_mutable_transaction(); - // @@protoc_insertion_point(field_mutable:google.firestore.v1.CommitRequest.transaction) + // @@protoc_insertion_point(field_mutable:google.firestore.v1.RunQueryResponse.transaction) return _s; } -inline const std::string& CommitRequest::_internal_transaction() const { +inline const std::string& RunQueryResponse::_internal_transaction() const { PROTOBUF_TSAN_READ(&_impl_._tsan_detect_race); return _impl_.transaction_.Get(); } -inline void CommitRequest::_internal_set_transaction(const std::string& value) { +inline void RunQueryResponse::_internal_set_transaction(const std::string& value) { PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); ; _impl_.transaction_.Set(value, GetArena()); } -inline std::string* CommitRequest::_internal_mutable_transaction() { +inline std::string* RunQueryResponse::_internal_mutable_transaction() { PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); ; return _impl_.transaction_.Mutable( GetArena()); } -inline std::string* CommitRequest::release_transaction() { - PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); - // @@protoc_insertion_point(field_release:google.firestore.v1.CommitRequest.transaction) - return _impl_.transaction_.Release(); -} -inline void CommitRequest::set_allocated_transaction(std::string* value) { - PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); - _impl_.transaction_.SetAllocated(value, GetArena()); - #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING - if (_impl_.transaction_.IsDefault()) { - _impl_.transaction_.Set("", GetArena()); - } - #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING - // @@protoc_insertion_point(field_set_allocated:google.firestore.v1.CommitRequest.transaction) -} - -// ------------------------------------------------------------------- - -// CommitResponse - -// repeated .google.firestore.v1.WriteResult write_results = 1; -inline int CommitResponse::_internal_write_results_size() const { - return _internal_write_results().size(); -} -inline int CommitResponse::write_results_size() const { - return _internal_write_results_size(); -} -inline ::google::firestore::v1::WriteResult* CommitResponse::mutable_write_results(int index) - ABSL_ATTRIBUTE_LIFETIME_BOUND { - // @@protoc_insertion_point(field_mutable:google.firestore.v1.CommitResponse.write_results) - return _internal_mutable_write_results()->Mutable(index); -} -inline ::google::protobuf::RepeatedPtrField<::google::firestore::v1::WriteResult>* CommitResponse::mutable_write_results() - ABSL_ATTRIBUTE_LIFETIME_BOUND { - // @@protoc_insertion_point(field_mutable_list:google.firestore.v1.CommitResponse.write_results) - PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); - return _internal_mutable_write_results(); -} -inline const ::google::firestore::v1::WriteResult& CommitResponse::write_results(int index) const - ABSL_ATTRIBUTE_LIFETIME_BOUND { - // @@protoc_insertion_point(field_get:google.firestore.v1.CommitResponse.write_results) - return _internal_write_results().Get(index); -} -inline ::google::firestore::v1::WriteResult* CommitResponse::add_write_results() ABSL_ATTRIBUTE_LIFETIME_BOUND { +inline std::string* RunQueryResponse::release_transaction() { PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); - ::google::firestore::v1::WriteResult* _add = _internal_mutable_write_results()->Add(); - // @@protoc_insertion_point(field_add:google.firestore.v1.CommitResponse.write_results) - return _add; -} -inline const ::google::protobuf::RepeatedPtrField<::google::firestore::v1::WriteResult>& CommitResponse::write_results() const - ABSL_ATTRIBUTE_LIFETIME_BOUND { - // @@protoc_insertion_point(field_list:google.firestore.v1.CommitResponse.write_results) - return _internal_write_results(); -} -inline const ::google::protobuf::RepeatedPtrField<::google::firestore::v1::WriteResult>& -CommitResponse::_internal_write_results() const { - PROTOBUF_TSAN_READ(&_impl_._tsan_detect_race); - return _impl_.write_results_; -} -inline ::google::protobuf::RepeatedPtrField<::google::firestore::v1::WriteResult>* -CommitResponse::_internal_mutable_write_results() { - PROTOBUF_TSAN_READ(&_impl_._tsan_detect_race); - return &_impl_.write_results_; + // @@protoc_insertion_point(field_release:google.firestore.v1.RunQueryResponse.transaction) + return _impl_.transaction_.Release(); +} +inline void RunQueryResponse::set_allocated_transaction(std::string* value) { + PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); + _impl_.transaction_.SetAllocated(value, GetArena()); + #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING + if (_impl_.transaction_.IsDefault()) { + _impl_.transaction_.Set("", GetArena()); + } + #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING + // @@protoc_insertion_point(field_set_allocated:google.firestore.v1.RunQueryResponse.transaction) } -// .google.protobuf.Timestamp commit_time = 2; -inline bool CommitResponse::has_commit_time() const { +// .google.firestore.v1.Document document = 1; +inline bool RunQueryResponse::has_document() const { bool value = (_impl_._has_bits_[0] & 0x00000001u) != 0; - PROTOBUF_ASSUME(!value || _impl_.commit_time_ != nullptr); + PROTOBUF_ASSUME(!value || _impl_.document_ != nullptr); return value; } -inline const ::google::protobuf::Timestamp& CommitResponse::_internal_commit_time() const { +inline const ::google::firestore::v1::Document& RunQueryResponse::_internal_document() const { PROTOBUF_TSAN_READ(&_impl_._tsan_detect_race); - const ::google::protobuf::Timestamp* p = _impl_.commit_time_; - return p != nullptr ? *p : reinterpret_cast(::google::protobuf::_Timestamp_default_instance_); + const ::google::firestore::v1::Document* p = _impl_.document_; + return p != nullptr ? *p : reinterpret_cast(::google::firestore::v1::_Document_default_instance_); } -inline const ::google::protobuf::Timestamp& CommitResponse::commit_time() const ABSL_ATTRIBUTE_LIFETIME_BOUND { - // @@protoc_insertion_point(field_get:google.firestore.v1.CommitResponse.commit_time) - return _internal_commit_time(); +inline const ::google::firestore::v1::Document& RunQueryResponse::document() const ABSL_ATTRIBUTE_LIFETIME_BOUND { + // @@protoc_insertion_point(field_get:google.firestore.v1.RunQueryResponse.document) + return _internal_document(); } -inline void CommitResponse::unsafe_arena_set_allocated_commit_time(::google::protobuf::Timestamp* value) { +inline void RunQueryResponse::unsafe_arena_set_allocated_document(::google::firestore::v1::Document* value) { PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); if (GetArena() == nullptr) { - delete reinterpret_cast<::google::protobuf::MessageLite*>(_impl_.commit_time_); + delete reinterpret_cast<::google::protobuf::MessageLite*>(_impl_.document_); } - _impl_.commit_time_ = reinterpret_cast<::google::protobuf::Timestamp*>(value); + _impl_.document_ = reinterpret_cast<::google::firestore::v1::Document*>(value); if (value != nullptr) { _impl_._has_bits_[0] |= 0x00000001u; } else { _impl_._has_bits_[0] &= ~0x00000001u; } - // @@protoc_insertion_point(field_unsafe_arena_set_allocated:google.firestore.v1.CommitResponse.commit_time) + // @@protoc_insertion_point(field_unsafe_arena_set_allocated:google.firestore.v1.RunQueryResponse.document) } -inline ::google::protobuf::Timestamp* CommitResponse::release_commit_time() { +inline ::google::firestore::v1::Document* RunQueryResponse::release_document() { PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); _impl_._has_bits_[0] &= ~0x00000001u; - ::google::protobuf::Timestamp* released = _impl_.commit_time_; - _impl_.commit_time_ = nullptr; + ::google::firestore::v1::Document* released = _impl_.document_; + _impl_.document_ = nullptr; #ifdef PROTOBUF_FORCE_COPY_IN_RELEASE auto* old = reinterpret_cast<::google::protobuf::MessageLite*>(released); released = ::google::protobuf::internal::DuplicateIfNonNull(released); @@ -9889,34 +11052,34 @@ inline ::google::protobuf::Timestamp* CommitResponse::release_commit_time() { #endif // !PROTOBUF_FORCE_COPY_IN_RELEASE return released; } -inline ::google::protobuf::Timestamp* CommitResponse::unsafe_arena_release_commit_time() { +inline ::google::firestore::v1::Document* RunQueryResponse::unsafe_arena_release_document() { PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); - // @@protoc_insertion_point(field_release:google.firestore.v1.CommitResponse.commit_time) + // @@protoc_insertion_point(field_release:google.firestore.v1.RunQueryResponse.document) _impl_._has_bits_[0] &= ~0x00000001u; - ::google::protobuf::Timestamp* temp = _impl_.commit_time_; - _impl_.commit_time_ = nullptr; + ::google::firestore::v1::Document* temp = _impl_.document_; + _impl_.document_ = nullptr; return temp; } -inline ::google::protobuf::Timestamp* CommitResponse::_internal_mutable_commit_time() { +inline ::google::firestore::v1::Document* RunQueryResponse::_internal_mutable_document() { PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); _impl_._has_bits_[0] |= 0x00000001u; - if (_impl_.commit_time_ == nullptr) { - auto* p = CreateMaybeMessage<::google::protobuf::Timestamp>(GetArena()); - _impl_.commit_time_ = reinterpret_cast<::google::protobuf::Timestamp*>(p); + if (_impl_.document_ == nullptr) { + auto* p = CreateMaybeMessage<::google::firestore::v1::Document>(GetArena()); + _impl_.document_ = reinterpret_cast<::google::firestore::v1::Document*>(p); } - return _impl_.commit_time_; + return _impl_.document_; } -inline ::google::protobuf::Timestamp* CommitResponse::mutable_commit_time() ABSL_ATTRIBUTE_LIFETIME_BOUND { - ::google::protobuf::Timestamp* _msg = _internal_mutable_commit_time(); - // @@protoc_insertion_point(field_mutable:google.firestore.v1.CommitResponse.commit_time) +inline ::google::firestore::v1::Document* RunQueryResponse::mutable_document() ABSL_ATTRIBUTE_LIFETIME_BOUND { + ::google::firestore::v1::Document* _msg = _internal_mutable_document(); + // @@protoc_insertion_point(field_mutable:google.firestore.v1.RunQueryResponse.document) return _msg; } -inline void CommitResponse::set_allocated_commit_time(::google::protobuf::Timestamp* value) { +inline void RunQueryResponse::set_allocated_document(::google::firestore::v1::Document* value) { ::google::protobuf::Arena* message_arena = GetArena(); PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); if (message_arena == nullptr) { - delete reinterpret_cast<::google::protobuf::MessageLite*>(_impl_.commit_time_); + delete reinterpret_cast<::google::protobuf::MessageLite*>(_impl_.document_); } if (value != nullptr) { @@ -9929,265 +11092,269 @@ inline void CommitResponse::set_allocated_commit_time(::google::protobuf::Timest _impl_._has_bits_[0] &= ~0x00000001u; } - _impl_.commit_time_ = reinterpret_cast<::google::protobuf::Timestamp*>(value); - // @@protoc_insertion_point(field_set_allocated:google.firestore.v1.CommitResponse.commit_time) + _impl_.document_ = reinterpret_cast<::google::firestore::v1::Document*>(value); + // @@protoc_insertion_point(field_set_allocated:google.firestore.v1.RunQueryResponse.document) } -// ------------------------------------------------------------------- - -// RollbackRequest - -// string database = 1; -inline void RollbackRequest::clear_database() { - PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); - _impl_.database_.ClearToEmpty(); -} -inline const std::string& RollbackRequest::database() const - ABSL_ATTRIBUTE_LIFETIME_BOUND { - // @@protoc_insertion_point(field_get:google.firestore.v1.RollbackRequest.database) - return _internal_database(); +// .google.protobuf.Timestamp read_time = 3; +inline bool RunQueryResponse::has_read_time() const { + bool value = (_impl_._has_bits_[0] & 0x00000002u) != 0; + PROTOBUF_ASSUME(!value || _impl_.read_time_ != nullptr); + return value; } -template -inline PROTOBUF_ALWAYS_INLINE void RollbackRequest::set_database(Arg_&& arg, - Args_... args) { - PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); - ; - _impl_.database_.Set(static_cast(arg), args..., GetArena()); - // @@protoc_insertion_point(field_set:google.firestore.v1.RollbackRequest.database) +inline const ::google::protobuf::Timestamp& RunQueryResponse::_internal_read_time() const { + PROTOBUF_TSAN_READ(&_impl_._tsan_detect_race); + const ::google::protobuf::Timestamp* p = _impl_.read_time_; + return p != nullptr ? *p : reinterpret_cast(::google::protobuf::_Timestamp_default_instance_); } -inline std::string* RollbackRequest::mutable_database() ABSL_ATTRIBUTE_LIFETIME_BOUND { - std::string* _s = _internal_mutable_database(); - // @@protoc_insertion_point(field_mutable:google.firestore.v1.RollbackRequest.database) - return _s; +inline const ::google::protobuf::Timestamp& RunQueryResponse::read_time() const ABSL_ATTRIBUTE_LIFETIME_BOUND { + // @@protoc_insertion_point(field_get:google.firestore.v1.RunQueryResponse.read_time) + return _internal_read_time(); } -inline const std::string& RollbackRequest::_internal_database() const { - PROTOBUF_TSAN_READ(&_impl_._tsan_detect_race); - return _impl_.database_.Get(); +inline void RunQueryResponse::unsafe_arena_set_allocated_read_time(::google::protobuf::Timestamp* value) { + PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); + if (GetArena() == nullptr) { + delete reinterpret_cast<::google::protobuf::MessageLite*>(_impl_.read_time_); + } + _impl_.read_time_ = reinterpret_cast<::google::protobuf::Timestamp*>(value); + if (value != nullptr) { + _impl_._has_bits_[0] |= 0x00000002u; + } else { + _impl_._has_bits_[0] &= ~0x00000002u; + } + // @@protoc_insertion_point(field_unsafe_arena_set_allocated:google.firestore.v1.RunQueryResponse.read_time) } -inline void RollbackRequest::_internal_set_database(const std::string& value) { +inline ::google::protobuf::Timestamp* RunQueryResponse::release_read_time() { PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); - ; - _impl_.database_.Set(value, GetArena()); + + _impl_._has_bits_[0] &= ~0x00000002u; + ::google::protobuf::Timestamp* released = _impl_.read_time_; + _impl_.read_time_ = nullptr; +#ifdef PROTOBUF_FORCE_COPY_IN_RELEASE + auto* old = reinterpret_cast<::google::protobuf::MessageLite*>(released); + released = ::google::protobuf::internal::DuplicateIfNonNull(released); + if (GetArena() == nullptr) { + delete old; + } +#else // PROTOBUF_FORCE_COPY_IN_RELEASE + if (GetArena() != nullptr) { + released = ::google::protobuf::internal::DuplicateIfNonNull(released); + } +#endif // !PROTOBUF_FORCE_COPY_IN_RELEASE + return released; } -inline std::string* RollbackRequest::_internal_mutable_database() { +inline ::google::protobuf::Timestamp* RunQueryResponse::unsafe_arena_release_read_time() { PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); - ; - return _impl_.database_.Mutable( GetArena()); + // @@protoc_insertion_point(field_release:google.firestore.v1.RunQueryResponse.read_time) + + _impl_._has_bits_[0] &= ~0x00000002u; + ::google::protobuf::Timestamp* temp = _impl_.read_time_; + _impl_.read_time_ = nullptr; + return temp; } -inline std::string* RollbackRequest::release_database() { +inline ::google::protobuf::Timestamp* RunQueryResponse::_internal_mutable_read_time() { PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); - // @@protoc_insertion_point(field_release:google.firestore.v1.RollbackRequest.database) - return _impl_.database_.Release(); + _impl_._has_bits_[0] |= 0x00000002u; + if (_impl_.read_time_ == nullptr) { + auto* p = CreateMaybeMessage<::google::protobuf::Timestamp>(GetArena()); + _impl_.read_time_ = reinterpret_cast<::google::protobuf::Timestamp*>(p); + } + return _impl_.read_time_; } -inline void RollbackRequest::set_allocated_database(std::string* value) { +inline ::google::protobuf::Timestamp* RunQueryResponse::mutable_read_time() ABSL_ATTRIBUTE_LIFETIME_BOUND { + ::google::protobuf::Timestamp* _msg = _internal_mutable_read_time(); + // @@protoc_insertion_point(field_mutable:google.firestore.v1.RunQueryResponse.read_time) + return _msg; +} +inline void RunQueryResponse::set_allocated_read_time(::google::protobuf::Timestamp* value) { + ::google::protobuf::Arena* message_arena = GetArena(); PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); - _impl_.database_.SetAllocated(value, GetArena()); - #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING - if (_impl_.database_.IsDefault()) { - _impl_.database_.Set("", GetArena()); - } - #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING - // @@protoc_insertion_point(field_set_allocated:google.firestore.v1.RollbackRequest.database) + if (message_arena == nullptr) { + delete reinterpret_cast<::google::protobuf::MessageLite*>(_impl_.read_time_); + } + + if (value != nullptr) { + ::google::protobuf::Arena* submessage_arena = reinterpret_cast<::google::protobuf::MessageLite*>(value)->GetArena(); + if (message_arena != submessage_arena) { + value = ::google::protobuf::internal::GetOwnedMessage(message_arena, value, submessage_arena); + } + _impl_._has_bits_[0] |= 0x00000002u; + } else { + _impl_._has_bits_[0] &= ~0x00000002u; + } + + _impl_.read_time_ = reinterpret_cast<::google::protobuf::Timestamp*>(value); + // @@protoc_insertion_point(field_set_allocated:google.firestore.v1.RunQueryResponse.read_time) } -// bytes transaction = 2; -inline void RollbackRequest::clear_transaction() { +// int32 skipped_results = 4; +inline void RunQueryResponse::clear_skipped_results() { PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); - _impl_.transaction_.ClearToEmpty(); -} -inline const std::string& RollbackRequest::transaction() const - ABSL_ATTRIBUTE_LIFETIME_BOUND { - // @@protoc_insertion_point(field_get:google.firestore.v1.RollbackRequest.transaction) - return _internal_transaction(); + _impl_.skipped_results_ = 0; } -template -inline PROTOBUF_ALWAYS_INLINE void RollbackRequest::set_transaction(Arg_&& arg, - Args_... args) { - PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); - ; - _impl_.transaction_.SetBytes(static_cast(arg), args..., GetArena()); - // @@protoc_insertion_point(field_set:google.firestore.v1.RollbackRequest.transaction) +inline ::int32_t RunQueryResponse::skipped_results() const { + // @@protoc_insertion_point(field_get:google.firestore.v1.RunQueryResponse.skipped_results) + return _internal_skipped_results(); } -inline std::string* RollbackRequest::mutable_transaction() ABSL_ATTRIBUTE_LIFETIME_BOUND { - std::string* _s = _internal_mutable_transaction(); - // @@protoc_insertion_point(field_mutable:google.firestore.v1.RollbackRequest.transaction) - return _s; +inline void RunQueryResponse::set_skipped_results(::int32_t value) { + _internal_set_skipped_results(value); + // @@protoc_insertion_point(field_set:google.firestore.v1.RunQueryResponse.skipped_results) } -inline const std::string& RollbackRequest::_internal_transaction() const { +inline ::int32_t RunQueryResponse::_internal_skipped_results() const { PROTOBUF_TSAN_READ(&_impl_._tsan_detect_race); - return _impl_.transaction_.Get(); -} -inline void RollbackRequest::_internal_set_transaction(const std::string& value) { - PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); - ; - _impl_.transaction_.Set(value, GetArena()); + return _impl_.skipped_results_; } -inline std::string* RollbackRequest::_internal_mutable_transaction() { +inline void RunQueryResponse::_internal_set_skipped_results(::int32_t value) { PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); ; - return _impl_.transaction_.Mutable( GetArena()); -} -inline std::string* RollbackRequest::release_transaction() { - PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); - // @@protoc_insertion_point(field_release:google.firestore.v1.RollbackRequest.transaction) - return _impl_.transaction_.Release(); -} -inline void RollbackRequest::set_allocated_transaction(std::string* value) { - PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); - _impl_.transaction_.SetAllocated(value, GetArena()); - #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING - if (_impl_.transaction_.IsDefault()) { - _impl_.transaction_.Set("", GetArena()); - } - #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING - // @@protoc_insertion_point(field_set_allocated:google.firestore.v1.RollbackRequest.transaction) + _impl_.skipped_results_ = value; } // ------------------------------------------------------------------- -// RunQueryRequest +// ExecutePipelineRequest -// string parent = 1; -inline void RunQueryRequest::clear_parent() { +// string database = 1 [(.google.api.field_behavior) = REQUIRED]; +inline void ExecutePipelineRequest::clear_database() { PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); - _impl_.parent_.ClearToEmpty(); + _impl_.database_.ClearToEmpty(); } -inline const std::string& RunQueryRequest::parent() const +inline const std::string& ExecutePipelineRequest::database() const ABSL_ATTRIBUTE_LIFETIME_BOUND { - // @@protoc_insertion_point(field_get:google.firestore.v1.RunQueryRequest.parent) - return _internal_parent(); + // @@protoc_insertion_point(field_get:google.firestore.v1.ExecutePipelineRequest.database) + return _internal_database(); } template -inline PROTOBUF_ALWAYS_INLINE void RunQueryRequest::set_parent(Arg_&& arg, +inline PROTOBUF_ALWAYS_INLINE void ExecutePipelineRequest::set_database(Arg_&& arg, Args_... args) { PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); ; - _impl_.parent_.Set(static_cast(arg), args..., GetArena()); - // @@protoc_insertion_point(field_set:google.firestore.v1.RunQueryRequest.parent) + _impl_.database_.Set(static_cast(arg), args..., GetArena()); + // @@protoc_insertion_point(field_set:google.firestore.v1.ExecutePipelineRequest.database) } -inline std::string* RunQueryRequest::mutable_parent() ABSL_ATTRIBUTE_LIFETIME_BOUND { - std::string* _s = _internal_mutable_parent(); - // @@protoc_insertion_point(field_mutable:google.firestore.v1.RunQueryRequest.parent) +inline std::string* ExecutePipelineRequest::mutable_database() ABSL_ATTRIBUTE_LIFETIME_BOUND { + std::string* _s = _internal_mutable_database(); + // @@protoc_insertion_point(field_mutable:google.firestore.v1.ExecutePipelineRequest.database) return _s; } -inline const std::string& RunQueryRequest::_internal_parent() const { +inline const std::string& ExecutePipelineRequest::_internal_database() const { PROTOBUF_TSAN_READ(&_impl_._tsan_detect_race); - return _impl_.parent_.Get(); + return _impl_.database_.Get(); } -inline void RunQueryRequest::_internal_set_parent(const std::string& value) { +inline void ExecutePipelineRequest::_internal_set_database(const std::string& value) { PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); ; - _impl_.parent_.Set(value, GetArena()); + _impl_.database_.Set(value, GetArena()); } -inline std::string* RunQueryRequest::_internal_mutable_parent() { +inline std::string* ExecutePipelineRequest::_internal_mutable_database() { PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); ; - return _impl_.parent_.Mutable( GetArena()); + return _impl_.database_.Mutable( GetArena()); } -inline std::string* RunQueryRequest::release_parent() { +inline std::string* ExecutePipelineRequest::release_database() { PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); - // @@protoc_insertion_point(field_release:google.firestore.v1.RunQueryRequest.parent) - return _impl_.parent_.Release(); + // @@protoc_insertion_point(field_release:google.firestore.v1.ExecutePipelineRequest.database) + return _impl_.database_.Release(); } -inline void RunQueryRequest::set_allocated_parent(std::string* value) { +inline void ExecutePipelineRequest::set_allocated_database(std::string* value) { PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); - _impl_.parent_.SetAllocated(value, GetArena()); + _impl_.database_.SetAllocated(value, GetArena()); #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING - if (_impl_.parent_.IsDefault()) { - _impl_.parent_.Set("", GetArena()); + if (_impl_.database_.IsDefault()) { + _impl_.database_.Set("", GetArena()); } #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING - // @@protoc_insertion_point(field_set_allocated:google.firestore.v1.RunQueryRequest.parent) + // @@protoc_insertion_point(field_set_allocated:google.firestore.v1.ExecutePipelineRequest.database) } -// .google.firestore.v1.StructuredQuery structured_query = 2; -inline bool RunQueryRequest::has_structured_query() const { - return query_type_case() == kStructuredQuery; +// .google.firestore.v1.StructuredPipeline structured_pipeline = 2; +inline bool ExecutePipelineRequest::has_structured_pipeline() const { + return pipeline_type_case() == kStructuredPipeline; } -inline bool RunQueryRequest::_internal_has_structured_query() const { - return query_type_case() == kStructuredQuery; +inline bool ExecutePipelineRequest::_internal_has_structured_pipeline() const { + return pipeline_type_case() == kStructuredPipeline; } -inline void RunQueryRequest::set_has_structured_query() { - _impl_._oneof_case_[0] = kStructuredQuery; +inline void ExecutePipelineRequest::set_has_structured_pipeline() { + _impl_._oneof_case_[0] = kStructuredPipeline; } -inline ::google::firestore::v1::StructuredQuery* RunQueryRequest::release_structured_query() { - // @@protoc_insertion_point(field_release:google.firestore.v1.RunQueryRequest.structured_query) - if (query_type_case() == kStructuredQuery) { - clear_has_query_type(); - auto* temp = _impl_.query_type_.structured_query_; +inline ::google::firestore::v1::StructuredPipeline* ExecutePipelineRequest::release_structured_pipeline() { + // @@protoc_insertion_point(field_release:google.firestore.v1.ExecutePipelineRequest.structured_pipeline) + if (pipeline_type_case() == kStructuredPipeline) { + clear_has_pipeline_type(); + auto* temp = _impl_.pipeline_type_.structured_pipeline_; if (GetArena() != nullptr) { temp = ::google::protobuf::internal::DuplicateIfNonNull(temp); } - _impl_.query_type_.structured_query_ = nullptr; + _impl_.pipeline_type_.structured_pipeline_ = nullptr; return temp; } else { return nullptr; } } -inline const ::google::firestore::v1::StructuredQuery& RunQueryRequest::_internal_structured_query() const { - return query_type_case() == kStructuredQuery ? *_impl_.query_type_.structured_query_ : reinterpret_cast<::google::firestore::v1::StructuredQuery&>(::google::firestore::v1::_StructuredQuery_default_instance_); +inline const ::google::firestore::v1::StructuredPipeline& ExecutePipelineRequest::_internal_structured_pipeline() const { + return pipeline_type_case() == kStructuredPipeline ? *_impl_.pipeline_type_.structured_pipeline_ : reinterpret_cast<::google::firestore::v1::StructuredPipeline&>(::google::firestore::v1::_StructuredPipeline_default_instance_); } -inline const ::google::firestore::v1::StructuredQuery& RunQueryRequest::structured_query() const ABSL_ATTRIBUTE_LIFETIME_BOUND { - // @@protoc_insertion_point(field_get:google.firestore.v1.RunQueryRequest.structured_query) - return _internal_structured_query(); +inline const ::google::firestore::v1::StructuredPipeline& ExecutePipelineRequest::structured_pipeline() const ABSL_ATTRIBUTE_LIFETIME_BOUND { + // @@protoc_insertion_point(field_get:google.firestore.v1.ExecutePipelineRequest.structured_pipeline) + return _internal_structured_pipeline(); } -inline ::google::firestore::v1::StructuredQuery* RunQueryRequest::unsafe_arena_release_structured_query() { - // @@protoc_insertion_point(field_unsafe_arena_release:google.firestore.v1.RunQueryRequest.structured_query) - if (query_type_case() == kStructuredQuery) { - clear_has_query_type(); - auto* temp = _impl_.query_type_.structured_query_; - _impl_.query_type_.structured_query_ = nullptr; +inline ::google::firestore::v1::StructuredPipeline* ExecutePipelineRequest::unsafe_arena_release_structured_pipeline() { + // @@protoc_insertion_point(field_unsafe_arena_release:google.firestore.v1.ExecutePipelineRequest.structured_pipeline) + if (pipeline_type_case() == kStructuredPipeline) { + clear_has_pipeline_type(); + auto* temp = _impl_.pipeline_type_.structured_pipeline_; + _impl_.pipeline_type_.structured_pipeline_ = nullptr; return temp; } else { return nullptr; } } -inline void RunQueryRequest::unsafe_arena_set_allocated_structured_query(::google::firestore::v1::StructuredQuery* value) { +inline void ExecutePipelineRequest::unsafe_arena_set_allocated_structured_pipeline(::google::firestore::v1::StructuredPipeline* value) { // We rely on the oneof clear method to free the earlier contents // of this oneof. We can directly use the pointer we're given to // set the new value. - clear_query_type(); + clear_pipeline_type(); if (value) { - set_has_structured_query(); - _impl_.query_type_.structured_query_ = value; + set_has_structured_pipeline(); + _impl_.pipeline_type_.structured_pipeline_ = value; } - // @@protoc_insertion_point(field_unsafe_arena_set_allocated:google.firestore.v1.RunQueryRequest.structured_query) + // @@protoc_insertion_point(field_unsafe_arena_set_allocated:google.firestore.v1.ExecutePipelineRequest.structured_pipeline) } -inline ::google::firestore::v1::StructuredQuery* RunQueryRequest::_internal_mutable_structured_query() { - if (query_type_case() != kStructuredQuery) { - clear_query_type(); - set_has_structured_query(); - _impl_.query_type_.structured_query_ = CreateMaybeMessage<::google::firestore::v1::StructuredQuery>(GetArena()); +inline ::google::firestore::v1::StructuredPipeline* ExecutePipelineRequest::_internal_mutable_structured_pipeline() { + if (pipeline_type_case() != kStructuredPipeline) { + clear_pipeline_type(); + set_has_structured_pipeline(); + _impl_.pipeline_type_.structured_pipeline_ = CreateMaybeMessage<::google::firestore::v1::StructuredPipeline>(GetArena()); } - return _impl_.query_type_.structured_query_; + return _impl_.pipeline_type_.structured_pipeline_; } -inline ::google::firestore::v1::StructuredQuery* RunQueryRequest::mutable_structured_query() ABSL_ATTRIBUTE_LIFETIME_BOUND { - ::google::firestore::v1::StructuredQuery* _msg = _internal_mutable_structured_query(); - // @@protoc_insertion_point(field_mutable:google.firestore.v1.RunQueryRequest.structured_query) +inline ::google::firestore::v1::StructuredPipeline* ExecutePipelineRequest::mutable_structured_pipeline() ABSL_ATTRIBUTE_LIFETIME_BOUND { + ::google::firestore::v1::StructuredPipeline* _msg = _internal_mutable_structured_pipeline(); + // @@protoc_insertion_point(field_mutable:google.firestore.v1.ExecutePipelineRequest.structured_pipeline) return _msg; } // bytes transaction = 5; -inline bool RunQueryRequest::has_transaction() const { +inline bool ExecutePipelineRequest::has_transaction() const { return consistency_selector_case() == kTransaction; } -inline void RunQueryRequest::set_has_transaction() { +inline void ExecutePipelineRequest::set_has_transaction() { _impl_._oneof_case_[1] = kTransaction; } -inline void RunQueryRequest::clear_transaction() { +inline void ExecutePipelineRequest::clear_transaction() { PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); if (consistency_selector_case() == kTransaction) { _impl_.consistency_selector_.transaction_.Destroy(); clear_has_consistency_selector(); } } -inline const std::string& RunQueryRequest::transaction() const +inline const std::string& ExecutePipelineRequest::transaction() const ABSL_ATTRIBUTE_LIFETIME_BOUND { - // @@protoc_insertion_point(field_get:google.firestore.v1.RunQueryRequest.transaction) + // @@protoc_insertion_point(field_get:google.firestore.v1.ExecutePipelineRequest.transaction) return _internal_transaction(); } template -inline PROTOBUF_ALWAYS_INLINE void RunQueryRequest::set_transaction(Arg_&& arg, +inline PROTOBUF_ALWAYS_INLINE void ExecutePipelineRequest::set_transaction(Arg_&& arg, Args_... args) { PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); if (consistency_selector_case() != kTransaction) { @@ -10197,21 +11364,21 @@ inline PROTOBUF_ALWAYS_INLINE void RunQueryRequest::set_transaction(Arg_&& arg, _impl_.consistency_selector_.transaction_.InitDefault(); } _impl_.consistency_selector_.transaction_.SetBytes(static_cast(arg), args..., GetArena()); - // @@protoc_insertion_point(field_set:google.firestore.v1.RunQueryRequest.transaction) + // @@protoc_insertion_point(field_set:google.firestore.v1.ExecutePipelineRequest.transaction) } -inline std::string* RunQueryRequest::mutable_transaction() ABSL_ATTRIBUTE_LIFETIME_BOUND { +inline std::string* ExecutePipelineRequest::mutable_transaction() ABSL_ATTRIBUTE_LIFETIME_BOUND { std::string* _s = _internal_mutable_transaction(); - // @@protoc_insertion_point(field_mutable:google.firestore.v1.RunQueryRequest.transaction) + // @@protoc_insertion_point(field_mutable:google.firestore.v1.ExecutePipelineRequest.transaction) return _s; } -inline const std::string& RunQueryRequest::_internal_transaction() const { +inline const std::string& ExecutePipelineRequest::_internal_transaction() const { PROTOBUF_TSAN_READ(&_impl_._tsan_detect_race); if (consistency_selector_case() != kTransaction) { return ::google::protobuf::internal::GetEmptyStringAlreadyInited(); } return _impl_.consistency_selector_.transaction_.Get(); } -inline void RunQueryRequest::_internal_set_transaction(const std::string& value) { +inline void ExecutePipelineRequest::_internal_set_transaction(const std::string& value) { PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); if (consistency_selector_case() != kTransaction) { clear_consistency_selector(); @@ -10221,7 +11388,7 @@ inline void RunQueryRequest::_internal_set_transaction(const std::string& value) } _impl_.consistency_selector_.transaction_.Set(value, GetArena()); } -inline std::string* RunQueryRequest::_internal_mutable_transaction() { +inline std::string* ExecutePipelineRequest::_internal_mutable_transaction() { PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); if (consistency_selector_case() != kTransaction) { clear_consistency_selector(); @@ -10231,16 +11398,16 @@ inline std::string* RunQueryRequest::_internal_mutable_transaction() { } return _impl_.consistency_selector_.transaction_.Mutable( GetArena()); } -inline std::string* RunQueryRequest::release_transaction() { +inline std::string* ExecutePipelineRequest::release_transaction() { PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); - // @@protoc_insertion_point(field_release:google.firestore.v1.RunQueryRequest.transaction) + // @@protoc_insertion_point(field_release:google.firestore.v1.ExecutePipelineRequest.transaction) if (consistency_selector_case() != kTransaction) { return nullptr; } clear_has_consistency_selector(); return _impl_.consistency_selector_.transaction_.Release(); } -inline void RunQueryRequest::set_allocated_transaction(std::string* value) { +inline void ExecutePipelineRequest::set_allocated_transaction(std::string* value) { PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); if (has_consistency_selector()) { clear_consistency_selector(); @@ -10249,21 +11416,21 @@ inline void RunQueryRequest::set_allocated_transaction(std::string* value) { set_has_transaction(); _impl_.consistency_selector_.transaction_.InitAllocated(value, GetArena()); } - // @@protoc_insertion_point(field_set_allocated:google.firestore.v1.RunQueryRequest.transaction) + // @@protoc_insertion_point(field_set_allocated:google.firestore.v1.ExecutePipelineRequest.transaction) } // .google.firestore.v1.TransactionOptions new_transaction = 6; -inline bool RunQueryRequest::has_new_transaction() const { +inline bool ExecutePipelineRequest::has_new_transaction() const { return consistency_selector_case() == kNewTransaction; } -inline bool RunQueryRequest::_internal_has_new_transaction() const { +inline bool ExecutePipelineRequest::_internal_has_new_transaction() const { return consistency_selector_case() == kNewTransaction; } -inline void RunQueryRequest::set_has_new_transaction() { +inline void ExecutePipelineRequest::set_has_new_transaction() { _impl_._oneof_case_[1] = kNewTransaction; } -inline ::google::firestore::v1::TransactionOptions* RunQueryRequest::release_new_transaction() { - // @@protoc_insertion_point(field_release:google.firestore.v1.RunQueryRequest.new_transaction) +inline ::google::firestore::v1::TransactionOptions* ExecutePipelineRequest::release_new_transaction() { + // @@protoc_insertion_point(field_release:google.firestore.v1.ExecutePipelineRequest.new_transaction) if (consistency_selector_case() == kNewTransaction) { clear_has_consistency_selector(); auto* temp = _impl_.consistency_selector_.new_transaction_; @@ -10276,15 +11443,15 @@ inline ::google::firestore::v1::TransactionOptions* RunQueryRequest::release_new return nullptr; } } -inline const ::google::firestore::v1::TransactionOptions& RunQueryRequest::_internal_new_transaction() const { +inline const ::google::firestore::v1::TransactionOptions& ExecutePipelineRequest::_internal_new_transaction() const { return consistency_selector_case() == kNewTransaction ? *_impl_.consistency_selector_.new_transaction_ : reinterpret_cast<::google::firestore::v1::TransactionOptions&>(::google::firestore::v1::_TransactionOptions_default_instance_); } -inline const ::google::firestore::v1::TransactionOptions& RunQueryRequest::new_transaction() const ABSL_ATTRIBUTE_LIFETIME_BOUND { - // @@protoc_insertion_point(field_get:google.firestore.v1.RunQueryRequest.new_transaction) +inline const ::google::firestore::v1::TransactionOptions& ExecutePipelineRequest::new_transaction() const ABSL_ATTRIBUTE_LIFETIME_BOUND { + // @@protoc_insertion_point(field_get:google.firestore.v1.ExecutePipelineRequest.new_transaction) return _internal_new_transaction(); } -inline ::google::firestore::v1::TransactionOptions* RunQueryRequest::unsafe_arena_release_new_transaction() { - // @@protoc_insertion_point(field_unsafe_arena_release:google.firestore.v1.RunQueryRequest.new_transaction) +inline ::google::firestore::v1::TransactionOptions* ExecutePipelineRequest::unsafe_arena_release_new_transaction() { + // @@protoc_insertion_point(field_unsafe_arena_release:google.firestore.v1.ExecutePipelineRequest.new_transaction) if (consistency_selector_case() == kNewTransaction) { clear_has_consistency_selector(); auto* temp = _impl_.consistency_selector_.new_transaction_; @@ -10294,7 +11461,7 @@ inline ::google::firestore::v1::TransactionOptions* RunQueryRequest::unsafe_aren return nullptr; } } -inline void RunQueryRequest::unsafe_arena_set_allocated_new_transaction(::google::firestore::v1::TransactionOptions* value) { +inline void ExecutePipelineRequest::unsafe_arena_set_allocated_new_transaction(::google::firestore::v1::TransactionOptions* value) { // We rely on the oneof clear method to free the earlier contents // of this oneof. We can directly use the pointer we're given to // set the new value. @@ -10303,9 +11470,9 @@ inline void RunQueryRequest::unsafe_arena_set_allocated_new_transaction(::google set_has_new_transaction(); _impl_.consistency_selector_.new_transaction_ = value; } - // @@protoc_insertion_point(field_unsafe_arena_set_allocated:google.firestore.v1.RunQueryRequest.new_transaction) + // @@protoc_insertion_point(field_unsafe_arena_set_allocated:google.firestore.v1.ExecutePipelineRequest.new_transaction) } -inline ::google::firestore::v1::TransactionOptions* RunQueryRequest::_internal_mutable_new_transaction() { +inline ::google::firestore::v1::TransactionOptions* ExecutePipelineRequest::_internal_mutable_new_transaction() { if (consistency_selector_case() != kNewTransaction) { clear_consistency_selector(); set_has_new_transaction(); @@ -10313,24 +11480,24 @@ inline ::google::firestore::v1::TransactionOptions* RunQueryRequest::_internal_m } return _impl_.consistency_selector_.new_transaction_; } -inline ::google::firestore::v1::TransactionOptions* RunQueryRequest::mutable_new_transaction() ABSL_ATTRIBUTE_LIFETIME_BOUND { +inline ::google::firestore::v1::TransactionOptions* ExecutePipelineRequest::mutable_new_transaction() ABSL_ATTRIBUTE_LIFETIME_BOUND { ::google::firestore::v1::TransactionOptions* _msg = _internal_mutable_new_transaction(); - // @@protoc_insertion_point(field_mutable:google.firestore.v1.RunQueryRequest.new_transaction) + // @@protoc_insertion_point(field_mutable:google.firestore.v1.ExecutePipelineRequest.new_transaction) return _msg; } // .google.protobuf.Timestamp read_time = 7; -inline bool RunQueryRequest::has_read_time() const { +inline bool ExecutePipelineRequest::has_read_time() const { return consistency_selector_case() == kReadTime; } -inline bool RunQueryRequest::_internal_has_read_time() const { +inline bool ExecutePipelineRequest::_internal_has_read_time() const { return consistency_selector_case() == kReadTime; } -inline void RunQueryRequest::set_has_read_time() { +inline void ExecutePipelineRequest::set_has_read_time() { _impl_._oneof_case_[1] = kReadTime; } -inline ::google::protobuf::Timestamp* RunQueryRequest::release_read_time() { - // @@protoc_insertion_point(field_release:google.firestore.v1.RunQueryRequest.read_time) +inline ::google::protobuf::Timestamp* ExecutePipelineRequest::release_read_time() { + // @@protoc_insertion_point(field_release:google.firestore.v1.ExecutePipelineRequest.read_time) if (consistency_selector_case() == kReadTime) { clear_has_consistency_selector(); auto* temp = _impl_.consistency_selector_.read_time_; @@ -10343,15 +11510,15 @@ inline ::google::protobuf::Timestamp* RunQueryRequest::release_read_time() { return nullptr; } } -inline const ::google::protobuf::Timestamp& RunQueryRequest::_internal_read_time() const { +inline const ::google::protobuf::Timestamp& ExecutePipelineRequest::_internal_read_time() const { return consistency_selector_case() == kReadTime ? *_impl_.consistency_selector_.read_time_ : reinterpret_cast<::google::protobuf::Timestamp&>(::google::protobuf::_Timestamp_default_instance_); } -inline const ::google::protobuf::Timestamp& RunQueryRequest::read_time() const ABSL_ATTRIBUTE_LIFETIME_BOUND { - // @@protoc_insertion_point(field_get:google.firestore.v1.RunQueryRequest.read_time) +inline const ::google::protobuf::Timestamp& ExecutePipelineRequest::read_time() const ABSL_ATTRIBUTE_LIFETIME_BOUND { + // @@protoc_insertion_point(field_get:google.firestore.v1.ExecutePipelineRequest.read_time) return _internal_read_time(); } -inline ::google::protobuf::Timestamp* RunQueryRequest::unsafe_arena_release_read_time() { - // @@protoc_insertion_point(field_unsafe_arena_release:google.firestore.v1.RunQueryRequest.read_time) +inline ::google::protobuf::Timestamp* ExecutePipelineRequest::unsafe_arena_release_read_time() { + // @@protoc_insertion_point(field_unsafe_arena_release:google.firestore.v1.ExecutePipelineRequest.read_time) if (consistency_selector_case() == kReadTime) { clear_has_consistency_selector(); auto* temp = _impl_.consistency_selector_.read_time_; @@ -10361,7 +11528,7 @@ inline ::google::protobuf::Timestamp* RunQueryRequest::unsafe_arena_release_read return nullptr; } } -inline void RunQueryRequest::unsafe_arena_set_allocated_read_time(::google::protobuf::Timestamp* value) { +inline void ExecutePipelineRequest::unsafe_arena_set_allocated_read_time(::google::protobuf::Timestamp* value) { // We rely on the oneof clear method to free the earlier contents // of this oneof. We can directly use the pointer we're given to // set the new value. @@ -10370,9 +11537,9 @@ inline void RunQueryRequest::unsafe_arena_set_allocated_read_time(::google::prot set_has_read_time(); _impl_.consistency_selector_.read_time_ = value; } - // @@protoc_insertion_point(field_unsafe_arena_set_allocated:google.firestore.v1.RunQueryRequest.read_time) + // @@protoc_insertion_point(field_unsafe_arena_set_allocated:google.firestore.v1.ExecutePipelineRequest.read_time) } -inline ::google::protobuf::Timestamp* RunQueryRequest::_internal_mutable_read_time() { +inline ::google::protobuf::Timestamp* ExecutePipelineRequest::_internal_mutable_read_time() { if (consistency_selector_case() != kReadTime) { clear_consistency_selector(); set_has_read_time(); @@ -10380,77 +11547,77 @@ inline ::google::protobuf::Timestamp* RunQueryRequest::_internal_mutable_read_ti } return _impl_.consistency_selector_.read_time_; } -inline ::google::protobuf::Timestamp* RunQueryRequest::mutable_read_time() ABSL_ATTRIBUTE_LIFETIME_BOUND { +inline ::google::protobuf::Timestamp* ExecutePipelineRequest::mutable_read_time() ABSL_ATTRIBUTE_LIFETIME_BOUND { ::google::protobuf::Timestamp* _msg = _internal_mutable_read_time(); - // @@protoc_insertion_point(field_mutable:google.firestore.v1.RunQueryRequest.read_time) + // @@protoc_insertion_point(field_mutable:google.firestore.v1.ExecutePipelineRequest.read_time) return _msg; } -inline bool RunQueryRequest::has_query_type() const { - return query_type_case() != QUERY_TYPE_NOT_SET; +inline bool ExecutePipelineRequest::has_pipeline_type() const { + return pipeline_type_case() != PIPELINE_TYPE_NOT_SET; } -inline void RunQueryRequest::clear_has_query_type() { - _impl_._oneof_case_[0] = QUERY_TYPE_NOT_SET; +inline void ExecutePipelineRequest::clear_has_pipeline_type() { + _impl_._oneof_case_[0] = PIPELINE_TYPE_NOT_SET; } -inline bool RunQueryRequest::has_consistency_selector() const { +inline bool ExecutePipelineRequest::has_consistency_selector() const { return consistency_selector_case() != CONSISTENCY_SELECTOR_NOT_SET; } -inline void RunQueryRequest::clear_has_consistency_selector() { +inline void ExecutePipelineRequest::clear_has_consistency_selector() { _impl_._oneof_case_[1] = CONSISTENCY_SELECTOR_NOT_SET; } -inline RunQueryRequest::QueryTypeCase RunQueryRequest::query_type_case() const { - return RunQueryRequest::QueryTypeCase(_impl_._oneof_case_[0]); +inline ExecutePipelineRequest::PipelineTypeCase ExecutePipelineRequest::pipeline_type_case() const { + return ExecutePipelineRequest::PipelineTypeCase(_impl_._oneof_case_[0]); } -inline RunQueryRequest::ConsistencySelectorCase RunQueryRequest::consistency_selector_case() const { - return RunQueryRequest::ConsistencySelectorCase(_impl_._oneof_case_[1]); +inline ExecutePipelineRequest::ConsistencySelectorCase ExecutePipelineRequest::consistency_selector_case() const { + return ExecutePipelineRequest::ConsistencySelectorCase(_impl_._oneof_case_[1]); } // ------------------------------------------------------------------- -// RunQueryResponse +// ExecutePipelineResponse -// bytes transaction = 2; -inline void RunQueryResponse::clear_transaction() { +// bytes transaction = 1; +inline void ExecutePipelineResponse::clear_transaction() { PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); _impl_.transaction_.ClearToEmpty(); } -inline const std::string& RunQueryResponse::transaction() const +inline const std::string& ExecutePipelineResponse::transaction() const ABSL_ATTRIBUTE_LIFETIME_BOUND { - // @@protoc_insertion_point(field_get:google.firestore.v1.RunQueryResponse.transaction) + // @@protoc_insertion_point(field_get:google.firestore.v1.ExecutePipelineResponse.transaction) return _internal_transaction(); } template -inline PROTOBUF_ALWAYS_INLINE void RunQueryResponse::set_transaction(Arg_&& arg, +inline PROTOBUF_ALWAYS_INLINE void ExecutePipelineResponse::set_transaction(Arg_&& arg, Args_... args) { PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); ; _impl_.transaction_.SetBytes(static_cast(arg), args..., GetArena()); - // @@protoc_insertion_point(field_set:google.firestore.v1.RunQueryResponse.transaction) + // @@protoc_insertion_point(field_set:google.firestore.v1.ExecutePipelineResponse.transaction) } -inline std::string* RunQueryResponse::mutable_transaction() ABSL_ATTRIBUTE_LIFETIME_BOUND { +inline std::string* ExecutePipelineResponse::mutable_transaction() ABSL_ATTRIBUTE_LIFETIME_BOUND { std::string* _s = _internal_mutable_transaction(); - // @@protoc_insertion_point(field_mutable:google.firestore.v1.RunQueryResponse.transaction) + // @@protoc_insertion_point(field_mutable:google.firestore.v1.ExecutePipelineResponse.transaction) return _s; } -inline const std::string& RunQueryResponse::_internal_transaction() const { +inline const std::string& ExecutePipelineResponse::_internal_transaction() const { PROTOBUF_TSAN_READ(&_impl_._tsan_detect_race); return _impl_.transaction_.Get(); } -inline void RunQueryResponse::_internal_set_transaction(const std::string& value) { +inline void ExecutePipelineResponse::_internal_set_transaction(const std::string& value) { PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); ; _impl_.transaction_.Set(value, GetArena()); } -inline std::string* RunQueryResponse::_internal_mutable_transaction() { +inline std::string* ExecutePipelineResponse::_internal_mutable_transaction() { PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); ; return _impl_.transaction_.Mutable( GetArena()); } -inline std::string* RunQueryResponse::release_transaction() { +inline std::string* ExecutePipelineResponse::release_transaction() { PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); - // @@protoc_insertion_point(field_release:google.firestore.v1.RunQueryResponse.transaction) + // @@protoc_insertion_point(field_release:google.firestore.v1.ExecutePipelineResponse.transaction) return _impl_.transaction_.Release(); } -inline void RunQueryResponse::set_allocated_transaction(std::string* value) { +inline void ExecutePipelineResponse::set_allocated_transaction(std::string* value) { PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); _impl_.transaction_.SetAllocated(value, GetArena()); #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING @@ -10458,43 +11625,88 @@ inline void RunQueryResponse::set_allocated_transaction(std::string* value) { _impl_.transaction_.Set("", GetArena()); } #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING - // @@protoc_insertion_point(field_set_allocated:google.firestore.v1.RunQueryResponse.transaction) + // @@protoc_insertion_point(field_set_allocated:google.firestore.v1.ExecutePipelineResponse.transaction) } -// .google.firestore.v1.Document document = 1; -inline bool RunQueryResponse::has_document() const { +// repeated .google.firestore.v1.Document results = 2; +inline int ExecutePipelineResponse::_internal_results_size() const { + return _internal_results().size(); +} +inline int ExecutePipelineResponse::results_size() const { + return _internal_results_size(); +} +inline ::google::firestore::v1::Document* ExecutePipelineResponse::mutable_results(int index) + ABSL_ATTRIBUTE_LIFETIME_BOUND { + // @@protoc_insertion_point(field_mutable:google.firestore.v1.ExecutePipelineResponse.results) + return _internal_mutable_results()->Mutable(index); +} +inline ::google::protobuf::RepeatedPtrField<::google::firestore::v1::Document>* ExecutePipelineResponse::mutable_results() + ABSL_ATTRIBUTE_LIFETIME_BOUND { + // @@protoc_insertion_point(field_mutable_list:google.firestore.v1.ExecutePipelineResponse.results) + PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); + return _internal_mutable_results(); +} +inline const ::google::firestore::v1::Document& ExecutePipelineResponse::results(int index) const + ABSL_ATTRIBUTE_LIFETIME_BOUND { + // @@protoc_insertion_point(field_get:google.firestore.v1.ExecutePipelineResponse.results) + return _internal_results().Get(index); +} +inline ::google::firestore::v1::Document* ExecutePipelineResponse::add_results() ABSL_ATTRIBUTE_LIFETIME_BOUND { + PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); + ::google::firestore::v1::Document* _add = _internal_mutable_results()->Add(); + // @@protoc_insertion_point(field_add:google.firestore.v1.ExecutePipelineResponse.results) + return _add; +} +inline const ::google::protobuf::RepeatedPtrField<::google::firestore::v1::Document>& ExecutePipelineResponse::results() const + ABSL_ATTRIBUTE_LIFETIME_BOUND { + // @@protoc_insertion_point(field_list:google.firestore.v1.ExecutePipelineResponse.results) + return _internal_results(); +} +inline const ::google::protobuf::RepeatedPtrField<::google::firestore::v1::Document>& +ExecutePipelineResponse::_internal_results() const { + PROTOBUF_TSAN_READ(&_impl_._tsan_detect_race); + return _impl_.results_; +} +inline ::google::protobuf::RepeatedPtrField<::google::firestore::v1::Document>* +ExecutePipelineResponse::_internal_mutable_results() { + PROTOBUF_TSAN_READ(&_impl_._tsan_detect_race); + return &_impl_.results_; +} + +// .google.protobuf.Timestamp execution_time = 3; +inline bool ExecutePipelineResponse::has_execution_time() const { bool value = (_impl_._has_bits_[0] & 0x00000001u) != 0; - PROTOBUF_ASSUME(!value || _impl_.document_ != nullptr); + PROTOBUF_ASSUME(!value || _impl_.execution_time_ != nullptr); return value; } -inline const ::google::firestore::v1::Document& RunQueryResponse::_internal_document() const { +inline const ::google::protobuf::Timestamp& ExecutePipelineResponse::_internal_execution_time() const { PROTOBUF_TSAN_READ(&_impl_._tsan_detect_race); - const ::google::firestore::v1::Document* p = _impl_.document_; - return p != nullptr ? *p : reinterpret_cast(::google::firestore::v1::_Document_default_instance_); + const ::google::protobuf::Timestamp* p = _impl_.execution_time_; + return p != nullptr ? *p : reinterpret_cast(::google::protobuf::_Timestamp_default_instance_); } -inline const ::google::firestore::v1::Document& RunQueryResponse::document() const ABSL_ATTRIBUTE_LIFETIME_BOUND { - // @@protoc_insertion_point(field_get:google.firestore.v1.RunQueryResponse.document) - return _internal_document(); +inline const ::google::protobuf::Timestamp& ExecutePipelineResponse::execution_time() const ABSL_ATTRIBUTE_LIFETIME_BOUND { + // @@protoc_insertion_point(field_get:google.firestore.v1.ExecutePipelineResponse.execution_time) + return _internal_execution_time(); } -inline void RunQueryResponse::unsafe_arena_set_allocated_document(::google::firestore::v1::Document* value) { +inline void ExecutePipelineResponse::unsafe_arena_set_allocated_execution_time(::google::protobuf::Timestamp* value) { PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); if (GetArena() == nullptr) { - delete reinterpret_cast<::google::protobuf::MessageLite*>(_impl_.document_); + delete reinterpret_cast<::google::protobuf::MessageLite*>(_impl_.execution_time_); } - _impl_.document_ = reinterpret_cast<::google::firestore::v1::Document*>(value); + _impl_.execution_time_ = reinterpret_cast<::google::protobuf::Timestamp*>(value); if (value != nullptr) { _impl_._has_bits_[0] |= 0x00000001u; } else { _impl_._has_bits_[0] &= ~0x00000001u; } - // @@protoc_insertion_point(field_unsafe_arena_set_allocated:google.firestore.v1.RunQueryResponse.document) + // @@protoc_insertion_point(field_unsafe_arena_set_allocated:google.firestore.v1.ExecutePipelineResponse.execution_time) } -inline ::google::firestore::v1::Document* RunQueryResponse::release_document() { +inline ::google::protobuf::Timestamp* ExecutePipelineResponse::release_execution_time() { PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); _impl_._has_bits_[0] &= ~0x00000001u; - ::google::firestore::v1::Document* released = _impl_.document_; - _impl_.document_ = nullptr; + ::google::protobuf::Timestamp* released = _impl_.execution_time_; + _impl_.execution_time_ = nullptr; #ifdef PROTOBUF_FORCE_COPY_IN_RELEASE auto* old = reinterpret_cast<::google::protobuf::MessageLite*>(released); released = ::google::protobuf::internal::DuplicateIfNonNull(released); @@ -10508,34 +11720,34 @@ inline ::google::firestore::v1::Document* RunQueryResponse::release_document() { #endif // !PROTOBUF_FORCE_COPY_IN_RELEASE return released; } -inline ::google::firestore::v1::Document* RunQueryResponse::unsafe_arena_release_document() { +inline ::google::protobuf::Timestamp* ExecutePipelineResponse::unsafe_arena_release_execution_time() { PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); - // @@protoc_insertion_point(field_release:google.firestore.v1.RunQueryResponse.document) + // @@protoc_insertion_point(field_release:google.firestore.v1.ExecutePipelineResponse.execution_time) _impl_._has_bits_[0] &= ~0x00000001u; - ::google::firestore::v1::Document* temp = _impl_.document_; - _impl_.document_ = nullptr; + ::google::protobuf::Timestamp* temp = _impl_.execution_time_; + _impl_.execution_time_ = nullptr; return temp; } -inline ::google::firestore::v1::Document* RunQueryResponse::_internal_mutable_document() { +inline ::google::protobuf::Timestamp* ExecutePipelineResponse::_internal_mutable_execution_time() { PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); _impl_._has_bits_[0] |= 0x00000001u; - if (_impl_.document_ == nullptr) { - auto* p = CreateMaybeMessage<::google::firestore::v1::Document>(GetArena()); - _impl_.document_ = reinterpret_cast<::google::firestore::v1::Document*>(p); + if (_impl_.execution_time_ == nullptr) { + auto* p = CreateMaybeMessage<::google::protobuf::Timestamp>(GetArena()); + _impl_.execution_time_ = reinterpret_cast<::google::protobuf::Timestamp*>(p); } - return _impl_.document_; + return _impl_.execution_time_; } -inline ::google::firestore::v1::Document* RunQueryResponse::mutable_document() ABSL_ATTRIBUTE_LIFETIME_BOUND { - ::google::firestore::v1::Document* _msg = _internal_mutable_document(); - // @@protoc_insertion_point(field_mutable:google.firestore.v1.RunQueryResponse.document) +inline ::google::protobuf::Timestamp* ExecutePipelineResponse::mutable_execution_time() ABSL_ATTRIBUTE_LIFETIME_BOUND { + ::google::protobuf::Timestamp* _msg = _internal_mutable_execution_time(); + // @@protoc_insertion_point(field_mutable:google.firestore.v1.ExecutePipelineResponse.execution_time) return _msg; } -inline void RunQueryResponse::set_allocated_document(::google::firestore::v1::Document* value) { +inline void ExecutePipelineResponse::set_allocated_execution_time(::google::protobuf::Timestamp* value) { ::google::protobuf::Arena* message_arena = GetArena(); PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); if (message_arena == nullptr) { - delete reinterpret_cast<::google::protobuf::MessageLite*>(_impl_.document_); + delete reinterpret_cast<::google::protobuf::MessageLite*>(_impl_.execution_time_); } if (value != nullptr) { @@ -10548,44 +11760,44 @@ inline void RunQueryResponse::set_allocated_document(::google::firestore::v1::Do _impl_._has_bits_[0] &= ~0x00000001u; } - _impl_.document_ = reinterpret_cast<::google::firestore::v1::Document*>(value); - // @@protoc_insertion_point(field_set_allocated:google.firestore.v1.RunQueryResponse.document) + _impl_.execution_time_ = reinterpret_cast<::google::protobuf::Timestamp*>(value); + // @@protoc_insertion_point(field_set_allocated:google.firestore.v1.ExecutePipelineResponse.execution_time) } -// .google.protobuf.Timestamp read_time = 3; -inline bool RunQueryResponse::has_read_time() const { +// .google.firestore.v1.ExplainStats explain_stats = 4; +inline bool ExecutePipelineResponse::has_explain_stats() const { bool value = (_impl_._has_bits_[0] & 0x00000002u) != 0; - PROTOBUF_ASSUME(!value || _impl_.read_time_ != nullptr); + PROTOBUF_ASSUME(!value || _impl_.explain_stats_ != nullptr); return value; } -inline const ::google::protobuf::Timestamp& RunQueryResponse::_internal_read_time() const { +inline const ::google::firestore::v1::ExplainStats& ExecutePipelineResponse::_internal_explain_stats() const { PROTOBUF_TSAN_READ(&_impl_._tsan_detect_race); - const ::google::protobuf::Timestamp* p = _impl_.read_time_; - return p != nullptr ? *p : reinterpret_cast(::google::protobuf::_Timestamp_default_instance_); + const ::google::firestore::v1::ExplainStats* p = _impl_.explain_stats_; + return p != nullptr ? *p : reinterpret_cast(::google::firestore::v1::_ExplainStats_default_instance_); } -inline const ::google::protobuf::Timestamp& RunQueryResponse::read_time() const ABSL_ATTRIBUTE_LIFETIME_BOUND { - // @@protoc_insertion_point(field_get:google.firestore.v1.RunQueryResponse.read_time) - return _internal_read_time(); +inline const ::google::firestore::v1::ExplainStats& ExecutePipelineResponse::explain_stats() const ABSL_ATTRIBUTE_LIFETIME_BOUND { + // @@protoc_insertion_point(field_get:google.firestore.v1.ExecutePipelineResponse.explain_stats) + return _internal_explain_stats(); } -inline void RunQueryResponse::unsafe_arena_set_allocated_read_time(::google::protobuf::Timestamp* value) { +inline void ExecutePipelineResponse::unsafe_arena_set_allocated_explain_stats(::google::firestore::v1::ExplainStats* value) { PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); if (GetArena() == nullptr) { - delete reinterpret_cast<::google::protobuf::MessageLite*>(_impl_.read_time_); + delete reinterpret_cast<::google::protobuf::MessageLite*>(_impl_.explain_stats_); } - _impl_.read_time_ = reinterpret_cast<::google::protobuf::Timestamp*>(value); + _impl_.explain_stats_ = reinterpret_cast<::google::firestore::v1::ExplainStats*>(value); if (value != nullptr) { _impl_._has_bits_[0] |= 0x00000002u; } else { _impl_._has_bits_[0] &= ~0x00000002u; } - // @@protoc_insertion_point(field_unsafe_arena_set_allocated:google.firestore.v1.RunQueryResponse.read_time) + // @@protoc_insertion_point(field_unsafe_arena_set_allocated:google.firestore.v1.ExecutePipelineResponse.explain_stats) } -inline ::google::protobuf::Timestamp* RunQueryResponse::release_read_time() { +inline ::google::firestore::v1::ExplainStats* ExecutePipelineResponse::release_explain_stats() { PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); _impl_._has_bits_[0] &= ~0x00000002u; - ::google::protobuf::Timestamp* released = _impl_.read_time_; - _impl_.read_time_ = nullptr; + ::google::firestore::v1::ExplainStats* released = _impl_.explain_stats_; + _impl_.explain_stats_ = nullptr; #ifdef PROTOBUF_FORCE_COPY_IN_RELEASE auto* old = reinterpret_cast<::google::protobuf::MessageLite*>(released); released = ::google::protobuf::internal::DuplicateIfNonNull(released); @@ -10599,34 +11811,34 @@ inline ::google::protobuf::Timestamp* RunQueryResponse::release_read_time() { #endif // !PROTOBUF_FORCE_COPY_IN_RELEASE return released; } -inline ::google::protobuf::Timestamp* RunQueryResponse::unsafe_arena_release_read_time() { +inline ::google::firestore::v1::ExplainStats* ExecutePipelineResponse::unsafe_arena_release_explain_stats() { PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); - // @@protoc_insertion_point(field_release:google.firestore.v1.RunQueryResponse.read_time) + // @@protoc_insertion_point(field_release:google.firestore.v1.ExecutePipelineResponse.explain_stats) _impl_._has_bits_[0] &= ~0x00000002u; - ::google::protobuf::Timestamp* temp = _impl_.read_time_; - _impl_.read_time_ = nullptr; + ::google::firestore::v1::ExplainStats* temp = _impl_.explain_stats_; + _impl_.explain_stats_ = nullptr; return temp; } -inline ::google::protobuf::Timestamp* RunQueryResponse::_internal_mutable_read_time() { +inline ::google::firestore::v1::ExplainStats* ExecutePipelineResponse::_internal_mutable_explain_stats() { PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); _impl_._has_bits_[0] |= 0x00000002u; - if (_impl_.read_time_ == nullptr) { - auto* p = CreateMaybeMessage<::google::protobuf::Timestamp>(GetArena()); - _impl_.read_time_ = reinterpret_cast<::google::protobuf::Timestamp*>(p); + if (_impl_.explain_stats_ == nullptr) { + auto* p = CreateMaybeMessage<::google::firestore::v1::ExplainStats>(GetArena()); + _impl_.explain_stats_ = reinterpret_cast<::google::firestore::v1::ExplainStats*>(p); } - return _impl_.read_time_; + return _impl_.explain_stats_; } -inline ::google::protobuf::Timestamp* RunQueryResponse::mutable_read_time() ABSL_ATTRIBUTE_LIFETIME_BOUND { - ::google::protobuf::Timestamp* _msg = _internal_mutable_read_time(); - // @@protoc_insertion_point(field_mutable:google.firestore.v1.RunQueryResponse.read_time) +inline ::google::firestore::v1::ExplainStats* ExecutePipelineResponse::mutable_explain_stats() ABSL_ATTRIBUTE_LIFETIME_BOUND { + ::google::firestore::v1::ExplainStats* _msg = _internal_mutable_explain_stats(); + // @@protoc_insertion_point(field_mutable:google.firestore.v1.ExecutePipelineResponse.explain_stats) return _msg; } -inline void RunQueryResponse::set_allocated_read_time(::google::protobuf::Timestamp* value) { +inline void ExecutePipelineResponse::set_allocated_explain_stats(::google::firestore::v1::ExplainStats* value) { ::google::protobuf::Arena* message_arena = GetArena(); PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); if (message_arena == nullptr) { - delete reinterpret_cast<::google::protobuf::MessageLite*>(_impl_.read_time_); + delete reinterpret_cast<::google::protobuf::MessageLite*>(_impl_.explain_stats_); } if (value != nullptr) { @@ -10639,31 +11851,8 @@ inline void RunQueryResponse::set_allocated_read_time(::google::protobuf::Timest _impl_._has_bits_[0] &= ~0x00000002u; } - _impl_.read_time_ = reinterpret_cast<::google::protobuf::Timestamp*>(value); - // @@protoc_insertion_point(field_set_allocated:google.firestore.v1.RunQueryResponse.read_time) -} - -// int32 skipped_results = 4; -inline void RunQueryResponse::clear_skipped_results() { - PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); - _impl_.skipped_results_ = 0; -} -inline ::int32_t RunQueryResponse::skipped_results() const { - // @@protoc_insertion_point(field_get:google.firestore.v1.RunQueryResponse.skipped_results) - return _internal_skipped_results(); -} -inline void RunQueryResponse::set_skipped_results(::int32_t value) { - _internal_set_skipped_results(value); - // @@protoc_insertion_point(field_set:google.firestore.v1.RunQueryResponse.skipped_results) -} -inline ::int32_t RunQueryResponse::_internal_skipped_results() const { - PROTOBUF_TSAN_READ(&_impl_._tsan_detect_race); - return _impl_.skipped_results_; -} -inline void RunQueryResponse::_internal_set_skipped_results(::int32_t value) { - PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); - ; - _impl_.skipped_results_ = value; + _impl_.explain_stats_ = reinterpret_cast<::google::firestore::v1::ExplainStats*>(value); + // @@protoc_insertion_point(field_set_allocated:google.firestore.v1.ExecutePipelineResponse.explain_stats) } // ------------------------------------------------------------------- diff --git a/Firestore/Protos/cpp/google/firestore/v1/pipeline.pb.cc b/Firestore/Protos/cpp/google/firestore/v1/pipeline.pb.cc new file mode 100644 index 00000000000..db718366205 --- /dev/null +++ b/Firestore/Protos/cpp/google/firestore/v1/pipeline.pb.cc @@ -0,0 +1,466 @@ +/* + * Copyright 2025 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. + */ + +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: google/firestore/v1/pipeline.proto + +#include "google/firestore/v1/pipeline.pb.h" + +#include +#include "google/protobuf/io/coded_stream.h" +#include "google/protobuf/extension_set.h" +#include "google/protobuf/wire_format_lite.h" +#include "google/protobuf/descriptor.h" +#include "google/protobuf/generated_message_reflection.h" +#include "google/protobuf/reflection_ops.h" +#include "google/protobuf/wire_format.h" +#include "google/protobuf/generated_message_tctable_impl.h" +// @@protoc_insertion_point(includes) + +// Must be included last. +#include "google/protobuf/port_def.inc" +PROTOBUF_PRAGMA_INIT_SEG +namespace _pb = ::google::protobuf; +namespace _pbi = ::google::protobuf::internal; +namespace _fl = ::google::protobuf::internal::field_layout; +namespace google { +namespace firestore { +namespace v1 { + template +PROTOBUF_CONSTEXPR StructuredPipeline_OptionsEntry_DoNotUse::StructuredPipeline_OptionsEntry_DoNotUse(::_pbi::ConstantInitialized) {} +struct StructuredPipeline_OptionsEntry_DoNotUseDefaultTypeInternal { + PROTOBUF_CONSTEXPR StructuredPipeline_OptionsEntry_DoNotUseDefaultTypeInternal() : _instance(::_pbi::ConstantInitialized{}) {} + ~StructuredPipeline_OptionsEntry_DoNotUseDefaultTypeInternal() {} + union { + StructuredPipeline_OptionsEntry_DoNotUse _instance; + }; +}; + +PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT + PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 StructuredPipeline_OptionsEntry_DoNotUseDefaultTypeInternal _StructuredPipeline_OptionsEntry_DoNotUse_default_instance_; + +inline constexpr StructuredPipeline::Impl_::Impl_( + ::_pbi::ConstantInitialized) noexcept + : _cached_size_{0}, + options_{}, + pipeline_{nullptr} {} + +template +PROTOBUF_CONSTEXPR StructuredPipeline::StructuredPipeline(::_pbi::ConstantInitialized) + : _impl_(::_pbi::ConstantInitialized()) {} +struct StructuredPipelineDefaultTypeInternal { + PROTOBUF_CONSTEXPR StructuredPipelineDefaultTypeInternal() : _instance(::_pbi::ConstantInitialized{}) {} + ~StructuredPipelineDefaultTypeInternal() {} + union { + StructuredPipeline _instance; + }; +}; + +PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT + PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 StructuredPipelineDefaultTypeInternal _StructuredPipeline_default_instance_; +} // namespace v1 +} // namespace firestore +} // namespace google +static ::_pb::Metadata file_level_metadata_google_2ffirestore_2fv1_2fpipeline_2eproto[2]; +static constexpr const ::_pb::EnumDescriptor** + file_level_enum_descriptors_google_2ffirestore_2fv1_2fpipeline_2eproto = nullptr; +static constexpr const ::_pb::ServiceDescriptor** + file_level_service_descriptors_google_2ffirestore_2fv1_2fpipeline_2eproto = nullptr; +const ::uint32_t TableStruct_google_2ffirestore_2fv1_2fpipeline_2eproto::offsets[] PROTOBUF_SECTION_VARIABLE( + protodesc_cold) = { + PROTOBUF_FIELD_OFFSET(::google::firestore::v1::StructuredPipeline_OptionsEntry_DoNotUse, _has_bits_), + PROTOBUF_FIELD_OFFSET(::google::firestore::v1::StructuredPipeline_OptionsEntry_DoNotUse, _internal_metadata_), + ~0u, // no _extensions_ + ~0u, // no _oneof_case_ + ~0u, // no _weak_field_map_ + ~0u, // no _inlined_string_donated_ + ~0u, // no _split_ + ~0u, // no sizeof(Split) + PROTOBUF_FIELD_OFFSET(::google::firestore::v1::StructuredPipeline_OptionsEntry_DoNotUse, key_), + PROTOBUF_FIELD_OFFSET(::google::firestore::v1::StructuredPipeline_OptionsEntry_DoNotUse, value_), + 0, + 1, + PROTOBUF_FIELD_OFFSET(::google::firestore::v1::StructuredPipeline, _impl_._has_bits_), + PROTOBUF_FIELD_OFFSET(::google::firestore::v1::StructuredPipeline, _internal_metadata_), + ~0u, // no _extensions_ + ~0u, // no _oneof_case_ + ~0u, // no _weak_field_map_ + ~0u, // no _inlined_string_donated_ + ~0u, // no _split_ + ~0u, // no sizeof(Split) + PROTOBUF_FIELD_OFFSET(::google::firestore::v1::StructuredPipeline, _impl_.pipeline_), + PROTOBUF_FIELD_OFFSET(::google::firestore::v1::StructuredPipeline, _impl_.options_), + 0, + ~0u, +}; + +static const ::_pbi::MigrationSchema + schemas[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) = { + {0, 10, -1, sizeof(::google::firestore::v1::StructuredPipeline_OptionsEntry_DoNotUse)}, + {12, 22, -1, sizeof(::google::firestore::v1::StructuredPipeline)}, +}; + +static const ::_pb::Message* const file_default_instances[] = { + &::google::firestore::v1::_StructuredPipeline_OptionsEntry_DoNotUse_default_instance_._instance, + &::google::firestore::v1::_StructuredPipeline_default_instance_._instance, +}; +const char descriptor_table_protodef_google_2ffirestore_2fv1_2fpipeline_2eproto[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) = { + "\n\"google/firestore/v1/pipeline.proto\022\023go" + "ogle.firestore.v1\032\037google/api/field_beha" + "vior.proto\032\"google/firestore/v1/document" + ".proto\"\342\001\n\022StructuredPipeline\0224\n\010pipelin" + "e\030\001 \001(\0132\035.google.firestore.v1.PipelineB\003" + "\340A\002\022J\n\007options\030\002 \003(\01324.google.firestore." + "v1.StructuredPipeline.OptionsEntryB\003\340A\001\032" + "J\n\014OptionsEntry\022\013\n\003key\030\001 \001(\t\022)\n\005value\030\002 " + "\001(\0132\032.google.firestore.v1.Value:\0028\001B\305\001\n\027" + "com.google.firestore.v1B\rPipelineProtoP\001" + "Z;cloud.google.com/go/firestore/apiv1/fi" + "restorepb;firestorepb\242\002\004GCFS\252\002\031Google.Cl" + "oud.Firestore.V1\312\002\031Google\\Cloud\\Firestor" + "e\\V1\352\002\034Google::Cloud::Firestore::V1b\006pro" + "to3" +}; +static const ::_pbi::DescriptorTable* const descriptor_table_google_2ffirestore_2fv1_2fpipeline_2eproto_deps[2] = + { + &::descriptor_table_google_2fapi_2ffield_5fbehavior_2eproto, + &::descriptor_table_google_2ffirestore_2fv1_2fdocument_2eproto, +}; +static ::absl::once_flag descriptor_table_google_2ffirestore_2fv1_2fpipeline_2eproto_once; +const ::_pbi::DescriptorTable descriptor_table_google_2ffirestore_2fv1_2fpipeline_2eproto = { + false, + false, + 563, + descriptor_table_protodef_google_2ffirestore_2fv1_2fpipeline_2eproto, + "google/firestore/v1/pipeline.proto", + &descriptor_table_google_2ffirestore_2fv1_2fpipeline_2eproto_once, + descriptor_table_google_2ffirestore_2fv1_2fpipeline_2eproto_deps, + 2, + 2, + schemas, + file_default_instances, + TableStruct_google_2ffirestore_2fv1_2fpipeline_2eproto::offsets, + file_level_metadata_google_2ffirestore_2fv1_2fpipeline_2eproto, + file_level_enum_descriptors_google_2ffirestore_2fv1_2fpipeline_2eproto, + file_level_service_descriptors_google_2ffirestore_2fv1_2fpipeline_2eproto, +}; + +// This function exists to be marked as weak. +// It can significantly speed up compilation by breaking up LLVM's SCC +// in the .pb.cc translation units. Large translation units see a +// reduction of more than 35% of walltime for optimized builds. Without +// the weak attribute all the messages in the file, including all the +// vtables and everything they use become part of the same SCC through +// a cycle like: +// GetMetadata -> descriptor table -> default instances -> +// vtables -> GetMetadata +// By adding a weak function here we break the connection from the +// individual vtables back into the descriptor table. +PROTOBUF_ATTRIBUTE_WEAK const ::_pbi::DescriptorTable* descriptor_table_google_2ffirestore_2fv1_2fpipeline_2eproto_getter() { + return &descriptor_table_google_2ffirestore_2fv1_2fpipeline_2eproto; +} +// Force running AddDescriptors() at dynamic initialization time. +PROTOBUF_ATTRIBUTE_INIT_PRIORITY2 +static ::_pbi::AddDescriptorsRunner dynamic_init_dummy_google_2ffirestore_2fv1_2fpipeline_2eproto(&descriptor_table_google_2ffirestore_2fv1_2fpipeline_2eproto); +namespace google { +namespace firestore { +namespace v1 { +// =================================================================== + +StructuredPipeline_OptionsEntry_DoNotUse::StructuredPipeline_OptionsEntry_DoNotUse() {} +StructuredPipeline_OptionsEntry_DoNotUse::StructuredPipeline_OptionsEntry_DoNotUse(::google::protobuf::Arena* arena) + : SuperType(arena) {} +::google::protobuf::Metadata StructuredPipeline_OptionsEntry_DoNotUse::GetMetadata() const { + return ::_pbi::AssignDescriptors( + &descriptor_table_google_2ffirestore_2fv1_2fpipeline_2eproto_getter, &descriptor_table_google_2ffirestore_2fv1_2fpipeline_2eproto_once, + file_level_metadata_google_2ffirestore_2fv1_2fpipeline_2eproto[0]); +} +// =================================================================== + +class StructuredPipeline::_Internal { + public: + using HasBits = decltype(std::declval()._impl_._has_bits_); + static constexpr ::int32_t kHasBitsOffset = + 8 * PROTOBUF_FIELD_OFFSET(StructuredPipeline, _impl_._has_bits_); + static const ::google::firestore::v1::Pipeline& pipeline(const StructuredPipeline* msg); + static void set_has_pipeline(HasBits* has_bits) { + (*has_bits)[0] |= 1u; + } +}; + +const ::google::firestore::v1::Pipeline& StructuredPipeline::_Internal::pipeline(const StructuredPipeline* msg) { + return *msg->_impl_.pipeline_; +} +void StructuredPipeline::clear_pipeline() { + PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); + if (_impl_.pipeline_ != nullptr) _impl_.pipeline_->Clear(); + _impl_._has_bits_[0] &= ~0x00000001u; +} +void StructuredPipeline::clear_options() { + PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); + _impl_.options_.Clear(); +} +StructuredPipeline::StructuredPipeline(::google::protobuf::Arena* arena) + : ::google::protobuf::Message(arena) { + SharedCtor(arena); + // @@protoc_insertion_point(arena_constructor:google.firestore.v1.StructuredPipeline) +} +inline PROTOBUF_NDEBUG_INLINE StructuredPipeline::Impl_::Impl_( + ::google::protobuf::internal::InternalVisibility visibility, ::google::protobuf::Arena* arena, + const Impl_& from) + : _has_bits_{from._has_bits_}, + _cached_size_{0}, + options_{visibility, arena, from.options_} {} + +StructuredPipeline::StructuredPipeline( + ::google::protobuf::Arena* arena, + const StructuredPipeline& from) + : ::google::protobuf::Message(arena) { + StructuredPipeline* const _this = this; + (void)_this; + _internal_metadata_.MergeFrom<::google::protobuf::UnknownFieldSet>( + from._internal_metadata_); + new (&_impl_) Impl_(internal_visibility(), arena, from._impl_); + ::uint32_t cached_has_bits = _impl_._has_bits_[0]; + _impl_.pipeline_ = (cached_has_bits & 0x00000001u) + ? CreateMaybeMessage<::google::firestore::v1::Pipeline>(arena, *from._impl_.pipeline_) + : nullptr; + + // @@protoc_insertion_point(copy_constructor:google.firestore.v1.StructuredPipeline) +} +inline PROTOBUF_NDEBUG_INLINE StructuredPipeline::Impl_::Impl_( + ::google::protobuf::internal::InternalVisibility visibility, + ::google::protobuf::Arena* arena) + : _cached_size_{0}, + options_{visibility, arena} {} + +inline void StructuredPipeline::SharedCtor(::_pb::Arena* arena) { + new (&_impl_) Impl_(internal_visibility(), arena); + _impl_.pipeline_ = {}; +} +StructuredPipeline::~StructuredPipeline() { + // @@protoc_insertion_point(destructor:google.firestore.v1.StructuredPipeline) + _internal_metadata_.Delete<::google::protobuf::UnknownFieldSet>(); + SharedDtor(); +} +inline void StructuredPipeline::SharedDtor() { + ABSL_DCHECK(GetArena() == nullptr); + delete _impl_.pipeline_; + _impl_.~Impl_(); +} + +PROTOBUF_NOINLINE void StructuredPipeline::Clear() { +// @@protoc_insertion_point(message_clear_start:google.firestore.v1.StructuredPipeline) + PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); + ::uint32_t cached_has_bits = 0; + // Prevent compiler warnings about cached_has_bits being unused + (void) cached_has_bits; + + _impl_.options_.Clear(); + cached_has_bits = _impl_._has_bits_[0]; + if (cached_has_bits & 0x00000001u) { + ABSL_DCHECK(_impl_.pipeline_ != nullptr); + _impl_.pipeline_->Clear(); + } + _impl_._has_bits_.Clear(); + _internal_metadata_.Clear<::google::protobuf::UnknownFieldSet>(); +} + +const char* StructuredPipeline::_InternalParse( + const char* ptr, ::_pbi::ParseContext* ctx) { + ptr = ::_pbi::TcParser::ParseLoop(this, ptr, ctx, &_table_.header); + return ptr; +} + + +PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 +const ::_pbi::TcParseTable<0, 2, 3, 54, 2> StructuredPipeline::_table_ = { + { + PROTOBUF_FIELD_OFFSET(StructuredPipeline, _impl_._has_bits_), + 0, // no _extensions_ + 2, 0, // max_field_number, fast_idx_mask + offsetof(decltype(_table_), field_lookup_table), + 4294967292, // skipmap + offsetof(decltype(_table_), field_entries), + 2, // num_field_entries + 3, // num_aux_entries + offsetof(decltype(_table_), aux_entries), + &_StructuredPipeline_default_instance_._instance, + ::_pbi::TcParser::GenericFallback, // fallback + }, {{ + // .google.firestore.v1.Pipeline pipeline = 1 [(.google.api.field_behavior) = REQUIRED]; + {::_pbi::TcParser::FastMtS1, + {10, 0, 0, PROTOBUF_FIELD_OFFSET(StructuredPipeline, _impl_.pipeline_)}}, + }}, {{ + 65535, 65535 + }}, {{ + // .google.firestore.v1.Pipeline pipeline = 1 [(.google.api.field_behavior) = REQUIRED]; + {PROTOBUF_FIELD_OFFSET(StructuredPipeline, _impl_.pipeline_), _Internal::kHasBitsOffset + 0, 0, + (0 | ::_fl::kFcOptional | ::_fl::kMessage | ::_fl::kTvTable)}, + // map options = 2 [(.google.api.field_behavior) = OPTIONAL]; + {PROTOBUF_FIELD_OFFSET(StructuredPipeline, _impl_.options_), -1, 1, + (0 | ::_fl::kFcRepeated | ::_fl::kMap)}, + }}, {{ + {::_pbi::TcParser::GetTable<::google::firestore::v1::Pipeline>()}, + {::_pbi::TcParser::GetMapAuxInfo< + decltype(StructuredPipeline()._impl_.options_)>( + 1, 0, 0, 9, + 11)}, + {::_pbi::TcParser::CreateInArenaStorageCb<::google::firestore::v1::Value>}, + }}, {{ + "\46\0\7\0\0\0\0\0" + "google.firestore.v1.StructuredPipeline" + "options" + }}, +}; + +::uint8_t* StructuredPipeline::_InternalSerialize( + ::uint8_t* target, + ::google::protobuf::io::EpsCopyOutputStream* stream) const { + // @@protoc_insertion_point(serialize_to_array_start:google.firestore.v1.StructuredPipeline) + ::uint32_t cached_has_bits = 0; + (void)cached_has_bits; + + cached_has_bits = _impl_._has_bits_[0]; + // .google.firestore.v1.Pipeline pipeline = 1 [(.google.api.field_behavior) = REQUIRED]; + if (cached_has_bits & 0x00000001u) { + target = ::google::protobuf::internal::WireFormatLite::InternalWriteMessage( + 1, _Internal::pipeline(this), + _Internal::pipeline(this).GetCachedSize(), target, stream); + } + + // map options = 2 [(.google.api.field_behavior) = OPTIONAL]; + if (!_internal_options().empty()) { + using MapType = ::google::protobuf::Map; + using WireHelper = _pbi::MapEntryFuncs; + const auto& field = _internal_options(); + + if (stream->IsSerializationDeterministic() && field.size() > 1) { + for (const auto& entry : ::google::protobuf::internal::MapSorterPtr(field)) { + target = WireHelper::InternalSerialize( + 2, entry.first, entry.second, target, stream); + ::google::protobuf::internal::WireFormatLite::VerifyUtf8String( + entry.first.data(), static_cast(entry.first.length()), + ::google::protobuf::internal::WireFormatLite::SERIALIZE, "google.firestore.v1.StructuredPipeline.options"); + } + } else { + for (const auto& entry : field) { + target = WireHelper::InternalSerialize( + 2, entry.first, entry.second, target, stream); + ::google::protobuf::internal::WireFormatLite::VerifyUtf8String( + entry.first.data(), static_cast(entry.first.length()), + ::google::protobuf::internal::WireFormatLite::SERIALIZE, "google.firestore.v1.StructuredPipeline.options"); + } + } + } + + if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) { + target = + ::_pbi::WireFormat::InternalSerializeUnknownFieldsToArray( + _internal_metadata_.unknown_fields<::google::protobuf::UnknownFieldSet>(::google::protobuf::UnknownFieldSet::default_instance), target, stream); + } + // @@protoc_insertion_point(serialize_to_array_end:google.firestore.v1.StructuredPipeline) + return target; +} + +::size_t StructuredPipeline::ByteSizeLong() const { +// @@protoc_insertion_point(message_byte_size_start:google.firestore.v1.StructuredPipeline) + ::size_t total_size = 0; + + ::uint32_t cached_has_bits = 0; + // Prevent compiler warnings about cached_has_bits being unused + (void) cached_has_bits; + + // map options = 2 [(.google.api.field_behavior) = OPTIONAL]; + total_size += 1 * ::google::protobuf::internal::FromIntSize(_internal_options_size()); + for (const auto& entry : _internal_options()) { + total_size += _pbi::MapEntryFuncs::ByteSizeLong(entry.first, entry.second); + } + // .google.firestore.v1.Pipeline pipeline = 1 [(.google.api.field_behavior) = REQUIRED]; + cached_has_bits = _impl_._has_bits_[0]; + if (cached_has_bits & 0x00000001u) { + total_size += + 1 + ::google::protobuf::internal::WireFormatLite::MessageSize(*_impl_.pipeline_); + } + + return MaybeComputeUnknownFieldsSize(total_size, &_impl_._cached_size_); +} + +const ::google::protobuf::Message::ClassData StructuredPipeline::_class_data_ = { + StructuredPipeline::MergeImpl, + nullptr, // OnDemandRegisterArenaDtor +}; +const ::google::protobuf::Message::ClassData* StructuredPipeline::GetClassData() const { + return &_class_data_; +} + +void StructuredPipeline::MergeImpl(::google::protobuf::Message& to_msg, const ::google::protobuf::Message& from_msg) { + auto* const _this = static_cast(&to_msg); + auto& from = static_cast(from_msg); + // @@protoc_insertion_point(class_specific_merge_from_start:google.firestore.v1.StructuredPipeline) + ABSL_DCHECK_NE(&from, _this); + ::uint32_t cached_has_bits = 0; + (void) cached_has_bits; + + _this->_impl_.options_.MergeFrom(from._impl_.options_); + if ((from._impl_._has_bits_[0] & 0x00000001u) != 0) { + _this->_internal_mutable_pipeline()->::google::firestore::v1::Pipeline::MergeFrom( + from._internal_pipeline()); + } + _this->_internal_metadata_.MergeFrom<::google::protobuf::UnknownFieldSet>(from._internal_metadata_); +} + +void StructuredPipeline::CopyFrom(const StructuredPipeline& from) { +// @@protoc_insertion_point(class_specific_copy_from_start:google.firestore.v1.StructuredPipeline) + if (&from == this) return; + Clear(); + MergeFrom(from); +} + +PROTOBUF_NOINLINE bool StructuredPipeline::IsInitialized() const { + return true; +} + +::_pbi::CachedSize* StructuredPipeline::AccessCachedSize() const { + return &_impl_._cached_size_; +} +void StructuredPipeline::InternalSwap(StructuredPipeline* PROTOBUF_RESTRICT other) { + using std::swap; + _internal_metadata_.InternalSwap(&other->_internal_metadata_); + swap(_impl_._has_bits_[0], other->_impl_._has_bits_[0]); + _impl_.options_.InternalSwap(&other->_impl_.options_); + swap(_impl_.pipeline_, other->_impl_.pipeline_); +} + +::google::protobuf::Metadata StructuredPipeline::GetMetadata() const { + return ::_pbi::AssignDescriptors( + &descriptor_table_google_2ffirestore_2fv1_2fpipeline_2eproto_getter, &descriptor_table_google_2ffirestore_2fv1_2fpipeline_2eproto_once, + file_level_metadata_google_2ffirestore_2fv1_2fpipeline_2eproto[1]); +} +// @@protoc_insertion_point(namespace_scope) +} // namespace v1 +} // namespace firestore +} // namespace google +namespace google { +namespace protobuf { +} // namespace protobuf +} // namespace google +// @@protoc_insertion_point(global_scope) +#include "google/protobuf/port_undef.inc" diff --git a/Firestore/Protos/cpp/google/firestore/v1/pipeline.pb.h b/Firestore/Protos/cpp/google/firestore/v1/pipeline.pb.h new file mode 100644 index 00000000000..1487e6b1629 --- /dev/null +++ b/Firestore/Protos/cpp/google/firestore/v1/pipeline.pb.h @@ -0,0 +1,480 @@ +/* + * Copyright 2025 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. + */ + +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: google/firestore/v1/pipeline.proto +// Protobuf C++ Version: 4.25.1 + +#ifndef GOOGLE_PROTOBUF_INCLUDED_google_2ffirestore_2fv1_2fpipeline_2eproto_2epb_2eh +#define GOOGLE_PROTOBUF_INCLUDED_google_2ffirestore_2fv1_2fpipeline_2eproto_2epb_2eh + +#include +#include +#include +#include + +#include "google/protobuf/port_def.inc" +#if PROTOBUF_VERSION < 4025000 +#error "This file was generated by a newer version of protoc which is" +#error "incompatible with your Protocol Buffer headers. Please update" +#error "your headers." +#endif // PROTOBUF_VERSION + +#if 4025001 < PROTOBUF_MIN_PROTOC_VERSION +#error "This file was generated by an older version of protoc which is" +#error "incompatible with your Protocol Buffer headers. Please" +#error "regenerate this file with a newer version of protoc." +#endif // PROTOBUF_MIN_PROTOC_VERSION +#include "google/protobuf/port_undef.inc" +#include "google/protobuf/io/coded_stream.h" +#include "google/protobuf/arena.h" +#include "google/protobuf/arenastring.h" +#include "google/protobuf/generated_message_tctable_decl.h" +#include "google/protobuf/generated_message_util.h" +#include "google/protobuf/metadata_lite.h" +#include "google/protobuf/generated_message_reflection.h" +#include "google/protobuf/message.h" +#include "google/protobuf/repeated_field.h" // IWYU pragma: export +#include "google/protobuf/extension_set.h" // IWYU pragma: export +#include "google/protobuf/map.h" // IWYU pragma: export +#include "google/protobuf/map_entry.h" +#include "google/protobuf/map_field_inl.h" +#include "google/protobuf/unknown_field_set.h" +#include "google/api/field_behavior.pb.h" +#include "google/firestore/v1/document.pb.h" +// @@protoc_insertion_point(includes) + +// Must be included last. +#include "google/protobuf/port_def.inc" + +#define PROTOBUF_INTERNAL_EXPORT_google_2ffirestore_2fv1_2fpipeline_2eproto + +namespace google { +namespace protobuf { +namespace internal { +class AnyMetadata; +} // namespace internal +} // namespace protobuf +} // namespace google + +// Internal implementation detail -- do not use these members. +struct TableStruct_google_2ffirestore_2fv1_2fpipeline_2eproto { + static const ::uint32_t offsets[]; +}; +extern const ::google::protobuf::internal::DescriptorTable + descriptor_table_google_2ffirestore_2fv1_2fpipeline_2eproto; +namespace google { +namespace firestore { +namespace v1 { +class StructuredPipeline; +struct StructuredPipelineDefaultTypeInternal; +extern StructuredPipelineDefaultTypeInternal _StructuredPipeline_default_instance_; +class StructuredPipeline_OptionsEntry_DoNotUse; +struct StructuredPipeline_OptionsEntry_DoNotUseDefaultTypeInternal; +extern StructuredPipeline_OptionsEntry_DoNotUseDefaultTypeInternal _StructuredPipeline_OptionsEntry_DoNotUse_default_instance_; +} // namespace v1 +} // namespace firestore +namespace protobuf { +} // namespace protobuf +} // namespace google + +namespace google { +namespace firestore { +namespace v1 { + +// =================================================================== + + +// ------------------------------------------------------------------- + +class StructuredPipeline_OptionsEntry_DoNotUse final + : public ::google::protobuf::internal::MapEntry< + StructuredPipeline_OptionsEntry_DoNotUse, std::string, ::google::firestore::v1::Value, + ::google::protobuf::internal::WireFormatLite::TYPE_STRING, + ::google::protobuf::internal::WireFormatLite::TYPE_MESSAGE> { + public: + using SuperType = ::google::protobuf::internal::MapEntry< + StructuredPipeline_OptionsEntry_DoNotUse, std::string, ::google::firestore::v1::Value, + ::google::protobuf::internal::WireFormatLite::TYPE_STRING, + ::google::protobuf::internal::WireFormatLite::TYPE_MESSAGE>; + StructuredPipeline_OptionsEntry_DoNotUse(); + template + explicit PROTOBUF_CONSTEXPR StructuredPipeline_OptionsEntry_DoNotUse( + ::google::protobuf::internal::ConstantInitialized); + explicit StructuredPipeline_OptionsEntry_DoNotUse(::google::protobuf::Arena* arena); + static const StructuredPipeline_OptionsEntry_DoNotUse* internal_default_instance() { + return reinterpret_cast( + &_StructuredPipeline_OptionsEntry_DoNotUse_default_instance_); + } + static bool ValidateKey(std::string* s) { + return ::google::protobuf::internal::WireFormatLite::VerifyUtf8String(s->data(), static_cast(s->size()), ::google::protobuf::internal::WireFormatLite::PARSE, "google.firestore.v1.StructuredPipeline.OptionsEntry.key"); + } + static bool ValidateValue(void*) { return true; } + ::google::protobuf::Metadata GetMetadata() const final; + friend struct ::TableStruct_google_2ffirestore_2fv1_2fpipeline_2eproto; +}; +// ------------------------------------------------------------------- + +class StructuredPipeline final : + public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:google.firestore.v1.StructuredPipeline) */ { + public: + inline StructuredPipeline() : StructuredPipeline(nullptr) {} + ~StructuredPipeline() override; + template + explicit PROTOBUF_CONSTEXPR StructuredPipeline(::google::protobuf::internal::ConstantInitialized); + + inline StructuredPipeline(const StructuredPipeline& from) + : StructuredPipeline(nullptr, from) {} + StructuredPipeline(StructuredPipeline&& from) noexcept + : StructuredPipeline() { + *this = ::std::move(from); + } + + inline StructuredPipeline& operator=(const StructuredPipeline& from) { + CopyFrom(from); + return *this; + } + inline StructuredPipeline& operator=(StructuredPipeline&& from) noexcept { + if (this == &from) return *this; + if (GetArena() == from.GetArena() + #ifdef PROTOBUF_FORCE_COPY_IN_MOVE + && GetArena() != nullptr + #endif // !PROTOBUF_FORCE_COPY_IN_MOVE + ) { + InternalSwap(&from); + } else { + CopyFrom(from); + } + return *this; + } + + inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const + ABSL_ATTRIBUTE_LIFETIME_BOUND { + return _internal_metadata_.unknown_fields<::google::protobuf::UnknownFieldSet>(::google::protobuf::UnknownFieldSet::default_instance); + } + inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() + ABSL_ATTRIBUTE_LIFETIME_BOUND { + return _internal_metadata_.mutable_unknown_fields<::google::protobuf::UnknownFieldSet>(); + } + + static const ::google::protobuf::Descriptor* descriptor() { + return GetDescriptor(); + } + static const ::google::protobuf::Descriptor* GetDescriptor() { + return default_instance().GetMetadata().descriptor; + } + static const ::google::protobuf::Reflection* GetReflection() { + return default_instance().GetMetadata().reflection; + } + static const StructuredPipeline& default_instance() { + return *internal_default_instance(); + } + static inline const StructuredPipeline* internal_default_instance() { + return reinterpret_cast( + &_StructuredPipeline_default_instance_); + } + static constexpr int kIndexInFileMessages = + 1; + + friend void swap(StructuredPipeline& a, StructuredPipeline& b) { + a.Swap(&b); + } + inline void Swap(StructuredPipeline* other) { + if (other == this) return; + #ifdef PROTOBUF_FORCE_COPY_IN_SWAP + if (GetArena() != nullptr && + GetArena() == other->GetArena()) { + #else // PROTOBUF_FORCE_COPY_IN_SWAP + if (GetArena() == other->GetArena()) { + #endif // !PROTOBUF_FORCE_COPY_IN_SWAP + InternalSwap(other); + } else { + ::google::protobuf::internal::GenericSwap(this, other); + } + } + void UnsafeArenaSwap(StructuredPipeline* other) { + if (other == this) return; + ABSL_DCHECK(GetArena() == other->GetArena()); + InternalSwap(other); + } + + // implements Message ---------------------------------------------- + + StructuredPipeline* New(::google::protobuf::Arena* arena = nullptr) const final { + return CreateMaybeMessage(arena); + } + using ::google::protobuf::Message::CopyFrom; + void CopyFrom(const StructuredPipeline& from); + using ::google::protobuf::Message::MergeFrom; + void MergeFrom( const StructuredPipeline& from) { + StructuredPipeline::MergeImpl(*this, from); + } + private: + static void MergeImpl(::google::protobuf::Message& to_msg, const ::google::protobuf::Message& from_msg); + public: + PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final; + bool IsInitialized() const final; + + ::size_t ByteSizeLong() const final; + const char* _InternalParse(const char* ptr, ::google::protobuf::internal::ParseContext* ctx) final; + ::uint8_t* _InternalSerialize( + ::uint8_t* target, ::google::protobuf::io::EpsCopyOutputStream* stream) const final; + int GetCachedSize() const { return _impl_._cached_size_.Get(); } + + private: + ::google::protobuf::internal::CachedSize* AccessCachedSize() const final; + void SharedCtor(::google::protobuf::Arena* arena); + void SharedDtor(); + void InternalSwap(StructuredPipeline* other); + + private: + friend class ::google::protobuf::internal::AnyMetadata; + static ::absl::string_view FullMessageName() { + return "google.firestore.v1.StructuredPipeline"; + } + protected: + explicit StructuredPipeline(::google::protobuf::Arena* arena); + StructuredPipeline(::google::protobuf::Arena* arena, const StructuredPipeline& from); + public: + + static const ClassData _class_data_; + const ::google::protobuf::Message::ClassData*GetClassData() const final; + + ::google::protobuf::Metadata GetMetadata() const final; + + // nested types ---------------------------------------------------- + + + // accessors ------------------------------------------------------- + + enum : int { + kOptionsFieldNumber = 2, + kPipelineFieldNumber = 1, + }; + // map options = 2 [(.google.api.field_behavior) = OPTIONAL]; + int options_size() const; + private: + int _internal_options_size() const; + + public: + void clear_options() ; + const ::google::protobuf::Map& options() const; + ::google::protobuf::Map* mutable_options(); + + private: + const ::google::protobuf::Map& _internal_options() const; + ::google::protobuf::Map* _internal_mutable_options(); + + public: + // .google.firestore.v1.Pipeline pipeline = 1 [(.google.api.field_behavior) = REQUIRED]; + bool has_pipeline() const; + void clear_pipeline() ; + const ::google::firestore::v1::Pipeline& pipeline() const; + PROTOBUF_NODISCARD ::google::firestore::v1::Pipeline* release_pipeline(); + ::google::firestore::v1::Pipeline* mutable_pipeline(); + void set_allocated_pipeline(::google::firestore::v1::Pipeline* value); + void unsafe_arena_set_allocated_pipeline(::google::firestore::v1::Pipeline* value); + ::google::firestore::v1::Pipeline* unsafe_arena_release_pipeline(); + + private: + const ::google::firestore::v1::Pipeline& _internal_pipeline() const; + ::google::firestore::v1::Pipeline* _internal_mutable_pipeline(); + + public: + // @@protoc_insertion_point(class_scope:google.firestore.v1.StructuredPipeline) + private: + class _Internal; + + friend class ::google::protobuf::internal::TcParser; + static const ::google::protobuf::internal::TcParseTable< + 0, 2, 3, + 54, 2> + _table_; + friend class ::google::protobuf::MessageLite; + friend class ::google::protobuf::Arena; + template + friend class ::google::protobuf::Arena::InternalHelper; + using InternalArenaConstructable_ = void; + using DestructorSkippable_ = void; + struct Impl_ { + + inline explicit constexpr Impl_( + ::google::protobuf::internal::ConstantInitialized) noexcept; + inline explicit Impl_(::google::protobuf::internal::InternalVisibility visibility, + ::google::protobuf::Arena* arena); + inline explicit Impl_(::google::protobuf::internal::InternalVisibility visibility, + ::google::protobuf::Arena* arena, const Impl_& from); + ::google::protobuf::internal::HasBits<1> _has_bits_; + mutable ::google::protobuf::internal::CachedSize _cached_size_; + ::google::protobuf::internal::MapField + options_; + ::google::firestore::v1::Pipeline* pipeline_; + PROTOBUF_TSAN_DECLARE_MEMBER + }; + union { Impl_ _impl_; }; + friend struct ::TableStruct_google_2ffirestore_2fv1_2fpipeline_2eproto; +}; + +// =================================================================== + + + + +// =================================================================== + + +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wstrict-aliasing" +#endif // __GNUC__ +// ------------------------------------------------------------------- + +// ------------------------------------------------------------------- + +// StructuredPipeline + +// .google.firestore.v1.Pipeline pipeline = 1 [(.google.api.field_behavior) = REQUIRED]; +inline bool StructuredPipeline::has_pipeline() const { + bool value = (_impl_._has_bits_[0] & 0x00000001u) != 0; + PROTOBUF_ASSUME(!value || _impl_.pipeline_ != nullptr); + return value; +} +inline const ::google::firestore::v1::Pipeline& StructuredPipeline::_internal_pipeline() const { + PROTOBUF_TSAN_READ(&_impl_._tsan_detect_race); + const ::google::firestore::v1::Pipeline* p = _impl_.pipeline_; + return p != nullptr ? *p : reinterpret_cast(::google::firestore::v1::_Pipeline_default_instance_); +} +inline const ::google::firestore::v1::Pipeline& StructuredPipeline::pipeline() const ABSL_ATTRIBUTE_LIFETIME_BOUND { + // @@protoc_insertion_point(field_get:google.firestore.v1.StructuredPipeline.pipeline) + return _internal_pipeline(); +} +inline void StructuredPipeline::unsafe_arena_set_allocated_pipeline(::google::firestore::v1::Pipeline* value) { + PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); + if (GetArena() == nullptr) { + delete reinterpret_cast<::google::protobuf::MessageLite*>(_impl_.pipeline_); + } + _impl_.pipeline_ = reinterpret_cast<::google::firestore::v1::Pipeline*>(value); + if (value != nullptr) { + _impl_._has_bits_[0] |= 0x00000001u; + } else { + _impl_._has_bits_[0] &= ~0x00000001u; + } + // @@protoc_insertion_point(field_unsafe_arena_set_allocated:google.firestore.v1.StructuredPipeline.pipeline) +} +inline ::google::firestore::v1::Pipeline* StructuredPipeline::release_pipeline() { + PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); + + _impl_._has_bits_[0] &= ~0x00000001u; + ::google::firestore::v1::Pipeline* released = _impl_.pipeline_; + _impl_.pipeline_ = nullptr; +#ifdef PROTOBUF_FORCE_COPY_IN_RELEASE + auto* old = reinterpret_cast<::google::protobuf::MessageLite*>(released); + released = ::google::protobuf::internal::DuplicateIfNonNull(released); + if (GetArena() == nullptr) { + delete old; + } +#else // PROTOBUF_FORCE_COPY_IN_RELEASE + if (GetArena() != nullptr) { + released = ::google::protobuf::internal::DuplicateIfNonNull(released); + } +#endif // !PROTOBUF_FORCE_COPY_IN_RELEASE + return released; +} +inline ::google::firestore::v1::Pipeline* StructuredPipeline::unsafe_arena_release_pipeline() { + PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); + // @@protoc_insertion_point(field_release:google.firestore.v1.StructuredPipeline.pipeline) + + _impl_._has_bits_[0] &= ~0x00000001u; + ::google::firestore::v1::Pipeline* temp = _impl_.pipeline_; + _impl_.pipeline_ = nullptr; + return temp; +} +inline ::google::firestore::v1::Pipeline* StructuredPipeline::_internal_mutable_pipeline() { + PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); + _impl_._has_bits_[0] |= 0x00000001u; + if (_impl_.pipeline_ == nullptr) { + auto* p = CreateMaybeMessage<::google::firestore::v1::Pipeline>(GetArena()); + _impl_.pipeline_ = reinterpret_cast<::google::firestore::v1::Pipeline*>(p); + } + return _impl_.pipeline_; +} +inline ::google::firestore::v1::Pipeline* StructuredPipeline::mutable_pipeline() ABSL_ATTRIBUTE_LIFETIME_BOUND { + ::google::firestore::v1::Pipeline* _msg = _internal_mutable_pipeline(); + // @@protoc_insertion_point(field_mutable:google.firestore.v1.StructuredPipeline.pipeline) + return _msg; +} +inline void StructuredPipeline::set_allocated_pipeline(::google::firestore::v1::Pipeline* value) { + ::google::protobuf::Arena* message_arena = GetArena(); + PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); + if (message_arena == nullptr) { + delete reinterpret_cast<::google::protobuf::MessageLite*>(_impl_.pipeline_); + } + + if (value != nullptr) { + ::google::protobuf::Arena* submessage_arena = reinterpret_cast<::google::protobuf::MessageLite*>(value)->GetArena(); + if (message_arena != submessage_arena) { + value = ::google::protobuf::internal::GetOwnedMessage(message_arena, value, submessage_arena); + } + _impl_._has_bits_[0] |= 0x00000001u; + } else { + _impl_._has_bits_[0] &= ~0x00000001u; + } + + _impl_.pipeline_ = reinterpret_cast<::google::firestore::v1::Pipeline*>(value); + // @@protoc_insertion_point(field_set_allocated:google.firestore.v1.StructuredPipeline.pipeline) +} + +// map options = 2 [(.google.api.field_behavior) = OPTIONAL]; +inline int StructuredPipeline::_internal_options_size() const { + return _internal_options().size(); +} +inline int StructuredPipeline::options_size() const { + return _internal_options_size(); +} +inline const ::google::protobuf::Map& StructuredPipeline::_internal_options() const { + PROTOBUF_TSAN_READ(&_impl_._tsan_detect_race); + return _impl_.options_.GetMap(); +} +inline const ::google::protobuf::Map& StructuredPipeline::options() const ABSL_ATTRIBUTE_LIFETIME_BOUND { + // @@protoc_insertion_point(field_map:google.firestore.v1.StructuredPipeline.options) + return _internal_options(); +} +inline ::google::protobuf::Map* StructuredPipeline::_internal_mutable_options() { + PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race); + return _impl_.options_.MutableMap(); +} +inline ::google::protobuf::Map* StructuredPipeline::mutable_options() ABSL_ATTRIBUTE_LIFETIME_BOUND { + // @@protoc_insertion_point(field_mutable_map:google.firestore.v1.StructuredPipeline.options) + return _internal_mutable_options(); +} + +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif // __GNUC__ + +// @@protoc_insertion_point(namespace_scope) +} // namespace v1 +} // namespace firestore +} // namespace google + + +// @@protoc_insertion_point(global_scope) + +#include "google/protobuf/port_undef.inc" + +#endif // GOOGLE_PROTOBUF_INCLUDED_google_2ffirestore_2fv1_2fpipeline_2eproto_2epb_2eh diff --git a/Firestore/Protos/cpp/google/firestore/v1/query.pb.cc b/Firestore/Protos/cpp/google/firestore/v1/query.pb.cc index 7ad9fec1f02..af917d57906 100644 --- a/Firestore/Protos/cpp/google/firestore/v1/query.pb.cc +++ b/Firestore/Protos/cpp/google/firestore/v1/query.pb.cc @@ -1,5 +1,5 @@ /* - * Copyright 2024 Google LLC + * Copyright 2025 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/Firestore/Protos/cpp/google/firestore/v1/query.pb.h b/Firestore/Protos/cpp/google/firestore/v1/query.pb.h index 205f9bea8a0..52bdd1d4641 100644 --- a/Firestore/Protos/cpp/google/firestore/v1/query.pb.h +++ b/Firestore/Protos/cpp/google/firestore/v1/query.pb.h @@ -1,5 +1,5 @@ /* - * Copyright 2024 Google LLC + * Copyright 2025 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/Firestore/Protos/cpp/google/firestore/v1/write.pb.cc b/Firestore/Protos/cpp/google/firestore/v1/write.pb.cc index b1e26f29a16..51916110a2e 100644 --- a/Firestore/Protos/cpp/google/firestore/v1/write.pb.cc +++ b/Firestore/Protos/cpp/google/firestore/v1/write.pb.cc @@ -1,5 +1,5 @@ /* - * Copyright 2024 Google LLC + * Copyright 2025 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/Firestore/Protos/cpp/google/firestore/v1/write.pb.h b/Firestore/Protos/cpp/google/firestore/v1/write.pb.h index 46fd9394542..2bc4a3b3cf3 100644 --- a/Firestore/Protos/cpp/google/firestore/v1/write.pb.h +++ b/Firestore/Protos/cpp/google/firestore/v1/write.pb.h @@ -1,5 +1,5 @@ /* - * Copyright 2024 Google LLC + * Copyright 2025 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/Firestore/Protos/cpp/google/rpc/status.pb.cc b/Firestore/Protos/cpp/google/rpc/status.pb.cc index e053fa12c18..b6cfa669f6f 100644 --- a/Firestore/Protos/cpp/google/rpc/status.pb.cc +++ b/Firestore/Protos/cpp/google/rpc/status.pb.cc @@ -1,5 +1,5 @@ /* - * Copyright 2024 Google LLC + * Copyright 2025 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/Firestore/Protos/cpp/google/rpc/status.pb.h b/Firestore/Protos/cpp/google/rpc/status.pb.h index fdadd942ac4..d3b966147b6 100644 --- a/Firestore/Protos/cpp/google/rpc/status.pb.h +++ b/Firestore/Protos/cpp/google/rpc/status.pb.h @@ -1,5 +1,5 @@ /* - * Copyright 2024 Google LLC + * Copyright 2025 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/Firestore/Protos/cpp/google/type/latlng.pb.cc b/Firestore/Protos/cpp/google/type/latlng.pb.cc index 5303b0891a2..b9efd72a5af 100644 --- a/Firestore/Protos/cpp/google/type/latlng.pb.cc +++ b/Firestore/Protos/cpp/google/type/latlng.pb.cc @@ -1,5 +1,5 @@ /* - * Copyright 2024 Google LLC + * Copyright 2025 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/Firestore/Protos/cpp/google/type/latlng.pb.h b/Firestore/Protos/cpp/google/type/latlng.pb.h index 0f889988d23..6fd0da83cf0 100644 --- a/Firestore/Protos/cpp/google/type/latlng.pb.h +++ b/Firestore/Protos/cpp/google/type/latlng.pb.h @@ -1,5 +1,5 @@ /* - * Copyright 2024 Google LLC + * Copyright 2025 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/Firestore/Protos/nanopb/firestore/bundle.nanopb.cc b/Firestore/Protos/nanopb/firestore/bundle.nanopb.cc index 6e15969980e..f470145f1ad 100644 --- a/Firestore/Protos/nanopb/firestore/bundle.nanopb.cc +++ b/Firestore/Protos/nanopb/firestore/bundle.nanopb.cc @@ -1,5 +1,5 @@ /* - * Copyright 2024 Google LLC + * Copyright 2025 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/Firestore/Protos/nanopb/firestore/bundle.nanopb.h b/Firestore/Protos/nanopb/firestore/bundle.nanopb.h index 872ea118504..bb312068857 100644 --- a/Firestore/Protos/nanopb/firestore/bundle.nanopb.h +++ b/Firestore/Protos/nanopb/firestore/bundle.nanopb.h @@ -1,5 +1,5 @@ /* - * Copyright 2024 Google LLC + * Copyright 2025 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/Firestore/Protos/nanopb/firestore/local/maybe_document.nanopb.cc b/Firestore/Protos/nanopb/firestore/local/maybe_document.nanopb.cc index 2f906d9f95d..f145a4a81b8 100644 --- a/Firestore/Protos/nanopb/firestore/local/maybe_document.nanopb.cc +++ b/Firestore/Protos/nanopb/firestore/local/maybe_document.nanopb.cc @@ -1,5 +1,5 @@ /* - * Copyright 2024 Google LLC + * Copyright 2025 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/Firestore/Protos/nanopb/firestore/local/maybe_document.nanopb.h b/Firestore/Protos/nanopb/firestore/local/maybe_document.nanopb.h index 53762bb101f..a6373161785 100644 --- a/Firestore/Protos/nanopb/firestore/local/maybe_document.nanopb.h +++ b/Firestore/Protos/nanopb/firestore/local/maybe_document.nanopb.h @@ -1,5 +1,5 @@ /* - * Copyright 2024 Google LLC + * Copyright 2025 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/Firestore/Protos/nanopb/firestore/local/mutation.nanopb.cc b/Firestore/Protos/nanopb/firestore/local/mutation.nanopb.cc index 1a06d56941d..55f9a23489e 100644 --- a/Firestore/Protos/nanopb/firestore/local/mutation.nanopb.cc +++ b/Firestore/Protos/nanopb/firestore/local/mutation.nanopb.cc @@ -1,5 +1,5 @@ /* - * Copyright 2024 Google LLC + * Copyright 2025 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/Firestore/Protos/nanopb/firestore/local/mutation.nanopb.h b/Firestore/Protos/nanopb/firestore/local/mutation.nanopb.h index 28430465212..b316ea582b9 100644 --- a/Firestore/Protos/nanopb/firestore/local/mutation.nanopb.h +++ b/Firestore/Protos/nanopb/firestore/local/mutation.nanopb.h @@ -1,5 +1,5 @@ /* - * Copyright 2024 Google LLC + * Copyright 2025 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/Firestore/Protos/nanopb/firestore/local/target.nanopb.cc b/Firestore/Protos/nanopb/firestore/local/target.nanopb.cc index cd73d9344f7..7d0d51ab579 100644 --- a/Firestore/Protos/nanopb/firestore/local/target.nanopb.cc +++ b/Firestore/Protos/nanopb/firestore/local/target.nanopb.cc @@ -1,5 +1,5 @@ /* - * Copyright 2024 Google LLC + * Copyright 2025 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/Firestore/Protos/nanopb/firestore/local/target.nanopb.h b/Firestore/Protos/nanopb/firestore/local/target.nanopb.h index 7dedb4d91eb..34f926f3ea0 100644 --- a/Firestore/Protos/nanopb/firestore/local/target.nanopb.h +++ b/Firestore/Protos/nanopb/firestore/local/target.nanopb.h @@ -1,5 +1,5 @@ /* - * Copyright 2024 Google LLC + * Copyright 2025 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/Firestore/Protos/nanopb/google/api/annotations.nanopb.cc b/Firestore/Protos/nanopb/google/api/annotations.nanopb.cc index b755cad4926..c0bc8de7cdf 100644 --- a/Firestore/Protos/nanopb/google/api/annotations.nanopb.cc +++ b/Firestore/Protos/nanopb/google/api/annotations.nanopb.cc @@ -1,5 +1,5 @@ /* - * Copyright 2024 Google LLC + * Copyright 2025 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/Firestore/Protos/nanopb/google/api/annotations.nanopb.h b/Firestore/Protos/nanopb/google/api/annotations.nanopb.h index 4ddc9010007..46f6d833985 100644 --- a/Firestore/Protos/nanopb/google/api/annotations.nanopb.h +++ b/Firestore/Protos/nanopb/google/api/annotations.nanopb.h @@ -1,5 +1,5 @@ /* - * Copyright 2024 Google LLC + * Copyright 2025 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/Firestore/Protos/nanopb/google/api/field_behavior.nanopb.cc b/Firestore/Protos/nanopb/google/api/field_behavior.nanopb.cc new file mode 100644 index 00000000000..38e3aa6a29b --- /dev/null +++ b/Firestore/Protos/nanopb/google/api/field_behavior.nanopb.cc @@ -0,0 +1,77 @@ +/* + * Copyright 2025 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. + */ + +/* Automatically generated nanopb constant definitions */ +/* Generated by nanopb-0.3.9.8 */ + +#include "field_behavior.nanopb.h" + +#include "Firestore/core/src/nanopb/pretty_printing.h" + +namespace firebase { +namespace firestore { + +using nanopb::PrintEnumField; +using nanopb::PrintHeader; +using nanopb::PrintMessageField; +using nanopb::PrintPrimitiveField; +using nanopb::PrintTail; + +/* @@protoc_insertion_point(includes) */ +#if PB_PROTO_HEADER_VERSION != 30 +#error Regenerate this file with the current version of nanopb generator. +#endif + + + + + + +/* Check that field information fits in pb_field_t */ +#if !defined(PB_FIELD_16BIT) && !defined(PB_FIELD_32BIT) +#error Field descriptor for google_api_field_behavior_struct.field_behavior is too large. Define PB_FIELD_16BIT to fix this. +#endif + + +const char* EnumToString( + google_api_FieldBehavior value) { + switch (value) { + case google_api_FieldBehavior_FIELD_BEHAVIOR_UNSPECIFIED: + return "FIELD_BEHAVIOR_UNSPECIFIED"; + case google_api_FieldBehavior_OPTIONAL: + return "OPTIONAL"; + case google_api_FieldBehavior_REQUIRED: + return "REQUIRED"; + case google_api_FieldBehavior_OUTPUT_ONLY: + return "OUTPUT_ONLY"; + case google_api_FieldBehavior_INPUT_ONLY: + return "INPUT_ONLY"; + case google_api_FieldBehavior_IMMUTABLE: + return "IMMUTABLE"; + case google_api_FieldBehavior_UNORDERED_LIST: + return "UNORDERED_LIST"; + case google_api_FieldBehavior_NON_EMPTY_DEFAULT: + return "NON_EMPTY_DEFAULT"; + case google_api_FieldBehavior_IDENTIFIER: + return "IDENTIFIER"; + } + return ""; +} + +} // namespace firestore +} // namespace firebase + +/* @@protoc_insertion_point(eof) */ diff --git a/Firestore/Protos/nanopb/google/api/field_behavior.nanopb.h b/Firestore/Protos/nanopb/google/api/field_behavior.nanopb.h new file mode 100644 index 00000000000..ad18ad8b3cf --- /dev/null +++ b/Firestore/Protos/nanopb/google/api/field_behavior.nanopb.h @@ -0,0 +1,61 @@ +/* + * Copyright 2025 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. + */ + +/* Automatically generated nanopb header */ +/* Generated by nanopb-0.3.9.8 */ + +#ifndef PB_GOOGLE_API_FIELD_BEHAVIOR_NANOPB_H_INCLUDED +#define PB_GOOGLE_API_FIELD_BEHAVIOR_NANOPB_H_INCLUDED +#include + +#include + +namespace firebase { +namespace firestore { + +/* @@protoc_insertion_point(includes) */ +#if PB_PROTO_HEADER_VERSION != 30 +#error Regenerate this file with the current version of nanopb generator. +#endif + + +/* Enum definitions */ +typedef enum _google_api_FieldBehavior { + google_api_FieldBehavior_FIELD_BEHAVIOR_UNSPECIFIED = 0, + google_api_FieldBehavior_OPTIONAL = 1, + google_api_FieldBehavior_REQUIRED = 2, + google_api_FieldBehavior_OUTPUT_ONLY = 3, + google_api_FieldBehavior_INPUT_ONLY = 4, + google_api_FieldBehavior_IMMUTABLE = 5, + google_api_FieldBehavior_UNORDERED_LIST = 6, + google_api_FieldBehavior_NON_EMPTY_DEFAULT = 7, + google_api_FieldBehavior_IDENTIFIER = 8 +} google_api_FieldBehavior; +#define _google_api_FieldBehavior_MIN google_api_FieldBehavior_FIELD_BEHAVIOR_UNSPECIFIED +#define _google_api_FieldBehavior_MAX google_api_FieldBehavior_IDENTIFIER +#define _google_api_FieldBehavior_ARRAYSIZE ((google_api_FieldBehavior)(google_api_FieldBehavior_IDENTIFIER+1)) + +/* Extensions */ +/* Extension field google_api_field_behavior was skipped because only "optional" + type of extension fields is currently supported. */ + +const char* EnumToString(google_api_FieldBehavior value); +} // namespace firestore +} // namespace firebase + +/* @@protoc_insertion_point(eof) */ + +#endif diff --git a/Firestore/Protos/nanopb/google/api/http.nanopb.cc b/Firestore/Protos/nanopb/google/api/http.nanopb.cc index b69f3495d6f..6be59e2b5b8 100644 --- a/Firestore/Protos/nanopb/google/api/http.nanopb.cc +++ b/Firestore/Protos/nanopb/google/api/http.nanopb.cc @@ -1,5 +1,5 @@ /* - * Copyright 2024 Google LLC + * Copyright 2025 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/Firestore/Protos/nanopb/google/api/http.nanopb.h b/Firestore/Protos/nanopb/google/api/http.nanopb.h index 5d97d74d221..af98141f2c4 100644 --- a/Firestore/Protos/nanopb/google/api/http.nanopb.h +++ b/Firestore/Protos/nanopb/google/api/http.nanopb.h @@ -1,5 +1,5 @@ /* - * Copyright 2024 Google LLC + * Copyright 2025 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/Firestore/Protos/nanopb/google/api/resource.nanopb.cc b/Firestore/Protos/nanopb/google/api/resource.nanopb.cc index 82456fe0cc8..852f7122473 100644 --- a/Firestore/Protos/nanopb/google/api/resource.nanopb.cc +++ b/Firestore/Protos/nanopb/google/api/resource.nanopb.cc @@ -1,5 +1,5 @@ /* - * Copyright 2024 Google LLC + * Copyright 2025 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/Firestore/Protos/nanopb/google/api/resource.nanopb.h b/Firestore/Protos/nanopb/google/api/resource.nanopb.h index 7c7c1ffabaa..741cc580045 100644 --- a/Firestore/Protos/nanopb/google/api/resource.nanopb.h +++ b/Firestore/Protos/nanopb/google/api/resource.nanopb.h @@ -1,5 +1,5 @@ /* - * Copyright 2024 Google LLC + * Copyright 2025 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/Firestore/Protos/nanopb/google/firestore/admin/index.nanopb.cc b/Firestore/Protos/nanopb/google/firestore/admin/index.nanopb.cc index 5769d63aec7..acf9ce034d4 100644 --- a/Firestore/Protos/nanopb/google/firestore/admin/index.nanopb.cc +++ b/Firestore/Protos/nanopb/google/firestore/admin/index.nanopb.cc @@ -1,5 +1,5 @@ /* - * Copyright 2024 Google LLC + * Copyright 2025 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/Firestore/Protos/nanopb/google/firestore/admin/index.nanopb.h b/Firestore/Protos/nanopb/google/firestore/admin/index.nanopb.h index e9ba3c9cb86..9caefad8c54 100644 --- a/Firestore/Protos/nanopb/google/firestore/admin/index.nanopb.h +++ b/Firestore/Protos/nanopb/google/firestore/admin/index.nanopb.h @@ -1,5 +1,5 @@ /* - * Copyright 2024 Google LLC + * Copyright 2025 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/Firestore/Protos/nanopb/google/firestore/v1/aggregation_result.nanopb.cc b/Firestore/Protos/nanopb/google/firestore/v1/aggregation_result.nanopb.cc index 5a740ffd8be..6b6dfe77b90 100644 --- a/Firestore/Protos/nanopb/google/firestore/v1/aggregation_result.nanopb.cc +++ b/Firestore/Protos/nanopb/google/firestore/v1/aggregation_result.nanopb.cc @@ -1,5 +1,5 @@ /* - * Copyright 2024 Google LLC + * Copyright 2025 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/Firestore/Protos/nanopb/google/firestore/v1/aggregation_result.nanopb.h b/Firestore/Protos/nanopb/google/firestore/v1/aggregation_result.nanopb.h index a64f9163853..0bed00bba6d 100644 --- a/Firestore/Protos/nanopb/google/firestore/v1/aggregation_result.nanopb.h +++ b/Firestore/Protos/nanopb/google/firestore/v1/aggregation_result.nanopb.h @@ -1,5 +1,5 @@ /* - * Copyright 2024 Google LLC + * Copyright 2025 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/Firestore/Protos/nanopb/google/firestore/v1/bloom_filter.nanopb.cc b/Firestore/Protos/nanopb/google/firestore/v1/bloom_filter.nanopb.cc index 3ce3049039a..e30c4b9613f 100644 --- a/Firestore/Protos/nanopb/google/firestore/v1/bloom_filter.nanopb.cc +++ b/Firestore/Protos/nanopb/google/firestore/v1/bloom_filter.nanopb.cc @@ -1,5 +1,5 @@ /* - * Copyright 2024 Google LLC + * Copyright 2025 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/Firestore/Protos/nanopb/google/firestore/v1/bloom_filter.nanopb.h b/Firestore/Protos/nanopb/google/firestore/v1/bloom_filter.nanopb.h index 0f294a9b9e1..e46bb381ada 100644 --- a/Firestore/Protos/nanopb/google/firestore/v1/bloom_filter.nanopb.h +++ b/Firestore/Protos/nanopb/google/firestore/v1/bloom_filter.nanopb.h @@ -1,5 +1,5 @@ /* - * Copyright 2024 Google LLC + * Copyright 2025 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/Firestore/Protos/nanopb/google/firestore/v1/common.nanopb.cc b/Firestore/Protos/nanopb/google/firestore/v1/common.nanopb.cc index 26c423266d4..f3b4bed3ff7 100644 --- a/Firestore/Protos/nanopb/google/firestore/v1/common.nanopb.cc +++ b/Firestore/Protos/nanopb/google/firestore/v1/common.nanopb.cc @@ -1,5 +1,5 @@ /* - * Copyright 2024 Google LLC + * Copyright 2025 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/Firestore/Protos/nanopb/google/firestore/v1/common.nanopb.h b/Firestore/Protos/nanopb/google/firestore/v1/common.nanopb.h index 7772c08f7df..b63ff25e66e 100644 --- a/Firestore/Protos/nanopb/google/firestore/v1/common.nanopb.h +++ b/Firestore/Protos/nanopb/google/firestore/v1/common.nanopb.h @@ -1,5 +1,5 @@ /* - * Copyright 2024 Google LLC + * Copyright 2025 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/Firestore/Protos/nanopb/google/firestore/v1/document.nanopb.cc b/Firestore/Protos/nanopb/google/firestore/v1/document.nanopb.cc index f236b603132..0fa5a799153 100644 --- a/Firestore/Protos/nanopb/google/firestore/v1/document.nanopb.cc +++ b/Firestore/Protos/nanopb/google/firestore/v1/document.nanopb.cc @@ -1,5 +1,5 @@ /* - * Copyright 2024 Google LLC + * Copyright 2025 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -51,7 +51,7 @@ const pb_field_t google_firestore_v1_Document_FieldsEntry_fields[3] = { PB_LAST_FIELD }; -const pb_field_t google_firestore_v1_Value_fields[12] = { +const pb_field_t google_firestore_v1_Value_fields[15] = { PB_ANONYMOUS_ONEOF_FIELD(value_type, 1, BOOL , ONEOF, STATIC , FIRST, google_firestore_v1_Value, boolean_value, boolean_value, 0), PB_ANONYMOUS_ONEOF_FIELD(value_type, 2, INT64 , ONEOF, STATIC , UNION, google_firestore_v1_Value, integer_value, integer_value, 0), PB_ANONYMOUS_ONEOF_FIELD(value_type, 3, DOUBLE , ONEOF, STATIC , UNION, google_firestore_v1_Value, double_value, double_value, 0), @@ -63,6 +63,9 @@ const pb_field_t google_firestore_v1_Value_fields[12] = { PB_ANONYMOUS_ONEOF_FIELD(value_type, 11, UENUM , ONEOF, STATIC , UNION, google_firestore_v1_Value, null_value, null_value, 0), PB_ANONYMOUS_ONEOF_FIELD(value_type, 17, BYTES , ONEOF, POINTER , UNION, google_firestore_v1_Value, string_value, string_value, 0), PB_ANONYMOUS_ONEOF_FIELD(value_type, 18, BYTES , ONEOF, POINTER , UNION, google_firestore_v1_Value, bytes_value, bytes_value, 0), + PB_ANONYMOUS_ONEOF_FIELD(value_type, 19, BYTES , ONEOF, POINTER , UNION, google_firestore_v1_Value, field_reference_value, field_reference_value, 0), + PB_ANONYMOUS_ONEOF_FIELD(value_type, 20, MESSAGE , ONEOF, STATIC , UNION, google_firestore_v1_Value, function_value, function_value, &google_firestore_v1_Function_fields), + PB_ANONYMOUS_ONEOF_FIELD(value_type, 21, MESSAGE , ONEOF, STATIC , UNION, google_firestore_v1_Value, pipeline_value, pipeline_value, &google_firestore_v1_Pipeline_fields), PB_LAST_FIELD }; @@ -82,6 +85,37 @@ const pb_field_t google_firestore_v1_MapValue_FieldsEntry_fields[3] = { PB_LAST_FIELD }; +const pb_field_t google_firestore_v1_Function_fields[4] = { + PB_FIELD( 1, BYTES , SINGULAR, POINTER , FIRST, google_firestore_v1_Function, name, name, 0), + PB_FIELD( 2, MESSAGE , REPEATED, POINTER , OTHER, google_firestore_v1_Function, args, name, &google_firestore_v1_Value_fields), + PB_FIELD( 3, MESSAGE , REPEATED, POINTER , OTHER, google_firestore_v1_Function, options, args, &google_firestore_v1_Function_OptionsEntry_fields), + PB_LAST_FIELD +}; + +const pb_field_t google_firestore_v1_Function_OptionsEntry_fields[3] = { + PB_FIELD( 1, BYTES , SINGULAR, POINTER , FIRST, google_firestore_v1_Function_OptionsEntry, key, key, 0), + PB_FIELD( 2, MESSAGE , SINGULAR, STATIC , OTHER, google_firestore_v1_Function_OptionsEntry, value, key, &google_firestore_v1_Value_fields), + PB_LAST_FIELD +}; + +const pb_field_t google_firestore_v1_Pipeline_fields[2] = { + PB_FIELD( 1, MESSAGE , REPEATED, POINTER , FIRST, google_firestore_v1_Pipeline, stages, stages, &google_firestore_v1_Pipeline_Stage_fields), + PB_LAST_FIELD +}; + +const pb_field_t google_firestore_v1_Pipeline_Stage_fields[4] = { + PB_FIELD( 1, BYTES , SINGULAR, POINTER , FIRST, google_firestore_v1_Pipeline_Stage, name, name, 0), + PB_FIELD( 2, MESSAGE , REPEATED, POINTER , OTHER, google_firestore_v1_Pipeline_Stage, args, name, &google_firestore_v1_Value_fields), + PB_FIELD( 3, MESSAGE , REPEATED, POINTER , OTHER, google_firestore_v1_Pipeline_Stage, options, args, &google_firestore_v1_Pipeline_Stage_OptionsEntry_fields), + PB_LAST_FIELD +}; + +const pb_field_t google_firestore_v1_Pipeline_Stage_OptionsEntry_fields[3] = { + PB_FIELD( 1, BYTES , SINGULAR, POINTER , FIRST, google_firestore_v1_Pipeline_Stage_OptionsEntry, key, key, 0), + PB_FIELD( 2, MESSAGE , SINGULAR, STATIC , OTHER, google_firestore_v1_Pipeline_Stage_OptionsEntry, value, key, &google_firestore_v1_Value_fields), + PB_LAST_FIELD +}; + /* Check that field information fits in pb_field_t */ #if !defined(PB_FIELD_32BIT) @@ -92,7 +126,7 @@ const pb_field_t google_firestore_v1_MapValue_FieldsEntry_fields[3] = { * numbers or field sizes that are larger than what can fit in 8 or 16 bit * field descriptors. */ -PB_STATIC_ASSERT((pb_membersize(google_firestore_v1_Document, create_time) < 65536 && pb_membersize(google_firestore_v1_Document, update_time) < 65536 && pb_membersize(google_firestore_v1_Document_FieldsEntry, value) < 65536 && pb_membersize(google_firestore_v1_Value, map_value) < 65536 && pb_membersize(google_firestore_v1_Value, geo_point_value) < 65536 && pb_membersize(google_firestore_v1_Value, array_value) < 65536 && pb_membersize(google_firestore_v1_Value, timestamp_value) < 65536 && pb_membersize(google_firestore_v1_MapValue_FieldsEntry, value) < 65536), YOU_MUST_DEFINE_PB_FIELD_32BIT_FOR_MESSAGES_google_firestore_v1_Document_google_firestore_v1_Document_FieldsEntry_google_firestore_v1_Value_google_firestore_v1_ArrayValue_google_firestore_v1_MapValue_google_firestore_v1_MapValue_FieldsEntry) +PB_STATIC_ASSERT((pb_membersize(google_firestore_v1_Document, create_time) < 65536 && pb_membersize(google_firestore_v1_Document, update_time) < 65536 && pb_membersize(google_firestore_v1_Document_FieldsEntry, value) < 65536 && pb_membersize(google_firestore_v1_Value, map_value) < 65536 && pb_membersize(google_firestore_v1_Value, geo_point_value) < 65536 && pb_membersize(google_firestore_v1_Value, array_value) < 65536 && pb_membersize(google_firestore_v1_Value, timestamp_value) < 65536 && pb_membersize(google_firestore_v1_Value, function_value) < 65536 && pb_membersize(google_firestore_v1_Value, pipeline_value) < 65536 && pb_membersize(google_firestore_v1_MapValue_FieldsEntry, value) < 65536 && pb_membersize(google_firestore_v1_Function_OptionsEntry, value) < 65536 && pb_membersize(google_firestore_v1_Pipeline_Stage_OptionsEntry, value) < 65536), YOU_MUST_DEFINE_PB_FIELD_32BIT_FOR_MESSAGES_google_firestore_v1_Document_google_firestore_v1_Document_FieldsEntry_google_firestore_v1_Value_google_firestore_v1_ArrayValue_google_firestore_v1_MapValue_google_firestore_v1_MapValue_FieldsEntry_google_firestore_v1_Function_google_firestore_v1_Function_OptionsEntry_google_firestore_v1_Pipeline_google_firestore_v1_Pipeline_Stage_google_firestore_v1_Pipeline_Stage_OptionsEntry) #endif #if !defined(PB_FIELD_16BIT) && !defined(PB_FIELD_32BIT) @@ -103,7 +137,7 @@ PB_STATIC_ASSERT((pb_membersize(google_firestore_v1_Document, create_time) < 655 * numbers or field sizes that are larger than what can fit in the default * 8 bit descriptors. */ -PB_STATIC_ASSERT((pb_membersize(google_firestore_v1_Document, create_time) < 256 && pb_membersize(google_firestore_v1_Document, update_time) < 256 && pb_membersize(google_firestore_v1_Document_FieldsEntry, value) < 256 && pb_membersize(google_firestore_v1_Value, map_value) < 256 && pb_membersize(google_firestore_v1_Value, geo_point_value) < 256 && pb_membersize(google_firestore_v1_Value, array_value) < 256 && pb_membersize(google_firestore_v1_Value, timestamp_value) < 256 && pb_membersize(google_firestore_v1_MapValue_FieldsEntry, value) < 256), YOU_MUST_DEFINE_PB_FIELD_16BIT_FOR_MESSAGES_google_firestore_v1_Document_google_firestore_v1_Document_FieldsEntry_google_firestore_v1_Value_google_firestore_v1_ArrayValue_google_firestore_v1_MapValue_google_firestore_v1_MapValue_FieldsEntry) +PB_STATIC_ASSERT((pb_membersize(google_firestore_v1_Document, create_time) < 256 && pb_membersize(google_firestore_v1_Document, update_time) < 256 && pb_membersize(google_firestore_v1_Document_FieldsEntry, value) < 256 && pb_membersize(google_firestore_v1_Value, map_value) < 256 && pb_membersize(google_firestore_v1_Value, geo_point_value) < 256 && pb_membersize(google_firestore_v1_Value, array_value) < 256 && pb_membersize(google_firestore_v1_Value, timestamp_value) < 256 && pb_membersize(google_firestore_v1_Value, function_value) < 256 && pb_membersize(google_firestore_v1_Value, pipeline_value) < 256 && pb_membersize(google_firestore_v1_MapValue_FieldsEntry, value) < 256 && pb_membersize(google_firestore_v1_Function_OptionsEntry, value) < 256 && pb_membersize(google_firestore_v1_Pipeline_Stage_OptionsEntry, value) < 256), YOU_MUST_DEFINE_PB_FIELD_16BIT_FOR_MESSAGES_google_firestore_v1_Document_google_firestore_v1_Document_FieldsEntry_google_firestore_v1_Value_google_firestore_v1_ArrayValue_google_firestore_v1_MapValue_google_firestore_v1_MapValue_FieldsEntry_google_firestore_v1_Function_google_firestore_v1_Function_OptionsEntry_google_firestore_v1_Pipeline_google_firestore_v1_Pipeline_Stage_google_firestore_v1_Pipeline_Stage_OptionsEntry) #endif @@ -193,6 +227,18 @@ std::string google_firestore_v1_Value::ToString(int indent) const { tostring_result += PrintPrimitiveField("bytes_value: ", bytes_value, indent + 1, true); break; + case google_firestore_v1_Value_field_reference_value_tag: + tostring_result += PrintPrimitiveField("field_reference_value: ", + field_reference_value, indent + 1, true); + break; + case google_firestore_v1_Value_function_value_tag: + tostring_result += PrintMessageField("function_value ", + function_value, indent + 1, true); + break; + case google_firestore_v1_Value_pipeline_value_tag: + tostring_result += PrintMessageField("pipeline_value ", + pipeline_value, indent + 1, true); + break; } bool is_root = indent == 0; @@ -251,6 +297,92 @@ std::string google_firestore_v1_MapValue_FieldsEntry::ToString(int indent) const return tostring_header + tostring_result + tostring_tail; } +std::string google_firestore_v1_Function::ToString(int indent) const { + std::string tostring_header = PrintHeader(indent, "Function", this); + std::string tostring_result; + + tostring_result += PrintPrimitiveField("name: ", name, indent + 1, false); + for (pb_size_t i = 0; i != args_count; ++i) { + tostring_result += PrintMessageField("args ", + args[i], indent + 1, true); + } + for (pb_size_t i = 0; i != options_count; ++i) { + tostring_result += PrintMessageField("options ", + options[i], indent + 1, true); + } + + bool is_root = indent == 0; + if (!tostring_result.empty() || is_root) { + std::string tostring_tail = PrintTail(indent); + return tostring_header + tostring_result + tostring_tail; + } else { + return ""; + } +} + +std::string google_firestore_v1_Function_OptionsEntry::ToString(int indent) const { + std::string tostring_header = PrintHeader(indent, "OptionsEntry", this); + std::string tostring_result; + + tostring_result += PrintPrimitiveField("key: ", key, indent + 1, false); + tostring_result += PrintMessageField("value ", value, indent + 1, false); + + std::string tostring_tail = PrintTail(indent); + return tostring_header + tostring_result + tostring_tail; +} + +std::string google_firestore_v1_Pipeline::ToString(int indent) const { + std::string tostring_header = PrintHeader(indent, "Pipeline", this); + std::string tostring_result; + + for (pb_size_t i = 0; i != stages_count; ++i) { + tostring_result += PrintMessageField("stages ", + stages[i], indent + 1, true); + } + + bool is_root = indent == 0; + if (!tostring_result.empty() || is_root) { + std::string tostring_tail = PrintTail(indent); + return tostring_header + tostring_result + tostring_tail; + } else { + return ""; + } +} + +std::string google_firestore_v1_Pipeline_Stage::ToString(int indent) const { + std::string tostring_header = PrintHeader(indent, "Stage", this); + std::string tostring_result; + + tostring_result += PrintPrimitiveField("name: ", name, indent + 1, false); + for (pb_size_t i = 0; i != args_count; ++i) { + tostring_result += PrintMessageField("args ", + args[i], indent + 1, true); + } + for (pb_size_t i = 0; i != options_count; ++i) { + tostring_result += PrintMessageField("options ", + options[i], indent + 1, true); + } + + bool is_root = indent == 0; + if (!tostring_result.empty() || is_root) { + std::string tostring_tail = PrintTail(indent); + return tostring_header + tostring_result + tostring_tail; + } else { + return ""; + } +} + +std::string google_firestore_v1_Pipeline_Stage_OptionsEntry::ToString(int indent) const { + std::string tostring_header = PrintHeader(indent, "OptionsEntry", this); + std::string tostring_result; + + tostring_result += PrintPrimitiveField("key: ", key, indent + 1, false); + tostring_result += PrintMessageField("value ", value, indent + 1, false); + + std::string tostring_tail = PrintTail(indent); + return tostring_header + tostring_result + tostring_tail; +} + } // namespace firestore } // namespace firebase diff --git a/Firestore/Protos/nanopb/google/firestore/v1/document.nanopb.h b/Firestore/Protos/nanopb/google/firestore/v1/document.nanopb.h index 6a6435c05a3..c168433c5a8 100644 --- a/Firestore/Protos/nanopb/google/firestore/v1/document.nanopb.h +++ b/Firestore/Protos/nanopb/google/firestore/v1/document.nanopb.h @@ -1,5 +1,5 @@ /* - * Copyright 2024 Google LLC + * Copyright 2025 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,6 +21,8 @@ #define PB_GOOGLE_FIRESTORE_V1_DOCUMENT_NANOPB_H_INCLUDED #include +#include "google/api/field_behavior.nanopb.h" + #include "google/protobuf/struct.nanopb.h" #include "google/protobuf/timestamp.nanopb.h" @@ -47,6 +49,17 @@ typedef struct _google_firestore_v1_ArrayValue { /* @@protoc_insertion_point(struct:google_firestore_v1_ArrayValue) */ } google_firestore_v1_ArrayValue; +typedef struct _google_firestore_v1_Function { + pb_bytes_array_t *name; + pb_size_t args_count; + struct _google_firestore_v1_Value *args; + pb_size_t options_count; + struct _google_firestore_v1_Function_OptionsEntry *options; + + std::string ToString(int indent = 0) const; +/* @@protoc_insertion_point(struct:google_firestore_v1_Function) */ +} google_firestore_v1_Function; + typedef struct _google_firestore_v1_MapValue { pb_size_t fields_count; struct _google_firestore_v1_MapValue_FieldsEntry *fields; @@ -55,6 +68,25 @@ typedef struct _google_firestore_v1_MapValue { /* @@protoc_insertion_point(struct:google_firestore_v1_MapValue) */ } google_firestore_v1_MapValue; +typedef struct _google_firestore_v1_Pipeline { + pb_size_t stages_count; + struct _google_firestore_v1_Pipeline_Stage *stages; + + std::string ToString(int indent = 0) const; +/* @@protoc_insertion_point(struct:google_firestore_v1_Pipeline) */ +} google_firestore_v1_Pipeline; + +typedef struct _google_firestore_v1_Pipeline_Stage { + pb_bytes_array_t *name; + pb_size_t args_count; + struct _google_firestore_v1_Value *args; + pb_size_t options_count; + struct _google_firestore_v1_Pipeline_Stage_OptionsEntry *options; + + std::string ToString(int indent = 0) const; +/* @@protoc_insertion_point(struct:google_firestore_v1_Pipeline_Stage) */ +} google_firestore_v1_Pipeline_Stage; + typedef struct _google_firestore_v1_Document { pb_bytes_array_t *name; pb_size_t fields_count; @@ -81,6 +113,9 @@ typedef struct _google_firestore_v1_Value { google_protobuf_NullValue null_value; pb_bytes_array_t *string_value; pb_bytes_array_t *bytes_value; + pb_bytes_array_t *field_reference_value; + google_firestore_v1_Function function_value; + google_firestore_v1_Pipeline pipeline_value; }; std::string ToString(int indent = 0) const; @@ -95,6 +130,14 @@ typedef struct _google_firestore_v1_Document_FieldsEntry { /* @@protoc_insertion_point(struct:google_firestore_v1_Document_FieldsEntry) */ } google_firestore_v1_Document_FieldsEntry; +typedef struct _google_firestore_v1_Function_OptionsEntry { + pb_bytes_array_t *key; + google_firestore_v1_Value value; + + std::string ToString(int indent = 0) const; +/* @@protoc_insertion_point(struct:google_firestore_v1_Function_OptionsEntry) */ +} google_firestore_v1_Function_OptionsEntry; + typedef struct _google_firestore_v1_MapValue_FieldsEntry { pb_bytes_array_t *key; google_firestore_v1_Value value; @@ -103,6 +146,14 @@ typedef struct _google_firestore_v1_MapValue_FieldsEntry { /* @@protoc_insertion_point(struct:google_firestore_v1_MapValue_FieldsEntry) */ } google_firestore_v1_MapValue_FieldsEntry; +typedef struct _google_firestore_v1_Pipeline_Stage_OptionsEntry { + pb_bytes_array_t *key; + google_firestore_v1_Value value; + + std::string ToString(int indent = 0) const; +/* @@protoc_insertion_point(struct:google_firestore_v1_Pipeline_Stage_OptionsEntry) */ +} google_firestore_v1_Pipeline_Stage_OptionsEntry; + /* Default values for struct fields */ /* Initializer values for message structs */ @@ -112,16 +163,33 @@ typedef struct _google_firestore_v1_MapValue_FieldsEntry { #define google_firestore_v1_ArrayValue_init_default {0, NULL} #define google_firestore_v1_MapValue_init_default {0, NULL} #define google_firestore_v1_MapValue_FieldsEntry_init_default {NULL, google_firestore_v1_Value_init_default} +#define google_firestore_v1_Function_init_default {NULL, 0, NULL, 0, NULL} +#define google_firestore_v1_Function_OptionsEntry_init_default {NULL, google_firestore_v1_Value_init_default} +#define google_firestore_v1_Pipeline_init_default {0, NULL} +#define google_firestore_v1_Pipeline_Stage_init_default {NULL, 0, NULL, 0, NULL} +#define google_firestore_v1_Pipeline_Stage_OptionsEntry_init_default {NULL, google_firestore_v1_Value_init_default} #define google_firestore_v1_Document_init_zero {NULL, 0, NULL, google_protobuf_Timestamp_init_zero, false, google_protobuf_Timestamp_init_zero} #define google_firestore_v1_Document_FieldsEntry_init_zero {NULL, google_firestore_v1_Value_init_zero} #define google_firestore_v1_Value_init_zero {0, {0}} #define google_firestore_v1_ArrayValue_init_zero {0, NULL} #define google_firestore_v1_MapValue_init_zero {0, NULL} #define google_firestore_v1_MapValue_FieldsEntry_init_zero {NULL, google_firestore_v1_Value_init_zero} +#define google_firestore_v1_Function_init_zero {NULL, 0, NULL, 0, NULL} +#define google_firestore_v1_Function_OptionsEntry_init_zero {NULL, google_firestore_v1_Value_init_zero} +#define google_firestore_v1_Pipeline_init_zero {0, NULL} +#define google_firestore_v1_Pipeline_Stage_init_zero {NULL, 0, NULL, 0, NULL} +#define google_firestore_v1_Pipeline_Stage_OptionsEntry_init_zero {NULL, google_firestore_v1_Value_init_zero} /* Field tags (for use in manual encoding/decoding) */ #define google_firestore_v1_ArrayValue_values_tag 1 +#define google_firestore_v1_Function_name_tag 1 +#define google_firestore_v1_Function_args_tag 2 +#define google_firestore_v1_Function_options_tag 3 #define google_firestore_v1_MapValue_fields_tag 1 +#define google_firestore_v1_Pipeline_stages_tag 1 +#define google_firestore_v1_Pipeline_Stage_name_tag 1 +#define google_firestore_v1_Pipeline_Stage_args_tag 2 +#define google_firestore_v1_Pipeline_Stage_options_tag 3 #define google_firestore_v1_Document_name_tag 1 #define google_firestore_v1_Document_fields_tag 2 #define google_firestore_v1_Document_create_time_tag 3 @@ -137,18 +205,30 @@ typedef struct _google_firestore_v1_MapValue_FieldsEntry { #define google_firestore_v1_Value_null_value_tag 11 #define google_firestore_v1_Value_string_value_tag 17 #define google_firestore_v1_Value_bytes_value_tag 18 +#define google_firestore_v1_Value_field_reference_value_tag 19 +#define google_firestore_v1_Value_function_value_tag 20 +#define google_firestore_v1_Value_pipeline_value_tag 21 #define google_firestore_v1_Document_FieldsEntry_key_tag 1 #define google_firestore_v1_Document_FieldsEntry_value_tag 2 +#define google_firestore_v1_Function_OptionsEntry_key_tag 1 +#define google_firestore_v1_Function_OptionsEntry_value_tag 2 #define google_firestore_v1_MapValue_FieldsEntry_key_tag 1 #define google_firestore_v1_MapValue_FieldsEntry_value_tag 2 +#define google_firestore_v1_Pipeline_Stage_OptionsEntry_key_tag 1 +#define google_firestore_v1_Pipeline_Stage_OptionsEntry_value_tag 2 /* Struct field encoding specification for nanopb */ extern const pb_field_t google_firestore_v1_Document_fields[5]; extern const pb_field_t google_firestore_v1_Document_FieldsEntry_fields[3]; -extern const pb_field_t google_firestore_v1_Value_fields[12]; +extern const pb_field_t google_firestore_v1_Value_fields[15]; extern const pb_field_t google_firestore_v1_ArrayValue_fields[2]; extern const pb_field_t google_firestore_v1_MapValue_fields[2]; extern const pb_field_t google_firestore_v1_MapValue_FieldsEntry_fields[3]; +extern const pb_field_t google_firestore_v1_Function_fields[4]; +extern const pb_field_t google_firestore_v1_Function_OptionsEntry_fields[3]; +extern const pb_field_t google_firestore_v1_Pipeline_fields[2]; +extern const pb_field_t google_firestore_v1_Pipeline_Stage_fields[4]; +extern const pb_field_t google_firestore_v1_Pipeline_Stage_OptionsEntry_fields[3]; /* Maximum encoded size of messages (where known) */ /* google_firestore_v1_Document_size depends on runtime parameters */ @@ -157,6 +237,11 @@ extern const pb_field_t google_firestore_v1_MapValue_FieldsEntry_fields[3]; /* google_firestore_v1_ArrayValue_size depends on runtime parameters */ /* google_firestore_v1_MapValue_size depends on runtime parameters */ /* google_firestore_v1_MapValue_FieldsEntry_size depends on runtime parameters */ +/* google_firestore_v1_Function_size depends on runtime parameters */ +/* google_firestore_v1_Function_OptionsEntry_size depends on runtime parameters */ +/* google_firestore_v1_Pipeline_size depends on runtime parameters */ +/* google_firestore_v1_Pipeline_Stage_size depends on runtime parameters */ +/* google_firestore_v1_Pipeline_Stage_OptionsEntry_size depends on runtime parameters */ /* Message IDs (where set with "msgid" option) */ #ifdef PB_MSGID diff --git a/Firestore/Protos/nanopb/google/firestore/v1/explain_stats.nanopb.cc b/Firestore/Protos/nanopb/google/firestore/v1/explain_stats.nanopb.cc new file mode 100644 index 00000000000..60d7cfab731 --- /dev/null +++ b/Firestore/Protos/nanopb/google/firestore/v1/explain_stats.nanopb.cc @@ -0,0 +1,83 @@ +/* + * Copyright 2025 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. + */ + +/* Automatically generated nanopb constant definitions */ +/* Generated by nanopb-0.3.9.8 */ + +#include "explain_stats.nanopb.h" + +#include "Firestore/core/src/nanopb/pretty_printing.h" + +namespace firebase { +namespace firestore { + +using nanopb::PrintEnumField; +using nanopb::PrintHeader; +using nanopb::PrintMessageField; +using nanopb::PrintPrimitiveField; +using nanopb::PrintTail; + +/* @@protoc_insertion_point(includes) */ +#if PB_PROTO_HEADER_VERSION != 30 +#error Regenerate this file with the current version of nanopb generator. +#endif + + + +const pb_field_t google_firestore_v1_ExplainStats_fields[2] = { + PB_FIELD( 1, MESSAGE , SINGULAR, STATIC , FIRST, google_firestore_v1_ExplainStats, data, data, &google_protobuf_Any_fields), + PB_LAST_FIELD +}; + + +/* Check that field information fits in pb_field_t */ +#if !defined(PB_FIELD_32BIT) +/* If you get an error here, it means that you need to define PB_FIELD_32BIT + * compile-time option. You can do that in pb.h or on compiler command line. + * + * The reason you need to do this is that some of your messages contain tag + * numbers or field sizes that are larger than what can fit in 8 or 16 bit + * field descriptors. + */ +PB_STATIC_ASSERT((pb_membersize(google_firestore_v1_ExplainStats, data) < 65536), YOU_MUST_DEFINE_PB_FIELD_32BIT_FOR_MESSAGES_google_firestore_v1_ExplainStats) +#endif + +#if !defined(PB_FIELD_16BIT) && !defined(PB_FIELD_32BIT) +/* If you get an error here, it means that you need to define PB_FIELD_16BIT + * compile-time option. You can do that in pb.h or on compiler command line. + * + * The reason you need to do this is that some of your messages contain tag + * numbers or field sizes that are larger than what can fit in the default + * 8 bit descriptors. + */ +PB_STATIC_ASSERT((pb_membersize(google_firestore_v1_ExplainStats, data) < 256), YOU_MUST_DEFINE_PB_FIELD_16BIT_FOR_MESSAGES_google_firestore_v1_ExplainStats) +#endif + + +std::string google_firestore_v1_ExplainStats::ToString(int indent) const { + std::string tostring_header = PrintHeader(indent, "ExplainStats", this); + std::string tostring_result; + + tostring_result += PrintMessageField("data ", data, indent + 1, false); + + std::string tostring_tail = PrintTail(indent); + return tostring_header + tostring_result + tostring_tail; +} + +} // namespace firestore +} // namespace firebase + +/* @@protoc_insertion_point(eof) */ diff --git a/Firestore/Protos/nanopb/google/firestore/v1/explain_stats.nanopb.h b/Firestore/Protos/nanopb/google/firestore/v1/explain_stats.nanopb.h new file mode 100644 index 00000000000..f97eb64ee51 --- /dev/null +++ b/Firestore/Protos/nanopb/google/firestore/v1/explain_stats.nanopb.h @@ -0,0 +1,73 @@ +/* + * Copyright 2025 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. + */ + +/* Automatically generated nanopb header */ +/* Generated by nanopb-0.3.9.8 */ + +#ifndef PB_GOOGLE_FIRESTORE_V1_EXPLAIN_STATS_NANOPB_H_INCLUDED +#define PB_GOOGLE_FIRESTORE_V1_EXPLAIN_STATS_NANOPB_H_INCLUDED +#include + +#include "google/protobuf/any.nanopb.h" + +#include + +namespace firebase { +namespace firestore { + +/* @@protoc_insertion_point(includes) */ +#if PB_PROTO_HEADER_VERSION != 30 +#error Regenerate this file with the current version of nanopb generator. +#endif + + +/* Struct definitions */ +typedef struct _google_firestore_v1_ExplainStats { + google_protobuf_Any data; + + std::string ToString(int indent = 0) const; +/* @@protoc_insertion_point(struct:google_firestore_v1_ExplainStats) */ +} google_firestore_v1_ExplainStats; + +/* Default values for struct fields */ + +/* Initializer values for message structs */ +#define google_firestore_v1_ExplainStats_init_default {google_protobuf_Any_init_default} +#define google_firestore_v1_ExplainStats_init_zero {google_protobuf_Any_init_zero} + +/* Field tags (for use in manual encoding/decoding) */ +#define google_firestore_v1_ExplainStats_data_tag 1 + +/* Struct field encoding specification for nanopb */ +extern const pb_field_t google_firestore_v1_ExplainStats_fields[2]; + +/* Maximum encoded size of messages (where known) */ +#define google_firestore_v1_ExplainStats_size (6 + google_protobuf_Any_size) + +/* Message IDs (where set with "msgid" option) */ +#ifdef PB_MSGID + +#define EXPLAIN_STATS_MESSAGES \ + + +#endif + +} // namespace firestore +} // namespace firebase + +/* @@protoc_insertion_point(eof) */ + +#endif diff --git a/Firestore/Protos/nanopb/google/firestore/v1/firestore.nanopb.cc b/Firestore/Protos/nanopb/google/firestore/v1/firestore.nanopb.cc index 233d2025dc9..fabd2343097 100644 --- a/Firestore/Protos/nanopb/google/firestore/v1/firestore.nanopb.cc +++ b/Firestore/Protos/nanopb/google/firestore/v1/firestore.nanopb.cc @@ -1,5 +1,5 @@ /* - * Copyright 2024 Google LLC + * Copyright 2025 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -152,6 +152,23 @@ const pb_field_t google_firestore_v1_RunQueryResponse_fields[5] = { PB_LAST_FIELD }; +const pb_field_t google_firestore_v1_ExecutePipelineRequest_fields[6] = { + PB_FIELD( 1, BYTES , SINGULAR, POINTER , FIRST, google_firestore_v1_ExecutePipelineRequest, database, database, 0), + PB_ONEOF_FIELD(pipeline_type, 2, MESSAGE , ONEOF, STATIC , OTHER, google_firestore_v1_ExecutePipelineRequest, structured_pipeline, database, &google_firestore_v1_StructuredPipeline_fields), + PB_ONEOF_FIELD(consistency_selector, 5, BYTES , ONEOF, POINTER , OTHER, google_firestore_v1_ExecutePipelineRequest, transaction, pipeline_type.structured_pipeline, 0), + PB_ONEOF_FIELD(consistency_selector, 6, MESSAGE , ONEOF, STATIC , UNION, google_firestore_v1_ExecutePipelineRequest, new_transaction, pipeline_type.structured_pipeline, &google_firestore_v1_TransactionOptions_fields), + PB_ONEOF_FIELD(consistency_selector, 7, MESSAGE , ONEOF, STATIC , UNION, google_firestore_v1_ExecutePipelineRequest, read_time, pipeline_type.structured_pipeline, &google_protobuf_Timestamp_fields), + PB_LAST_FIELD +}; + +const pb_field_t google_firestore_v1_ExecutePipelineResponse_fields[5] = { + PB_FIELD( 1, BYTES , SINGULAR, POINTER , FIRST, google_firestore_v1_ExecutePipelineResponse, transaction, transaction, 0), + PB_FIELD( 2, MESSAGE , REPEATED, POINTER , OTHER, google_firestore_v1_ExecutePipelineResponse, results, transaction, &google_firestore_v1_Document_fields), + PB_FIELD( 3, MESSAGE , SINGULAR, STATIC , OTHER, google_firestore_v1_ExecutePipelineResponse, execution_time, results, &google_protobuf_Timestamp_fields), + PB_FIELD( 4, MESSAGE , SINGULAR, STATIC , OTHER, google_firestore_v1_ExecutePipelineResponse, explain_stats, execution_time, &google_firestore_v1_ExplainStats_fields), + PB_LAST_FIELD +}; + const pb_field_t google_firestore_v1_RunAggregationQueryRequest_fields[6] = { PB_FIELD( 1, BYTES , SINGULAR, POINTER , FIRST, google_firestore_v1_RunAggregationQueryRequest, parent, parent, 0), PB_ONEOF_FIELD(query_type, 2, MESSAGE , ONEOF, STATIC , OTHER, google_firestore_v1_RunAggregationQueryRequest, structured_aggregation_query, parent, &google_firestore_v1_StructuredAggregationQuery_fields), @@ -269,7 +286,7 @@ const pb_field_t google_firestore_v1_ListCollectionIdsResponse_fields[3] = { * numbers or field sizes that are larger than what can fit in 8 or 16 bit * field descriptors. */ -PB_STATIC_ASSERT((pb_membersize(google_firestore_v1_GetDocumentRequest, read_time) < 65536 && pb_membersize(google_firestore_v1_GetDocumentRequest, mask) < 65536 && pb_membersize(google_firestore_v1_ListDocumentsRequest, read_time) < 65536 && pb_membersize(google_firestore_v1_ListDocumentsRequest, mask) < 65536 && pb_membersize(google_firestore_v1_CreateDocumentRequest, document) < 65536 && pb_membersize(google_firestore_v1_CreateDocumentRequest, mask) < 65536 && pb_membersize(google_firestore_v1_UpdateDocumentRequest, document) < 65536 && pb_membersize(google_firestore_v1_UpdateDocumentRequest, update_mask) < 65536 && pb_membersize(google_firestore_v1_UpdateDocumentRequest, mask) < 65536 && pb_membersize(google_firestore_v1_UpdateDocumentRequest, current_document) < 65536 && pb_membersize(google_firestore_v1_DeleteDocumentRequest, current_document) < 65536 && pb_membersize(google_firestore_v1_BatchGetDocumentsRequest, new_transaction) < 65536 && pb_membersize(google_firestore_v1_BatchGetDocumentsRequest, read_time) < 65536 && pb_membersize(google_firestore_v1_BatchGetDocumentsRequest, mask) < 65536 && pb_membersize(google_firestore_v1_BatchGetDocumentsResponse, found) < 65536 && pb_membersize(google_firestore_v1_BatchGetDocumentsResponse, read_time) < 65536 && pb_membersize(google_firestore_v1_BeginTransactionRequest, options) < 65536 && pb_membersize(google_firestore_v1_CommitResponse, commit_time) < 65536 && pb_membersize(google_firestore_v1_RunQueryRequest, query_type.structured_query) < 65536 && pb_membersize(google_firestore_v1_RunQueryRequest, consistency_selector.new_transaction) < 65536 && pb_membersize(google_firestore_v1_RunQueryRequest, consistency_selector.read_time) < 65536 && pb_membersize(google_firestore_v1_RunQueryResponse, document) < 65536 && pb_membersize(google_firestore_v1_RunQueryResponse, read_time) < 65536 && pb_membersize(google_firestore_v1_RunAggregationQueryRequest, query_type.structured_aggregation_query) < 65536 && pb_membersize(google_firestore_v1_RunAggregationQueryRequest, consistency_selector.new_transaction) < 65536 && pb_membersize(google_firestore_v1_RunAggregationQueryRequest, consistency_selector.read_time) < 65536 && pb_membersize(google_firestore_v1_RunAggregationQueryResponse, result) < 65536 && pb_membersize(google_firestore_v1_RunAggregationQueryResponse, read_time) < 65536 && pb_membersize(google_firestore_v1_WriteResponse, commit_time) < 65536 && pb_membersize(google_firestore_v1_ListenRequest, add_target) < 65536 && pb_membersize(google_firestore_v1_ListenResponse, target_change) < 65536 && pb_membersize(google_firestore_v1_ListenResponse, document_change) < 65536 && pb_membersize(google_firestore_v1_ListenResponse, document_delete) < 65536 && pb_membersize(google_firestore_v1_ListenResponse, filter) < 65536 && pb_membersize(google_firestore_v1_ListenResponse, document_remove) < 65536 && pb_membersize(google_firestore_v1_Target, target_type.query) < 65536 && pb_membersize(google_firestore_v1_Target, target_type.documents) < 65536 && pb_membersize(google_firestore_v1_Target, resume_type.read_time) < 65536 && pb_membersize(google_firestore_v1_Target, expected_count) < 65536 && pb_membersize(google_firestore_v1_Target_QueryTarget, structured_query) < 65536 && pb_membersize(google_firestore_v1_TargetChange, cause) < 65536 && pb_membersize(google_firestore_v1_TargetChange, read_time) < 65536), YOU_MUST_DEFINE_PB_FIELD_32BIT_FOR_MESSAGES_google_firestore_v1_GetDocumentRequest_google_firestore_v1_ListDocumentsRequest_google_firestore_v1_ListDocumentsResponse_google_firestore_v1_CreateDocumentRequest_google_firestore_v1_UpdateDocumentRequest_google_firestore_v1_DeleteDocumentRequest_google_firestore_v1_BatchGetDocumentsRequest_google_firestore_v1_BatchGetDocumentsResponse_google_firestore_v1_BeginTransactionRequest_google_firestore_v1_BeginTransactionResponse_google_firestore_v1_CommitRequest_google_firestore_v1_CommitResponse_google_firestore_v1_RollbackRequest_google_firestore_v1_RunQueryRequest_google_firestore_v1_RunQueryResponse_google_firestore_v1_RunAggregationQueryRequest_google_firestore_v1_RunAggregationQueryResponse_google_firestore_v1_WriteRequest_google_firestore_v1_WriteRequest_LabelsEntry_google_firestore_v1_WriteResponse_google_firestore_v1_ListenRequest_google_firestore_v1_ListenRequest_LabelsEntry_google_firestore_v1_ListenResponse_google_firestore_v1_Target_google_firestore_v1_Target_DocumentsTarget_google_firestore_v1_Target_QueryTarget_google_firestore_v1_TargetChange_google_firestore_v1_ListCollectionIdsRequest_google_firestore_v1_ListCollectionIdsResponse) +PB_STATIC_ASSERT((pb_membersize(google_firestore_v1_GetDocumentRequest, read_time) < 65536 && pb_membersize(google_firestore_v1_GetDocumentRequest, mask) < 65536 && pb_membersize(google_firestore_v1_ListDocumentsRequest, read_time) < 65536 && pb_membersize(google_firestore_v1_ListDocumentsRequest, mask) < 65536 && pb_membersize(google_firestore_v1_CreateDocumentRequest, document) < 65536 && pb_membersize(google_firestore_v1_CreateDocumentRequest, mask) < 65536 && pb_membersize(google_firestore_v1_UpdateDocumentRequest, document) < 65536 && pb_membersize(google_firestore_v1_UpdateDocumentRequest, update_mask) < 65536 && pb_membersize(google_firestore_v1_UpdateDocumentRequest, mask) < 65536 && pb_membersize(google_firestore_v1_UpdateDocumentRequest, current_document) < 65536 && pb_membersize(google_firestore_v1_DeleteDocumentRequest, current_document) < 65536 && pb_membersize(google_firestore_v1_BatchGetDocumentsRequest, new_transaction) < 65536 && pb_membersize(google_firestore_v1_BatchGetDocumentsRequest, read_time) < 65536 && pb_membersize(google_firestore_v1_BatchGetDocumentsRequest, mask) < 65536 && pb_membersize(google_firestore_v1_BatchGetDocumentsResponse, found) < 65536 && pb_membersize(google_firestore_v1_BatchGetDocumentsResponse, read_time) < 65536 && pb_membersize(google_firestore_v1_BeginTransactionRequest, options) < 65536 && pb_membersize(google_firestore_v1_CommitResponse, commit_time) < 65536 && pb_membersize(google_firestore_v1_RunQueryRequest, query_type.structured_query) < 65536 && pb_membersize(google_firestore_v1_RunQueryRequest, consistency_selector.new_transaction) < 65536 && pb_membersize(google_firestore_v1_RunQueryRequest, consistency_selector.read_time) < 65536 && pb_membersize(google_firestore_v1_RunQueryResponse, document) < 65536 && pb_membersize(google_firestore_v1_RunQueryResponse, read_time) < 65536 && pb_membersize(google_firestore_v1_ExecutePipelineRequest, pipeline_type.structured_pipeline) < 65536 && pb_membersize(google_firestore_v1_ExecutePipelineRequest, consistency_selector.new_transaction) < 65536 && pb_membersize(google_firestore_v1_ExecutePipelineRequest, consistency_selector.read_time) < 65536 && pb_membersize(google_firestore_v1_ExecutePipelineResponse, execution_time) < 65536 && pb_membersize(google_firestore_v1_ExecutePipelineResponse, explain_stats) < 65536 && pb_membersize(google_firestore_v1_RunAggregationQueryRequest, query_type.structured_aggregation_query) < 65536 && pb_membersize(google_firestore_v1_RunAggregationQueryRequest, consistency_selector.new_transaction) < 65536 && pb_membersize(google_firestore_v1_RunAggregationQueryRequest, consistency_selector.read_time) < 65536 && pb_membersize(google_firestore_v1_RunAggregationQueryResponse, result) < 65536 && pb_membersize(google_firestore_v1_RunAggregationQueryResponse, read_time) < 65536 && pb_membersize(google_firestore_v1_WriteResponse, commit_time) < 65536 && pb_membersize(google_firestore_v1_ListenRequest, add_target) < 65536 && pb_membersize(google_firestore_v1_ListenResponse, target_change) < 65536 && pb_membersize(google_firestore_v1_ListenResponse, document_change) < 65536 && pb_membersize(google_firestore_v1_ListenResponse, document_delete) < 65536 && pb_membersize(google_firestore_v1_ListenResponse, filter) < 65536 && pb_membersize(google_firestore_v1_ListenResponse, document_remove) < 65536 && pb_membersize(google_firestore_v1_Target, target_type.query) < 65536 && pb_membersize(google_firestore_v1_Target, target_type.documents) < 65536 && pb_membersize(google_firestore_v1_Target, resume_type.read_time) < 65536 && pb_membersize(google_firestore_v1_Target, expected_count) < 65536 && pb_membersize(google_firestore_v1_Target_QueryTarget, structured_query) < 65536 && pb_membersize(google_firestore_v1_TargetChange, cause) < 65536 && pb_membersize(google_firestore_v1_TargetChange, read_time) < 65536), YOU_MUST_DEFINE_PB_FIELD_32BIT_FOR_MESSAGES_google_firestore_v1_GetDocumentRequest_google_firestore_v1_ListDocumentsRequest_google_firestore_v1_ListDocumentsResponse_google_firestore_v1_CreateDocumentRequest_google_firestore_v1_UpdateDocumentRequest_google_firestore_v1_DeleteDocumentRequest_google_firestore_v1_BatchGetDocumentsRequest_google_firestore_v1_BatchGetDocumentsResponse_google_firestore_v1_BeginTransactionRequest_google_firestore_v1_BeginTransactionResponse_google_firestore_v1_CommitRequest_google_firestore_v1_CommitResponse_google_firestore_v1_RollbackRequest_google_firestore_v1_RunQueryRequest_google_firestore_v1_RunQueryResponse_google_firestore_v1_ExecutePipelineRequest_google_firestore_v1_ExecutePipelineResponse_google_firestore_v1_RunAggregationQueryRequest_google_firestore_v1_RunAggregationQueryResponse_google_firestore_v1_WriteRequest_google_firestore_v1_WriteRequest_LabelsEntry_google_firestore_v1_WriteResponse_google_firestore_v1_ListenRequest_google_firestore_v1_ListenRequest_LabelsEntry_google_firestore_v1_ListenResponse_google_firestore_v1_Target_google_firestore_v1_Target_DocumentsTarget_google_firestore_v1_Target_QueryTarget_google_firestore_v1_TargetChange_google_firestore_v1_ListCollectionIdsRequest_google_firestore_v1_ListCollectionIdsResponse) #endif #if !defined(PB_FIELD_16BIT) && !defined(PB_FIELD_32BIT) @@ -280,7 +297,7 @@ PB_STATIC_ASSERT((pb_membersize(google_firestore_v1_GetDocumentRequest, read_tim * numbers or field sizes that are larger than what can fit in the default * 8 bit descriptors. */ -PB_STATIC_ASSERT((pb_membersize(google_firestore_v1_GetDocumentRequest, read_time) < 256 && pb_membersize(google_firestore_v1_GetDocumentRequest, mask) < 256 && pb_membersize(google_firestore_v1_ListDocumentsRequest, read_time) < 256 && pb_membersize(google_firestore_v1_ListDocumentsRequest, mask) < 256 && pb_membersize(google_firestore_v1_CreateDocumentRequest, document) < 256 && pb_membersize(google_firestore_v1_CreateDocumentRequest, mask) < 256 && pb_membersize(google_firestore_v1_UpdateDocumentRequest, document) < 256 && pb_membersize(google_firestore_v1_UpdateDocumentRequest, update_mask) < 256 && pb_membersize(google_firestore_v1_UpdateDocumentRequest, mask) < 256 && pb_membersize(google_firestore_v1_UpdateDocumentRequest, current_document) < 256 && pb_membersize(google_firestore_v1_DeleteDocumentRequest, current_document) < 256 && pb_membersize(google_firestore_v1_BatchGetDocumentsRequest, new_transaction) < 256 && pb_membersize(google_firestore_v1_BatchGetDocumentsRequest, read_time) < 256 && pb_membersize(google_firestore_v1_BatchGetDocumentsRequest, mask) < 256 && pb_membersize(google_firestore_v1_BatchGetDocumentsResponse, found) < 256 && pb_membersize(google_firestore_v1_BatchGetDocumentsResponse, read_time) < 256 && pb_membersize(google_firestore_v1_BeginTransactionRequest, options) < 256 && pb_membersize(google_firestore_v1_CommitResponse, commit_time) < 256 && pb_membersize(google_firestore_v1_RunQueryRequest, query_type.structured_query) < 256 && pb_membersize(google_firestore_v1_RunQueryRequest, consistency_selector.new_transaction) < 256 && pb_membersize(google_firestore_v1_RunQueryRequest, consistency_selector.read_time) < 256 && pb_membersize(google_firestore_v1_RunQueryResponse, document) < 256 && pb_membersize(google_firestore_v1_RunQueryResponse, read_time) < 256 && pb_membersize(google_firestore_v1_RunAggregationQueryRequest, query_type.structured_aggregation_query) < 256 && pb_membersize(google_firestore_v1_RunAggregationQueryRequest, consistency_selector.new_transaction) < 256 && pb_membersize(google_firestore_v1_RunAggregationQueryRequest, consistency_selector.read_time) < 256 && pb_membersize(google_firestore_v1_RunAggregationQueryResponse, result) < 256 && pb_membersize(google_firestore_v1_RunAggregationQueryResponse, read_time) < 256 && pb_membersize(google_firestore_v1_WriteResponse, commit_time) < 256 && pb_membersize(google_firestore_v1_ListenRequest, add_target) < 256 && pb_membersize(google_firestore_v1_ListenResponse, target_change) < 256 && pb_membersize(google_firestore_v1_ListenResponse, document_change) < 256 && pb_membersize(google_firestore_v1_ListenResponse, document_delete) < 256 && pb_membersize(google_firestore_v1_ListenResponse, filter) < 256 && pb_membersize(google_firestore_v1_ListenResponse, document_remove) < 256 && pb_membersize(google_firestore_v1_Target, target_type.query) < 256 && pb_membersize(google_firestore_v1_Target, target_type.documents) < 256 && pb_membersize(google_firestore_v1_Target, resume_type.read_time) < 256 && pb_membersize(google_firestore_v1_Target, expected_count) < 256 && pb_membersize(google_firestore_v1_Target_QueryTarget, structured_query) < 256 && pb_membersize(google_firestore_v1_TargetChange, cause) < 256 && pb_membersize(google_firestore_v1_TargetChange, read_time) < 256), YOU_MUST_DEFINE_PB_FIELD_16BIT_FOR_MESSAGES_google_firestore_v1_GetDocumentRequest_google_firestore_v1_ListDocumentsRequest_google_firestore_v1_ListDocumentsResponse_google_firestore_v1_CreateDocumentRequest_google_firestore_v1_UpdateDocumentRequest_google_firestore_v1_DeleteDocumentRequest_google_firestore_v1_BatchGetDocumentsRequest_google_firestore_v1_BatchGetDocumentsResponse_google_firestore_v1_BeginTransactionRequest_google_firestore_v1_BeginTransactionResponse_google_firestore_v1_CommitRequest_google_firestore_v1_CommitResponse_google_firestore_v1_RollbackRequest_google_firestore_v1_RunQueryRequest_google_firestore_v1_RunQueryResponse_google_firestore_v1_RunAggregationQueryRequest_google_firestore_v1_RunAggregationQueryResponse_google_firestore_v1_WriteRequest_google_firestore_v1_WriteRequest_LabelsEntry_google_firestore_v1_WriteResponse_google_firestore_v1_ListenRequest_google_firestore_v1_ListenRequest_LabelsEntry_google_firestore_v1_ListenResponse_google_firestore_v1_Target_google_firestore_v1_Target_DocumentsTarget_google_firestore_v1_Target_QueryTarget_google_firestore_v1_TargetChange_google_firestore_v1_ListCollectionIdsRequest_google_firestore_v1_ListCollectionIdsResponse) +PB_STATIC_ASSERT((pb_membersize(google_firestore_v1_GetDocumentRequest, read_time) < 256 && pb_membersize(google_firestore_v1_GetDocumentRequest, mask) < 256 && pb_membersize(google_firestore_v1_ListDocumentsRequest, read_time) < 256 && pb_membersize(google_firestore_v1_ListDocumentsRequest, mask) < 256 && pb_membersize(google_firestore_v1_CreateDocumentRequest, document) < 256 && pb_membersize(google_firestore_v1_CreateDocumentRequest, mask) < 256 && pb_membersize(google_firestore_v1_UpdateDocumentRequest, document) < 256 && pb_membersize(google_firestore_v1_UpdateDocumentRequest, update_mask) < 256 && pb_membersize(google_firestore_v1_UpdateDocumentRequest, mask) < 256 && pb_membersize(google_firestore_v1_UpdateDocumentRequest, current_document) < 256 && pb_membersize(google_firestore_v1_DeleteDocumentRequest, current_document) < 256 && pb_membersize(google_firestore_v1_BatchGetDocumentsRequest, new_transaction) < 256 && pb_membersize(google_firestore_v1_BatchGetDocumentsRequest, read_time) < 256 && pb_membersize(google_firestore_v1_BatchGetDocumentsRequest, mask) < 256 && pb_membersize(google_firestore_v1_BatchGetDocumentsResponse, found) < 256 && pb_membersize(google_firestore_v1_BatchGetDocumentsResponse, read_time) < 256 && pb_membersize(google_firestore_v1_BeginTransactionRequest, options) < 256 && pb_membersize(google_firestore_v1_CommitResponse, commit_time) < 256 && pb_membersize(google_firestore_v1_RunQueryRequest, query_type.structured_query) < 256 && pb_membersize(google_firestore_v1_RunQueryRequest, consistency_selector.new_transaction) < 256 && pb_membersize(google_firestore_v1_RunQueryRequest, consistency_selector.read_time) < 256 && pb_membersize(google_firestore_v1_RunQueryResponse, document) < 256 && pb_membersize(google_firestore_v1_RunQueryResponse, read_time) < 256 && pb_membersize(google_firestore_v1_ExecutePipelineRequest, pipeline_type.structured_pipeline) < 256 && pb_membersize(google_firestore_v1_ExecutePipelineRequest, consistency_selector.new_transaction) < 256 && pb_membersize(google_firestore_v1_ExecutePipelineRequest, consistency_selector.read_time) < 256 && pb_membersize(google_firestore_v1_ExecutePipelineResponse, execution_time) < 256 && pb_membersize(google_firestore_v1_ExecutePipelineResponse, explain_stats) < 256 && pb_membersize(google_firestore_v1_RunAggregationQueryRequest, query_type.structured_aggregation_query) < 256 && pb_membersize(google_firestore_v1_RunAggregationQueryRequest, consistency_selector.new_transaction) < 256 && pb_membersize(google_firestore_v1_RunAggregationQueryRequest, consistency_selector.read_time) < 256 && pb_membersize(google_firestore_v1_RunAggregationQueryResponse, result) < 256 && pb_membersize(google_firestore_v1_RunAggregationQueryResponse, read_time) < 256 && pb_membersize(google_firestore_v1_WriteResponse, commit_time) < 256 && pb_membersize(google_firestore_v1_ListenRequest, add_target) < 256 && pb_membersize(google_firestore_v1_ListenResponse, target_change) < 256 && pb_membersize(google_firestore_v1_ListenResponse, document_change) < 256 && pb_membersize(google_firestore_v1_ListenResponse, document_delete) < 256 && pb_membersize(google_firestore_v1_ListenResponse, filter) < 256 && pb_membersize(google_firestore_v1_ListenResponse, document_remove) < 256 && pb_membersize(google_firestore_v1_Target, target_type.query) < 256 && pb_membersize(google_firestore_v1_Target, target_type.documents) < 256 && pb_membersize(google_firestore_v1_Target, resume_type.read_time) < 256 && pb_membersize(google_firestore_v1_Target, expected_count) < 256 && pb_membersize(google_firestore_v1_Target_QueryTarget, structured_query) < 256 && pb_membersize(google_firestore_v1_TargetChange, cause) < 256 && pb_membersize(google_firestore_v1_TargetChange, read_time) < 256), YOU_MUST_DEFINE_PB_FIELD_16BIT_FOR_MESSAGES_google_firestore_v1_GetDocumentRequest_google_firestore_v1_ListDocumentsRequest_google_firestore_v1_ListDocumentsResponse_google_firestore_v1_CreateDocumentRequest_google_firestore_v1_UpdateDocumentRequest_google_firestore_v1_DeleteDocumentRequest_google_firestore_v1_BatchGetDocumentsRequest_google_firestore_v1_BatchGetDocumentsResponse_google_firestore_v1_BeginTransactionRequest_google_firestore_v1_BeginTransactionResponse_google_firestore_v1_CommitRequest_google_firestore_v1_CommitResponse_google_firestore_v1_RollbackRequest_google_firestore_v1_RunQueryRequest_google_firestore_v1_RunQueryResponse_google_firestore_v1_ExecutePipelineRequest_google_firestore_v1_ExecutePipelineResponse_google_firestore_v1_RunAggregationQueryRequest_google_firestore_v1_RunAggregationQueryResponse_google_firestore_v1_WriteRequest_google_firestore_v1_WriteRequest_LabelsEntry_google_firestore_v1_WriteResponse_google_firestore_v1_ListenRequest_google_firestore_v1_ListenRequest_LabelsEntry_google_firestore_v1_ListenResponse_google_firestore_v1_Target_google_firestore_v1_Target_DocumentsTarget_google_firestore_v1_Target_QueryTarget_google_firestore_v1_TargetChange_google_firestore_v1_ListCollectionIdsRequest_google_firestore_v1_ListCollectionIdsResponse) #endif @@ -610,6 +627,61 @@ std::string google_firestore_v1_RunQueryResponse::ToString(int indent) const { return tostring_header + tostring_result + tostring_tail; } +std::string google_firestore_v1_ExecutePipelineRequest::ToString(int indent) const { + std::string tostring_header = PrintHeader(indent, "ExecutePipelineRequest", this); + std::string tostring_result; + + tostring_result += PrintPrimitiveField("database: ", + database, indent + 1, false); + switch (which_pipeline_type) { + case google_firestore_v1_ExecutePipelineRequest_structured_pipeline_tag: + tostring_result += PrintMessageField("structured_pipeline ", + pipeline_type.structured_pipeline, indent + 1, true); + break; + } + switch (which_consistency_selector) { + case google_firestore_v1_ExecutePipelineRequest_transaction_tag: + tostring_result += PrintPrimitiveField("transaction: ", + consistency_selector.transaction, indent + 1, true); + break; + case google_firestore_v1_ExecutePipelineRequest_new_transaction_tag: + tostring_result += PrintMessageField("new_transaction ", + consistency_selector.new_transaction, indent + 1, true); + break; + case google_firestore_v1_ExecutePipelineRequest_read_time_tag: + tostring_result += PrintMessageField("read_time ", + consistency_selector.read_time, indent + 1, true); + break; + } + + bool is_root = indent == 0; + if (!tostring_result.empty() || is_root) { + std::string tostring_tail = PrintTail(indent); + return tostring_header + tostring_result + tostring_tail; + } else { + return ""; + } +} + +std::string google_firestore_v1_ExecutePipelineResponse::ToString(int indent) const { + std::string tostring_header = PrintHeader(indent, "ExecutePipelineResponse", this); + std::string tostring_result; + + tostring_result += PrintPrimitiveField("transaction: ", + transaction, indent + 1, false); + for (pb_size_t i = 0; i != results_count; ++i) { + tostring_result += PrintMessageField("results ", + results[i], indent + 1, true); + } + tostring_result += PrintMessageField("execution_time ", + execution_time, indent + 1, false); + tostring_result += PrintMessageField("explain_stats ", + explain_stats, indent + 1, false); + + std::string tostring_tail = PrintTail(indent); + return tostring_header + tostring_result + tostring_tail; +} + std::string google_firestore_v1_RunAggregationQueryRequest::ToString(int indent) const { std::string tostring_header = PrintHeader(indent, "RunAggregationQueryRequest", this); std::string tostring_result; diff --git a/Firestore/Protos/nanopb/google/firestore/v1/firestore.nanopb.h b/Firestore/Protos/nanopb/google/firestore/v1/firestore.nanopb.h index 3dd603a5b09..a6d32a0862d 100644 --- a/Firestore/Protos/nanopb/google/firestore/v1/firestore.nanopb.h +++ b/Firestore/Protos/nanopb/google/firestore/v1/firestore.nanopb.h @@ -1,5 +1,5 @@ /* - * Copyright 2024 Google LLC + * Copyright 2025 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -23,12 +23,18 @@ #include "google/api/annotations.nanopb.h" +#include "google/api/field_behavior.nanopb.h" + #include "google/firestore/v1/aggregation_result.nanopb.h" #include "google/firestore/v1/common.nanopb.h" #include "google/firestore/v1/document.nanopb.h" +#include "google/firestore/v1/explain_stats.nanopb.h" + +#include "google/firestore/v1/pipeline.nanopb.h" + #include "google/firestore/v1/query.nanopb.h" #include "google/firestore/v1/write.nanopb.h" @@ -210,6 +216,34 @@ typedef struct _google_firestore_v1_DeleteDocumentRequest { /* @@protoc_insertion_point(struct:google_firestore_v1_DeleteDocumentRequest) */ } google_firestore_v1_DeleteDocumentRequest; +typedef struct _google_firestore_v1_ExecutePipelineRequest { + pb_bytes_array_t *database; + pb_size_t which_pipeline_type; + union { + google_firestore_v1_StructuredPipeline structured_pipeline; + } pipeline_type; + pb_size_t which_consistency_selector; + union { + pb_bytes_array_t *transaction; + google_firestore_v1_TransactionOptions new_transaction; + google_protobuf_Timestamp read_time; + } consistency_selector; + + std::string ToString(int indent = 0) const; +/* @@protoc_insertion_point(struct:google_firestore_v1_ExecutePipelineRequest) */ +} google_firestore_v1_ExecutePipelineRequest; + +typedef struct _google_firestore_v1_ExecutePipelineResponse { + pb_bytes_array_t *transaction; + pb_size_t results_count; + struct _google_firestore_v1_Document *results; + google_protobuf_Timestamp execution_time; + google_firestore_v1_ExplainStats explain_stats; + + std::string ToString(int indent = 0) const; +/* @@protoc_insertion_point(struct:google_firestore_v1_ExecutePipelineResponse) */ +} google_firestore_v1_ExecutePipelineResponse; + typedef struct _google_firestore_v1_GetDocumentRequest { pb_bytes_array_t *name; google_firestore_v1_DocumentMask mask; @@ -414,6 +448,8 @@ typedef struct _google_firestore_v1_ListenRequest { #define google_firestore_v1_RollbackRequest_init_default {NULL, NULL} #define google_firestore_v1_RunQueryRequest_init_default {NULL, 0, {google_firestore_v1_StructuredQuery_init_default}, 0, {NULL}} #define google_firestore_v1_RunQueryResponse_init_default {google_firestore_v1_Document_init_default, NULL, google_protobuf_Timestamp_init_default, 0} +#define google_firestore_v1_ExecutePipelineRequest_init_default {NULL, 0, {google_firestore_v1_StructuredPipeline_init_default}, 0, {NULL}} +#define google_firestore_v1_ExecutePipelineResponse_init_default {NULL, 0, NULL, google_protobuf_Timestamp_init_default, google_firestore_v1_ExplainStats_init_default} #define google_firestore_v1_RunAggregationQueryRequest_init_default {NULL, 0, {google_firestore_v1_StructuredAggregationQuery_init_default}, 0, {NULL}} #define google_firestore_v1_RunAggregationQueryResponse_init_default {google_firestore_v1_AggregationResult_init_default, NULL, google_protobuf_Timestamp_init_default} #define google_firestore_v1_WriteRequest_init_default {NULL, NULL, 0, NULL, NULL, 0, NULL} @@ -443,6 +479,8 @@ typedef struct _google_firestore_v1_ListenRequest { #define google_firestore_v1_RollbackRequest_init_zero {NULL, NULL} #define google_firestore_v1_RunQueryRequest_init_zero {NULL, 0, {google_firestore_v1_StructuredQuery_init_zero}, 0, {NULL}} #define google_firestore_v1_RunQueryResponse_init_zero {google_firestore_v1_Document_init_zero, NULL, google_protobuf_Timestamp_init_zero, 0} +#define google_firestore_v1_ExecutePipelineRequest_init_zero {NULL, 0, {google_firestore_v1_StructuredPipeline_init_zero}, 0, {NULL}} +#define google_firestore_v1_ExecutePipelineResponse_init_zero {NULL, 0, NULL, google_protobuf_Timestamp_init_zero, google_firestore_v1_ExplainStats_init_zero} #define google_firestore_v1_RunAggregationQueryRequest_init_zero {NULL, 0, {google_firestore_v1_StructuredAggregationQuery_init_zero}, 0, {NULL}} #define google_firestore_v1_RunAggregationQueryResponse_init_zero {google_firestore_v1_AggregationResult_init_zero, NULL, google_protobuf_Timestamp_init_zero} #define google_firestore_v1_WriteRequest_init_zero {NULL, NULL, 0, NULL, NULL, 0, NULL} @@ -500,6 +538,15 @@ typedef struct _google_firestore_v1_ListenRequest { #define google_firestore_v1_CreateDocumentRequest_mask_tag 5 #define google_firestore_v1_DeleteDocumentRequest_name_tag 1 #define google_firestore_v1_DeleteDocumentRequest_current_document_tag 2 +#define google_firestore_v1_ExecutePipelineRequest_structured_pipeline_tag 2 +#define google_firestore_v1_ExecutePipelineRequest_transaction_tag 5 +#define google_firestore_v1_ExecutePipelineRequest_new_transaction_tag 6 +#define google_firestore_v1_ExecutePipelineRequest_read_time_tag 7 +#define google_firestore_v1_ExecutePipelineRequest_database_tag 1 +#define google_firestore_v1_ExecutePipelineResponse_transaction_tag 1 +#define google_firestore_v1_ExecutePipelineResponse_results_tag 2 +#define google_firestore_v1_ExecutePipelineResponse_execution_time_tag 3 +#define google_firestore_v1_ExecutePipelineResponse_explain_stats_tag 4 #define google_firestore_v1_GetDocumentRequest_transaction_tag 3 #define google_firestore_v1_GetDocumentRequest_read_time_tag 5 #define google_firestore_v1_GetDocumentRequest_name_tag 1 @@ -581,6 +628,8 @@ extern const pb_field_t google_firestore_v1_CommitResponse_fields[3]; extern const pb_field_t google_firestore_v1_RollbackRequest_fields[3]; extern const pb_field_t google_firestore_v1_RunQueryRequest_fields[6]; extern const pb_field_t google_firestore_v1_RunQueryResponse_fields[5]; +extern const pb_field_t google_firestore_v1_ExecutePipelineRequest_fields[6]; +extern const pb_field_t google_firestore_v1_ExecutePipelineResponse_fields[5]; extern const pb_field_t google_firestore_v1_RunAggregationQueryRequest_fields[6]; extern const pb_field_t google_firestore_v1_RunAggregationQueryResponse_fields[4]; extern const pb_field_t google_firestore_v1_WriteRequest_fields[6]; @@ -612,6 +661,8 @@ extern const pb_field_t google_firestore_v1_ListCollectionIdsResponse_fields[3]; /* google_firestore_v1_RollbackRequest_size depends on runtime parameters */ /* google_firestore_v1_RunQueryRequest_size depends on runtime parameters */ /* google_firestore_v1_RunQueryResponse_size depends on runtime parameters */ +/* google_firestore_v1_ExecutePipelineRequest_size depends on runtime parameters */ +/* google_firestore_v1_ExecutePipelineResponse_size depends on runtime parameters */ /* google_firestore_v1_RunAggregationQueryRequest_size depends on runtime parameters */ /* google_firestore_v1_RunAggregationQueryResponse_size depends on runtime parameters */ /* google_firestore_v1_WriteRequest_size depends on runtime parameters */ diff --git a/Firestore/Protos/nanopb/google/firestore/v1/pipeline.nanopb.cc b/Firestore/Protos/nanopb/google/firestore/v1/pipeline.nanopb.cc new file mode 100644 index 00000000000..96739c3630c --- /dev/null +++ b/Firestore/Protos/nanopb/google/firestore/v1/pipeline.nanopb.cc @@ -0,0 +1,106 @@ +/* + * Copyright 2025 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. + */ + +/* Automatically generated nanopb constant definitions */ +/* Generated by nanopb-0.3.9.8 */ + +#include "pipeline.nanopb.h" + +#include "Firestore/core/src/nanopb/pretty_printing.h" + +namespace firebase { +namespace firestore { + +using nanopb::PrintEnumField; +using nanopb::PrintHeader; +using nanopb::PrintMessageField; +using nanopb::PrintPrimitiveField; +using nanopb::PrintTail; + +/* @@protoc_insertion_point(includes) */ +#if PB_PROTO_HEADER_VERSION != 30 +#error Regenerate this file with the current version of nanopb generator. +#endif + + + +const pb_field_t google_firestore_v1_StructuredPipeline_fields[3] = { + PB_FIELD( 1, MESSAGE , SINGULAR, STATIC , FIRST, google_firestore_v1_StructuredPipeline, pipeline, pipeline, &google_firestore_v1_Pipeline_fields), + PB_FIELD( 2, MESSAGE , REPEATED, POINTER , OTHER, google_firestore_v1_StructuredPipeline, options, pipeline, &google_firestore_v1_StructuredPipeline_OptionsEntry_fields), + PB_LAST_FIELD +}; + +const pb_field_t google_firestore_v1_StructuredPipeline_OptionsEntry_fields[3] = { + PB_FIELD( 1, BYTES , SINGULAR, POINTER , FIRST, google_firestore_v1_StructuredPipeline_OptionsEntry, key, key, 0), + PB_FIELD( 2, MESSAGE , SINGULAR, STATIC , OTHER, google_firestore_v1_StructuredPipeline_OptionsEntry, value, key, &google_firestore_v1_Value_fields), + PB_LAST_FIELD +}; + + +/* Check that field information fits in pb_field_t */ +#if !defined(PB_FIELD_32BIT) +/* If you get an error here, it means that you need to define PB_FIELD_32BIT + * compile-time option. You can do that in pb.h or on compiler command line. + * + * The reason you need to do this is that some of your messages contain tag + * numbers or field sizes that are larger than what can fit in 8 or 16 bit + * field descriptors. + */ +PB_STATIC_ASSERT((pb_membersize(google_firestore_v1_StructuredPipeline, pipeline) < 65536 && pb_membersize(google_firestore_v1_StructuredPipeline_OptionsEntry, value) < 65536), YOU_MUST_DEFINE_PB_FIELD_32BIT_FOR_MESSAGES_google_firestore_v1_StructuredPipeline_google_firestore_v1_StructuredPipeline_OptionsEntry) +#endif + +#if !defined(PB_FIELD_16BIT) && !defined(PB_FIELD_32BIT) +/* If you get an error here, it means that you need to define PB_FIELD_16BIT + * compile-time option. You can do that in pb.h or on compiler command line. + * + * The reason you need to do this is that some of your messages contain tag + * numbers or field sizes that are larger than what can fit in the default + * 8 bit descriptors. + */ +PB_STATIC_ASSERT((pb_membersize(google_firestore_v1_StructuredPipeline, pipeline) < 256 && pb_membersize(google_firestore_v1_StructuredPipeline_OptionsEntry, value) < 256), YOU_MUST_DEFINE_PB_FIELD_16BIT_FOR_MESSAGES_google_firestore_v1_StructuredPipeline_google_firestore_v1_StructuredPipeline_OptionsEntry) +#endif + + +std::string google_firestore_v1_StructuredPipeline::ToString(int indent) const { + std::string tostring_header = PrintHeader(indent, "StructuredPipeline", this); + std::string tostring_result; + + tostring_result += PrintMessageField("pipeline ", + pipeline, indent + 1, false); + for (pb_size_t i = 0; i != options_count; ++i) { + tostring_result += PrintMessageField("options ", + options[i], indent + 1, true); + } + + std::string tostring_tail = PrintTail(indent); + return tostring_header + tostring_result + tostring_tail; +} + +std::string google_firestore_v1_StructuredPipeline_OptionsEntry::ToString(int indent) const { + std::string tostring_header = PrintHeader(indent, "OptionsEntry", this); + std::string tostring_result; + + tostring_result += PrintPrimitiveField("key: ", key, indent + 1, false); + tostring_result += PrintMessageField("value ", value, indent + 1, false); + + std::string tostring_tail = PrintTail(indent); + return tostring_header + tostring_result + tostring_tail; +} + +} // namespace firestore +} // namespace firebase + +/* @@protoc_insertion_point(eof) */ diff --git a/Firestore/Protos/nanopb/google/firestore/v1/pipeline.nanopb.h b/Firestore/Protos/nanopb/google/firestore/v1/pipeline.nanopb.h new file mode 100644 index 00000000000..df88e827f68 --- /dev/null +++ b/Firestore/Protos/nanopb/google/firestore/v1/pipeline.nanopb.h @@ -0,0 +1,92 @@ +/* + * Copyright 2025 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. + */ + +/* Automatically generated nanopb header */ +/* Generated by nanopb-0.3.9.8 */ + +#ifndef PB_GOOGLE_FIRESTORE_V1_PIPELINE_NANOPB_H_INCLUDED +#define PB_GOOGLE_FIRESTORE_V1_PIPELINE_NANOPB_H_INCLUDED +#include + +#include "google/api/field_behavior.nanopb.h" + +#include "google/firestore/v1/document.nanopb.h" + +#include + +namespace firebase { +namespace firestore { + +/* @@protoc_insertion_point(includes) */ +#if PB_PROTO_HEADER_VERSION != 30 +#error Regenerate this file with the current version of nanopb generator. +#endif + + +/* Struct definitions */ +typedef struct _google_firestore_v1_StructuredPipeline { + google_firestore_v1_Pipeline pipeline; + pb_size_t options_count; + struct _google_firestore_v1_StructuredPipeline_OptionsEntry *options; + + std::string ToString(int indent = 0) const; +/* @@protoc_insertion_point(struct:google_firestore_v1_StructuredPipeline) */ +} google_firestore_v1_StructuredPipeline; + +typedef struct _google_firestore_v1_StructuredPipeline_OptionsEntry { + pb_bytes_array_t *key; + google_firestore_v1_Value value; + + std::string ToString(int indent = 0) const; +/* @@protoc_insertion_point(struct:google_firestore_v1_StructuredPipeline_OptionsEntry) */ +} google_firestore_v1_StructuredPipeline_OptionsEntry; + +/* Default values for struct fields */ + +/* Initializer values for message structs */ +#define google_firestore_v1_StructuredPipeline_init_default {google_firestore_v1_Pipeline_init_default, 0, NULL} +#define google_firestore_v1_StructuredPipeline_OptionsEntry_init_default {NULL, google_firestore_v1_Value_init_default} +#define google_firestore_v1_StructuredPipeline_init_zero {google_firestore_v1_Pipeline_init_zero, 0, NULL} +#define google_firestore_v1_StructuredPipeline_OptionsEntry_init_zero {NULL, google_firestore_v1_Value_init_zero} + +/* Field tags (for use in manual encoding/decoding) */ +#define google_firestore_v1_StructuredPipeline_pipeline_tag 1 +#define google_firestore_v1_StructuredPipeline_options_tag 2 +#define google_firestore_v1_StructuredPipeline_OptionsEntry_key_tag 1 +#define google_firestore_v1_StructuredPipeline_OptionsEntry_value_tag 2 + +/* Struct field encoding specification for nanopb */ +extern const pb_field_t google_firestore_v1_StructuredPipeline_fields[3]; +extern const pb_field_t google_firestore_v1_StructuredPipeline_OptionsEntry_fields[3]; + +/* Maximum encoded size of messages (where known) */ +/* google_firestore_v1_StructuredPipeline_size depends on runtime parameters */ +/* google_firestore_v1_StructuredPipeline_OptionsEntry_size depends on runtime parameters */ + +/* Message IDs (where set with "msgid" option) */ +#ifdef PB_MSGID + +#define PIPELINE_MESSAGES \ + + +#endif + +} // namespace firestore +} // namespace firebase + +/* @@protoc_insertion_point(eof) */ + +#endif diff --git a/Firestore/Protos/nanopb/google/firestore/v1/query.nanopb.cc b/Firestore/Protos/nanopb/google/firestore/v1/query.nanopb.cc index decd34e2ca2..ca3ce6c85d6 100644 --- a/Firestore/Protos/nanopb/google/firestore/v1/query.nanopb.cc +++ b/Firestore/Protos/nanopb/google/firestore/v1/query.nanopb.cc @@ -1,5 +1,5 @@ /* - * Copyright 2024 Google LLC + * Copyright 2025 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/Firestore/Protos/nanopb/google/firestore/v1/query.nanopb.h b/Firestore/Protos/nanopb/google/firestore/v1/query.nanopb.h index cac63add141..b54d343853f 100644 --- a/Firestore/Protos/nanopb/google/firestore/v1/query.nanopb.h +++ b/Firestore/Protos/nanopb/google/firestore/v1/query.nanopb.h @@ -1,5 +1,5 @@ /* - * Copyright 2024 Google LLC + * Copyright 2025 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/Firestore/Protos/nanopb/google/firestore/v1/write.nanopb.cc b/Firestore/Protos/nanopb/google/firestore/v1/write.nanopb.cc index d423c292d4a..1f4a31bb164 100644 --- a/Firestore/Protos/nanopb/google/firestore/v1/write.nanopb.cc +++ b/Firestore/Protos/nanopb/google/firestore/v1/write.nanopb.cc @@ -1,5 +1,5 @@ /* - * Copyright 2024 Google LLC + * Copyright 2025 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/Firestore/Protos/nanopb/google/firestore/v1/write.nanopb.h b/Firestore/Protos/nanopb/google/firestore/v1/write.nanopb.h index 0db9c6d2874..9fd6d1688bd 100644 --- a/Firestore/Protos/nanopb/google/firestore/v1/write.nanopb.h +++ b/Firestore/Protos/nanopb/google/firestore/v1/write.nanopb.h @@ -1,5 +1,5 @@ /* - * Copyright 2024 Google LLC + * Copyright 2025 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/Firestore/Protos/nanopb/google/protobuf/any.nanopb.cc b/Firestore/Protos/nanopb/google/protobuf/any.nanopb.cc index 2a57547086a..5efdaf04dd4 100644 --- a/Firestore/Protos/nanopb/google/protobuf/any.nanopb.cc +++ b/Firestore/Protos/nanopb/google/protobuf/any.nanopb.cc @@ -1,5 +1,5 @@ /* - * Copyright 2024 Google LLC + * Copyright 2025 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/Firestore/Protos/nanopb/google/protobuf/any.nanopb.h b/Firestore/Protos/nanopb/google/protobuf/any.nanopb.h index c06c82ca2db..5a418826834 100644 --- a/Firestore/Protos/nanopb/google/protobuf/any.nanopb.h +++ b/Firestore/Protos/nanopb/google/protobuf/any.nanopb.h @@ -1,5 +1,5 @@ /* - * Copyright 2024 Google LLC + * Copyright 2025 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/Firestore/Protos/nanopb/google/protobuf/empty.nanopb.cc b/Firestore/Protos/nanopb/google/protobuf/empty.nanopb.cc index ea00f4e2640..bc43bb31233 100644 --- a/Firestore/Protos/nanopb/google/protobuf/empty.nanopb.cc +++ b/Firestore/Protos/nanopb/google/protobuf/empty.nanopb.cc @@ -1,5 +1,5 @@ /* - * Copyright 2024 Google LLC + * Copyright 2025 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/Firestore/Protos/nanopb/google/protobuf/empty.nanopb.h b/Firestore/Protos/nanopb/google/protobuf/empty.nanopb.h index be77b64f2b7..5820d750a0d 100644 --- a/Firestore/Protos/nanopb/google/protobuf/empty.nanopb.h +++ b/Firestore/Protos/nanopb/google/protobuf/empty.nanopb.h @@ -1,5 +1,5 @@ /* - * Copyright 2024 Google LLC + * Copyright 2025 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/Firestore/Protos/nanopb/google/protobuf/struct.nanopb.cc b/Firestore/Protos/nanopb/google/protobuf/struct.nanopb.cc index 1eeb1d963c8..9cc956eb61a 100644 --- a/Firestore/Protos/nanopb/google/protobuf/struct.nanopb.cc +++ b/Firestore/Protos/nanopb/google/protobuf/struct.nanopb.cc @@ -1,5 +1,5 @@ /* - * Copyright 2024 Google LLC + * Copyright 2025 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/Firestore/Protos/nanopb/google/protobuf/struct.nanopb.h b/Firestore/Protos/nanopb/google/protobuf/struct.nanopb.h index 086fabdc900..9fa79620456 100644 --- a/Firestore/Protos/nanopb/google/protobuf/struct.nanopb.h +++ b/Firestore/Protos/nanopb/google/protobuf/struct.nanopb.h @@ -1,5 +1,5 @@ /* - * Copyright 2024 Google LLC + * Copyright 2025 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/Firestore/Protos/nanopb/google/protobuf/timestamp.nanopb.cc b/Firestore/Protos/nanopb/google/protobuf/timestamp.nanopb.cc index d45c5991ef4..cfa685b724e 100644 --- a/Firestore/Protos/nanopb/google/protobuf/timestamp.nanopb.cc +++ b/Firestore/Protos/nanopb/google/protobuf/timestamp.nanopb.cc @@ -1,5 +1,5 @@ /* - * Copyright 2024 Google LLC + * Copyright 2025 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/Firestore/Protos/nanopb/google/protobuf/timestamp.nanopb.h b/Firestore/Protos/nanopb/google/protobuf/timestamp.nanopb.h index a094a954fbc..d5757078e51 100644 --- a/Firestore/Protos/nanopb/google/protobuf/timestamp.nanopb.h +++ b/Firestore/Protos/nanopb/google/protobuf/timestamp.nanopb.h @@ -1,5 +1,5 @@ /* - * Copyright 2024 Google LLC + * Copyright 2025 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/Firestore/Protos/nanopb/google/protobuf/wrappers.nanopb.cc b/Firestore/Protos/nanopb/google/protobuf/wrappers.nanopb.cc index e9832439ffc..a6f03ac797b 100644 --- a/Firestore/Protos/nanopb/google/protobuf/wrappers.nanopb.cc +++ b/Firestore/Protos/nanopb/google/protobuf/wrappers.nanopb.cc @@ -1,5 +1,5 @@ /* - * Copyright 2024 Google LLC + * Copyright 2025 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/Firestore/Protos/nanopb/google/protobuf/wrappers.nanopb.h b/Firestore/Protos/nanopb/google/protobuf/wrappers.nanopb.h index 7efae8dc674..98da8de2209 100644 --- a/Firestore/Protos/nanopb/google/protobuf/wrappers.nanopb.h +++ b/Firestore/Protos/nanopb/google/protobuf/wrappers.nanopb.h @@ -1,5 +1,5 @@ /* - * Copyright 2024 Google LLC + * Copyright 2025 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/Firestore/Protos/nanopb/google/rpc/status.nanopb.cc b/Firestore/Protos/nanopb/google/rpc/status.nanopb.cc index b71c001f277..cf7cc2768d9 100644 --- a/Firestore/Protos/nanopb/google/rpc/status.nanopb.cc +++ b/Firestore/Protos/nanopb/google/rpc/status.nanopb.cc @@ -1,5 +1,5 @@ /* - * Copyright 2024 Google LLC + * Copyright 2025 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/Firestore/Protos/nanopb/google/rpc/status.nanopb.h b/Firestore/Protos/nanopb/google/rpc/status.nanopb.h index cadd9ece3a0..bd59ff0a20e 100644 --- a/Firestore/Protos/nanopb/google/rpc/status.nanopb.h +++ b/Firestore/Protos/nanopb/google/rpc/status.nanopb.h @@ -1,5 +1,5 @@ /* - * Copyright 2024 Google LLC + * Copyright 2025 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/Firestore/Protos/nanopb/google/type/latlng.nanopb.cc b/Firestore/Protos/nanopb/google/type/latlng.nanopb.cc index f6b9e6870e3..378c66500bf 100644 --- a/Firestore/Protos/nanopb/google/type/latlng.nanopb.cc +++ b/Firestore/Protos/nanopb/google/type/latlng.nanopb.cc @@ -1,5 +1,5 @@ /* - * Copyright 2024 Google LLC + * Copyright 2025 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/Firestore/Protos/nanopb/google/type/latlng.nanopb.h b/Firestore/Protos/nanopb/google/type/latlng.nanopb.h index 2daf244dd19..1e78b1896ca 100644 --- a/Firestore/Protos/nanopb/google/type/latlng.nanopb.h +++ b/Firestore/Protos/nanopb/google/type/latlng.nanopb.h @@ -1,5 +1,5 @@ /* - * Copyright 2024 Google LLC + * Copyright 2025 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/Firestore/Protos/protos/google/api/field_behavior.proto b/Firestore/Protos/protos/google/api/field_behavior.proto new file mode 100644 index 00000000000..3c114c3fc8e --- /dev/null +++ b/Firestore/Protos/protos/google/api/field_behavior.proto @@ -0,0 +1,104 @@ +// 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. + +syntax = "proto3"; + +package google.api; + +import "google/protobuf/descriptor.proto"; + +option go_package = "google.golang.org/genproto/googleapis/api/annotations;annotations"; +option java_multiple_files = true; +option java_outer_classname = "FieldBehaviorProto"; +option java_package = "com.google.api"; +option objc_class_prefix = "GAPI"; + +extend google.protobuf.FieldOptions { + // A designation of a specific field behavior (required, output only, etc.) + // in protobuf messages. + // + // Examples: + // + // string name = 1 [(google.api.field_behavior) = REQUIRED]; + // State state = 1 [(google.api.field_behavior) = OUTPUT_ONLY]; + // google.protobuf.Duration ttl = 1 + // [(google.api.field_behavior) = INPUT_ONLY]; + // google.protobuf.Timestamp expire_time = 1 + // [(google.api.field_behavior) = OUTPUT_ONLY, + // (google.api.field_behavior) = IMMUTABLE]; + repeated google.api.FieldBehavior field_behavior = 1052 [packed = false]; +} + +// An indicator of the behavior of a given field (for example, that a field +// is required in requests, or given as output but ignored as input). +// This **does not** change the behavior in protocol buffers itself; it only +// denotes the behavior and may affect how API tooling handles the field. +// +// Note: This enum **may** receive new values in the future. +enum FieldBehavior { + // Conventional default for enums. Do not use this. + FIELD_BEHAVIOR_UNSPECIFIED = 0; + + // Specifically denotes a field as optional. + // While all fields in protocol buffers are optional, this may be specified + // for emphasis if appropriate. + OPTIONAL = 1; + + // Denotes a field as required. + // This indicates that the field **must** be provided as part of the request, + // and failure to do so will cause an error (usually `INVALID_ARGUMENT`). + REQUIRED = 2; + + // Denotes a field as output only. + // This indicates that the field is provided in responses, but including the + // field in a request does nothing (the server *must* ignore it and + // *must not* throw an error as a result of the field's presence). + OUTPUT_ONLY = 3; + + // Denotes a field as input only. + // This indicates that the field is provided in requests, and the + // corresponding field is not included in output. + INPUT_ONLY = 4; + + // Denotes a field as immutable. + // This indicates that the field may be set once in a request to create a + // resource, but may not be changed thereafter. + IMMUTABLE = 5; + + // Denotes that a (repeated) field is an unordered list. + // This indicates that the service may provide the elements of the list + // in any arbitrary order, rather than the order the user originally + // provided. Additionally, the list's order may or may not be stable. + UNORDERED_LIST = 6; + + // Denotes that this field returns a non-empty default value if not set. + // This indicates that if the user provides the empty value in a request, + // a non-empty value will be returned. The user will not be aware of what + // non-empty value to expect. + NON_EMPTY_DEFAULT = 7; + + // Denotes that the field in a resource (a message annotated with + // google.api.resource) is used in the resource name to uniquely identify the + // resource. For AIP-compliant APIs, this should only be applied to the + // `name` field on the resource. + // + // This behavior should not be applied to references to other resources within + // the message. + // + // The identifier field of resources often have different field behavior + // depending on the request it is embedded in (e.g. for Create methods name + // is optional and unused, while for Update methods it is required). Instead + // of method-specific annotations, only `IDENTIFIER` is required. + IDENTIFIER = 8; +} \ No newline at end of file diff --git a/Firestore/Protos/protos/google/firestore/v1/document.proto b/Firestore/Protos/protos/google/firestore/v1/document.proto index 7414c3c2c48..ec7de3d5aca 100644 --- a/Firestore/Protos/protos/google/firestore/v1/document.proto +++ b/Firestore/Protos/protos/google/firestore/v1/document.proto @@ -1,4 +1,4 @@ -// Copyright 2018 Google LLC. +// 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. @@ -11,24 +11,24 @@ // 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. -// syntax = "proto3"; package google.firestore.v1; +import "google/api/field_behavior.proto"; import "google/protobuf/struct.proto"; import "google/protobuf/timestamp.proto"; import "google/type/latlng.proto"; -option csharp_namespace = "Google.Cloud.Firestore.V1Beta1"; -option go_package = "google.golang.org/genproto/googleapis/firestore/v1;firestore"; +option csharp_namespace = "Google.Cloud.Firestore.V1"; +option go_package = "cloud.google.com/go/firestore/apiv1/firestorepb;firestorepb"; option java_multiple_files = true; option java_outer_classname = "DocumentProto"; option java_package = "com.google.firestore.v1"; option objc_class_prefix = "GCFS"; -option php_namespace = "Google\\Cloud\\Firestore\\V1beta1"; - +option php_namespace = "Google\\Cloud\\Firestore\\V1"; +option ruby_package = "Google::Cloud::Firestore::V1"; // A Firestore document. // @@ -42,23 +42,23 @@ message Document { // // The map keys represent field names. // - // A simple field name contains only characters `a` to `z`, `A` to `Z`, - // `0` to `9`, or `_`, and must not start with `0` to `9`. For example, - // `foo_bar_17`. - // // Field names matching the regular expression `__.*__` are reserved. Reserved - // field names are forbidden except in certain documented contexts. The map - // keys, represented as UTF-8, must not exceed 1,500 bytes and cannot be + // field names are forbidden except in certain documented contexts. The field + // names, represented as UTF-8, must not exceed 1,500 bytes and cannot be // empty. // // Field paths may be used in other contexts to refer to structured fields - // defined here. For `map_value`, the field path is represented by the simple - // or quoted field names of the containing fields, delimited by `.`. For - // example, the structured field - // `"foo" : { map_value: { "x&y" : { string_value: "hello" }}}` would be - // represented by the field path `foo.x&y`. + // defined here. For `map_value`, the field path is represented by a + // dot-delimited (`.`) string of segments. Each segment is either a simple + // field name (defined below) or a quoted field name. For example, the + // structured field `"foo" : { map_value: { "x&y" : { string_value: "hello" + // }}}` would be represented by the field path `` foo.`x&y` ``. + // + // A simple field name contains only characters `a` to `z`, `A` to `Z`, + // `0` to `9`, or `_`, and must not start with `0` to `9`. For example, + // `foo_bar_17`. // - // Within a field path, a quoted field name starts and ends with `` ` `` and + // A quoted field name starts and ends with `` ` `` and // may contain any character. Some characters, including `` ` ``, must be // escaped using a `\`. For example, `` `x&y` `` represents `x&y` and // `` `bak\`tik` `` represents `` bak`tik ``. @@ -123,12 +123,38 @@ message Value { // An array value. // - // Cannot directly contain another array value, though can contain an + // Cannot directly contain another array value, though can contain a // map which contains another array. ArrayValue array_value = 9; // A map value. MapValue map_value = 6; + + // Value which references a field. + // + // This is considered relative (vs absolute) since it only refers to a field + // and not a field within a particular document. + // + // **Requires:** + // + // * Must follow [field reference][FieldReference.field_path] limitations. + // + // * Not allowed to be used when writing documents. + string field_reference_value = 19; + + // A value that represents an unevaluated expression. + // + // **Requires:** + // + // * Not allowed to be used when writing documents. + Function function_value = 20; + + // A value that represents an unevaluated pipeline. + // + // **Requires:** + // + // * Not allowed to be used when writing documents. + Pipeline pipeline_value = 21; } } @@ -148,3 +174,67 @@ message MapValue { // not exceed 1,500 bytes and cannot be empty. map fields = 1; } + +// Represents an unevaluated scalar expression. +// +// For example, the expression `like(user_name, "%alice%")` is represented as: +// +// ``` +// name: "like" +// args { field_reference: "user_name" } +// args { string_value: "%alice%" } +// ``` +message Function { + // Required. The name of the function to evaluate. + // + // **Requires:** + // + // * must be in snake case (lower case with underscore separator). + string name = 1 [(google.api.field_behavior) = REQUIRED]; + + // Optional. Ordered list of arguments the given function expects. + repeated Value args = 2 [(google.api.field_behavior) = OPTIONAL]; + + // Optional. Optional named arguments that certain functions may support. + map options = 3 [(google.api.field_behavior) = OPTIONAL]; +} + +// A Firestore query represented as an ordered list of operations / stages. +message Pipeline { + // A single operation within a pipeline. + // + // A stage is made up of a unique name, and a list of arguments. The exact + // number of arguments & types is dependent on the stage type. + // + // To give an example, the stage `filter(state = "MD")` would be encoded as: + // + // ``` + // name: "filter" + // args { + // function_value { + // name: "eq" + // args { field_reference_value: "state" } + // args { string_value: "MD" } + // } + // } + // ``` + // + // See public documentation for the full list. + message Stage { + // Required. The name of the stage to evaluate. + // + // **Requires:** + // + // * must be in snake case (lower case with underscore separator). + string name = 1 [(google.api.field_behavior) = REQUIRED]; + + // Optional. Ordered list of arguments the given stage expects. + repeated Value args = 2 [(google.api.field_behavior) = OPTIONAL]; + + // Optional. Optional named arguments that certain functions may support. + map options = 3 [(google.api.field_behavior) = OPTIONAL]; + } + + // Required. Ordered list of stages to evaluate. + repeated Stage stages = 1 [(google.api.field_behavior) = REQUIRED]; +} \ No newline at end of file diff --git a/Firestore/Protos/protos/google/firestore/v1/explain_stats.proto b/Firestore/Protos/protos/google/firestore/v1/explain_stats.proto new file mode 100644 index 00000000000..285fe34066a --- /dev/null +++ b/Firestore/Protos/protos/google/firestore/v1/explain_stats.proto @@ -0,0 +1,38 @@ +// 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. + +syntax = "proto3"; + +package google.firestore.v1; + +import "google/protobuf/any.proto"; + +option csharp_namespace = "Google.Cloud.Firestore.V1"; +option go_package = "cloud.google.com/go/firestore/apiv1/firestorepb;firestorepb"; +option java_multiple_files = true; +option java_outer_classname = "ExplainStatsProto"; +option java_package = "com.google.firestore.v1"; +option php_namespace = "Google\\Cloud\\Firestore\\V1"; +option ruby_package = "Google::Cloud::Firestore::V1"; + +// Specification of Firestore Explain Stats fields. + +// Explain stats for an RPC request, includes both the optimized plan and +// execution stats. +message ExplainStats { + // The format depends on the `output_format` options in the request. + // + // The only option today is `TEXT`, which is a `google.protobuf.StringValue`. + google.protobuf.Any data = 1; +} \ No newline at end of file diff --git a/Firestore/Protos/protos/google/firestore/v1/firestore.proto b/Firestore/Protos/protos/google/firestore/v1/firestore.proto index 9dafa8858c3..ebcb1249773 100644 --- a/Firestore/Protos/protos/google/firestore/v1/firestore.proto +++ b/Firestore/Protos/protos/google/firestore/v1/firestore.proto @@ -18,9 +18,12 @@ syntax = "proto3"; package google.firestore.v1; import "google/api/annotations.proto"; +import "google/api/field_behavior.proto"; import "google/firestore/v1/aggregation_result.proto"; import "google/firestore/v1/common.proto"; import "google/firestore/v1/document.proto"; +import "google/firestore/v1/explain_stats.proto"; +import "google/firestore/v1/pipeline.proto"; import "google/firestore/v1/query.proto"; import "google/firestore/v1/write.proto"; import "google/protobuf/empty.proto"; @@ -138,6 +141,15 @@ service Firestore { }; } + // Executes a pipeline query. + rpc ExecutePipeline(ExecutePipelineRequest) + returns (stream ExecutePipelineResponse) { + option (google.api.http) = { + post: "/v1/{database=projects/*/databases/*}/documents:executePipeline" + body: "*" + }; + } + // Runs an aggregation query. // // Rather than producing [Document][google.firestore.v1.Document] results like [Firestore.RunQuery][google.firestore.v1.Firestore.RunQuery], @@ -510,6 +522,81 @@ message RunQueryResponse { int32 skipped_results = 4; } +// The request for +// [Firestore.ExecutePipeline][google.firestore.v1.Firestore.ExecutePipeline]. +message ExecutePipelineRequest { + // Required. Database identifier, in the form + // `projects/{project}/databases/{database}`. + string database = 1 [(google.api.field_behavior) = REQUIRED]; + + oneof pipeline_type { + // A pipelined operation. + StructuredPipeline structured_pipeline = 2; + } + + // Optional consistency arguments, defaults to strong consistency. + oneof consistency_selector { + // Run the query within an already active transaction. + // + // The value here is the opaque transaction ID to execute the query in. + bytes transaction = 5; + + // Execute the pipeline in a new transaction. + // + // The identifier of the newly created transaction will be returned in the + // first response on the stream. This defaults to a read-only transaction. + TransactionOptions new_transaction = 6; + + // Execute the pipeline in a snapshot transaction at the given time. + // + // This must be a microsecond precision timestamp within the past one hour, + // or if Point-in-Time Recovery is enabled, can additionally be a whole + // minute timestamp within the past 7 days. + google.protobuf.Timestamp read_time = 7; + } +} + +// The response for [Firestore.Execute][]. +message ExecutePipelineResponse { + // Newly created transaction identifier. + // + // This field is only specified as part of the first response from the server, + // alongside the `results` field when the original request specified + // [ExecuteRequest.new_transaction][]. + bytes transaction = 1; + + // An ordered batch of results returned executing a pipeline. + // + // The batch size is variable, and can even be zero for when only a partial + // progress message is returned. + // + // The fields present in the returned documents are only those that were + // explicitly requested in the pipeline, this include those like + // [`__name__`][google.firestore.v1.Document.name] & + // [`__update_time__`][google.firestore.v1.Document.update_time]. This is + // explicitly a divergence from `Firestore.RunQuery` / `Firestore.GetDocument` + // RPCs which always return such fields even when they are not specified in + // the [`mask`][google.firestore.v1.DocumentMask]. + repeated Document results = 2; + + // The time at which the document(s) were read. + // + // This may be monotonically increasing; in this case, the previous documents + // in the result stream are guaranteed not to have changed between their + // `execution_time` and this one. + // + // If the query returns no results, a response with `execution_time` and no + // `results` will be sent, and this represents the time at which the operation + // was run. + google.protobuf.Timestamp execution_time = 3; + + // Query explain stats. + // + // Contains all metadata related to pipeline planning and execution, specific + // contents depend on the supplied pipeline options. + ExplainStats explain_stats = 4; +} + // The request for [Firestore.RunAggregationQuery][google.firestore.v1.Firestore.RunAggregationQuery]. message RunAggregationQueryRequest { // Required. The parent resource name. In the format: diff --git a/Firestore/Protos/protos/google/firestore/v1/pipeline.proto b/Firestore/Protos/protos/google/firestore/v1/pipeline.proto new file mode 100644 index 00000000000..33508166ea7 --- /dev/null +++ b/Firestore/Protos/protos/google/firestore/v1/pipeline.proto @@ -0,0 +1,43 @@ +// 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. + +syntax = "proto3"; + +package google.firestore.v1; + +import "google/api/field_behavior.proto"; +import "google/firestore/v1/document.proto"; + +option csharp_namespace = "Google.Cloud.Firestore.V1"; +option go_package = "cloud.google.com/go/firestore/apiv1/firestorepb;firestorepb"; +option java_multiple_files = true; +option java_outer_classname = "PipelineProto"; +option java_package = "com.google.firestore.v1"; +option objc_class_prefix = "GCFS"; +option php_namespace = "Google\\Cloud\\Firestore\\V1"; +option ruby_package = "Google::Cloud::Firestore::V1"; + +// A Firestore query represented as an ordered list of operations / stages. +// +// This is considered the top-level function which plans & executes a query. +// It is logically equivalent to `query(stages, options)`, but prevents the +// client from having to build a function wrapper. +message StructuredPipeline { + // Required. The pipeline query to execute. + Pipeline pipeline = 1 [(google.api.field_behavior) = REQUIRED]; + + // Optional. Optional query-level arguments. + // + map options = 2 [(google.api.field_behavior) = OPTIONAL]; +} \ No newline at end of file From 0cd0224d4976a18061cf55653c23318740f8ae3e Mon Sep 17 00:00:00 2001 From: wu-hui <53845758+wu-hui@users.noreply.github.com> Date: Thu, 13 Mar 2025 14:13:41 -0400 Subject: [PATCH 003/113] End-to-end minimalistic ppl (#14546) --- .../FirebaseFirestore/FIRPipelineBridge.h | 17 ++ .../Firestore.xcodeproj/project.pbxproj | 12 +- Firestore/Source/API/FIRFirestore+Internal.h | 2 +- .../Source/API/FIRPipelineBridge+Internal.h | 49 +++++ Firestore/Source/API/FIRPipelineBridge.mm | 191 ++++++++++++++++++ .../FirebaseFirestore/FIRPipelineBridge.h | 89 ++++++++ .../FirebaseFirestore/FirebaseFirestore.h | 1 + .../Swift/Source/SwiftAPI/Expressions.swift | 70 +++++++ .../Source/SwiftAPI/Firestore+Pipeline.swift | 23 +++ .../Swift/Source/SwiftAPI/Pipeline.swift | 45 +++++ .../Source/SwiftAPI/PipelineSnapshot.swift | 25 +++ .../Source/SwiftAPI/PipelineSource.swift | 28 +++ Firestore/Swift/Source/SwiftAPI/Stages.swift | 47 +++++ .../Tests/Integration/PipelineTests.swift | 31 +++ Firestore/core/src/api/api_fwd.h | 2 + Firestore/core/src/api/expressions.cc | 61 ++++++ Firestore/core/src/api/expressions.h | 75 +++++++ Firestore/core/src/api/firestore.cc | 7 + Firestore/core/src/api/firestore.h | 2 + Firestore/core/src/api/pipeline.cc | 45 +++++ Firestore/core/src/api/pipeline.h | 59 ++++++ Firestore/core/src/api/pipeline_result.cc | 52 +++++ Firestore/core/src/api/pipeline_result.h | 71 +++++++ Firestore/core/src/api/pipeline_snapshot.h | 53 +++++ Firestore/core/src/api/stages.cc | 59 ++++++ Firestore/core/src/api/stages.h | 66 ++++++ Firestore/core/src/core/firestore_client.cc | 19 ++ Firestore/core/src/core/firestore_client.h | 4 + Firestore/core/src/nanopb/fields_array.h | 12 ++ Firestore/core/src/remote/datastore.cc | 48 +++++ Firestore/core/src/remote/datastore.h | 11 + .../core/src/remote/remote_objc_bridge.cc | 26 +++ .../core/src/remote/remote_objc_bridge.h | 8 + Firestore/core/src/remote/remote_store.cc | 11 + Firestore/core/src/remote/remote_store.h | 4 + Firestore/core/src/remote/serializer.cc | 58 ++++++ Firestore/core/src/remote/serializer.h | 9 + 37 files changed, 1389 insertions(+), 3 deletions(-) create mode 100644 FirebaseFirestoreInternal/FirebaseFirestore/FIRPipelineBridge.h create mode 100644 Firestore/Source/API/FIRPipelineBridge+Internal.h create mode 100644 Firestore/Source/API/FIRPipelineBridge.mm create mode 100644 Firestore/Source/Public/FirebaseFirestore/FIRPipelineBridge.h create mode 100644 Firestore/Swift/Source/SwiftAPI/Expressions.swift create mode 100644 Firestore/Swift/Source/SwiftAPI/Firestore+Pipeline.swift create mode 100644 Firestore/Swift/Source/SwiftAPI/Pipeline.swift create mode 100644 Firestore/Swift/Source/SwiftAPI/PipelineSnapshot.swift create mode 100644 Firestore/Swift/Source/SwiftAPI/PipelineSource.swift create mode 100644 Firestore/Swift/Source/SwiftAPI/Stages.swift create mode 100644 Firestore/Swift/Tests/Integration/PipelineTests.swift create mode 100644 Firestore/core/src/api/expressions.cc create mode 100644 Firestore/core/src/api/expressions.h create mode 100644 Firestore/core/src/api/pipeline.cc create mode 100644 Firestore/core/src/api/pipeline.h create mode 100644 Firestore/core/src/api/pipeline_result.cc create mode 100644 Firestore/core/src/api/pipeline_result.h create mode 100644 Firestore/core/src/api/pipeline_snapshot.h create mode 100644 Firestore/core/src/api/stages.cc create mode 100644 Firestore/core/src/api/stages.h diff --git a/FirebaseFirestoreInternal/FirebaseFirestore/FIRPipelineBridge.h b/FirebaseFirestoreInternal/FirebaseFirestore/FIRPipelineBridge.h new file mode 100644 index 00000000000..35e39ab7904 --- /dev/null +++ b/FirebaseFirestoreInternal/FirebaseFirestore/FIRPipelineBridge.h @@ -0,0 +1,17 @@ +/* + * Copyright 2025 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 diff --git a/Firestore/Example/Firestore.xcodeproj/project.pbxproj b/Firestore/Example/Firestore.xcodeproj/project.pbxproj index 5cf594fd314..1146b8a5dde 100644 --- a/Firestore/Example/Firestore.xcodeproj/project.pbxproj +++ b/Firestore/Example/Firestore.xcodeproj/project.pbxproj @@ -127,6 +127,9 @@ 11F8EE69182C9699E90A9E3D /* database_info_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = AB38D92E20235D22000A432D /* database_info_test.cc */; }; 12158DFCEE09D24B7988A340 /* maybe_document.pb.cc in Sources */ = {isa = PBXBuildFile; fileRef = 618BBE7E20B89AAC00B5BCE7 /* maybe_document.pb.cc */; }; 121F0FB9DCCBFB7573C7AF48 /* bundle_serializer_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = B5C2A94EE24E60543F62CC35 /* bundle_serializer_test.cc */; }; + 12260A2A2D56A3CE001766EB /* PipelineTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12260A292D56A3CE001766EB /* PipelineTests.swift */; }; + 12260A2B2D56A3CE001766EB /* PipelineTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12260A292D56A3CE001766EB /* PipelineTests.swift */; }; + 12260A2C2D56A3CE001766EB /* PipelineTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12260A292D56A3CE001766EB /* PipelineTests.swift */; }; 124AAEE987451820F24EEA8E /* user_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = CCC9BD953F121B9E29F9AA42 /* user_test.cc */; }; 125B1048ECB755C2106802EB /* executor_std_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = B6FB4687208F9B9100554BA2 /* executor_std_test.cc */; }; 1290FA77A922B76503AE407C /* lru_garbage_collector_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 277EAACC4DD7C21332E8496A /* lru_garbage_collector_test.cc */; }; @@ -1735,6 +1738,7 @@ 0D964D4936953635AC7E0834 /* Validation_BloomFilterTest_MD5_1_01_bloom_filter_proto.json */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.json; name = Validation_BloomFilterTest_MD5_1_01_bloom_filter_proto.json; path = bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_1_01_bloom_filter_proto.json; sourceTree = ""; }; 0EE5300F8233D14025EF0456 /* string_apple_test.mm */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.objcpp; path = string_apple_test.mm; sourceTree = ""; }; 11984BA0A99D7A7ABA5B0D90 /* Pods-Firestore_Example_iOS-Firestore_SwiftTests_iOS.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Firestore_Example_iOS-Firestore_SwiftTests_iOS.release.xcconfig"; path = "Pods/Target Support Files/Pods-Firestore_Example_iOS-Firestore_SwiftTests_iOS/Pods-Firestore_Example_iOS-Firestore_SwiftTests_iOS.release.xcconfig"; sourceTree = ""; }; + 12260A292D56A3CE001766EB /* PipelineTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PipelineTests.swift; sourceTree = ""; }; 1235769122B7E915007DDFA9 /* EncodableFieldValueTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EncodableFieldValueTests.swift; sourceTree = ""; }; 1235769422B86E65007DDFA9 /* FirestoreEncoderTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FirestoreEncoderTests.swift; sourceTree = ""; }; 124C932B22C1642C00CA8C2D /* CodableIntegrationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CodableIntegrationTests.swift; sourceTree = ""; }; @@ -1797,7 +1801,7 @@ 4334F87873015E3763954578 /* status_testing.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = status_testing.h; sourceTree = ""; }; 4375BDCDBCA9938C7F086730 /* Validation_BloomFilterTest_MD5_5000_1_bloom_filter_proto.json */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.json; name = Validation_BloomFilterTest_MD5_5000_1_bloom_filter_proto.json; path = bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_5000_1_bloom_filter_proto.json; sourceTree = ""; }; 444B7AB3F5A2929070CB1363 /* hard_assert_test.cc */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; path = hard_assert_test.cc; sourceTree = ""; }; - 4564AD9C55EC39C080EB9476 /* globals_cache_test.cc */ = {isa = PBXFileReference; includeInIndex = 1; path = globals_cache_test.cc; sourceTree = ""; }; + 4564AD9C55EC39C080EB9476 /* globals_cache_test.cc */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; path = globals_cache_test.cc; sourceTree = ""; }; 478DC75A0DCA6249A616DD30 /* Validation_BloomFilterTest_MD5_500_0001_membership_test_result.json */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.json; name = Validation_BloomFilterTest_MD5_500_0001_membership_test_result.json; path = bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_500_0001_membership_test_result.json; sourceTree = ""; }; 48D0915834C3D234E5A875A9 /* grpc_stream_tester.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = grpc_stream_tester.h; sourceTree = ""; }; 4B3E4A77493524333133C5DC /* Validation_BloomFilterTest_MD5_50000_1_bloom_filter_proto.json */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.json; name = Validation_BloomFilterTest_MD5_50000_1_bloom_filter_proto.json; path = bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_50000_1_bloom_filter_proto.json; sourceTree = ""; }; @@ -1915,7 +1919,7 @@ 5B5414D28802BC76FDADABD6 /* stream_test.cc */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; path = stream_test.cc; sourceTree = ""; }; 5B96CC29E9946508F022859C /* Validation_BloomFilterTest_MD5_50000_0001_membership_test_result.json */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.json; name = Validation_BloomFilterTest_MD5_50000_0001_membership_test_result.json; path = bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_50000_0001_membership_test_result.json; sourceTree = ""; }; 5C68EE4CB94C0DD6E333F546 /* Validation_BloomFilterTest_MD5_1_01_membership_test_result.json */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.json; name = Validation_BloomFilterTest_MD5_1_01_membership_test_result.json; path = bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_1_01_membership_test_result.json; sourceTree = ""; }; - 5C6DEA63FBDE19D841291723 /* memory_globals_cache_test.cc */ = {isa = PBXFileReference; includeInIndex = 1; path = memory_globals_cache_test.cc; sourceTree = ""; }; + 5C6DEA63FBDE19D841291723 /* memory_globals_cache_test.cc */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; path = memory_globals_cache_test.cc; sourceTree = ""; }; 5C7942B6244F4C416B11B86C /* leveldb_mutation_queue_test.cc */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; path = leveldb_mutation_queue_test.cc; sourceTree = ""; }; 5CAE131920FFFED600BE9A4A /* Firestore_Benchmarks_iOS.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = Firestore_Benchmarks_iOS.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 5CAE131D20FFFED600BE9A4A /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; @@ -2296,6 +2300,7 @@ 124C932B22C1642C00CA8C2D /* CodableIntegrationTests.swift */, 3355BE9391CC4857AF0BDAE3 /* DatabaseTests.swift */, 62E54B832A9E910A003347C8 /* IndexingTests.swift */, + 12260A292D56A3CE001766EB /* PipelineTests.swift */, 621D620928F9CE7400D2FA26 /* QueryIntegrationTests.swift */, 4D65F6E69993611D47DC8E7C /* SnapshotListenerSourceTests.swift */, EFF22EA92C5060A4009A369B /* VectorIntegrationTests.swift */, @@ -4685,6 +4690,7 @@ 432056C4D1259F76C80FC2A8 /* FSTUserDataReaderTests.mm in Sources */, 3B1E27D951407FD237E64D07 /* FirestoreEncoderTests.swift in Sources */, 62E54B862A9E910B003347C8 /* IndexingTests.swift in Sources */, + 12260A2C2D56A3CE001766EB /* PipelineTests.swift in Sources */, 621D620C28F9CE7400D2FA26 /* QueryIntegrationTests.swift in Sources */, 1CFBD4563960D8A20C4679A3 /* SnapshotListenerSourceTests.swift in Sources */, EFF22EAC2C5060A4009A369B /* VectorIntegrationTests.swift in Sources */, @@ -4935,6 +4941,7 @@ 75A176239B37354588769206 /* FSTUserDataReaderTests.mm in Sources */, 5E89B1A5A5430713C79C4854 /* FirestoreEncoderTests.swift in Sources */, 62E54B852A9E910B003347C8 /* IndexingTests.swift in Sources */, + 12260A2B2D56A3CE001766EB /* PipelineTests.swift in Sources */, 621D620B28F9CE7400D2FA26 /* QueryIntegrationTests.swift in Sources */, A0BC30D482B0ABD1A3A24CDC /* SnapshotListenerSourceTests.swift in Sources */, EFF22EAB2C5060A4009A369B /* VectorIntegrationTests.swift in Sources */, @@ -5440,6 +5447,7 @@ F5BDECEB3B43BD1591EEADBD /* FSTUserDataReaderTests.mm in Sources */, 6F45846C159D3C063DBD3CBE /* FirestoreEncoderTests.swift in Sources */, 62E54B842A9E910B003347C8 /* IndexingTests.swift in Sources */, + 12260A2A2D56A3CE001766EB /* PipelineTests.swift in Sources */, 621D620A28F9CE7400D2FA26 /* QueryIntegrationTests.swift in Sources */, B00F8D1819EE20C45B660940 /* SnapshotListenerSourceTests.swift in Sources */, EFF22EAA2C5060A4009A369B /* VectorIntegrationTests.swift in Sources */, diff --git a/Firestore/Source/API/FIRFirestore+Internal.h b/Firestore/Source/API/FIRFirestore+Internal.h index 5c5da4c525d..eecc1160a5f 100644 --- a/Firestore/Source/API/FIRFirestore+Internal.h +++ b/Firestore/Source/API/FIRFirestore+Internal.h @@ -1,5 +1,5 @@ /* - * Copyright 2017 Google + * Copyright 2025 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/Firestore/Source/API/FIRPipelineBridge+Internal.h b/Firestore/Source/API/FIRPipelineBridge+Internal.h new file mode 100644 index 00000000000..bfe7befe923 --- /dev/null +++ b/Firestore/Source/API/FIRPipelineBridge+Internal.h @@ -0,0 +1,49 @@ +/* + * Copyright 2025 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 "FIRPipelineBridge.h" + +#include + +#include "Firestore/core/src/api/expressions.h" +#include "Firestore/core/src/api/pipeline.h" +#include "Firestore/core/src/api/stages.h" + +@class FIRFilter; + +namespace api = firebase::firestore::api; + +NS_ASSUME_NONNULL_BEGIN + +@interface FIRExprBridge (Internal) + +- (std::shared_ptr)cpp_expr; + +@end + +@interface FIRStageBridge (Internal) + +- (std::shared_ptr)cpp_stage; + +@end + +@interface __FIRPipelineSnapshotBridge (Internal) + +- (id)initWithCppSnapshot:(api::PipelineSnapshot)snapshot; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Firestore/Source/API/FIRPipelineBridge.mm b/Firestore/Source/API/FIRPipelineBridge.mm new file mode 100644 index 00000000000..013cedcccab --- /dev/null +++ b/Firestore/Source/API/FIRPipelineBridge.mm @@ -0,0 +1,191 @@ +/* + * Copyright 2025 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 "FIRPipelineBridge.h" + +#include + +#import "Firestore/Source/API/FIRFirestore+Internal.h" +#import "Firestore/Source/API/FIRPipelineBridge+Internal.h" + +#include "Firestore/core/src/api/expressions.h" +#include "Firestore/core/src/api/pipeline.h" +#include "Firestore/core/src/api/pipeline_result.h" +#include "Firestore/core/src/api/pipeline_snapshot.h" +#include "Firestore/core/src/api/stages.h" +#include "Firestore/core/src/util/error_apple.h" +#include "Firestore/core/src/util/status.h" +#include "Firestore/core/src/util/string_apple.h" + +using firebase::firestore::api::CollectionSource; +using firebase::firestore::api::Constant; +using firebase::firestore::api::Expr; +using firebase::firestore::api::Field; +using firebase::firestore::api::FunctionExpr; +using firebase::firestore::api::Pipeline; +using firebase::firestore::api::Where; +using firebase::firestore::util::MakeCallback; +using firebase::firestore::util::MakeString; + +NS_ASSUME_NONNULL_BEGIN + +@implementation FIRExprBridge +@end + +@implementation FIRFieldBridge { + std::shared_ptr field; +} + +- (id)init:(NSString *)name { + self = [super init]; + if (self) { + field = std::make_shared(MakeString(name)); + } + return self; +} + +- (std::shared_ptr)cpp_expr { + return field; +} + +@end + +@implementation FIRConstantBridge { + std::shared_ptr constant; +} +- (id)init:(NSNumber *)value { + self = [super init]; + if (self) { + constant = std::make_shared(value.doubleValue); + } + return self; +} + +- (std::shared_ptr)cpp_expr { + return constant; +} + +@end + +@implementation FIRFunctionExprBridge { + std::shared_ptr eq; +} + +- (nonnull id)initWithName:(NSString *)name Args:(nonnull NSArray *)args { + self = [super init]; + if (self) { + std::vector> cpp_args; + for (FIRExprBridge *arg in args) { + cpp_args.push_back(arg.cpp_expr); + } + + eq = std::make_shared(MakeString(name), std::move(cpp_args)); + } + return self; +} + +- (std::shared_ptr)cpp_expr { + return eq; +} + +@end + +@implementation FIRStageBridge +@end + +@implementation FIRCollectionSourceStageBridge { + std::shared_ptr collection_source; +} + +- (id)initWithPath:(NSString *)path { + self = [super init]; + if (self) { + collection_source = std::make_shared(MakeString(path)); + } + return self; +} + +- (std::shared_ptr)cpp_stage { + return collection_source; +} + +@end + +@implementation FIRWhereStageBridge { + std::shared_ptr where; +} + +- (id)initWithExpr:(FIRExprBridge *)expr { + self = [super init]; + if (self) { + where = std::make_shared(expr.cpp_expr); + } + return self; +} + +- (std::shared_ptr)cpp_stage { + return where; +} + +@end + +@implementation __FIRPipelineSnapshotBridge { + absl::optional pipeline; +} + +- (id)initWithCppSnapshot:(api::PipelineSnapshot)snapshot { + self = [super init]; + if (self) { + pipeline = std::move(snapshot); + } + + return self; +} + +@end + +@implementation FIRPipelineBridge { + std::shared_ptr pipeline; +} + +- (id)initWithStages:(NSArray *)stages db:(FIRFirestore *)db { + self = [super init]; + if (self) { + std::vector> cpp_stages; + for (FIRStageBridge *stage in stages) { + cpp_stages.push_back(stage.cpp_stage); + } + pipeline = std::make_shared(cpp_stages, db.wrapped); + } + return self; +} + +- (void)executeWithCompletion:(void (^)(__FIRPipelineSnapshotBridge *_Nullable result, + NSError *_Nullable error))completion { + pipeline->execute([completion](StatusOr maybe_value) { + if (maybe_value.ok()) { + __FIRPipelineSnapshotBridge *bridge = [[__FIRPipelineSnapshotBridge alloc] + initWithCppSnapshot:std::move(maybe_value).ValueOrDie()]; + completion(bridge, nil); + } else { + completion(nil, MakeNSError(std::move(maybe_value).status())); + } + }); +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/Firestore/Source/Public/FirebaseFirestore/FIRPipelineBridge.h b/Firestore/Source/Public/FirebaseFirestore/FIRPipelineBridge.h new file mode 100644 index 00000000000..fa7472e3292 --- /dev/null +++ b/Firestore/Source/Public/FirebaseFirestore/FIRPipelineBridge.h @@ -0,0 +1,89 @@ +/* + * Copyright 2025 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 "FIRFirestore.h" + +#import + +NS_ASSUME_NONNULL_BEGIN + +NS_SWIFT_NAME(ExprBridge) +@interface FIRExprBridge : NSObject +@end + +NS_SWIFT_NAME(FieldBridge) +@interface FIRFieldBridge : FIRExprBridge +- (id)init:(NSString *)name; +@end + +NS_SWIFT_NAME(ConstantBridge) +@interface FIRConstantBridge : FIRExprBridge +- (id)init:(NSNumber *)value; +@end + +NS_SWIFT_NAME(FunctionExprBridge) +@interface FIRFunctionExprBridge : FIRExprBridge +- (id)initWithName:(NSString *)name Args:(NSArray *)args; +@end + +NS_SWIFT_NAME(StageBridge) +@interface FIRStageBridge : NSObject +@end + +NS_SWIFT_NAME(CollectionSourceStageBridge) +@interface FIRCollectionSourceStageBridge : FIRStageBridge + +- (id)initWithPath:(NSString *)path; + +@end + +NS_SWIFT_NAME(WhereStageBridge) +@interface FIRWhereStageBridge : FIRStageBridge + +- (id)initWithExpr:(FIRExprBridge *)expr; + +@end + +NS_SWIFT_NAME(__PipelineSnapshotBridge) +@interface __FIRPipelineSnapshotBridge : NSObject + +@property(nonatomic, strong, readonly) NSArray<__FIRPipelineSnapshotBridge *> *results; + +@end + +NS_SWIFT_NAME(__PipelineResultBridge) +@interface __FIRPipelineResultBridge : NSObject + +@property(nonatomic, strong, readonly) FIRDocumentReference *reference; + +@property(nonatomic, copy, readonly) NSString *documentID; + +- (nullable NSDictionary *)data; + +@end + +NS_SWIFT_NAME(PipelineBridge) +@interface FIRPipelineBridge : NSObject + +/** :nodoc: */ +- (id)initWithStages:(NSArray *)stages db:(FIRFirestore *)db; + +- (void)executeWithCompletion:(void (^)(__FIRPipelineSnapshotBridge *_Nullable result, + NSError *_Nullable error))completion; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Firestore/Source/Public/FirebaseFirestore/FirebaseFirestore.h b/Firestore/Source/Public/FirebaseFirestore/FirebaseFirestore.h index 7fabad323c8..0f10968565a 100644 --- a/Firestore/Source/Public/FirebaseFirestore/FirebaseFirestore.h +++ b/Firestore/Source/Public/FirebaseFirestore/FirebaseFirestore.h @@ -32,6 +32,7 @@ #import "FIRListenerRegistration.h" #import "FIRLoadBundleTask.h" #import "FIRLocalCacheSettings.h" +#import "FIRPipelineBridge.h" #import "FIRQuery.h" #import "FIRQuerySnapshot.h" #import "FIRSnapshotListenOptions.h" diff --git a/Firestore/Swift/Source/SwiftAPI/Expressions.swift b/Firestore/Swift/Source/SwiftAPI/Expressions.swift new file mode 100644 index 00000000000..729b5c9fb67 --- /dev/null +++ b/Firestore/Swift/Source/SwiftAPI/Expressions.swift @@ -0,0 +1,70 @@ +/* + * Copyright 2025 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 + +public protocol Expr { + var bridge: ExprBridge { get } +} + +public struct Constant: Expr { + public var bridge: ExprBridge + + var value: any Numeric + init(value: any Numeric) { + self.value = value + bridge = ConstantBridge(value as! NSNumber) + } +} + +public func constant(_ number: any Numeric) -> Constant { + return Constant(value: number) +} + +public struct Field: Expr { + public var bridge: ExprBridge + + var name: String + init(name: String) { + self.name = name + bridge = FieldBridge(name) + } +} + +public func field(_ name: String) -> Field { + return Field(name: name) +} + +protocol Function: Expr { + var name: String { get } +} + +public struct FunctionExpr: Function { + public var bridge: ExprBridge + + var name: String + private var args: [Expr] + + init(name: String, args: [Expr]) { + self.name = name + self.args = args + bridge = FunctionExprBridge(name: name, args: args.map { $0.bridge }) + } +} + +public func eq(_ left: Expr, _ right: Expr) -> FunctionExpr { + return FunctionExpr(name: "eq", args: [left, right]) +} diff --git a/Firestore/Swift/Source/SwiftAPI/Firestore+Pipeline.swift b/Firestore/Swift/Source/SwiftAPI/Firestore+Pipeline.swift new file mode 100644 index 00000000000..0179ece4e04 --- /dev/null +++ b/Firestore/Swift/Source/SwiftAPI/Firestore+Pipeline.swift @@ -0,0 +1,23 @@ +/* + * Copyright 2025 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 + +@objc public extension Firestore { + @nonobjc func pipeline() -> PipelineSource { + return PipelineSource(db: self) + } +} diff --git a/Firestore/Swift/Source/SwiftAPI/Pipeline.swift b/Firestore/Swift/Source/SwiftAPI/Pipeline.swift new file mode 100644 index 00000000000..8c8a4364d30 --- /dev/null +++ b/Firestore/Swift/Source/SwiftAPI/Pipeline.swift @@ -0,0 +1,45 @@ +/* + * Copyright 2025 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 + +public struct Pipeline { + private var stages: [Stage] + private var bridge: PipelineBridge + private let db: Firestore + + init(stages: [Stage], db: Firestore) { + self.stages = stages + self.db = db + bridge = PipelineBridge(stages: stages.map { $0.bridge }, db: db) + } + + public func `where`(_ condition: Expr) -> Pipeline { + return Pipeline(stages: stages + [Where(condition: condition)], db: db) + } + + public func execute() async throws -> PipelineSnapshot { + return try await withCheckedThrowingContinuation { continuation in + self.bridge.execute { result, error in + if let error { + continuation.resume(throwing: error) + } else { + continuation.resume(returning: PipelineSnapshot(result!)) + } + } + } + } +} diff --git a/Firestore/Swift/Source/SwiftAPI/PipelineSnapshot.swift b/Firestore/Swift/Source/SwiftAPI/PipelineSnapshot.swift new file mode 100644 index 00000000000..00386d0c6dc --- /dev/null +++ b/Firestore/Swift/Source/SwiftAPI/PipelineSnapshot.swift @@ -0,0 +1,25 @@ +/* + * Copyright 2025 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 + +public struct PipelineSnapshot { + private let bridge: __PipelineSnapshotBridge + + init(_ bridge: __PipelineSnapshotBridge) { + self.bridge = bridge + } +} diff --git a/Firestore/Swift/Source/SwiftAPI/PipelineSource.swift b/Firestore/Swift/Source/SwiftAPI/PipelineSource.swift new file mode 100644 index 00000000000..ce84c0356ac --- /dev/null +++ b/Firestore/Swift/Source/SwiftAPI/PipelineSource.swift @@ -0,0 +1,28 @@ +/* + * Copyright 2025 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 + +public class PipelineSource { + private let db: Firestore + public init(db: Firestore) { + self.db = db + } + + public func collection(path: String) -> Pipeline { + return Pipeline(stages: [CollectionSource(collection: path)], db: db) + } +} diff --git a/Firestore/Swift/Source/SwiftAPI/Stages.swift b/Firestore/Swift/Source/SwiftAPI/Stages.swift new file mode 100644 index 00000000000..df3c163e803 --- /dev/null +++ b/Firestore/Swift/Source/SwiftAPI/Stages.swift @@ -0,0 +1,47 @@ +/* + * Copyright 2025 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 +import Foundation + +protocol Stage { + var name: String { get } + var bridge: StageBridge { get } +} + +class CollectionSource: Stage { + var name: String = "collection" + + var bridge: StageBridge + private var collection: String + + init(collection: String) { + self.collection = collection + bridge = CollectionSourceStageBridge(path: collection) + } +} + +class Where: Stage { + var name: String = "where" + + var bridge: StageBridge + private var condition: Expr // TODO: should be FilterCondition + + init(condition: Expr) { + self.condition = condition + bridge = WhereStageBridge(expr: condition.bridge) + } +} diff --git a/Firestore/Swift/Tests/Integration/PipelineTests.swift b/Firestore/Swift/Tests/Integration/PipelineTests.swift new file mode 100644 index 00000000000..79185762b91 --- /dev/null +++ b/Firestore/Swift/Tests/Integration/PipelineTests.swift @@ -0,0 +1,31 @@ +/* + * Copyright 2025 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 FirebaseFirestore +import Foundation + +@available(iOS 13, tvOS 13, macOS 10.15, macCatalyst 13, watchOS 7, *) +class PipelineIntegrationTests: FSTIntegrationTestCase { + func testCount() async throws { + let snapshot = try await firestore() + .pipeline() + .collection(path: "foo") + .where(eq(field("foo"), constant(42))) + .execute() + + print(snapshot) + } +} diff --git a/Firestore/core/src/api/api_fwd.h b/Firestore/core/src/api/api_fwd.h index 0c35c567157..ded3bfb76af 100644 --- a/Firestore/core/src/api/api_fwd.h +++ b/Firestore/core/src/api/api_fwd.h @@ -44,6 +44,8 @@ class DocumentReference; class DocumentSnapshot; class Firestore; class ListenerRegistration; +class Pipeline; +class PipelineSnapshot; class Query; class QuerySnapshot; class Settings; diff --git a/Firestore/core/src/api/expressions.cc b/Firestore/core/src/api/expressions.cc new file mode 100644 index 00000000000..07e99b1e848 --- /dev/null +++ b/Firestore/core/src/api/expressions.cc @@ -0,0 +1,61 @@ +/* + * Copyright 2025 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. + */ + +#include "Firestore/core/src/api/expressions.h" + +#include + +#include "Firestore/Protos/nanopb/google/firestore/v1/document.nanopb.h" +#include "Firestore/core/src/nanopb/nanopb_util.h" + +namespace firebase { +namespace firestore { +namespace api { + +google_firestore_v1_Value Field::to_proto() const { + google_firestore_v1_Value result; + + result.which_value_type = google_firestore_v1_Value_field_reference_value_tag; + result.field_reference_value = nanopb::MakeBytesArray(this->name_); + + return result; +} + +google_firestore_v1_Value Constant::to_proto() const { + google_firestore_v1_Value result; + + result.which_value_type = google_firestore_v1_Value_double_value_tag; + result.double_value = this->value_; + + return result; +} + +google_firestore_v1_Value FunctionExpr::to_proto() const { + google_firestore_v1_Value result; + + result.which_value_type = google_firestore_v1_Value_function_value_tag; + result.function_value = google_firestore_v1_Function{}; + result.function_value.name = nanopb::MakeBytesArray(name_); + nanopb::SetRepeatedField( + &result.function_value.args, &result.function_value.args_count, args_, + [](const std::shared_ptr& arg) { return arg->to_proto(); }); + + return result; +} + +} // namespace api +} // namespace firestore +} // namespace firebase diff --git a/Firestore/core/src/api/expressions.h b/Firestore/core/src/api/expressions.h new file mode 100644 index 00000000000..2ab134249cf --- /dev/null +++ b/Firestore/core/src/api/expressions.h @@ -0,0 +1,75 @@ +/* + * Copyright 2025 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. + */ + +#ifndef FIRESTORE_CORE_SRC_API_EXPRESSIONS_H_ +#define FIRESTORE_CORE_SRC_API_EXPRESSIONS_H_ + +#include +#include +#include +#include + +#include "Firestore/Protos/nanopb/google/firestore/v1/document.nanopb.h" + +namespace firebase { +namespace firestore { +namespace api { + +class Expr { + public: + Expr() = default; + virtual ~Expr() = default; + virtual google_firestore_v1_Value to_proto() const = 0; +}; + +class Field : public Expr { + public: + explicit Field(std::string name) : name_(std::move(name)) { + } + google_firestore_v1_Value to_proto() const override; + + private: + std::string name_; +}; + +class Constant : public Expr { + public: + explicit Constant(double value) : value_(value) { + } + google_firestore_v1_Value to_proto() const override; + + private: + double value_; +}; + +class FunctionExpr : public Expr { + public: + FunctionExpr(std::string name, std::vector> args) + : name_(std::move(name)), args_(std::move(args)) { + } + + google_firestore_v1_Value to_proto() const override; + + private: + std::string name_; + std::vector> args_; +}; + +} // namespace api +} // namespace firestore +} // namespace firebase + +#endif // FIRESTORE_CORE_SRC_API_EXPRESSIONS_H_ diff --git a/Firestore/core/src/api/firestore.cc b/Firestore/core/src/api/firestore.cc index 70cb975cc71..1484f3a27fc 100644 --- a/Firestore/core/src/api/firestore.cc +++ b/Firestore/core/src/api/firestore.cc @@ -179,6 +179,13 @@ void Firestore::RunTransaction(core::TransactionUpdateCallback update_callback, std::move(result_callback)); } +void Firestore::RunPipeline(const api::Pipeline& pipeline, + util::StatusOrCallback callback) { + EnsureClientConfigured(); + + client_->RunPipeline(pipeline, std::move(callback)); +} + void Firestore::Terminate(util::StatusCallback callback) { // The client must be initialized to ensure that all subsequent API usage // throws an exception. diff --git a/Firestore/core/src/api/firestore.h b/Firestore/core/src/api/firestore.h index 0300f6c61f2..de22a87c14c 100644 --- a/Firestore/core/src/api/firestore.h +++ b/Firestore/core/src/api/firestore.h @@ -102,6 +102,8 @@ class Firestore : public std::enable_shared_from_this { void RunTransaction(core::TransactionUpdateCallback update_callback, core::TransactionResultCallback result_callback, int max_attempts); + void RunPipeline(const api::Pipeline& pipeline, + util::StatusOrCallback callback); void Terminate(util::StatusCallback callback); void ClearPersistence(util::StatusCallback callback); diff --git a/Firestore/core/src/api/pipeline.cc b/Firestore/core/src/api/pipeline.cc new file mode 100644 index 00000000000..24c5109bd95 --- /dev/null +++ b/Firestore/core/src/api/pipeline.cc @@ -0,0 +1,45 @@ +/* + * Copyright 2025 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. + */ + +#include "Firestore/core/src/api/pipeline.h" + +#include +#include + +#include "Firestore/core/src/core/firestore_client.h" + +namespace firebase { +namespace firestore { +namespace api { + +Pipeline Pipeline::AddingStage(std::shared_ptr stage) { + auto copy = std::vector>(this->stages_); + copy.push_back(stage); + + return {copy, this->firestore_}; +} + +const std::vector>& Pipeline::stages() const { + return this->stages_; +} + +void Pipeline::execute(util::StatusOrCallback callback) { + this->firestore_->RunPipeline(*this, std::move(callback)); +} + +} // namespace api +} // namespace firestore +} // namespace firebase diff --git a/Firestore/core/src/api/pipeline.h b/Firestore/core/src/api/pipeline.h new file mode 100644 index 00000000000..6103f366eda --- /dev/null +++ b/Firestore/core/src/api/pipeline.h @@ -0,0 +1,59 @@ +/* + * Copyright 2025 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. + */ + +#ifndef FIRESTORE_CORE_SRC_API_PIPELINE_H_ +#define FIRESTORE_CORE_SRC_API_PIPELINE_H_ + +#include +#include +#include + +#include "Firestore/core/src/api/firestore.h" +#include "Firestore/core/src/api/pipeline_snapshot.h" +#include "Firestore/core/src/api/stages.h" +#include "Firestore/core/src/util/status_fwd.h" + +namespace firebase { +namespace firestore { +namespace api { + +class Pipeline { + public: + Pipeline(std::vector> stages, + std::shared_ptr firestore) + : stages_(std::move(stages)), firestore_(firestore) { + } + + const std::shared_ptr& firestore() const { + return firestore_; + } + + Pipeline AddingStage(std::shared_ptr stage); + + const std::vector>& stages() const; + + void execute(util::StatusOrCallback callback); + + private: + std::vector> stages_; + std::shared_ptr firestore_; +}; + +} // namespace api +} // namespace firestore +} // namespace firebase + +#endif // FIRESTORE_CORE_SRC_API_PIPELINE_H_ diff --git a/Firestore/core/src/api/pipeline_result.cc b/Firestore/core/src/api/pipeline_result.cc new file mode 100644 index 00000000000..655fd7b4132 --- /dev/null +++ b/Firestore/core/src/api/pipeline_result.cc @@ -0,0 +1,52 @@ +/* + * Copyright 2025 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. + */ + +#include "Firestore/core/src/api/pipeline_result.h" + +#include + +#include "Firestore/core/src/api/document_reference.h" +#include "Firestore/core/src/model/document.h" +#include "Firestore/core/src/model/document_key.h" +#include "Firestore/core/src/model/field_path.h" +#include "Firestore/core/src/model/object_value.h" +#include "Firestore/core/src/model/resource_path.h" +#include "absl/strings/string_view.h" +#include "absl/types/optional.h" + +namespace firebase { +namespace firestore { +namespace api { + +using model::Document; +using model::DocumentKey; +using model::FieldPath; +using model::ObjectValue; + +std::shared_ptr PipelineResult::internal_value() const { + return value_; +} + +absl::optional PipelineResult::document_id() const { + if (!internal_key_.has_value()) { + return absl::nullopt; + } + return internal_key_.value().path().last_segment(); +} + +} // namespace api +} // namespace firestore +} // namespace firebase diff --git a/Firestore/core/src/api/pipeline_result.h b/Firestore/core/src/api/pipeline_result.h new file mode 100644 index 00000000000..4680d058c7b --- /dev/null +++ b/Firestore/core/src/api/pipeline_result.h @@ -0,0 +1,71 @@ +/* + * Copyright 2025 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. + */ + +#ifndef FIRESTORE_CORE_SRC_API_PIPELINE_RESULT_H_ +#define FIRESTORE_CORE_SRC_API_PIPELINE_RESULT_H_ + +#include +#include +#include + +#include "Firestore/core/src/model/document.h" +#include "Firestore/core/src/model/document_key.h" +#include "Firestore/core/src/model/model_fwd.h" +#include "absl/strings/string_view.h" +#include "absl/types/optional.h" + +namespace firebase { +namespace firestore { +namespace api { + +class DocumentReference; +class Firestore; + +class PipelineResult { + public: + PipelineResult(absl::optional document_key, + std::shared_ptr value, + absl::optional create_time, + absl::optional update_time, + absl::optional execution_time) + : internal_key_{std::move(document_key)}, + value_{std::move(value)}, + create_time_{create_time}, + update_time_{update_time}, + execution_time_{execution_time} { + } + + PipelineResult() = default; + + std::shared_ptr internal_value() const; + absl::optional document_id() const; + + private: + absl::optional internal_key_; + // Using a shared pointer to ObjectValue makes PipelineResult copy-assignable + // without having to manually create a deep clone of its Protobuf contents. + std::shared_ptr value_ = + std::make_shared(); + absl::optional create_time_; + absl::optional update_time_; + absl::optional execution_time_; +}; + +} // namespace api +} // namespace firestore +} // namespace firebase + +#endif // FIRESTORE_CORE_SRC_API_PIPELINE_RESULT_H_ diff --git a/Firestore/core/src/api/pipeline_snapshot.h b/Firestore/core/src/api/pipeline_snapshot.h new file mode 100644 index 00000000000..a19e76138a7 --- /dev/null +++ b/Firestore/core/src/api/pipeline_snapshot.h @@ -0,0 +1,53 @@ +/* + * Copyright 2025 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. + */ + +#ifndef FIRESTORE_CORE_SRC_API_PIPELINE_SNAPSHOT_H_ +#define FIRESTORE_CORE_SRC_API_PIPELINE_SNAPSHOT_H_ + +#include +#include +#include +#include + +#include "Firestore/core/src/api/api_fwd.h" +#include "Firestore/core/src/api/pipeline_result.h" +#include "Firestore/core/src/model/snapshot_version.h" + +namespace firebase { +namespace firestore { +namespace api { + +class PipelineSnapshot { + public: + explicit PipelineSnapshot(std::vector&& results, + model::SnapshotVersion execution_time) + : results_(std::move(results)), execution_time_(execution_time) { + } + + const std::vector& results() const { + return results_; + } + + private: + std::vector results_; + model::SnapshotVersion execution_time_; +}; + +} // namespace api +} // namespace firestore +} // namespace firebase + +#endif // FIRESTORE_CORE_SRC_API_PIPELINE_SNAPSHOT_H_ diff --git a/Firestore/core/src/api/stages.cc b/Firestore/core/src/api/stages.cc new file mode 100644 index 00000000000..6843a1b4ce5 --- /dev/null +++ b/Firestore/core/src/api/stages.cc @@ -0,0 +1,59 @@ +/* + * Copyright 2025 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. + */ + +#include "Firestore/core/src/api/stages.h" + +#include "Firestore/core/src/nanopb/nanopb_util.h" + +namespace firebase { +namespace firestore { +namespace api { + +google_firestore_v1_Pipeline_Stage CollectionSource::to_proto() const { + google_firestore_v1_Pipeline_Stage result; + + result.name = nanopb::MakeBytesArray("collection"); + + result.args_count = 1; + result.args = nanopb::MakeArray(1); + result.args[0].which_value_type = + google_firestore_v1_Value_reference_value_tag; + result.args[0].reference_value = nanopb::MakeBytesArray(this->path_); + + result.options_count = 0; + result.options = nullptr; + + return result; +} + +google_firestore_v1_Pipeline_Stage Where::to_proto() const { + google_firestore_v1_Pipeline_Stage result; + + result.name = nanopb::MakeBytesArray("where"); + + result.args_count = 1; + result.args = nanopb::MakeArray(1); + result.args[0] = this->expr_->to_proto(); + + result.options_count = 0; + result.options = nullptr; + + return result; +} + +} // namespace api +} // namespace firestore +} // namespace firebase diff --git a/Firestore/core/src/api/stages.h b/Firestore/core/src/api/stages.h new file mode 100644 index 00000000000..f037a70408e --- /dev/null +++ b/Firestore/core/src/api/stages.h @@ -0,0 +1,66 @@ +/* + * Copyright 2025 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. + */ + +#ifndef FIRESTORE_CORE_SRC_API_STAGES_H_ +#define FIRESTORE_CORE_SRC_API_STAGES_H_ + +#include +#include + +#include "Firestore/Protos/nanopb/google/firestore/v1/document.nanopb.h" +#include "Firestore/core/src/api/expressions.h" + +namespace firebase { +namespace firestore { +namespace api { + +class Stage { + public: + Stage() = default; + virtual ~Stage() = default; + + virtual google_firestore_v1_Pipeline_Stage to_proto() const = 0; +}; + +class CollectionSource : public Stage { + public: + explicit CollectionSource(std::string path) : path_(path) { + } + ~CollectionSource() override = default; + + google_firestore_v1_Pipeline_Stage to_proto() const override; + + private: + std::string path_; +}; + +class Where : public Stage { + public: + explicit Where(std::shared_ptr expr) : expr_(expr) { + } + ~Where() override = default; + + google_firestore_v1_Pipeline_Stage to_proto() const override; + + private: + std::shared_ptr expr_; +}; + +} // namespace api +} // namespace firestore +} // namespace firebase + +#endif // FIRESTORE_CORE_SRC_API_STAGES_H_ diff --git a/Firestore/core/src/core/firestore_client.cc b/Firestore/core/src/core/firestore_client.cc index c6dd50634c1..0c6ac315dea 100644 --- a/Firestore/core/src/core/firestore_client.cc +++ b/Firestore/core/src/core/firestore_client.cc @@ -575,6 +575,25 @@ void FirestoreClient::RunAggregateQuery( }); } +void FirestoreClient::RunPipeline( + const api::Pipeline& pipeline, + util::StatusOrCallback callback) { + VerifyNotTerminated(); + + // Dispatch the result back onto the user dispatch queue. + auto async_callback = + [this, callback](const StatusOr& status) { + if (callback) { + user_executor_->Execute([=] { callback(std::move(status)); }); + } + }; + + worker_queue_->Enqueue( + [this, pipeline, async_callback = std::move(async_callback)] { + remote_store_->RunPipeline(pipeline, async_callback); + }); +} + void FirestoreClient::AddSnapshotsInSyncListener( const std::shared_ptr>& user_listener) { worker_queue_->Enqueue([this, user_listener] { diff --git a/Firestore/core/src/core/firestore_client.h b/Firestore/core/src/core/firestore_client.h index d752deff66a..24c0e8c396a 100644 --- a/Firestore/core/src/core/firestore_client.h +++ b/Firestore/core/src/core/firestore_client.h @@ -23,6 +23,7 @@ #include "Firestore/core/src/api/api_fwd.h" #include "Firestore/core/src/api/load_bundle_task.h" +#include "Firestore/core/src/api/pipeline.h" #include "Firestore/core/src/bundle/bundle_serializer.h" #include "Firestore/core/src/core/core_fwd.h" #include "Firestore/core/src/core/database_info.h" @@ -159,6 +160,9 @@ class FirestoreClient : public std::enable_shared_from_this { const std::vector& aggregates, api::AggregateQueryCallback&& result_callback); + void RunPipeline(const api::Pipeline& pipeline, + util::StatusOrCallback callback); + /** * Adds a listener to be called when a snapshots-in-sync event fires. */ diff --git a/Firestore/core/src/nanopb/fields_array.h b/Firestore/core/src/nanopb/fields_array.h index 3b89b2ecd06..29fdc1c66dd 100644 --- a/Firestore/core/src/nanopb/fields_array.h +++ b/Firestore/core/src/nanopb/fields_array.h @@ -227,6 +227,18 @@ inline const pb_field_t* FieldsArray< return google_firestore_v1_StructuredAggregationQuery_Aggregation_Count_fields; } +template <> +inline const pb_field_t* +FieldsArray() { + return google_firestore_v1_ExecutePipelineRequest_fields; +} + +template <> +inline const pb_field_t* +FieldsArray() { + return google_firestore_v1_ExecutePipelineResponse_fields; +} + template <> inline const pb_field_t* FieldsArray() { return google_firestore_v1_ExistenceFilter_fields; diff --git a/Firestore/core/src/remote/datastore.cc b/Firestore/core/src/remote/datastore.cc index 47a8fb716b5..d5950ca09c6 100644 --- a/Firestore/core/src/remote/datastore.cc +++ b/Firestore/core/src/remote/datastore.cc @@ -63,6 +63,8 @@ const auto kRpcNameCommit = "/google.firestore.v1.Firestore/Commit"; const auto kRpcNameLookup = "/google.firestore.v1.Firestore/BatchGetDocuments"; const auto kRpcNameRunAggregationQuery = "/google.firestore.v1.Firestore/RunAggregationQuery"; +const auto kRpcNameExecutePipeline = + "/google.firestore.v1.Firestore/ExecutePipeline"; std::unique_ptr CreateExecutor() { return Executor::CreateSerial("com.google.firebase.firestore.rpc"); @@ -308,6 +310,52 @@ void Datastore::RunAggregateQueryWithCredentials( }); } +void Datastore::RunPipeline( + const api::Pipeline& pipeline, + util::StatusOrCallback&& result_callback) { + ResumeRpcWithCredentials( + [this, pipeline, result_callback = std::move(result_callback)]( + const StatusOr& auth_token, + const std::string& app_check_token) mutable { + if (!auth_token.ok()) { + // result_callback(auth_token.status()); + return; + } + RunPipelineWithCredentials(auth_token.ValueOrDie(), app_check_token, + pipeline, std::move(result_callback)); + }); +} + +void Datastore::RunPipelineWithCredentials( + const credentials::AuthToken& auth_token, + const std::string& app_check_token, + const api::Pipeline& pipeline, + util::StatusOrCallback&& callback) { + auto request = datastore_serializer_.EncodeExecutePipelineRequest(pipeline); + LOG_DEBUG("Run Pipeline: %s", request.ToString()); + + grpc::ByteBuffer message = MakeByteBuffer(request); + std::unique_ptr call_owning = grpc_connection_.CreateUnaryCall( + kRpcNameExecutePipeline, auth_token, app_check_token, std::move(message)); + GrpcUnaryCall* call = call_owning.get(); + active_calls_.push_back(std::move(call_owning)); + + call->Start([this, call, callback = std::move(callback)]( + const StatusOr& result) { + LogGrpcCallFinished("ExecutePipeline", call, result.status()); + HandleCallStatus(result.status()); + + if (result.ok()) { + callback(datastore_serializer_.DecodeExecutePipelineResponse( + result.ValueOrDie())); + } else { + callback(result.status()); + } + + RemoveGrpcCall(call); + }); +} + void Datastore::ResumeRpcWithCredentials(const OnCredentials& on_credentials) { // Auth/AppCheck may outlive Firestore std::weak_ptr weak_this{shared_from_this()}; diff --git a/Firestore/core/src/remote/datastore.h b/Firestore/core/src/remote/datastore.h index 7de64663d11..df912159eef 100644 --- a/Firestore/core/src/remote/datastore.h +++ b/Firestore/core/src/remote/datastore.h @@ -23,6 +23,7 @@ #include #include "Firestore/core/src/api/api_fwd.h" +#include "Firestore/core/src/api/pipeline.h" #include "Firestore/core/src/core/core_fwd.h" #include "Firestore/core/src/credentials/auth_token.h" #include "Firestore/core/src/credentials/credentials_fwd.h" @@ -112,6 +113,10 @@ class Datastore : public std::enable_shared_from_this { const std::vector& aggregates, api::AggregateQueryCallback&& result_callback); + void RunPipeline( + const api::Pipeline& pipeline, + util::StatusOrCallback&& result_callback); + /** Returns true if the given error is a gRPC ABORTED error. */ static bool IsAbortedError(const util::Status& error); @@ -195,6 +200,12 @@ class Datastore : public std::enable_shared_from_this { const std::vector& aggregates, api::AggregateQueryCallback&& callback); + void RunPipelineWithCredentials( + const credentials::AuthToken& auth_token, + const std::string& app_check_token, + const api::Pipeline& pipeline, + util::StatusOrCallback&& result_callback); + using OnCredentials = std::function&, const std::string&)>; void ResumeRpcWithCredentials(const OnCredentials& on_credentials); diff --git a/Firestore/core/src/remote/remote_objc_bridge.cc b/Firestore/core/src/remote/remote_objc_bridge.cc index ae7fcb246ea..466ed1229cc 100644 --- a/Firestore/core/src/remote/remote_objc_bridge.cc +++ b/Firestore/core/src/remote/remote_objc_bridge.cc @@ -383,6 +383,32 @@ util::StatusOr DatastoreSerializer::DecodeAggregateQueryResponse( aliasMap); } +Message +DatastoreSerializer::EncodeExecutePipelineRequest( + const firebase::firestore::api::Pipeline& pipeline) const { + Message result; + result->database = serializer_.EncodeDatabaseName(); + result->which_pipeline_type = + google_firestore_v1_ExecutePipelineRequest_structured_pipeline_tag; + result->pipeline_type.structured_pipeline = + serializer_.EncodePipeline(pipeline); + + return result; +} + +util::StatusOr +DatastoreSerializer::DecodeExecutePipelineResponse( + const grpc::ByteBuffer& response) const { + ByteBufferReader reader{response}; + auto message = + Message::TryParse(&reader); + if (!reader.ok()) { + return reader.status(); + } + + return serializer_.DecodePipelineResponse(reader.context(), message); +} + } // namespace remote } // namespace firestore } // namespace firebase diff --git a/Firestore/core/src/remote/remote_objc_bridge.h b/Firestore/core/src/remote/remote_objc_bridge.h index 0aa2b93f988..f6615003eed 100644 --- a/Firestore/core/src/remote/remote_objc_bridge.h +++ b/Firestore/core/src/remote/remote_objc_bridge.h @@ -32,6 +32,7 @@ #include "Firestore/core/src/util/status_fwd.h" #include "grpcpp/support/byte_buffer.h" +#include "Firestore/core/src/api/pipeline.h" #include "absl/container/flat_hash_map.h" namespace firebase { @@ -150,6 +151,13 @@ class DatastoreSerializer { return serializer_; } + nanopb::Message + EncodeExecutePipelineRequest( + const firebase::firestore::api::Pipeline& pipeline) const; + + util::StatusOr DecodeExecutePipelineResponse( + const grpc::ByteBuffer& response) const; + private: Serializer serializer_; }; diff --git a/Firestore/core/src/remote/remote_store.cc b/Firestore/core/src/remote/remote_store.cc index 86455fcd15e..1bf4370240b 100644 --- a/Firestore/core/src/remote/remote_store.cc +++ b/Firestore/core/src/remote/remote_store.cc @@ -390,6 +390,17 @@ void RemoteStore::RunAggregateQuery( } } +void RemoteStore::RunPipeline( + const api::Pipeline& pipeline, + util::StatusOrCallback result_callback) { + if (CanUseNetwork()) { + datastore_->RunPipeline(pipeline, std::move(result_callback)); + } else { + result_callback(Status::FromErrno(Error::kErrorUnavailable, + "Failed to get result from server.")); + } +} + // Write Stream void RemoteStore::FillWritePipeline() { diff --git a/Firestore/core/src/remote/remote_store.h b/Firestore/core/src/remote/remote_store.h index ae6bd7023bc..cd0d7b8e7ca 100644 --- a/Firestore/core/src/remote/remote_store.h +++ b/Firestore/core/src/remote/remote_store.h @@ -21,6 +21,7 @@ #include #include +#include "Firestore/core/src/api/pipeline.h" #include "Firestore/core/src/core/transaction.h" #include "Firestore/core/src/local/target_data.h" #include "Firestore/core/src/model/model_fwd.h" @@ -203,6 +204,9 @@ class RemoteStore : public TargetMetadataProvider, const std::vector& aggregates, api::AggregateQueryCallback&& result_callback); + void RunPipeline(const api::Pipeline& pipeline, + util::StatusOrCallback callback); + void OnWatchStreamOpen() override; void OnWatchStreamChange( const WatchChange& change, diff --git a/Firestore/core/src/remote/serializer.cc b/Firestore/core/src/remote/serializer.cc index f301a65e37f..2985f86d623 100644 --- a/Firestore/core/src/remote/serializer.cc +++ b/Firestore/core/src/remote/serializer.cc @@ -175,6 +175,15 @@ FieldPath InvalidFieldPath() { return FieldPath::EmptyPath(); } +absl::optional NotNoneVersionOrNullOpt( + const SnapshotVersion& version) { + if (version == SnapshotVersion::None()) { + return absl::nullopt; + } else { + return version; + } +} + } // namespace Serializer::Serializer(DatabaseId database_id) @@ -1197,6 +1206,26 @@ Serializer::DecodeCursorValue(google_firestore_v1_Cursor& cursor) const { return index_components; } +google_firestore_v1_StructuredPipeline Serializer::EncodePipeline( + const api::Pipeline& pipeline) const { + google_firestore_v1_StructuredPipeline result; + auto* stages = + MakeArray(pipeline.stages().size()); + + size_t i = 0; + for (const auto& stage : pipeline.stages()) { + stages[i++] = stage->to_proto(); + } + + result.pipeline.stages_count = pipeline.stages().size(); + result.pipeline.stages = stages; + + result.options_count = 0; + result.options = nullptr; + + return result; +} + /* static */ pb_bytes_array_t* Serializer::EncodeFieldPath(const FieldPath& field_path) { return EncodeString(field_path.CanonicalString()); @@ -1479,6 +1508,35 @@ bool Serializer::IsLocalDocumentKey(absl::string_view path) const { DocumentKey::IsDocumentKey(resource.PopFirst(5)); } +api::PipelineSnapshot Serializer::DecodePipelineResponse( + util::ReadContext* context, + const nanopb::Message& message) + const { + auto execution_time = DecodeVersion(context, message->execution_time); + + std::vector results(message->results_count); + + for (pb_size_t i = 0; i < message->results_count; ++i) { + absl::optional key; + if (message->results[i].name != nullptr) { + key = DecodeKey(context, message->results[i].name); + } + + auto create_time = DecodeVersion(context, message->results[i].create_time); + auto update_time = DecodeVersion(context, message->results[i].update_time); + + auto value = ObjectValue::FromFieldsEntry(message->results[i].fields, + message->results[i].fields_count); + results.push_back({std::move(key), + std::make_shared(std::move(value)), + NotNoneVersionOrNullOpt(create_time), + NotNoneVersionOrNullOpt(update_time), + NotNoneVersionOrNullOpt(execution_time)}); + } + + return api::PipelineSnapshot(std::move(results), execution_time); +} + } // namespace remote } // namespace firestore } // namespace firebase diff --git a/Firestore/core/src/remote/serializer.h b/Firestore/core/src/remote/serializer.h index c42c6c3ac1b..2105b7eb754 100644 --- a/Firestore/core/src/remote/serializer.h +++ b/Firestore/core/src/remote/serializer.h @@ -28,6 +28,7 @@ #include "Firestore/Protos/nanopb/google/firestore/v1/document.nanopb.h" #include "Firestore/Protos/nanopb/google/firestore/v1/firestore.nanopb.h" #include "Firestore/Protos/nanopb/google/type/latlng.nanopb.h" +#include "Firestore/core/src/api/pipeline.h" #include "Firestore/core/src/core/composite_filter.h" #include "Firestore/core/src/core/core_fwd.h" #include "Firestore/core/src/core/field_filter.h" @@ -204,6 +205,9 @@ class Serializer { pb_bytes_array_t* parent, google_firestore_v1_StructuredQuery& query) const; + google_firestore_v1_StructuredPipeline EncodePipeline( + const api::Pipeline& pipeline) const; + /** * Decodes the watch change. Modifies the provided proto to release * ownership of any Value messages. @@ -241,6 +245,11 @@ class Serializer { return database_id_; } + api::PipelineSnapshot DecodePipelineResponse( + util::ReadContext* context, + const nanopb::Message& + message) const; + private: friend class SerializerTest; From 15046ffadc8401a1fea100a5e3692406e0e2d828 Mon Sep 17 00:00:00 2001 From: wu-hui <53845758+wu-hui@users.noreply.github.com> Date: Mon, 24 Mar 2025 14:03:53 -0400 Subject: [PATCH 004/113] Add C++ stages/expressions and Constant value support (#14588) --- .../Source/API/FIRPipelineBridge+Internal.h | 11 +- Firestore/Source/API/FIRPipelineBridge.mm | 154 +++++++++-- .../FirebaseFirestore/FIRPipelineBridge.h | 6 +- .../Swift/Source/SwiftAPI/Expressions.swift | 30 ++- Firestore/Swift/Source/SwiftAPI/Stages.swift | 2 +- .../Tests/Integration/PipelineTests.swift | 5 +- .../core/src/api/aggregate_expressions.cc | 43 +++ .../core/src/api/aggregate_expressions.h | 50 ++++ Firestore/core/src/api/expressions.cc | 9 +- Firestore/core/src/api/expressions.h | 17 +- Firestore/core/src/api/ordering.cc | 47 ++++ Firestore/core/src/api/ordering.h | 52 ++++ Firestore/core/src/api/pipeline_result.h | 4 + Firestore/core/src/api/pipeline_snapshot.h | 9 + Firestore/core/src/api/stages.cc | 250 ++++++++++++++++++ Firestore/core/src/api/stages.h | 188 ++++++++++++- Firestore/core/src/remote/datastore.cc | 26 +- .../core/src/remote/remote_objc_bridge.cc | 14 +- .../core/src/remote/remote_objc_bridge.h | 3 +- 19 files changed, 849 insertions(+), 71 deletions(-) create mode 100644 Firestore/core/src/api/aggregate_expressions.cc create mode 100644 Firestore/core/src/api/aggregate_expressions.h create mode 100644 Firestore/core/src/api/ordering.cc create mode 100644 Firestore/core/src/api/ordering.h diff --git a/Firestore/Source/API/FIRPipelineBridge+Internal.h b/Firestore/Source/API/FIRPipelineBridge+Internal.h index bfe7befe923..30bee14aa02 100644 --- a/Firestore/Source/API/FIRPipelineBridge+Internal.h +++ b/Firestore/Source/API/FIRPipelineBridge+Internal.h @@ -19,6 +19,7 @@ #include #include "Firestore/core/src/api/expressions.h" +#include "Firestore/core/src/api/firestore.h" #include "Firestore/core/src/api/pipeline.h" #include "Firestore/core/src/api/stages.h" @@ -30,13 +31,13 @@ NS_ASSUME_NONNULL_BEGIN @interface FIRExprBridge (Internal) -- (std::shared_ptr)cpp_expr; +- (std::shared_ptr)cppExprWithReader:(FSTUserDataReader *)reader; @end @interface FIRStageBridge (Internal) -- (std::shared_ptr)cpp_stage; +- (std::shared_ptr)cppStageWithReader:(FSTUserDataReader *)reader; @end @@ -46,4 +47,10 @@ NS_ASSUME_NONNULL_BEGIN @end +@interface __FIRPipelineResultBridge (Internal) + +- (id)initWithCppResult:(api::PipelineResult)result db:(std::shared_ptr)db; + +@end + NS_ASSUME_NONNULL_END diff --git a/Firestore/Source/API/FIRPipelineBridge.mm b/Firestore/Source/API/FIRPipelineBridge.mm index 013cedcccab..c10a05f4d88 100644 --- a/Firestore/Source/API/FIRPipelineBridge.mm +++ b/Firestore/Source/API/FIRPipelineBridge.mm @@ -18,9 +18,15 @@ #include +#import "Firestore/Source/API/FIRDocumentReference+Internal.h" #import "Firestore/Source/API/FIRFirestore+Internal.h" #import "Firestore/Source/API/FIRPipelineBridge+Internal.h" +#import "Firestore/Source/API/FSTUserDataReader.h" +#import "Firestore/Source/API/FSTUserDataWriter.h" +#include "Firestore/Protos/nanopb/google/firestore/v1/document.nanopb.h" + +#include "Firestore/core/src/api/document_reference.h" #include "Firestore/core/src/api/expressions.h" #include "Firestore/core/src/api/pipeline.h" #include "Firestore/core/src/api/pipeline_result.h" @@ -32,12 +38,14 @@ using firebase::firestore::api::CollectionSource; using firebase::firestore::api::Constant; +using firebase::firestore::api::DocumentReference; using firebase::firestore::api::Expr; using firebase::firestore::api::Field; using firebase::firestore::api::FunctionExpr; using firebase::firestore::api::Pipeline; using firebase::firestore::api::Where; using firebase::firestore::util::MakeCallback; +using firebase::firestore::util::MakeNSString; using firebase::firestore::util::MakeString; NS_ASSUME_NONNULL_BEGIN @@ -57,7 +65,7 @@ - (id)init:(NSString *)name { return self; } -- (std::shared_ptr)cpp_expr { +- (std::shared_ptr)cppExprWithReader:(FSTUserDataReader *)reader { return field; } @@ -65,16 +73,22 @@ - (id)init:(NSString *)name { @implementation FIRConstantBridge { std::shared_ptr constant; + id _input; + Boolean isUserDataRead; } -- (id)init:(NSNumber *)value { +- (id)init:(id)input { self = [super init]; - if (self) { - constant = std::make_shared(value.doubleValue); - } + _input = input; + isUserDataRead = NO; return self; } -- (std::shared_ptr)cpp_expr { +- (std::shared_ptr)cppExprWithReader:(FSTUserDataReader *)reader { + if (!isUserDataRead) { + constant = std::make_shared([reader parsedQueryValue:_input]); + } + + isUserDataRead = YES; return constant; } @@ -82,22 +96,29 @@ - (id)init:(NSNumber *)value { @implementation FIRFunctionExprBridge { std::shared_ptr eq; + NSString *_name; + NSArray *_args; + Boolean isUserDataRead; } - (nonnull id)initWithName:(NSString *)name Args:(nonnull NSArray *)args { self = [super init]; - if (self) { + _name = name; + _args = args; + isUserDataRead = NO; + return self; +} + +- (std::shared_ptr)cppExprWithReader:(FSTUserDataReader *)reader { + if (!isUserDataRead) { std::vector> cpp_args; - for (FIRExprBridge *arg in args) { - cpp_args.push_back(arg.cpp_expr); + for (FIRExprBridge *arg in _args) { + cpp_args.push_back([arg cppExprWithReader:reader]); } - - eq = std::make_shared(MakeString(name), std::move(cpp_args)); + eq = std::make_shared(MakeString(_name), std::move(cpp_args)); } - return self; -} -- (std::shared_ptr)cpp_expr { + isUserDataRead = YES; return eq; } @@ -118,63 +139,142 @@ - (id)initWithPath:(NSString *)path { return self; } -- (std::shared_ptr)cpp_stage { +- (std::shared_ptr)cppStageWithReader:(FSTUserDataReader *)reader { return collection_source; } @end @implementation FIRWhereStageBridge { + FIRExprBridge *_exprBridge; + Boolean isUserDataRead; std::shared_ptr where; } - (id)initWithExpr:(FIRExprBridge *)expr { self = [super init]; if (self) { - where = std::make_shared(expr.cpp_expr); + _exprBridge = expr; + isUserDataRead = NO; } return self; } -- (std::shared_ptr)cpp_stage { +- (std::shared_ptr)cppStageWithReader:(FSTUserDataReader *)reader { + if (!isUserDataRead) { + where = std::make_shared([_exprBridge cppExprWithReader:reader]); + } + + isUserDataRead = YES; return where; } @end +@interface __FIRPipelineSnapshotBridge () + +@property(nonatomic, strong, readwrite) NSArray<__FIRPipelineSnapshotBridge *> *results; + +@end + @implementation __FIRPipelineSnapshotBridge { - absl::optional pipeline; + absl::optional snapshot_; + NSMutableArray<__FIRPipelineResultBridge *> *results_; } - (id)initWithCppSnapshot:(api::PipelineSnapshot)snapshot { self = [super init]; if (self) { - pipeline = std::move(snapshot); + snapshot_ = std::move(snapshot); + if (!snapshot_.has_value()) { + results_ = nil; + } else { + NSMutableArray<__FIRPipelineResultBridge *> *results = [NSMutableArray array]; + for (auto &result : snapshot_.value().results()) { + [results addObject:[[__FIRPipelineResultBridge alloc] + initWithCppResult:result + db:snapshot_.value().firestore()]]; + } + results_ = results; + } } return self; } +- (NSArray<__FIRPipelineResultBridge *> *)results { + return results_; +} + @end -@implementation FIRPipelineBridge { - std::shared_ptr pipeline; +@implementation __FIRPipelineResultBridge { + api::PipelineResult _result; + std::shared_ptr _db; } -- (id)initWithStages:(NSArray *)stages db:(FIRFirestore *)db { +- (FIRDocumentReference *)reference { + if (!_result.internal_key().has_value()) return nil; + + return [[FIRDocumentReference alloc] initWithKey:_result.internal_key().value() firestore:_db]; +} + +- (NSString *)documentID { + if (!_result.document_id().has_value()) { + return nil; + } + + return MakeNSString(_result.document_id().value()); +} + +- (id)initWithCppResult:(api::PipelineResult)result db:(std::shared_ptr)db { self = [super init]; if (self) { - std::vector> cpp_stages; - for (FIRStageBridge *stage in stages) { - cpp_stages.push_back(stage.cpp_stage); - } - pipeline = std::make_shared(cpp_stages, db.wrapped); + _result = std::move(result); + _db = std::move(db); } + return self; } +- (nullable NSDictionary *)data { + return [self dataWithServerTimestampBehavior:FIRServerTimestampBehaviorNone]; +} + +- (nullable NSDictionary *)dataWithServerTimestampBehavior: + (FIRServerTimestampBehavior)serverTimestampBehavior { + absl::optional data = + _result.internal_value()->Get(); + if (!data) return nil; + + FSTUserDataWriter *dataWriter = + [[FSTUserDataWriter alloc] initWithFirestore:_db + serverTimestampBehavior:serverTimestampBehavior]; + return [dataWriter convertedValue:*data]; +} + +@end + +@implementation FIRPipelineBridge { + NSArray *_stages; + FIRFirestore *firestore; + std::shared_ptr pipeline; +} + +- (id)initWithStages:(NSArray *)stages db:(FIRFirestore *)db { + _stages = stages; + firestore = db; + return [super init]; +} + - (void)executeWithCompletion:(void (^)(__FIRPipelineSnapshotBridge *_Nullable result, NSError *_Nullable error))completion { + std::vector> cpp_stages; + for (FIRStageBridge *stage in _stages) { + cpp_stages.push_back([stage cppStageWithReader:firestore.dataReader]); + } + pipeline = std::make_shared(cpp_stages, firestore.wrapped); + pipeline->execute([completion](StatusOr maybe_value) { if (maybe_value.ok()) { __FIRPipelineSnapshotBridge *bridge = [[__FIRPipelineSnapshotBridge alloc] diff --git a/Firestore/Source/Public/FirebaseFirestore/FIRPipelineBridge.h b/Firestore/Source/Public/FirebaseFirestore/FIRPipelineBridge.h index fa7472e3292..a27b2b7aa18 100644 --- a/Firestore/Source/Public/FirebaseFirestore/FIRPipelineBridge.h +++ b/Firestore/Source/Public/FirebaseFirestore/FIRPipelineBridge.h @@ -18,6 +18,8 @@ #import +#import "FIRDocumentSnapshot.h" + NS_ASSUME_NONNULL_BEGIN NS_SWIFT_NAME(ExprBridge) @@ -31,7 +33,7 @@ NS_SWIFT_NAME(FieldBridge) NS_SWIFT_NAME(ConstantBridge) @interface FIRConstantBridge : FIRExprBridge -- (id)init:(NSNumber *)value; +- (id)init:(id)input; @end NS_SWIFT_NAME(FunctionExprBridge) @@ -72,6 +74,8 @@ NS_SWIFT_NAME(__PipelineResultBridge) @property(nonatomic, copy, readonly) NSString *documentID; - (nullable NSDictionary *)data; +- (nullable NSDictionary *)dataWithServerTimestampBehavior: + (FIRServerTimestampBehavior)serverTimestampBehavior; @end diff --git a/Firestore/Swift/Source/SwiftAPI/Expressions.swift b/Firestore/Swift/Source/SwiftAPI/Expressions.swift index 729b5c9fb67..22af7ae6471 100644 --- a/Firestore/Swift/Source/SwiftAPI/Expressions.swift +++ b/Firestore/Swift/Source/SwiftAPI/Expressions.swift @@ -16,26 +16,28 @@ import Foundation -public protocol Expr { +public protocol Expr {} + +protocol BridgeWrapper { var bridge: ExprBridge { get } } -public struct Constant: Expr { - public var bridge: ExprBridge +public struct Constant: Expr, BridgeWrapper { + var bridge: ExprBridge - var value: any Numeric - init(value: any Numeric) { + var value: Any + init(value: Any) { self.value = value - bridge = ConstantBridge(value as! NSNumber) + bridge = ConstantBridge(value) } } -public func constant(_ number: any Numeric) -> Constant { +public func constant(_ number: Any) -> Constant { return Constant(value: number) } -public struct Field: Expr { - public var bridge: ExprBridge +public struct Field: Expr, BridgeWrapper { + var bridge: ExprBridge var name: String init(name: String) { @@ -52,8 +54,8 @@ protocol Function: Expr { var name: String { get } } -public struct FunctionExpr: Function { - public var bridge: ExprBridge +public struct FunctionExpr: Function, BridgeWrapper { + var bridge: ExprBridge var name: String private var args: [Expr] @@ -61,7 +63,11 @@ public struct FunctionExpr: Function { init(name: String, args: [Expr]) { self.name = name self.args = args - bridge = FunctionExprBridge(name: name, args: args.map { $0.bridge }) + bridge = FunctionExprBridge( + name: name, + args: args.map { ($0 as! (Expr & BridgeWrapper)).bridge + } + ) } } diff --git a/Firestore/Swift/Source/SwiftAPI/Stages.swift b/Firestore/Swift/Source/SwiftAPI/Stages.swift index df3c163e803..c5de0c00e52 100644 --- a/Firestore/Swift/Source/SwiftAPI/Stages.swift +++ b/Firestore/Swift/Source/SwiftAPI/Stages.swift @@ -42,6 +42,6 @@ class Where: Stage { init(condition: Expr) { self.condition = condition - bridge = WhereStageBridge(expr: condition.bridge) + bridge = WhereStageBridge(expr: (condition as! (Expr & BridgeWrapper)).bridge) } } diff --git a/Firestore/Swift/Tests/Integration/PipelineTests.swift b/Firestore/Swift/Tests/Integration/PipelineTests.swift index 79185762b91..a2252488312 100644 --- a/Firestore/Swift/Tests/Integration/PipelineTests.swift +++ b/Firestore/Swift/Tests/Integration/PipelineTests.swift @@ -20,10 +20,11 @@ import Foundation @available(iOS 13, tvOS 13, macOS 10.15, macCatalyst 13, watchOS 7, *) class PipelineIntegrationTests: FSTIntegrationTestCase { func testCount() async throws { + try await firestore().collection("foo").document("bar").setData(["foo": "bar", "x": 42]) let snapshot = try await firestore() .pipeline() - .collection(path: "foo") - .where(eq(field("foo"), constant(42))) + .collection(path: "/foo") + .where(eq(field("foo"), constant("bar"))) .execute() print(snapshot) diff --git a/Firestore/core/src/api/aggregate_expressions.cc b/Firestore/core/src/api/aggregate_expressions.cc new file mode 100644 index 00000000000..87fc69c368a --- /dev/null +++ b/Firestore/core/src/api/aggregate_expressions.cc @@ -0,0 +1,43 @@ +/* + * Copyright 2025 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. + */ + +#include "Firestore/core/src/api/aggregate_expressions.h" + +#include "Firestore/core/src/nanopb/nanopb_util.h" + +namespace firebase { +namespace firestore { +namespace api { + +google_firestore_v1_Value AggregateExpr::to_proto() const { + google_firestore_v1_Value result; + result.which_value_type = google_firestore_v1_Value_function_value_tag; + + result.function_value.name = nanopb::MakeBytesArray(name_); + result.function_value.args_count = static_cast(params_.size()); + result.function_value.args = nanopb::MakeArray( + result.function_value.args_count); + + for (size_t i = 0; i < params_.size(); ++i) { + result.function_value.args[i] = params_[i]->to_proto(); + } + + return result; +} + +} // namespace api +} // namespace firestore +} // namespace firebase diff --git a/Firestore/core/src/api/aggregate_expressions.h b/Firestore/core/src/api/aggregate_expressions.h new file mode 100644 index 00000000000..119198b2abd --- /dev/null +++ b/Firestore/core/src/api/aggregate_expressions.h @@ -0,0 +1,50 @@ +/* + * Copyright 2025 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. + */ + +#ifndef FIRESTORE_CORE_SRC_API_AGGREGATE_EXPRESSIONS_H_ +#define FIRESTORE_CORE_SRC_API_AGGREGATE_EXPRESSIONS_H_ + +#include +#include +#include +#include + +#include "Firestore/Protos/nanopb/google/firestore/v1/document.nanopb.h" +#include "Firestore/core/src/api/expressions.h" + +namespace firebase { +namespace firestore { +namespace api { + +class AggregateExpr { + public: + AggregateExpr(std::string name, std::vector> params) + : name_(std::move(name)), params_(std::move(params)) { + } + ~AggregateExpr() = default; + + google_firestore_v1_Value to_proto() const; + + private: + std::string name_; + std::vector> params_; +}; + +} // namespace api +} // namespace firestore +} // namespace firebase + +#endif // FIRESTORE_CORE_SRC_API_AGGREGATE_EXPRESSIONS_H_ diff --git a/Firestore/core/src/api/expressions.cc b/Firestore/core/src/api/expressions.cc index 07e99b1e848..7ec517f2aab 100644 --- a/Firestore/core/src/api/expressions.cc +++ b/Firestore/core/src/api/expressions.cc @@ -19,6 +19,7 @@ #include #include "Firestore/Protos/nanopb/google/firestore/v1/document.nanopb.h" +#include "Firestore/core/src/model/value_util.h" #include "Firestore/core/src/nanopb/nanopb_util.h" namespace firebase { @@ -35,12 +36,8 @@ google_firestore_v1_Value Field::to_proto() const { } google_firestore_v1_Value Constant::to_proto() const { - google_firestore_v1_Value result; - - result.which_value_type = google_firestore_v1_Value_double_value_tag; - result.double_value = this->value_; - - return result; + // Return a copy of the value proto to avoid double delete. + return *model::DeepClone(*value_).release(); } google_firestore_v1_Value FunctionExpr::to_proto() const { diff --git a/Firestore/core/src/api/expressions.h b/Firestore/core/src/api/expressions.h index 2ab134249cf..5b08a277e3b 100644 --- a/Firestore/core/src/api/expressions.h +++ b/Firestore/core/src/api/expressions.h @@ -23,6 +23,7 @@ #include #include "Firestore/Protos/nanopb/google/firestore/v1/document.nanopb.h" +#include "Firestore/core/src/nanopb/message.h" namespace firebase { namespace firestore { @@ -35,11 +36,20 @@ class Expr { virtual google_firestore_v1_Value to_proto() const = 0; }; -class Field : public Expr { +class Selectable : public Expr { + public: + virtual ~Selectable() = default; + virtual const std::string& alias() const = 0; +}; + +class Field : public Selectable { public: explicit Field(std::string name) : name_(std::move(name)) { } google_firestore_v1_Value to_proto() const override; + const std::string& alias() const override { + return name_; + } private: std::string name_; @@ -47,12 +57,13 @@ class Field : public Expr { class Constant : public Expr { public: - explicit Constant(double value) : value_(value) { + explicit Constant(nanopb::SharedMessage value) + : value_(std::move(value)) { } google_firestore_v1_Value to_proto() const override; private: - double value_; + nanopb::SharedMessage value_; }; class FunctionExpr : public Expr { diff --git a/Firestore/core/src/api/ordering.cc b/Firestore/core/src/api/ordering.cc new file mode 100644 index 00000000000..6520cea5b6f --- /dev/null +++ b/Firestore/core/src/api/ordering.cc @@ -0,0 +1,47 @@ +/* + * Copyright 2025 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. + */ + +#include "Firestore/core/src/api/ordering.h" + +#include "Firestore/Protos/nanopb/google/firestore/v1/document.nanopb.h" +#include "Firestore/core/src/nanopb/nanopb_util.h" + +namespace firebase { +namespace firestore { +namespace api { + +google_firestore_v1_Value Ordering::to_proto() const { + google_firestore_v1_Value result; + result.which_value_type = google_firestore_v1_Value_map_value_tag; + + result.map_value.fields_count = 2; + result.map_value.fields = + nanopb::MakeArray(2); + result.map_value.fields[0].key = nanopb::MakeBytesArray("expression"); + result.map_value.fields[0].value = field_.to_proto(); + result.map_value.fields[1].key = nanopb::MakeBytesArray("direction"); + google_firestore_v1_Value direction; + direction.which_value_type = google_firestore_v1_Value_string_value_tag; + direction.string_value = nanopb::MakeBytesArray( + this->direction_ == ASCENDING ? "ascending" : "descending"); + result.map_value.fields[1].value = direction; + + return result; +} + +} // namespace api +} // namespace firestore +} // namespace firebase diff --git a/Firestore/core/src/api/ordering.h b/Firestore/core/src/api/ordering.h new file mode 100644 index 00000000000..130dda12b19 --- /dev/null +++ b/Firestore/core/src/api/ordering.h @@ -0,0 +1,52 @@ +/* + * Copyright 2025 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. + */ + +#ifndef FIRESTORE_CORE_SRC_API_ORDERING_H_ +#define FIRESTORE_CORE_SRC_API_ORDERING_H_ + +#include + +#include "Firestore/core/src/api/expressions.h" + +namespace firebase { +namespace firestore { +namespace api { + +class UserDataReader; // forward declaration + +class Ordering { + public: + enum Direction { + ASCENDING, + DESCENDING, + }; + + Ordering(Field field, Direction direction) + : field_(std::move(field)), direction_(direction) { + } + + google_firestore_v1_Value to_proto() const; + + private: + Field field_; + Direction direction_; +}; + +} // namespace api +} // namespace firestore +} // namespace firebase + +#endif // FIRESTORE_CORE_SRC_API_ORDERING_H_ diff --git a/Firestore/core/src/api/pipeline_result.h b/Firestore/core/src/api/pipeline_result.h index 4680d058c7b..53761752cdc 100644 --- a/Firestore/core/src/api/pipeline_result.h +++ b/Firestore/core/src/api/pipeline_result.h @@ -53,6 +53,10 @@ class PipelineResult { std::shared_ptr internal_value() const; absl::optional document_id() const; + const absl::optional& internal_key() const { + return internal_key_; + } + private: absl::optional internal_key_; // Using a shared pointer to ObjectValue makes PipelineResult copy-assignable diff --git a/Firestore/core/src/api/pipeline_snapshot.h b/Firestore/core/src/api/pipeline_snapshot.h index a19e76138a7..079f2d57375 100644 --- a/Firestore/core/src/api/pipeline_snapshot.h +++ b/Firestore/core/src/api/pipeline_snapshot.h @@ -41,9 +41,18 @@ class PipelineSnapshot { return results_; } + const std::shared_ptr firestore() const { + return firestore_; + } + + void SetFirestore(std::shared_ptr db) { + firestore_ = std::move(db); + } + private: std::vector results_; model::SnapshotVersion execution_time_; + std::shared_ptr firestore_; }; } // namespace api diff --git a/Firestore/core/src/api/stages.cc b/Firestore/core/src/api/stages.cc index 6843a1b4ce5..eaa19cb03bd 100644 --- a/Firestore/core/src/api/stages.cc +++ b/Firestore/core/src/api/stages.cc @@ -16,6 +16,11 @@ #include "Firestore/core/src/api/stages.h" +#include +#include + +#include "Firestore/Protos/nanopb/google/firestore/v1/document.nanopb.h" +#include "Firestore/core/src/nanopb/message.h" #include "Firestore/core/src/nanopb/nanopb_util.h" namespace firebase { @@ -39,6 +44,112 @@ google_firestore_v1_Pipeline_Stage CollectionSource::to_proto() const { return result; } +google_firestore_v1_Pipeline_Stage DatabaseSource::to_proto() const { + google_firestore_v1_Pipeline_Stage result; + + result.name = nanopb::MakeBytesArray("database"); + result.args_count = 0; + result.args = nullptr; + result.options_count = 0; + result.options = nullptr; + + return result; +} + +google_firestore_v1_Pipeline_Stage CollectionGroupSource::to_proto() const { + google_firestore_v1_Pipeline_Stage result; + + result.name = nanopb::MakeBytesArray("collection_group"); + + result.args_count = 2; + result.args = nanopb::MakeArray(2); + // First argument is an empty reference value. + result.args[0].which_value_type = + google_firestore_v1_Value_reference_value_tag; + result.args[0].reference_value = nanopb::MakeBytesArray(""); + + // Second argument is the collection ID (encoded as a string value). + result.args[1].which_value_type = google_firestore_v1_Value_string_value_tag; + result.args[1].string_value = nanopb::MakeBytesArray(collection_id_); + + result.options_count = 0; + result.options = nullptr; + + return result; +} + +google_firestore_v1_Pipeline_Stage DocumentsSource::to_proto() const { + google_firestore_v1_Pipeline_Stage result; + + result.name = nanopb::MakeBytesArray("documents"); + + result.args_count = documents_.size(); + result.args = nanopb::MakeArray(result.args_count); + + for (size_t i = 0; i < documents_.size(); ++i) { + result.args[i].which_value_type = + google_firestore_v1_Value_string_value_tag; + result.args[i].string_value = nanopb::MakeBytesArray(documents_[i]); + } + + result.options_count = 0; + result.options = nullptr; + + return result; +} + +google_firestore_v1_Pipeline_Stage AddFields::to_proto() const { + google_firestore_v1_Pipeline_Stage result; + result.name = nanopb::MakeBytesArray("add_fields"); + + result.args_count = 1; + result.args = nanopb::MakeArray(1); + + result.args[0].which_value_type = google_firestore_v1_Value_map_value_tag; + nanopb::SetRepeatedField( + &result.args[0].map_value.fields, &result.args[0].map_value.fields_count, + fields_, [](const std::shared_ptr& entry) { + return _google_firestore_v1_MapValue_FieldsEntry{ + nanopb::MakeBytesArray(entry->alias()), entry->to_proto()}; + }); + + result.options_count = 0; + result.options = nullptr; + return result; +} + +google_firestore_v1_Pipeline_Stage AggregateStage::to_proto() const { + google_firestore_v1_Pipeline_Stage result; + result.name = nanopb::MakeBytesArray("aggregate"); + + result.args_count = 2; + result.args = nanopb::MakeArray(2); + + // Encode accumulators map. + result.args[0].which_value_type = google_firestore_v1_Value_map_value_tag; + nanopb::SetRepeatedField( + &result.args[0].map_value.fields, &result.args[0].map_value.fields_count, + this->accumulators_, + [](const std::pair>& entry) { + return _google_firestore_v1_MapValue_FieldsEntry{ + nanopb::MakeBytesArray(entry.first), entry.second->to_proto()}; + }); + + // Encode groups map. + result.args[1].which_value_type = google_firestore_v1_Value_map_value_tag; + nanopb::SetRepeatedField( + &result.args[1].map_value.fields, &result.args[1].map_value.fields_count, + this->groups_, + [](const std::pair>& entry) { + return _google_firestore_v1_MapValue_FieldsEntry{ + nanopb::MakeBytesArray(entry.first), entry.second->to_proto()}; + }); + + result.options_count = 0; + result.options = nullptr; + return result; +} + google_firestore_v1_Pipeline_Stage Where::to_proto() const { google_firestore_v1_Pipeline_Stage result; @@ -54,6 +165,145 @@ google_firestore_v1_Pipeline_Stage Where::to_proto() const { return result; } +google_firestore_v1_Value FindNearestStage::DistanceMeasure::proto() const { + google_firestore_v1_Value result; + result.which_value_type = google_firestore_v1_Value_string_value_tag; + switch (measure_) { + case EUCLIDEAN: + result.string_value = nanopb::MakeBytesArray("euclidean"); + break; + case COSINE: + result.string_value = nanopb::MakeBytesArray("cosine"); + break; + case DOT_PRODUCT: + result.string_value = nanopb::MakeBytesArray("dot_product"); + break; + } + return result; +} + +google_firestore_v1_Pipeline_Stage FindNearestStage::to_proto() const { + google_firestore_v1_Pipeline_Stage result; + result.name = nanopb::MakeBytesArray("find_nearest"); + + result.args_count = 3; + result.args = nanopb::MakeArray(3); + result.args[0] = property_->to_proto(); + result.args[1] = *vector_; + result.args[2] = distance_measure_.proto(); + + nanopb::SetRepeatedField( + &result.options, &result.options_count, options_, + [](const std::pair>& + entry) { + return _google_firestore_v1_Pipeline_Stage_OptionsEntry{ + nanopb::MakeBytesArray(entry.first), *entry.second}; + }); + + return result; +} + +google_firestore_v1_Pipeline_Stage LimitStage::to_proto() const { + google_firestore_v1_Pipeline_Stage result; + result.name = nanopb::MakeBytesArray("limit"); + + result.args_count = 1; + result.args = nanopb::MakeArray(1); + result.args[0].which_value_type = google_firestore_v1_Value_integer_value_tag; + result.args[0].integer_value = limit_; + + result.options_count = 0; + result.options = nullptr; + return result; +} + +google_firestore_v1_Pipeline_Stage OffsetStage::to_proto() const { + google_firestore_v1_Pipeline_Stage result; + result.name = nanopb::MakeBytesArray("offset"); + + result.args_count = 1; + result.args = nanopb::MakeArray(1); + result.args[0].which_value_type = google_firestore_v1_Value_integer_value_tag; + result.args[0].integer_value = offset_; + + result.options_count = 0; + result.options = nullptr; + return result; +} + +google_firestore_v1_Pipeline_Stage SelectStage::to_proto() const { + google_firestore_v1_Pipeline_Stage result; + result.name = nanopb::MakeBytesArray("select"); + + result.args_count = 1; + result.args = nanopb::MakeArray(1); + + result.args[0].which_value_type = google_firestore_v1_Value_map_value_tag; + nanopb::SetRepeatedField( + &result.args[0].map_value.fields, &result.args[0].map_value.fields_count, + fields_, [](const std::shared_ptr& entry) { + return _google_firestore_v1_MapValue_FieldsEntry{ + nanopb::MakeBytesArray(entry->alias()), entry->to_proto()}; + }); + + result.options_count = 0; + result.options = nullptr; + return result; +} + +google_firestore_v1_Pipeline_Stage SortStage::to_proto() const { + google_firestore_v1_Pipeline_Stage result; + result.name = nanopb::MakeBytesArray("sort"); + + result.args_count = static_cast(orders_.size()); + result.args = nanopb::MakeArray(result.args_count); + + for (size_t i = 0; i < orders_.size(); ++i) { + result.args[i] = orders_[i].to_proto(); + } + + result.options_count = 0; + result.options = nullptr; + return result; +} + +google_firestore_v1_Pipeline_Stage DistinctStage::to_proto() const { + google_firestore_v1_Pipeline_Stage result; + result.name = nanopb::MakeBytesArray("distinct"); + + result.args_count = 1; + result.args = nanopb::MakeArray(1); + + result.args[0].which_value_type = google_firestore_v1_Value_map_value_tag; + nanopb::SetRepeatedField( + &result.args[0].map_value.fields, &result.args[0].map_value.fields_count, + groups_, [](const std::shared_ptr& entry) { + return _google_firestore_v1_MapValue_FieldsEntry{ + nanopb::MakeBytesArray(entry->alias()), entry->to_proto()}; + }); + + result.options_count = 0; + result.options = nullptr; + return result; +} + +google_firestore_v1_Pipeline_Stage RemoveFieldsStage::to_proto() const { + google_firestore_v1_Pipeline_Stage result; + result.name = nanopb::MakeBytesArray("remove_fields"); + + result.args_count = static_cast(fields_.size()); + result.args = nanopb::MakeArray(result.args_count); + + for (size_t i = 0; i < fields_.size(); ++i) { + result.args[i] = fields_[i].to_proto(); + } + + result.options_count = 0; + result.options = nullptr; + return result; +} + } // namespace api } // namespace firestore } // namespace firebase diff --git a/Firestore/core/src/api/stages.h b/Firestore/core/src/api/stages.h index f037a70408e..11534278002 100644 --- a/Firestore/core/src/api/stages.h +++ b/Firestore/core/src/api/stages.h @@ -19,9 +19,15 @@ #include #include +#include +#include +#include #include "Firestore/Protos/nanopb/google/firestore/v1/document.nanopb.h" +#include "Firestore/core/src/api/aggregate_expressions.h" #include "Firestore/core/src/api/expressions.h" +#include "Firestore/core/src/api/ordering.h" +#include "Firestore/core/src/nanopb/message.h" namespace firebase { namespace firestore { @@ -37,7 +43,7 @@ class Stage { class CollectionSource : public Stage { public: - explicit CollectionSource(std::string path) : path_(path) { + explicit CollectionSource(std::string path) : path_(std::move(path)) { } ~CollectionSource() override = default; @@ -47,9 +53,71 @@ class CollectionSource : public Stage { std::string path_; }; +class DatabaseSource : public Stage { + public: + DatabaseSource() = default; + ~DatabaseSource() override = default; + + google_firestore_v1_Pipeline_Stage to_proto() const override; +}; + +class CollectionGroupSource : public Stage { + public: + explicit CollectionGroupSource(std::string collection_id) + : collection_id_(std::move(collection_id)) { + } + ~CollectionGroupSource() override = default; + + google_firestore_v1_Pipeline_Stage to_proto() const override; + + private: + std::string collection_id_; +}; + +class DocumentsSource : public Stage { + public: + explicit DocumentsSource(std::vector documents) + : documents_(std::move(documents)) { + } + ~DocumentsSource() override = default; + + google_firestore_v1_Pipeline_Stage to_proto() const override; + + private: + std::vector documents_; +}; + +class AddFields : public Stage { + public: + explicit AddFields(std::vector> fields) + : fields_(std::move(fields)) { + } + ~AddFields() override = default; + + google_firestore_v1_Pipeline_Stage to_proto() const override; + + private: + std::vector> fields_; +}; + +class AggregateStage : public Stage { + public: + AggregateStage(std::unordered_map> + accumulators, + std::unordered_map> groups) + : accumulators_(std::move(accumulators)), groups_(std::move(groups)) { + } + + google_firestore_v1_Pipeline_Stage to_proto() const override; + + private: + std::unordered_map> accumulators_; + std::unordered_map> groups_; +}; + class Where : public Stage { public: - explicit Where(std::shared_ptr expr) : expr_(expr) { + explicit Where(std::shared_ptr expr) : expr_(std::move(expr)) { } ~Where() override = default; @@ -59,6 +127,122 @@ class Where : public Stage { std::shared_ptr expr_; }; +class FindNearestStage : public Stage { + public: + class DistanceMeasure { + public: + enum Measure { EUCLIDEAN, COSINE, DOT_PRODUCT }; + + explicit DistanceMeasure(Measure measure) : measure_(measure) { + } + google_firestore_v1_Value proto() const; + + private: + Measure measure_; + }; + + FindNearestStage( + std::shared_ptr property, + nanopb::SharedMessage vector, + DistanceMeasure distance_measure, + std::unordered_map> + options) + : property_(std::move(property)), + vector_(std::move(vector)), + distance_measure_(distance_measure), + options_(options) { + } + + ~FindNearestStage() override = default; + + google_firestore_v1_Pipeline_Stage to_proto() const override; + + private: + std::shared_ptr property_; + nanopb::SharedMessage vector_; + DistanceMeasure distance_measure_; + std::unordered_map> + options_; +}; + +class LimitStage : public Stage { + public: + explicit LimitStage(int64_t limit) : limit_(limit) { + } + ~LimitStage() override = default; + + google_firestore_v1_Pipeline_Stage to_proto() const override; + + private: + int64_t limit_; +}; + +class OffsetStage : public Stage { + public: + explicit OffsetStage(int64_t offset) : offset_(offset) { + } + ~OffsetStage() override = default; + + google_firestore_v1_Pipeline_Stage to_proto() const override; + + private: + int64_t offset_; +}; + +class SelectStage : public Stage { + public: + explicit SelectStage(std::vector> fields) + : fields_(std::move(fields)) { + } + ~SelectStage() override = default; + + google_firestore_v1_Pipeline_Stage to_proto() const override; + + private: + std::vector> fields_; +}; + +class SortStage : public Stage { + public: + explicit SortStage(std::vector orders) + : orders_(std::move(orders)) { + } + ~SortStage() override = default; + + google_firestore_v1_Pipeline_Stage to_proto() const override; + + private: + std::vector orders_; +}; + +class DistinctStage : public Stage { + public: + explicit DistinctStage(std::vector> groups) + : groups_(std::move(groups)) { + } + ~DistinctStage() override = default; + + google_firestore_v1_Pipeline_Stage to_proto() const override; + + private: + std::vector> groups_; +}; + +class RemoveFieldsStage : public Stage { + public: + explicit RemoveFieldsStage(std::vector fields) + : fields_(std::move(fields)) { + } + ~RemoveFieldsStage() override = default; + + google_firestore_v1_Pipeline_Stage to_proto() const override; + + private: + std::vector fields_; +}; + } // namespace api } // namespace firestore } // namespace firebase diff --git a/Firestore/core/src/remote/datastore.cc b/Firestore/core/src/remote/datastore.cc index d5950ca09c6..504beadbd99 100644 --- a/Firestore/core/src/remote/datastore.cc +++ b/Firestore/core/src/remote/datastore.cc @@ -340,20 +340,22 @@ void Datastore::RunPipelineWithCredentials( GrpcUnaryCall* call = call_owning.get(); active_calls_.push_back(std::move(call_owning)); - call->Start([this, call, callback = std::move(callback)]( - const StatusOr& result) { - LogGrpcCallFinished("ExecutePipeline", call, result.status()); - HandleCallStatus(result.status()); + call->Start( + [this, db = pipeline.firestore(), call, callback = std::move(callback)]( + const StatusOr& result) { + LogGrpcCallFinished("ExecutePipeline", call, result.status()); + HandleCallStatus(result.status()); - if (result.ok()) { - callback(datastore_serializer_.DecodeExecutePipelineResponse( - result.ValueOrDie())); - } else { - callback(result.status()); - } + if (result.ok()) { + auto response = datastore_serializer_.DecodeExecutePipelineResponse( + result.ValueOrDie(), std::move(db)); + callback(response); + } else { + callback(result.status()); + } - RemoveGrpcCall(call); - }); + RemoveGrpcCall(call); + }); } void Datastore::ResumeRpcWithCredentials(const OnCredentials& on_credentials) { diff --git a/Firestore/core/src/remote/remote_objc_bridge.cc b/Firestore/core/src/remote/remote_objc_bridge.cc index 466ed1229cc..6cc675d4f7f 100644 --- a/Firestore/core/src/remote/remote_objc_bridge.cc +++ b/Firestore/core/src/remote/remote_objc_bridge.cc @@ -33,6 +33,7 @@ #include "Firestore/core/src/remote/grpc_util.h" #include "Firestore/core/src/remote/watch_change.h" #include "Firestore/core/src/util/hard_assert.h" +#include "Firestore/core/src/util/log.h" #include "Firestore/core/src/util/status.h" #include "Firestore/core/src/util/statusor.h" #include "grpcpp/support/status.h" @@ -398,7 +399,8 @@ DatastoreSerializer::EncodeExecutePipelineRequest( util::StatusOr DatastoreSerializer::DecodeExecutePipelineResponse( - const grpc::ByteBuffer& response) const { + const grpc::ByteBuffer& response, + std::shared_ptr db) const { ByteBufferReader reader{response}; auto message = Message::TryParse(&reader); @@ -406,7 +408,15 @@ DatastoreSerializer::DecodeExecutePipelineResponse( return reader.status(); } - return serializer_.DecodePipelineResponse(reader.context(), message); + LOG_DEBUG("Pipeline Response: %s", message.ToString()); + + auto snapshot = serializer_.DecodePipelineResponse(reader.context(), message); + if (!reader.ok()) { + return reader.status(); + } + + snapshot.SetFirestore(std::move(db)); + return snapshot; } } // namespace remote diff --git a/Firestore/core/src/remote/remote_objc_bridge.h b/Firestore/core/src/remote/remote_objc_bridge.h index f6615003eed..96329c1ae25 100644 --- a/Firestore/core/src/remote/remote_objc_bridge.h +++ b/Firestore/core/src/remote/remote_objc_bridge.h @@ -156,7 +156,8 @@ class DatastoreSerializer { const firebase::firestore::api::Pipeline& pipeline) const; util::StatusOr DecodeExecutePipelineResponse( - const grpc::ByteBuffer& response) const; + const grpc::ByteBuffer& response, + std::shared_ptr db) const; private: Serializer serializer_; From abd856035f6e92991f3db656c15713b02e1000f2 Mon Sep 17 00:00:00 2001 From: cherylEnkidu Date: Fri, 25 Apr 2025 14:27:22 -0400 Subject: [PATCH 005/113] Manually set cmake version --- .github/workflows/firestore.yml | 20 ++++++++++++++++++++ scripts/install_prereqs.sh | 1 - 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/.github/workflows/firestore.yml b/.github/workflows/firestore.yml index 9d1ccf875b0..f433b884c2c 100644 --- a/.github/workflows/firestore.yml +++ b/.github/workflows/firestore.yml @@ -142,6 +142,11 @@ jobs: with: python-version: '3.11' + - name: Setup cmake + uses: jwlawson/actions-setup-cmake@v2 + with: + cmake-version: '3.16.x' + - name: Setup build run: scripts/install_prereqs.sh Firestore ${{ runner.os }} cmake @@ -230,6 +235,11 @@ jobs: GOOGLE_APPLICATION_CREDENTIALS: ../google-service-account.json continue-on-error: true + - name: Setup cmake + uses: jwlawson/actions-setup-cmake@v2 + with: + cmake-version: '3.16.x' + - name: Setup build run: scripts/install_prereqs.sh Firestore ${{ runner.os }} cmake @@ -271,6 +281,11 @@ jobs: with: python-version: '3.11' + - name: Setup cmake + uses: jwlawson/actions-setup-cmake@v2 + with: + cmake-version: '3.16.x' + - name: Setup build run: scripts/install_prereqs.sh Firestore ${{ runner.os }} cmake @@ -317,6 +332,11 @@ jobs: with: python-version: '3.11' + - name: Setup cmake + uses: jwlawson/actions-setup-cmake@v2 + with: + cmake-version: '3.16.x' + - name: Setup build run: scripts/install_prereqs.sh Firestore ${{ runner.os }} cmake diff --git a/scripts/install_prereqs.sh b/scripts/install_prereqs.sh index 079ff6076ac..e35507de6bc 100755 --- a/scripts/install_prereqs.sh +++ b/scripts/install_prereqs.sh @@ -104,7 +104,6 @@ case "$project-$platform-$method" in ;; Firestore-iOS-cmake | Firestore-tvOS-cmake | Firestore-macOS-cmake) - brew outdated cmake || brew upgrade cmake brew outdated go || brew upgrade go # Somehow the build for Abseil requires this. brew install ccache brew install ninja From fc8220fb287519c980d48b95748733ca4230d051 Mon Sep 17 00:00:00 2001 From: cherylEnkidu <96084918+cherylEnkidu@users.noreply.github.com> Date: Fri, 25 Apr 2025 15:32:47 -0400 Subject: [PATCH 006/113] Update firestore.yml --- .github/workflows/firestore.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/firestore.yml b/.github/workflows/firestore.yml index f433b884c2c..7bc5eba6732 100644 --- a/.github/workflows/firestore.yml +++ b/.github/workflows/firestore.yml @@ -145,7 +145,7 @@ jobs: - name: Setup cmake uses: jwlawson/actions-setup-cmake@v2 with: - cmake-version: '3.16.x' + cmake-version: '3.31.1' - name: Setup build run: scripts/install_prereqs.sh Firestore ${{ runner.os }} cmake @@ -238,7 +238,7 @@ jobs: - name: Setup cmake uses: jwlawson/actions-setup-cmake@v2 with: - cmake-version: '3.16.x' + cmake-version: '3.31.1' - name: Setup build run: scripts/install_prereqs.sh Firestore ${{ runner.os }} cmake @@ -284,7 +284,7 @@ jobs: - name: Setup cmake uses: jwlawson/actions-setup-cmake@v2 with: - cmake-version: '3.16.x' + cmake-version: '3.31.1' - name: Setup build run: scripts/install_prereqs.sh Firestore ${{ runner.os }} cmake @@ -335,7 +335,7 @@ jobs: - name: Setup cmake uses: jwlawson/actions-setup-cmake@v2 with: - cmake-version: '3.16.x' + cmake-version: '3.31.1' - name: Setup build run: scripts/install_prereqs.sh Firestore ${{ runner.os }} cmake From 54b5b9f3177e32835e8b12be6aeea963264836f8 Mon Sep 17 00:00:00 2001 From: cherylEnkidu Date: Fri, 25 Apr 2025 16:13:53 -0400 Subject: [PATCH 007/113] set flag --- .github/workflows/firestore.yml | 4 ++++ scripts/install_prereqs.sh | 7 +++++++ 2 files changed, 11 insertions(+) diff --git a/.github/workflows/firestore.yml b/.github/workflows/firestore.yml index 7bc5eba6732..a8ed245cc76 100644 --- a/.github/workflows/firestore.yml +++ b/.github/workflows/firestore.yml @@ -118,6 +118,7 @@ jobs: env: MINT_PATH: ${{ github.workspace }}/mint + USE_LATEST_CMAKE: false runs-on: ${{ matrix.os }} steps: @@ -173,6 +174,7 @@ jobs: plist_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} MINT_PATH: ${{ github.workspace }}/mint TARGET_DATABASE_ID: ${{ matrix.databaseId }} + USE_LATEST_CMAKE: false runs-on: ${{ matrix.os }} steps: @@ -265,6 +267,7 @@ jobs: env: SANITIZERS: ${{ matrix.sanitizer }} + USE_LATEST_CMAKE: false steps: - uses: actions/checkout@v4 @@ -316,6 +319,7 @@ jobs: env: SANITIZERS: ${{ matrix.sanitizer }} ASAN_OPTIONS: detect_leaks=0 + USE_LATEST_CMAKE: false steps: - uses: actions/checkout@v3 diff --git a/scripts/install_prereqs.sh b/scripts/install_prereqs.sh index e35507de6bc..1b0177e16fe 100755 --- a/scripts/install_prereqs.sh +++ b/scripts/install_prereqs.sh @@ -104,6 +104,13 @@ case "$project-$platform-$method" in ;; Firestore-iOS-cmake | Firestore-tvOS-cmake | Firestore-macOS-cmake) + # Only upgrade CMake if explicitly requested + if [[ "${USE_LATEST_CMAKE:-false}" == "true" ]]; then + echo "Use latest CMake because USE_LATEST_CMAKE=true" + brew outdated cmake || brew upgrade cmake + else + echo "Skipping CMake upgrade" + fi brew outdated go || brew upgrade go # Somehow the build for Abseil requires this. brew install ccache brew install ninja From 11ae3e2c490e5c992d8c8453e720c3448958b619 Mon Sep 17 00:00:00 2001 From: cherylEnkidu <96084918+cherylEnkidu@users.noreply.github.com> Date: Tue, 20 May 2025 21:00:53 -0400 Subject: [PATCH 008/113] Ppl API (#14513) Co-authored-by: wu-hui Co-authored-by: Nick Cooke <36927374+ncooke3@users.noreply.github.com> --- .github/workflows/firestore-nightly.yml | 8 + .gitignore | 1 + .../Firestore.xcodeproj/project.pbxproj | 124 +- .../Tests/Util/FSTIntegrationTestCase.h | 2 + .../Tests/Util/FSTIntegrationTestCase.mm | 5 + .../Source/API/FIRPipelineBridge+Internal.h | 12 + Firestore/Source/API/FIRPipelineBridge.mm | 713 +++++++- .../FirebaseFirestore/FIRPipelineBridge.h | 169 +- Firestore/Swift/Source/ExprImpl.swift | 607 +++++++ .../Swift/Source/Helper/PipelineHelper.swift | 51 + Firestore/Swift/Source/PipelineWrapper.swift | 26 + .../Swift/Source/SwiftAPI/Expressions.swift | 76 - .../Source/SwiftAPI/Firestore+Pipeline.swift | 8 +- .../Swift/Source/SwiftAPI/Pipeline.swift | 45 - .../Aggregation/AggregateFunction.swift | 34 + .../Aggregation/AggregateWithAlias.swift | 18 + .../Pipeline/Aggregation/CountAll.swift | 19 + .../SwiftAPI/Pipeline/ArrayContains.swift | 19 + .../Source/SwiftAPI/Pipeline/Ascending.swift | 19 + .../Source/SwiftAPI/Pipeline/Descending.swift | 19 + .../SwiftAPI/Pipeline/DistanceMeasure.swift | 47 + .../Swift/Source/SwiftAPI/Pipeline/Expr.swift | 1558 +++++++++++++++++ .../SwiftAPI/Pipeline/Expr/Constant.swift | 77 + .../SwiftAPI/Pipeline/Expr/DocumentId.swift | 19 + .../Source/SwiftAPI/Pipeline/Expr/Field.swift | 32 + .../SwiftAPI/Pipeline/Expr/FunctionExpr.swift | 30 + .../Expr/FunctionExpr/BooleanExpr.swift | 33 + .../SwiftAPI/Pipeline/ExprWithAlias.swift | 24 + .../Source/SwiftAPI/Pipeline/Ordering.swift | 50 + .../Source/SwiftAPI/Pipeline/Pipeline.swift | 722 ++++++++ .../SwiftAPI/Pipeline/PipelineResult.swift | 70 + .../SwiftAPI/Pipeline/PipelineSnapshot.swift | 45 + .../SwiftAPI/Pipeline/PipelineSource.swift | 56 + .../SwiftAPI/Pipeline/RealtimePipeline.swift | 15 + .../Source/SwiftAPI/Pipeline/Selectable.swift | 15 + .../Source/SwiftAPI/Pipeline/TimeUnit.swift | 37 + .../Source/SwiftAPI/PipelineSnapshot.swift | 25 - .../Source/SwiftAPI/PipelineSource.swift | 28 - Firestore/Swift/Source/SwiftAPI/Stages.swift | 323 +++- .../Tests/Integration/PipelineApiTests.swift | 404 +++++ .../Tests/Integration/PipelineTests.swift | 140 +- .../core/src/api/aggregate_expressions.cc | 2 +- .../core/src/api/aggregate_expressions.h | 6 +- Firestore/core/src/api/expressions.h | 10 +- Firestore/core/src/api/ordering.cc | 2 +- Firestore/core/src/api/ordering.h | 17 +- Firestore/core/src/api/pipeline.cc | 14 + Firestore/core/src/api/pipeline.h | 2 + Firestore/core/src/api/pipeline_result.h | 8 + Firestore/core/src/api/pipeline_snapshot.h | 4 + Firestore/core/src/api/stages.cc | 139 +- Firestore/core/src/api/stages.h | 94 +- Firestore/core/src/remote/serializer.cc | 13 +- 53 files changed, 5715 insertions(+), 321 deletions(-) create mode 100644 Firestore/Swift/Source/ExprImpl.swift create mode 100644 Firestore/Swift/Source/Helper/PipelineHelper.swift create mode 100644 Firestore/Swift/Source/PipelineWrapper.swift delete mode 100644 Firestore/Swift/Source/SwiftAPI/Expressions.swift delete mode 100644 Firestore/Swift/Source/SwiftAPI/Pipeline.swift create mode 100644 Firestore/Swift/Source/SwiftAPI/Pipeline/Aggregation/AggregateFunction.swift create mode 100644 Firestore/Swift/Source/SwiftAPI/Pipeline/Aggregation/AggregateWithAlias.swift create mode 100644 Firestore/Swift/Source/SwiftAPI/Pipeline/Aggregation/CountAll.swift create mode 100644 Firestore/Swift/Source/SwiftAPI/Pipeline/ArrayContains.swift create mode 100644 Firestore/Swift/Source/SwiftAPI/Pipeline/Ascending.swift create mode 100644 Firestore/Swift/Source/SwiftAPI/Pipeline/Descending.swift create mode 100644 Firestore/Swift/Source/SwiftAPI/Pipeline/DistanceMeasure.swift create mode 100644 Firestore/Swift/Source/SwiftAPI/Pipeline/Expr.swift create mode 100644 Firestore/Swift/Source/SwiftAPI/Pipeline/Expr/Constant.swift create mode 100644 Firestore/Swift/Source/SwiftAPI/Pipeline/Expr/DocumentId.swift create mode 100644 Firestore/Swift/Source/SwiftAPI/Pipeline/Expr/Field.swift create mode 100644 Firestore/Swift/Source/SwiftAPI/Pipeline/Expr/FunctionExpr.swift create mode 100644 Firestore/Swift/Source/SwiftAPI/Pipeline/Expr/FunctionExpr/BooleanExpr.swift create mode 100644 Firestore/Swift/Source/SwiftAPI/Pipeline/ExprWithAlias.swift create mode 100644 Firestore/Swift/Source/SwiftAPI/Pipeline/Ordering.swift create mode 100644 Firestore/Swift/Source/SwiftAPI/Pipeline/Pipeline.swift create mode 100644 Firestore/Swift/Source/SwiftAPI/Pipeline/PipelineResult.swift create mode 100644 Firestore/Swift/Source/SwiftAPI/Pipeline/PipelineSnapshot.swift create mode 100644 Firestore/Swift/Source/SwiftAPI/Pipeline/PipelineSource.swift create mode 100644 Firestore/Swift/Source/SwiftAPI/Pipeline/RealtimePipeline.swift create mode 100644 Firestore/Swift/Source/SwiftAPI/Pipeline/Selectable.swift create mode 100644 Firestore/Swift/Source/SwiftAPI/Pipeline/TimeUnit.swift delete mode 100644 Firestore/Swift/Source/SwiftAPI/PipelineSnapshot.swift delete mode 100644 Firestore/Swift/Source/SwiftAPI/PipelineSource.swift create mode 100644 Firestore/Swift/Tests/Integration/PipelineApiTests.swift diff --git a/.github/workflows/firestore-nightly.yml b/.github/workflows/firestore-nightly.yml index 36beeadb4ac..cd2afee4f43 100644 --- a/.github/workflows/firestore-nightly.yml +++ b/.github/workflows/firestore-nightly.yml @@ -15,6 +15,8 @@ name: firestore_nightly on: + pull_request: + branches: [ "cheryllin/pplapi", "cheryllin/ppl" ] workflow_dispatch: concurrency: @@ -49,6 +51,7 @@ jobs: plist_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} MINT_PATH: ${{ github.workspace }}/mint TARGET_DATABASE_ID: ${{ matrix.databaseId }} + USE_LATEST_CMAKE: false runs-on: ${{ matrix.os }} steps: @@ -77,6 +80,11 @@ jobs: run: scripts/decrypt_gha_secret.sh scripts/gha-encrypted/firestore-nightly.plist.gpg \ Firestore/Example/App/GoogleService-Info.plist "$plist_secret" + - name: Setup cmake + uses: jwlawson/actions-setup-cmake@v2 + with: + cmake-version: '3.31.1' + # Skipping terraform index creation because we are not allowed to download SA key json. - name: Setup build diff --git a/.gitignore b/.gitignore index dc909fe4338..74607c5993b 100644 --- a/.gitignore +++ b/.gitignore @@ -155,6 +155,7 @@ FirebaseAppCheck/Apps/AppCheckCustomProvideApp/AppCheckCustomProvideApp/GoogleSe /Example/FirestoreSample/ui-debug.log /Example/FirestoreSample/firestore-debug.log /Example/FirestoreSample/firebase-debug.log +Firestore/Example/GoogleService-Info.plist # generated Terraform docs .terraform/* diff --git a/Firestore/Example/Firestore.xcodeproj/project.pbxproj b/Firestore/Example/Firestore.xcodeproj/project.pbxproj index 1146b8a5dde..abba41a6f55 100644 --- a/Firestore/Example/Firestore.xcodeproj/project.pbxproj +++ b/Firestore/Example/Firestore.xcodeproj/project.pbxproj @@ -104,7 +104,6 @@ 0E17927CE45F5E3FC6691E24 /* firebase_auth_credentials_provider_test.mm in Sources */ = {isa = PBXBuildFile; fileRef = F869D85E900E5AF6CD02E2FC /* firebase_auth_credentials_provider_test.mm */; }; 0E4C94369FFF7EC0C9229752 /* iterator_adaptors_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 54A0353420A3D8CB003E0143 /* iterator_adaptors_test.cc */; }; 0E4F266A9FDF55CD38BB6D0F /* leveldb_query_engine_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = DB1F1E1B1ED15E8D042144B1 /* leveldb_query_engine_test.cc */; }; - 0E7A39BD9C87CC33F91A672F /* explain_stats.pb.cc in Sources */ = {isa = PBXBuildFile; fileRef = 682582E5728F3F1C531990EA /* explain_stats.pb.cc */; }; 0EA40EDACC28F445F9A3F32F /* pretty_printing_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = AB323F9553050F4F6490F9FF /* pretty_printing_test.cc */; }; 0EC3921AE220410F7394729B /* aggregation_result.pb.cc in Sources */ = {isa = PBXBuildFile; fileRef = D872D754B8AD88E28AF28B28 /* aggregation_result.pb.cc */; }; 0EDFC8A6593477E1D17CDD8F /* leveldb_bundle_cache_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 8E9CD82E60893DDD7757B798 /* leveldb_bundle_cache_test.cc */; }; @@ -127,9 +126,6 @@ 11F8EE69182C9699E90A9E3D /* database_info_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = AB38D92E20235D22000A432D /* database_info_test.cc */; }; 12158DFCEE09D24B7988A340 /* maybe_document.pb.cc in Sources */ = {isa = PBXBuildFile; fileRef = 618BBE7E20B89AAC00B5BCE7 /* maybe_document.pb.cc */; }; 121F0FB9DCCBFB7573C7AF48 /* bundle_serializer_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = B5C2A94EE24E60543F62CC35 /* bundle_serializer_test.cc */; }; - 12260A2A2D56A3CE001766EB /* PipelineTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12260A292D56A3CE001766EB /* PipelineTests.swift */; }; - 12260A2B2D56A3CE001766EB /* PipelineTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12260A292D56A3CE001766EB /* PipelineTests.swift */; }; - 12260A2C2D56A3CE001766EB /* PipelineTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12260A292D56A3CE001766EB /* PipelineTests.swift */; }; 124AAEE987451820F24EEA8E /* user_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = CCC9BD953F121B9E29F9AA42 /* user_test.cc */; }; 125B1048ECB755C2106802EB /* executor_std_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = B6FB4687208F9B9100554BA2 /* executor_std_test.cc */; }; 1290FA77A922B76503AE407C /* lru_garbage_collector_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 277EAACC4DD7C21332E8496A /* lru_garbage_collector_test.cc */; }; @@ -233,7 +229,6 @@ 1F4930A8366F74288121F627 /* create_noop_connectivity_monitor.cc in Sources */ = {isa = PBXBuildFile; fileRef = CF39535F2C41AB0006FA6C0E /* create_noop_connectivity_monitor.cc */; }; 1F56F51EB6DF0951B1F4F85B /* lru_garbage_collector_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 277EAACC4DD7C21332E8496A /* lru_garbage_collector_test.cc */; }; 1F998DDECB54A66222CC66AA /* string_format_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 54131E9620ADE678001DF3FF /* string_format_test.cc */; }; - 1F9FFAE375C88EFF88CBB6F8 /* field_behavior.pb.cc in Sources */ = {isa = PBXBuildFile; fileRef = FAAF1A69F4A315C38357BDC4 /* field_behavior.pb.cc */; }; 1FE23E911F0761AA896FAD67 /* Validation_BloomFilterTest_MD5_500_1_bloom_filter_proto.json in Resources */ = {isa = PBXBuildFile; fileRef = D8E530B27D5641B9C26A452C /* Validation_BloomFilterTest_MD5_500_1_bloom_filter_proto.json */; }; 2045517602D767BD01EA71D9 /* overlay_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E1459FA70B8FC18DE4B80D0D /* overlay_test.cc */; }; 205601D1C6A40A4DD3BBAA04 /* target_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 526D755F65AC676234F57125 /* target_test.cc */; }; @@ -300,7 +295,6 @@ 2A86AB04B38DBB770A1D8B13 /* Validation_BloomFilterTest_MD5_1_1_membership_test_result.json in Resources */ = {isa = PBXBuildFile; fileRef = 3369AC938F82A70685C5ED58 /* Validation_BloomFilterTest_MD5_1_1_membership_test_result.json */; }; 2AAEABFD550255271E3BAC91 /* to_string_apple_test.mm in Sources */ = {isa = PBXBuildFile; fileRef = B68B1E002213A764008977EF /* to_string_apple_test.mm */; }; 2ABA80088D70E7A58F95F7D8 /* delayed_constructor_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = D0A6E9136804A41CEC9D55D4 /* delayed_constructor_test.cc */; }; - 2AD2CB51469AE35331C39258 /* pipeline.pb.cc in Sources */ = {isa = PBXBuildFile; fileRef = 7142B5EC46E88349FAB3384F /* pipeline.pb.cc */; }; 2AD8EE91928AE68DF268BEDA /* limbo_spec_test.json in Resources */ = {isa = PBXBuildFile; fileRef = 54DA129E1F315EE100DD57A1 /* limbo_spec_test.json */; }; 2AD98CD29CC6F820A74CDD5E /* Validation_BloomFilterTest_MD5_1_0001_bloom_filter_proto.json in Resources */ = {isa = PBXBuildFile; fileRef = 4B59C0A7B2A4548496ED4E7D /* Validation_BloomFilterTest_MD5_1_0001_bloom_filter_proto.json */; }; 2AE3914BBC4EDF91BD852939 /* memory_query_engine_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 8EF6A33BC2D84233C355F1D0 /* memory_query_engine_test.cc */; }; @@ -328,9 +322,11 @@ 2EC1C4D202A01A632339A161 /* field_transform_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 7515B47C92ABEEC66864B55C /* field_transform_test.cc */; }; 2F3740131CC8F8230351B91D /* byte_stream_cpp_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 01D10113ECC5B446DB35E96D /* byte_stream_cpp_test.cc */; }; 2F69187F601E00054469F4A5 /* DatabaseTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3355BE9391CC4857AF0BDAE3 /* DatabaseTests.swift */; }; + 2F72DBE2EC6E24A81C69DEF0 /* explain_stats.pb.cc in Sources */ = {isa = PBXBuildFile; fileRef = 428662F00938E9E21F7080D7 /* explain_stats.pb.cc */; }; 2F8FDF35BBB549A6F4D2118E /* FSTMemorySpecTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5492E02F20213FFC00B64F25 /* FSTMemorySpecTests.mm */; }; 2FA0BAE32D587DF2EA5EEB97 /* async_queue_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = B6FB467B208E9A8200554BA2 /* async_queue_test.cc */; }; 2FAE0BCBE559ED7214AEFEB7 /* Validation_BloomFilterTest_MD5_1_01_bloom_filter_proto.json in Resources */ = {isa = PBXBuildFile; fileRef = 0D964D4936953635AC7E0834 /* Validation_BloomFilterTest_MD5_1_01_bloom_filter_proto.json */; }; + 2FC2B732841BF2C425EB35DF /* field_behavior.pb.cc in Sources */ = {isa = PBXBuildFile; fileRef = 1F78CD3208A1D5885B4C134E /* field_behavior.pb.cc */; }; 3040FD156E1B7C92B0F2A70C /* ordered_code_benchmark.cc in Sources */ = {isa = PBXBuildFile; fileRef = 0473AFFF5567E667A125347B /* ordered_code_benchmark.cc */; }; 3056418E81BC7584FBE8AD6C /* user_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = CCC9BD953F121B9E29F9AA42 /* user_test.cc */; }; 306E762DC6B829CED4FD995D /* target_id_generator_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = AB380CF82019382300D97691 /* target_id_generator_test.cc */; }; @@ -348,7 +344,6 @@ 32F022CB75AEE48CDDAF2982 /* mutation_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = C8522DE226C467C54E6788D8 /* mutation_test.cc */; }; 32F8B4652010E8224E353041 /* persistence_spec_test.json in Resources */ = {isa = PBXBuildFile; fileRef = 54DA12A31F315EE100DD57A1 /* persistence_spec_test.json */; }; 330DE2A5AE6AF8D66C9C849F /* Validation_BloomFilterTest_MD5_5000_0001_membership_test_result.json in Resources */ = {isa = PBXBuildFile; fileRef = C8582DFD74E8060C7072104B /* Validation_BloomFilterTest_MD5_5000_0001_membership_test_result.json */; }; - 332E7D2D8489E6DA42947C59 /* field_behavior.pb.cc in Sources */ = {isa = PBXBuildFile; fileRef = FAAF1A69F4A315C38357BDC4 /* field_behavior.pb.cc */; }; 336E415DD06E719F9C9E2A14 /* grpc_stream_tester.cc in Sources */ = {isa = PBXBuildFile; fileRef = 87553338E42B8ECA05BA987E /* grpc_stream_tester.cc */; }; 338DFD5BCD142DF6C82A0D56 /* cc_compilation_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 1B342370EAE3AA02393E33EB /* cc_compilation_test.cc */; }; 339CFFD1323BDCA61EAAFE31 /* query_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = B9C261C26C5D311E1E3C0CB9 /* query_test.cc */; }; @@ -388,6 +383,7 @@ 39790AC7E71BC06D48144BED /* memory_globals_cache_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 5C6DEA63FBDE19D841291723 /* memory_globals_cache_test.cc */; }; 3987A3E8534BAA496D966735 /* memory_index_manager_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = DB5A1E760451189DA36028B3 /* memory_index_manager_test.cc */; }; 39CDC9EC5FD2E891D6D49151 /* secure_random_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 54740A531FC913E500713A1A /* secure_random_test.cc */; }; + 3A110ECBF96B6E44BA77011A /* field_behavior.pb.cc in Sources */ = {isa = PBXBuildFile; fileRef = 1F78CD3208A1D5885B4C134E /* field_behavior.pb.cc */; }; 3A307F319553A977258BB3D6 /* view_snapshot_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = CC572A9168BBEF7B83E4BBC5 /* view_snapshot_test.cc */; }; 3A7CB01751697ED599F2D9A1 /* executor_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = B6FB4688208F9B9100554BA2 /* executor_test.cc */; }; 3A93D8FB318C6491A6B654F5 /* Validation_BloomFilterTest_MD5_50000_01_bloom_filter_proto.json in Resources */ = {isa = PBXBuildFile; fileRef = 7B44DD11682C4803B73DCC34 /* Validation_BloomFilterTest_MD5_50000_01_bloom_filter_proto.json */; }; @@ -399,7 +395,6 @@ 3B256CCF6AEEE12E22F16BB8 /* hashing_test_apple.mm in Sources */ = {isa = PBXBuildFile; fileRef = B69CF3F02227386500B281C8 /* hashing_test_apple.mm */; }; 3B37BD3C13A66625EC82CF77 /* hard_assert_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 444B7AB3F5A2929070CB1363 /* hard_assert_test.cc */; }; 3B47CC43DBA24434E215B8ED /* memory_index_manager_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = DB5A1E760451189DA36028B3 /* memory_index_manager_test.cc */; }; - 3B4CFB45208A7EEF1EA58ADC /* pipeline.pb.cc in Sources */ = {isa = PBXBuildFile; fileRef = 7142B5EC46E88349FAB3384F /* pipeline.pb.cc */; }; 3B5CEA04AC1627256A1AE8BA /* bloom_filter_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = A2E6F09AD1EE0A6A452E9A08 /* bloom_filter_test.cc */; }; 3B843E4C1F3A182900548890 /* remote_store_spec_test.json in Resources */ = {isa = PBXBuildFile; fileRef = 3B843E4A1F3930A400548890 /* remote_store_spec_test.json */; }; 3BA4EEA6153B3833F86B8104 /* writer_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = BC3C788D290A935C353CEAA1 /* writer_test.cc */; }; @@ -409,6 +404,7 @@ 3CCABD7BB5ED39DF1140B5F0 /* leveldb_globals_cache_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = FC44D934D4A52C790659C8D6 /* leveldb_globals_cache_test.cc */; }; 3CFFA6F016231446367E3A69 /* listen_spec_test.json in Resources */ = {isa = PBXBuildFile; fileRef = 54DA12A01F315EE100DD57A1 /* listen_spec_test.json */; }; 3D22F56C0DE7C7256C75DC06 /* tree_sorted_map_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 549CCA4D20A36DBB00BCEB75 /* tree_sorted_map_test.cc */; }; + 3D5F7AA7BB68529F47BE4B12 /* PipelineApiTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 59BF06E5A4988F9F949DD871 /* PipelineApiTests.swift */; }; 3D6AC48D6197E6539BBBD28F /* thread_safe_memoizer_testing.cc in Sources */ = {isa = PBXBuildFile; fileRef = 6E42FA109D363EA7F3387AAE /* thread_safe_memoizer_testing.cc */; }; 3D9619906F09108E34FF0C95 /* FSTSmokeTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5492E07C202154EB00B64F25 /* FSTSmokeTests.mm */; }; 3DBB48F077C97200F32B51A0 /* value_util_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 40F9D09063A07F710811A84F /* value_util_test.cc */; }; @@ -523,7 +519,6 @@ 50454F81EC4584D4EB5F5ED5 /* serializer_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 61F72C5520BC48FD001A68CB /* serializer_test.cc */; }; 50B749CA98365368AE34B71C /* filter_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = F02F734F272C3C70D1307076 /* filter_test.cc */; }; 50C852E08626CFA7DC889EEA /* field_index_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = BF76A8DA34B5B67B4DD74666 /* field_index_test.cc */; }; - 50EA1F41D766C92894E9B078 /* explain_stats.pb.cc in Sources */ = {isa = PBXBuildFile; fileRef = 682582E5728F3F1C531990EA /* explain_stats.pb.cc */; }; 51018EA27CF914DD1CC79CB3 /* thread_safe_memoizer_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 1A8141230C7E3986EACEF0B6 /* thread_safe_memoizer_test.cc */; }; 513D34C9964E8C60C5C2EE1C /* leveldb_bundle_cache_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 8E9CD82E60893DDD7757B798 /* leveldb_bundle_cache_test.cc */; }; 5150E9F256E6E82D6F3CB3F1 /* bundle_cache_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = F7FC06E0A47D393DE1759AE1 /* bundle_cache_test.cc */; }; @@ -693,6 +688,7 @@ 5BE49546D57C43DDFCDB6FBD /* to_string_apple_test.mm in Sources */ = {isa = PBXBuildFile; fileRef = B68B1E002213A764008977EF /* to_string_apple_test.mm */; }; 5C9B5696644675636A052018 /* token_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = A082AFDD981B07B5AD78FDE8 /* token_test.cc */; }; 5CADE71A1CA6358E1599F0F9 /* hashing_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 54511E8D209805F8005BD28F /* hashing_test.cc */; }; + 5CDD24225992674A4D3E3D4E /* pipeline.pb.cc in Sources */ = {isa = PBXBuildFile; fileRef = D49E7AEE500651D25C5360C3 /* pipeline.pb.cc */; }; 5CEB0E83DA68652927D2CF07 /* memory_document_overlay_cache_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 29D9C76922DAC6F710BC1EF4 /* memory_document_overlay_cache_test.cc */; }; 5D405BE298CE4692CB00790A /* Pods_Firestore_Tests_iOS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2B50B3A0DF77100EEE887891 /* Pods_Firestore_Tests_iOS.framework */; }; 5D45CC300ED037358EF33A8F /* snapshot_version_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = ABA495B9202B7E79008A7851 /* snapshot_version_test.cc */; }; @@ -741,6 +737,7 @@ 604B75044D6BEC2B7515EA1B /* index_spec_test.json in Resources */ = {isa = PBXBuildFile; fileRef = 8C7278B604B8799F074F4E8C /* index_spec_test.json */; }; 60985657831B8DDE2C65AC8B /* FIRFieldsTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5492E06A202154D500B64F25 /* FIRFieldsTests.mm */; }; 60C72F86D2231B1B6592A5E6 /* filesystem_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = F51859B394D01C0C507282F1 /* filesystem_test.cc */; }; + 60DA778E447F9ACD402FDA2F /* pipeline.pb.cc in Sources */ = {isa = PBXBuildFile; fileRef = D49E7AEE500651D25C5360C3 /* pipeline.pb.cc */; }; 6105A1365831B79A7DEEA4F3 /* path_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 403DBF6EFB541DFD01582AA3 /* path_test.cc */; }; 6141D3FDF5728FCE9CC1DBFA /* bundle_spec_test.json in Resources */ = {isa = PBXBuildFile; fileRef = 79EAA9F7B1B9592B5F053923 /* bundle_spec_test.json */; }; 6156C6A837D78D49ED8B8812 /* index_spec_test.json in Resources */ = {isa = PBXBuildFile; fileRef = 8C7278B604B8799F074F4E8C /* index_spec_test.json */; }; @@ -778,6 +775,7 @@ 64D8241E9F56973DAD3077BC /* Validation_BloomFilterTest_MD5_1_01_membership_test_result.json in Resources */ = {isa = PBXBuildFile; fileRef = 5C68EE4CB94C0DD6E333F546 /* Validation_BloomFilterTest_MD5_1_01_membership_test_result.json */; }; 650B31A5EC6F8D2AEA79C350 /* index_manager_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = AE4A9E38D65688EE000EE2A1 /* index_manager_test.cc */; }; 65537B22A73E3909666FB5BC /* remote_document_cache_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 7EB299CF85034F09CFD6F3FD /* remote_document_cache_test.cc */; }; + 655F8647F57E5F2155DFF7B5 /* PipelineTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 861684E49DAC993D153E60D0 /* PipelineTests.swift */; }; 658CBF4A717EA160E27C973E /* Validation_BloomFilterTest_MD5_50000_0001_bloom_filter_proto.json in Resources */ = {isa = PBXBuildFile; fileRef = A5D9044B72061CAF284BC9E4 /* Validation_BloomFilterTest_MD5_50000_0001_bloom_filter_proto.json */; }; 659FFE071CD0F60DAEADD50B /* bloom_filter.pb.cc in Sources */ = {isa = PBXBuildFile; fileRef = 1E0C7C0DCD2790019E66D8CC /* bloom_filter.pb.cc */; }; 65D54B964A2021E5A36AB21F /* bundle_loader_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = A853C81A6A5A51C9D0389EDA /* bundle_loader_test.cc */; }; @@ -792,7 +790,6 @@ 66DFEA9E324797E6EA81CBA9 /* perf_spec_test.json in Resources */ = {isa = PBXBuildFile; fileRef = D5B2593BCB52957D62F1C9D3 /* perf_spec_test.json */; }; 66FAB8EAC012A3822BD4D0C9 /* leveldb_util_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 332485C4DCC6BA0DBB5E31B7 /* leveldb_util_test.cc */; }; 6711E75A10EBA662341F5C9D /* leveldb_document_overlay_cache_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = AE89CFF09C6804573841397F /* leveldb_document_overlay_cache_test.cc */; }; - 676933F59F2F0A0D221A4F8F /* explain_stats.pb.cc in Sources */ = {isa = PBXBuildFile; fileRef = 682582E5728F3F1C531990EA /* explain_stats.pb.cc */; }; 677C833244550767B71DB1BA /* log_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 54C2294E1FECABAE007D065B /* log_test.cc */; }; 67B8C34BDF0FFD7532D7BE4F /* Validation_BloomFilterTest_MD5_500_0001_membership_test_result.json in Resources */ = {isa = PBXBuildFile; fileRef = 478DC75A0DCA6249A616DD30 /* Validation_BloomFilterTest_MD5_500_0001_membership_test_result.json */; }; 67BC2B77C1CC47388E79D774 /* FIRSnapshotMetadataTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5492E04D202154AA00B64F25 /* FIRSnapshotMetadataTests.mm */; }; @@ -850,7 +847,6 @@ 6FF2B680CC8631B06C7BD7AB /* FSTMemorySpecTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5492E02F20213FFC00B64F25 /* FSTMemorySpecTests.mm */; }; 70A171FC43BE328767D1B243 /* path_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 403DBF6EFB541DFD01582AA3 /* path_test.cc */; }; 70AB665EB6A473FF6C4CFD31 /* CodableTimestampTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B65C996438B84DBC7616640 /* CodableTimestampTests.swift */; }; - 715A0E92C83AE4384A13B882 /* pipeline.pb.cc in Sources */ = {isa = PBXBuildFile; fileRef = 7142B5EC46E88349FAB3384F /* pipeline.pb.cc */; }; 716289F99B5316B3CC5E5CE9 /* FIRSnapshotMetadataTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5492E04D202154AA00B64F25 /* FIRSnapshotMetadataTests.mm */; }; 71702588BFBF5D3A670508E7 /* ordered_code_benchmark.cc in Sources */ = {isa = PBXBuildFile; fileRef = 0473AFFF5567E667A125347B /* ordered_code_benchmark.cc */; }; 71719F9F1E33DC2100824A3D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 71719F9D1E33DC2100824A3D /* LaunchScreen.storyboard */; }; @@ -872,7 +868,6 @@ 73E42D984FB36173A2BDA57C /* FSTEventAccumulator.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5492E0392021401F00B64F25 /* FSTEventAccumulator.mm */; }; 73FE5066020EF9B2892C86BF /* hard_assert_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 444B7AB3F5A2929070CB1363 /* hard_assert_test.cc */; }; 743DF2DF38CE289F13F44043 /* status_testing.cc in Sources */ = {isa = PBXBuildFile; fileRef = 3CAA33F964042646FDDAF9F9 /* status_testing.cc */; }; - 7492C447277CDC8CB7A165CB /* explain_stats.pb.cc in Sources */ = {isa = PBXBuildFile; fileRef = 682582E5728F3F1C531990EA /* explain_stats.pb.cc */; }; 7495E3BAE536CD839EE20F31 /* FSTLevelDBSpecTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5492E02C20213FFB00B64F25 /* FSTLevelDBSpecTests.mm */; }; 74985DE2C7EF4150D7A455FD /* statusor_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 54A0352D20A3B3D7003E0143 /* statusor_test.cc */; }; 74A63A931F834D1D6CF3BA9A /* Validation_BloomFilterTest_MD5_1_1_membership_test_result.json in Resources */ = {isa = PBXBuildFile; fileRef = 3369AC938F82A70685C5ED58 /* Validation_BloomFilterTest_MD5_1_1_membership_test_result.json */; }; @@ -909,6 +904,7 @@ 7AD020FC27493FF8E659436C /* existence_filter_spec_test.json in Resources */ = {isa = PBXBuildFile; fileRef = 54DA129D1F315EE100DD57A1 /* existence_filter_spec_test.json */; }; 7B0EA399F899537ACCC84E53 /* string_format_apple_test.mm in Sources */ = {isa = PBXBuildFile; fileRef = 9CFD366B783AE27B9E79EE7A /* string_format_apple_test.mm */; }; 7B0F073BDB6D0D6E542E23D4 /* query.pb.cc in Sources */ = {isa = PBXBuildFile; fileRef = 544129D621C2DDC800EFB9CC /* query.pb.cc */; }; + 7B58861D0978827BC4CB1DFA /* field_behavior.pb.cc in Sources */ = {isa = PBXBuildFile; fileRef = 1F78CD3208A1D5885B4C134E /* field_behavior.pb.cc */; }; 7B74447D211586D9D1CC82BB /* datastore_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 3167BD972EFF8EC636530E59 /* datastore_test.cc */; }; 7B8320F12E8092BC86FFCC2C /* fields_array_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = BA4CBA48204C9E25B56993BC /* fields_array_test.cc */; }; 7B86B1B21FD0EF2A67547F66 /* byte_string_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 5342CDDB137B4E93E2E85CCA /* byte_string_test.cc */; }; @@ -919,6 +915,7 @@ 7C1DC1B44729381126D083AE /* leveldb_snappy_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = D9D94300B9C02F7069523C00 /* leveldb_snappy_test.cc */; }; 7C5E017689012489AAB7718D /* CodableGeoPointTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5495EB022040E90200EBA509 /* CodableGeoPointTests.swift */; }; 7C7BA1DB0B66EB899A928283 /* hashing_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 54511E8D209805F8005BD28F /* hashing_test.cc */; }; + 7CAF0E8C47FB2DD486240D47 /* explain_stats.pb.cc in Sources */ = {isa = PBXBuildFile; fileRef = 428662F00938E9E21F7080D7 /* explain_stats.pb.cc */; }; 7D25D41B013BB70ADE526055 /* target_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 526D755F65AC676234F57125 /* target_test.cc */; }; 7D320113FD076A1EF9A8B612 /* filter_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = F02F734F272C3C70D1307076 /* filter_test.cc */; }; 7D3207DEE229EFCF16E52693 /* Validation_BloomFilterTest_MD5_500_01_bloom_filter_proto.json in Resources */ = {isa = PBXBuildFile; fileRef = 4BD051DBE754950FEAC7A446 /* Validation_BloomFilterTest_MD5_500_01_bloom_filter_proto.json */; }; @@ -965,6 +962,7 @@ 8405FF2BFBB233031A887398 /* event_manager_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 6F57521E161450FAF89075ED /* event_manager_test.cc */; }; 8413BD9958F6DD52C466D70F /* sorted_set_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 549CCA4C20A36DBB00BCEB75 /* sorted_set_test.cc */; }; 84285C3F63D916A4786724A8 /* field_index_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = BF76A8DA34B5B67B4DD74666 /* field_index_test.cc */; }; + 8429E18EFBAF473209731E01 /* pipeline.pb.cc in Sources */ = {isa = PBXBuildFile; fileRef = D49E7AEE500651D25C5360C3 /* pipeline.pb.cc */; }; 843EE932AA9A8F43721F189E /* leveldb_local_store_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 5FF903AEFA7A3284660FA4C5 /* leveldb_local_store_test.cc */; }; 8460C97C9209D7DAF07090BD /* FIRFieldsTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5492E06A202154D500B64F25 /* FIRFieldsTests.mm */; }; 84E75527F3739131C09BEAA5 /* target_index_matcher_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 63136A2371C0C013EC7A540C /* target_index_matcher_test.cc */; }; @@ -984,7 +982,6 @@ 8683BBC3AC7B01937606A83B /* firestore.pb.cc in Sources */ = {isa = PBXBuildFile; fileRef = 544129D421C2DDC800EFB9CC /* firestore.pb.cc */; }; 86B413EC49E3BBBEBF1FB7A0 /* Validation_BloomFilterTest_MD5_500_1_membership_test_result.json in Resources */ = {isa = PBXBuildFile; fileRef = 8AB49283E544497A9C5A0E59 /* Validation_BloomFilterTest_MD5_500_1_membership_test_result.json */; }; 86E6FC2B7657C35B342E1436 /* sorted_map_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 549CCA4E20A36DBB00BCEB75 /* sorted_map_test.cc */; }; - 86E73F6286E87834CF37D5D9 /* field_behavior.pb.cc in Sources */ = {isa = PBXBuildFile; fileRef = FAAF1A69F4A315C38357BDC4 /* field_behavior.pb.cc */; }; 8705C4856498F66E471A0997 /* FIRWriteBatchTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5492E06F202154D600B64F25 /* FIRWriteBatchTests.mm */; }; 873B8AEB1B1F5CCA007FD442 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 873B8AEA1B1F5CCA007FD442 /* Main.storyboard */; }; 8778C1711059598070F86D3C /* leveldb_globals_cache_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = FC44D934D4A52C790659C8D6 /* leveldb_globals_cache_test.cc */; }; @@ -1019,7 +1016,6 @@ 8F3AE423677A4C50F7E0E5C0 /* database_info_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = AB38D92E20235D22000A432D /* database_info_test.cc */; }; 8F4F40E9BC7ED588F67734D5 /* app_testing.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5467FB07203E6A44009C9584 /* app_testing.mm */; }; 8F781F527ED72DC6C123689E /* autoid_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 54740A521FC913E500713A1A /* autoid_test.cc */; }; - 8FE63980976481EBA001B789 /* explain_stats.pb.cc in Sources */ = {isa = PBXBuildFile; fileRef = 682582E5728F3F1C531990EA /* explain_stats.pb.cc */; }; 9009C285F418EA80C46CF06B /* fake_target_metadata_provider.cc in Sources */ = {isa = PBXBuildFile; fileRef = 71140E5D09C6E76F7C71B2FC /* fake_target_metadata_provider.cc */; }; 900D0E9F18CE3DB954DD0D1E /* async_queue_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = B6FB467B208E9A8200554BA2 /* async_queue_test.cc */; }; 9012B0E121B99B9C7E54160B /* query_engine_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = B8A853940305237AFDA8050B /* query_engine_test.cc */; }; @@ -1038,7 +1034,6 @@ 920B6ABF76FDB3547F1CCD84 /* firestore.pb.cc in Sources */ = {isa = PBXBuildFile; fileRef = 544129D421C2DDC800EFB9CC /* firestore.pb.cc */; }; 9236478E01DF2EC7DF58B1FC /* index_backfiller_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 1F50E872B3F117A674DA8E94 /* index_backfiller_test.cc */; }; 925BE64990449E93242A00A2 /* memory_mutation_queue_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 74FBEFA4FE4B12C435011763 /* memory_mutation_queue_test.cc */; }; - 92B593DCD86543D8C90F64F9 /* pipeline.pb.cc in Sources */ = {isa = PBXBuildFile; fileRef = 7142B5EC46E88349FAB3384F /* pipeline.pb.cc */; }; 92D7081085679497DC112EDB /* persistence_testing.cc in Sources */ = {isa = PBXBuildFile; fileRef = 9113B6F513D0473AEABBAF1F /* persistence_testing.cc */; }; 92EFF0CC2993B43CBC7A61FF /* grpc_streaming_reader_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = B6D964922154AB8F00EB9CFB /* grpc_streaming_reader_test.cc */; }; 9382BE7190E7750EE7CCCE7C /* write_spec_test.json in Resources */ = {isa = PBXBuildFile; fileRef = 54DA12A51F315EE100DD57A1 /* write_spec_test.json */; }; @@ -1085,7 +1080,6 @@ 9C366448F9BA7A4AC0821AF7 /* bundle_spec_test.json in Resources */ = {isa = PBXBuildFile; fileRef = 79EAA9F7B1B9592B5F053923 /* bundle_spec_test.json */; }; 9C86EEDEA131BFD50255EEF1 /* comparison_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 548DB928200D59F600E00ABC /* comparison_test.cc */; }; 9CC32ACF397022BB7DF11B52 /* Validation_BloomFilterTest_MD5_500_0001_bloom_filter_proto.json in Resources */ = {isa = PBXBuildFile; fileRef = D22D4C211AC32E4F8B4883DA /* Validation_BloomFilterTest_MD5_500_0001_bloom_filter_proto.json */; }; - 9CD1E9301EC44ED10DAEA5FB /* pipeline.pb.cc in Sources */ = {isa = PBXBuildFile; fileRef = 7142B5EC46E88349FAB3384F /* pipeline.pb.cc */; }; 9CE07BAAD3D3BC5F069D38FE /* grpc_streaming_reader_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = B6D964922154AB8F00EB9CFB /* grpc_streaming_reader_test.cc */; }; 9CFF379C7404F7CE6B26AF29 /* listen_source_spec_test.json in Resources */ = {isa = PBXBuildFile; fileRef = 4D9E51DA7A275D8B1CAEAEB2 /* listen_source_spec_test.json */; }; 9D71628E38D9F64C965DF29E /* FSTAPIHelpers.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5492E04E202154AA00B64F25 /* FSTAPIHelpers.mm */; }; @@ -1114,6 +1108,7 @@ A25FF76DEF542E01A2DF3B0E /* time_testing.cc in Sources */ = {isa = PBXBuildFile; fileRef = 5497CB76229DECDE000FB92F /* time_testing.cc */; }; A27096F764227BC73526FED3 /* leveldb_remote_document_cache_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 0840319686A223CC4AD3FAB1 /* leveldb_remote_document_cache_test.cc */; }; A27908A198E1D2230C1801AC /* bundle_serializer_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = B5C2A94EE24E60543F62CC35 /* bundle_serializer_test.cc */; }; + A296B0110550890E1D8D59A3 /* explain_stats.pb.cc in Sources */ = {isa = PBXBuildFile; fileRef = 428662F00938E9E21F7080D7 /* explain_stats.pb.cc */; }; A2E9978E02F7BCB016555F09 /* Validation_BloomFilterTest_MD5_1_1_membership_test_result.json in Resources */ = {isa = PBXBuildFile; fileRef = 3369AC938F82A70685C5ED58 /* Validation_BloomFilterTest_MD5_1_1_membership_test_result.json */; }; A3262936317851958C8EABAF /* byte_stream_cpp_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 01D10113ECC5B446DB35E96D /* byte_stream_cpp_test.cc */; }; A4757C171D2407F61332EA38 /* byte_stream_cpp_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 01D10113ECC5B446DB35E96D /* byte_stream_cpp_test.cc */; }; @@ -1121,7 +1116,6 @@ A4AD189BDEF7A609953457A6 /* leveldb_key_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 54995F6E205B6E12004EFFA0 /* leveldb_key_test.cc */; }; A4ECA8335000CBDF94586C94 /* FSTDatastoreTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5492E07E202154EC00B64F25 /* FSTDatastoreTests.mm */; }; A5175CA2E677E13CC5F23D72 /* document_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = AB6B908320322E4D00CC290A /* document_test.cc */; }; - A5301AA55748A11801E3EE47 /* field_behavior.pb.cc in Sources */ = {isa = PBXBuildFile; fileRef = FAAF1A69F4A315C38357BDC4 /* field_behavior.pb.cc */; }; A55266E6C986251D283CE948 /* FIRCursorTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5492E070202154D600B64F25 /* FIRCursorTests.mm */; }; A5583822218F9D5B1E86FCAC /* overlay_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E1459FA70B8FC18DE4B80D0D /* overlay_test.cc */; }; A57EC303CD2D6AA4F4745551 /* FIRFieldValueTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5492E04A202154AA00B64F25 /* FIRFieldValueTests.mm */; }; @@ -1166,6 +1160,7 @@ AB8209455BAA17850D5E196D /* http.pb.cc in Sources */ = {isa = PBXBuildFile; fileRef = 618BBE9720B89AAC00B5BCE7 /* http.pb.cc */; }; AB9FF792C60FC581909EF381 /* recovery_spec_test.json in Resources */ = {isa = PBXBuildFile; fileRef = 9C1AFCC9E616EC33D6E169CF /* recovery_spec_test.json */; }; ABA495BB202B7E80008A7851 /* snapshot_version_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = ABA495B9202B7E79008A7851 /* snapshot_version_test.cc */; }; + ABE599C3BF9FB6AFF18AA901 /* explain_stats.pb.cc in Sources */ = {isa = PBXBuildFile; fileRef = 428662F00938E9E21F7080D7 /* explain_stats.pb.cc */; }; ABE6637A201FA81900ED349A /* database_id_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = AB71064B201FA60300344F18 /* database_id_test.cc */; }; ABF6506C201131F8005F2C74 /* timestamp_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = ABF6506B201131F8005F2C74 /* timestamp_test.cc */; }; ABFD599019CF312CFF96B3EC /* perf_spec_test.json in Resources */ = {isa = PBXBuildFile; fileRef = D5B2593BCB52957D62F1C9D3 /* perf_spec_test.json */; }; @@ -1211,7 +1206,6 @@ B220E091D8F4E6DE1EA44F57 /* executor_libdispatch_test.mm in Sources */ = {isa = PBXBuildFile; fileRef = B6FB4689208F9B9100554BA2 /* executor_libdispatch_test.mm */; }; B235E260EA0DCB7BAC04F69B /* field_path_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = B686F2AD2023DDB20028D6BE /* field_path_test.cc */; }; B2554A2BA211D10823646DBE /* Validation_BloomFilterTest_MD5_500_01_bloom_filter_proto.json in Resources */ = {isa = PBXBuildFile; fileRef = 4BD051DBE754950FEAC7A446 /* Validation_BloomFilterTest_MD5_500_01_bloom_filter_proto.json */; }; - B280370F84393808250B28BC /* explain_stats.pb.cc in Sources */ = {isa = PBXBuildFile; fileRef = 682582E5728F3F1C531990EA /* explain_stats.pb.cc */; }; B28ACC69EB1F232AE612E77B /* async_testing.cc in Sources */ = {isa = PBXBuildFile; fileRef = 872C92ABD71B12784A1C5520 /* async_testing.cc */; }; B2A9965ED0114E39A911FD09 /* Validation_BloomFilterTest_MD5_5000_1_bloom_filter_proto.json in Resources */ = {isa = PBXBuildFile; fileRef = 4375BDCDBCA9938C7F086730 /* Validation_BloomFilterTest_MD5_5000_1_bloom_filter_proto.json */; }; B31B5E0D4EA72C5916CC71F5 /* thread_safe_memoizer_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 1A8141230C7E3986EACEF0B6 /* thread_safe_memoizer_test.cc */; }; @@ -1292,11 +1286,13 @@ BC549E3F3F119D80741D8612 /* leveldb_util_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 332485C4DCC6BA0DBB5E31B7 /* leveldb_util_test.cc */; }; BC5AC8890974E0821431267E /* limit_spec_test.json in Resources */ = {isa = PBXBuildFile; fileRef = 54DA129F1F315EE100DD57A1 /* limit_spec_test.json */; }; BC8DFBCB023DBD914E27AA7D /* query_listener_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 7C3F995E040E9E9C5E8514BB /* query_listener_test.cc */; }; + BC9966788F245D79A63C2E47 /* pipeline.pb.cc in Sources */ = {isa = PBXBuildFile; fileRef = D49E7AEE500651D25C5360C3 /* pipeline.pb.cc */; }; BCA720A0F54D23654F806323 /* ConditionalConformanceTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E3228F51DCDC2E90D5C58F97 /* ConditionalConformanceTests.swift */; }; BCAC9F7A865BD2320A4D8752 /* bloom_filter_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = A2E6F09AD1EE0A6A452E9A08 /* bloom_filter_test.cc */; }; BD0882A40BD8AE042629C179 /* thread_safe_memoizer_testing_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = EA10515F99A42D71DA2D2841 /* thread_safe_memoizer_testing_test.cc */; }; BD3A421C9E40C57D25697E75 /* Validation_BloomFilterTest_MD5_500_01_bloom_filter_proto.json in Resources */ = {isa = PBXBuildFile; fileRef = 4BD051DBE754950FEAC7A446 /* Validation_BloomFilterTest_MD5_500_01_bloom_filter_proto.json */; }; BD6CC8614970A3D7D2CF0D49 /* exponential_backoff_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = B6D1B68420E2AB1A00B35856 /* exponential_backoff_test.cc */; }; + BD74B0E1FC752236A7376BC3 /* PipelineApiTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 59BF06E5A4988F9F949DD871 /* PipelineApiTests.swift */; }; BDD2D1812BAD962E3C81A53F /* hashing_test_apple.mm in Sources */ = {isa = PBXBuildFile; fileRef = B69CF3F02227386500B281C8 /* hashing_test_apple.mm */; }; BDDAE67000DBF10E9EA7FED0 /* nanopb_util_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 6F5B6C1399F92FD60F2C582B /* nanopb_util_test.cc */; }; BDF3A6C121F2773BB3A347A7 /* counting_query_engine.cc in Sources */ = {isa = PBXBuildFile; fileRef = 99434327614FEFF7F7DC88EC /* counting_query_engine.cc */; }; @@ -1356,9 +1352,11 @@ C840AD39F7EC5524F1C0F5AE /* filter_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = F02F734F272C3C70D1307076 /* filter_test.cc */; }; C86E85101352B5CDBF5909F9 /* md5_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 3D050936A2D52257FD17FB6E /* md5_test.cc */; }; C8722550B56CEB96F84DCE94 /* target_index_matcher_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 63136A2371C0C013EC7A540C /* target_index_matcher_test.cc */; }; + C8889F3C37F1CC3E64558287 /* pipeline.pb.cc in Sources */ = {isa = PBXBuildFile; fileRef = D49E7AEE500651D25C5360C3 /* pipeline.pb.cc */; }; C8A573895D819A92BF16B5E5 /* mutation_queue_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 3068AA9DFBBA86C1FE2A946E /* mutation_queue_test.cc */; }; C8BA36C8B5E26C173F91E677 /* aggregation_result.pb.cc in Sources */ = {isa = PBXBuildFile; fileRef = D872D754B8AD88E28AF28B28 /* aggregation_result.pb.cc */; }; C8BC50508337800E8B098F57 /* bundle_loader_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = A853C81A6A5A51C9D0389EDA /* bundle_loader_test.cc */; }; + C8C2B945D84DD98391145F3F /* PipelineTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 861684E49DAC993D153E60D0 /* PipelineTests.swift */; }; C8C4CB7B6E23FC340BEC6D7F /* load_bundle_task_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 8F1A7B4158D9DD76EE4836BF /* load_bundle_task_test.cc */; }; C8D3CE2343E53223E6487F2C /* Pods_Firestore_Example_iOS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5918805E993304321A05E82B /* Pods_Firestore_Example_iOS.framework */; }; C901A1BFD553B6DD70BB7CC7 /* bundle_cache_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = F7FC06E0A47D393DE1759AE1 /* bundle_cache_test.cc */; }; @@ -1425,6 +1423,7 @@ D5B25CBF07F65E885C9D68AB /* perf_spec_test.json in Resources */ = {isa = PBXBuildFile; fileRef = D5B2593BCB52957D62F1C9D3 /* perf_spec_test.json */; }; D5E9954FC1C5ABBC7A180B33 /* FSTSpecTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5492E03020213FFC00B64F25 /* FSTSpecTests.mm */; }; D5F6AAA1A1B9AE84205ECE27 /* Validation_BloomFilterTest_MD5_50000_1_bloom_filter_proto.json in Resources */ = {isa = PBXBuildFile; fileRef = 4B3E4A77493524333133C5DC /* Validation_BloomFilterTest_MD5_50000_1_bloom_filter_proto.json */; }; + D64792BBFA130E26CB3D1028 /* pipeline.pb.cc in Sources */ = {isa = PBXBuildFile; fileRef = D49E7AEE500651D25C5360C3 /* pipeline.pb.cc */; }; D6486C7FFA8BE6F9C7D2F4C4 /* filesystem_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = F51859B394D01C0C507282F1 /* filesystem_test.cc */; }; D658E6DA5A218E08810E1688 /* byte_string_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 5342CDDB137B4E93E2E85CCA /* byte_string_test.cc */; }; D6962E598CEDABA312D87760 /* bundle_reader_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 6ECAF7DE28A19C69DF386D88 /* bundle_reader_test.cc */; }; @@ -1437,7 +1436,6 @@ D73BBA4AB42940AB187169E3 /* listen_spec_test.json in Resources */ = {isa = PBXBuildFile; fileRef = 54DA12A01F315EE100DD57A1 /* listen_spec_test.json */; }; D756A1A63E626572EE8DF592 /* firestore.pb.cc in Sources */ = {isa = PBXBuildFile; fileRef = 544129D421C2DDC800EFB9CC /* firestore.pb.cc */; }; D77941FD93DBE862AEF1F623 /* FSTTransactionTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5492E07B202154EB00B64F25 /* FSTTransactionTests.mm */; }; - D8F427680C3165DCD1A6BA2A /* field_behavior.pb.cc in Sources */ = {isa = PBXBuildFile; fileRef = FAAF1A69F4A315C38357BDC4 /* field_behavior.pb.cc */; }; D91D86B29B86A60C05879A48 /* timestamp_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = ABF6506B201131F8005F2C74 /* timestamp_test.cc */; }; D928302820891CCCAD0437DD /* thread_safe_memoizer_testing.cc in Sources */ = {isa = PBXBuildFile; fileRef = 6E42FA109D363EA7F3387AAE /* thread_safe_memoizer_testing.cc */; }; D9366A834BFF13246DC3AF9E /* field_path_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = B686F2AD2023DDB20028D6BE /* field_path_test.cc */; }; @@ -1473,7 +1471,7 @@ DD6C480629B3F87933FAF440 /* filesystem_testing.cc in Sources */ = {isa = PBXBuildFile; fileRef = BA02DA2FCD0001CFC6EB08DA /* filesystem_testing.cc */; }; DD935E243A64A4EB688E4C1C /* credentials_provider_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 2F4FA4576525144C5069A7A5 /* credentials_provider_test.cc */; }; DD941BF189E38312E7A2CB21 /* Validation_BloomFilterTest_MD5_500_1_bloom_filter_proto.json in Resources */ = {isa = PBXBuildFile; fileRef = D8E530B27D5641B9C26A452C /* Validation_BloomFilterTest_MD5_500_1_bloom_filter_proto.json */; }; - DDABEDF95A5B44E590064EF7 /* field_behavior.pb.cc in Sources */ = {isa = PBXBuildFile; fileRef = FAAF1A69F4A315C38357BDC4 /* field_behavior.pb.cc */; }; + DDC782CBA37AA9B0EA373B7A /* explain_stats.pb.cc in Sources */ = {isa = PBXBuildFile; fileRef = 428662F00938E9E21F7080D7 /* explain_stats.pb.cc */; }; DDD219222EEE13E3F9F2C703 /* leveldb_transaction_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 88CF09277CFA45EE1273E3BA /* leveldb_transaction_test.cc */; }; DDDE74C752E65DE7D39A7166 /* view_testing.cc in Sources */ = {isa = PBXBuildFile; fileRef = A5466E7809AD2871FFDE6C76 /* view_testing.cc */; }; DE03B2D41F2149D600A30B9C /* XCTest.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6003F5AF195388D20070C39A /* XCTest.framework */; }; @@ -1486,11 +1484,13 @@ DEC033E4FB3E09A3C7CE6016 /* aggregate_query_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = AF924C79F49F793992A84879 /* aggregate_query_test.cc */; }; DEF4BF5FAA83C37100408F89 /* bundle_spec_test.json in Resources */ = {isa = PBXBuildFile; fileRef = 79EAA9F7B1B9592B5F053923 /* bundle_spec_test.json */; }; DF4B3835C5AA4835C01CD255 /* local_store_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 307FF03D0297024D59348EBD /* local_store_test.cc */; }; + DF6FBE5BBD578B0DD34CEFA1 /* PipelineApiTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 59BF06E5A4988F9F949DD871 /* PipelineApiTests.swift */; }; DF7ABEB48A650117CBEBCD26 /* object_value_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 214877F52A705012D6720CA0 /* object_value_test.cc */; }; DF96816EC67F9B8DF19B0CFD /* document_overlay_cache_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = FFCA39825D9678A03D1845D0 /* document_overlay_cache_test.cc */; }; DF983A9C1FBF758AF3AF110D /* aggregation_result.pb.cc in Sources */ = {isa = PBXBuildFile; fileRef = D872D754B8AD88E28AF28B28 /* aggregation_result.pb.cc */; }; E042112665DD2504E3F495D5 /* Validation_BloomFilterTest_MD5_5000_1_bloom_filter_proto.json in Resources */ = {isa = PBXBuildFile; fileRef = 4375BDCDBCA9938C7F086730 /* Validation_BloomFilterTest_MD5_5000_1_bloom_filter_proto.json */; }; E04607A1E2964684184E8AEA /* index_spec_test.json in Resources */ = {isa = PBXBuildFile; fileRef = 8C7278B604B8799F074F4E8C /* index_spec_test.json */; }; + E04CB0D580980748D5DC453F /* PipelineTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 861684E49DAC993D153E60D0 /* PipelineTests.swift */; }; E08297B35E12106105F448EB /* ordered_code_benchmark.cc in Sources */ = {isa = PBXBuildFile; fileRef = 0473AFFF5567E667A125347B /* ordered_code_benchmark.cc */; }; E084921EFB7CF8CB1E950D6C /* iterator_adaptors_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 54A0353420A3D8CB003E0143 /* iterator_adaptors_test.cc */; }; E0E640226A1439C59BBBA9C1 /* hard_assert_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 444B7AB3F5A2929070CB1363 /* hard_assert_test.cc */; }; @@ -1542,8 +1542,10 @@ E884336B43BBD1194C17E3C4 /* status_testing.cc in Sources */ = {isa = PBXBuildFile; fileRef = 3CAA33F964042646FDDAF9F9 /* status_testing.cc */; }; E8AB8024B70F6C960D8C7530 /* document_overlay_cache_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = FFCA39825D9678A03D1845D0 /* document_overlay_cache_test.cc */; }; E8BA7055EDB8B03CC99A528F /* recovery_spec_test.json in Resources */ = {isa = PBXBuildFile; fileRef = 9C1AFCC9E616EC33D6E169CF /* recovery_spec_test.json */; }; + E9071BE412DC42300B936BAF /* explain_stats.pb.cc in Sources */ = {isa = PBXBuildFile; fileRef = 428662F00938E9E21F7080D7 /* explain_stats.pb.cc */; }; E962CA641FB1312638593131 /* leveldb_document_overlay_cache_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = AE89CFF09C6804573841397F /* leveldb_document_overlay_cache_test.cc */; }; E99D5467483B746D4AA44F74 /* fields_array_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = BA4CBA48204C9E25B56993BC /* fields_array_test.cc */; }; + E9BC6A5BC2B209B1BA2F8BD6 /* field_behavior.pb.cc in Sources */ = {isa = PBXBuildFile; fileRef = 1F78CD3208A1D5885B4C134E /* field_behavior.pb.cc */; }; EA38690795FBAA182A9AA63E /* FIRDatabaseTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5492E06C202154D500B64F25 /* FIRDatabaseTests.mm */; }; EA46611779C3EEF12822508C /* annotations.pb.cc in Sources */ = {isa = PBXBuildFile; fileRef = 618BBE9520B89AAC00B5BCE7 /* annotations.pb.cc */; }; EAA1962BFBA0EBFBA53B343F /* bundle_builder.cc in Sources */ = {isa = PBXBuildFile; fileRef = 4F5B96F3ABCD2CA901DB1CD4 /* bundle_builder.cc */; }; @@ -1605,6 +1607,7 @@ F19B749671F2552E964422F7 /* FIRListenerRegistrationTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5492E06B202154D500B64F25 /* FIRListenerRegistrationTests.mm */; }; F1EAEE9DF819C017A9506AEB /* FIRIndexingTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 795AA8FC31D2AF6864B07D39 /* FIRIndexingTests.mm */; }; F1F8FB9254E9A5107161A7B2 /* Validation_BloomFilterTest_MD5_500_01_membership_test_result.json in Resources */ = {isa = PBXBuildFile; fileRef = DD990FD89C165F4064B4F608 /* Validation_BloomFilterTest_MD5_500_01_membership_test_result.json */; }; + F21A3E06BBEC807FADB43AAF /* field_behavior.pb.cc in Sources */ = {isa = PBXBuildFile; fileRef = 1F78CD3208A1D5885B4C134E /* field_behavior.pb.cc */; }; F272A8C41D2353700A11D1FB /* field_mask_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 549CCA5320A36E1F00BCEB75 /* field_mask_test.cc */; }; F27347560A963E8162C56FF3 /* target_index_matcher_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 63136A2371C0C013EC7A540C /* target_index_matcher_test.cc */; }; F2876F16CF689FD7FFBA9DFA /* Validation_BloomFilterTest_MD5_1_01_bloom_filter_proto.json in Resources */ = {isa = PBXBuildFile; fileRef = 0D964D4936953635AC7E0834 /* Validation_BloomFilterTest_MD5_1_01_bloom_filter_proto.json */; }; @@ -1621,7 +1624,6 @@ F58A23FEF328EB74F681FE83 /* index_manager_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = AE4A9E38D65688EE000EE2A1 /* index_manager_test.cc */; }; F5A654E92FF6F3FF16B93E6B /* mutation_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = C8522DE226C467C54E6788D8 /* mutation_test.cc */; }; F5B1F219E912F645FB79D08E /* firebase_app_check_credentials_provider_test.mm in Sources */ = {isa = PBXBuildFile; fileRef = F119BDDF2F06B3C0883B8297 /* firebase_app_check_credentials_provider_test.mm */; }; - F5BA649242983E2E54345BDD /* pipeline.pb.cc in Sources */ = {isa = PBXBuildFile; fileRef = 7142B5EC46E88349FAB3384F /* pipeline.pb.cc */; }; F5BDECEB3B43BD1591EEADBD /* FSTUserDataReaderTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 8D9892F204959C50613F16C8 /* FSTUserDataReaderTests.mm */; }; F6079BFC9460B190DA85C2E6 /* pretty_printing_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = AB323F9553050F4F6490F9FF /* pretty_printing_test.cc */; }; F609600E9A88A4D44FD1FCEB /* FSTSpecTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5492E03020213FFC00B64F25 /* FSTSpecTests.mm */; }; @@ -1652,6 +1654,7 @@ FB2111D9205822CC8E7368C2 /* FIRDocumentReferenceTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5492E049202154AA00B64F25 /* FIRDocumentReferenceTests.mm */; }; FB2D5208A6B5816A7244D77A /* query_engine_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = B8A853940305237AFDA8050B /* query_engine_test.cc */; }; FB3D9E01547436163C456A3C /* message_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = CE37875365497FFA8687B745 /* message_test.cc */; }; + FB462B2C6D3C167DF32BA0E1 /* field_behavior.pb.cc in Sources */ = {isa = PBXBuildFile; fileRef = 1F78CD3208A1D5885B4C134E /* field_behavior.pb.cc */; }; FBBB13329D3B5827C21AE7AB /* reference_set_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 132E32997D781B896672D30A /* reference_set_test.cc */; }; FC1D22B6EC4E5F089AE39B8C /* memory_target_cache_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 2286F308EFB0534B1BDE05B9 /* memory_target_cache_test.cc */; }; FC6C9D1A8B24A5C9507272F7 /* globals_cache_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 4564AD9C55EC39C080EB9476 /* globals_cache_test.cc */; }; @@ -1738,7 +1741,6 @@ 0D964D4936953635AC7E0834 /* Validation_BloomFilterTest_MD5_1_01_bloom_filter_proto.json */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.json; name = Validation_BloomFilterTest_MD5_1_01_bloom_filter_proto.json; path = bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_1_01_bloom_filter_proto.json; sourceTree = ""; }; 0EE5300F8233D14025EF0456 /* string_apple_test.mm */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.objcpp; path = string_apple_test.mm; sourceTree = ""; }; 11984BA0A99D7A7ABA5B0D90 /* Pods-Firestore_Example_iOS-Firestore_SwiftTests_iOS.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Firestore_Example_iOS-Firestore_SwiftTests_iOS.release.xcconfig"; path = "Pods/Target Support Files/Pods-Firestore_Example_iOS-Firestore_SwiftTests_iOS/Pods-Firestore_Example_iOS-Firestore_SwiftTests_iOS.release.xcconfig"; sourceTree = ""; }; - 12260A292D56A3CE001766EB /* PipelineTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PipelineTests.swift; sourceTree = ""; }; 1235769122B7E915007DDFA9 /* EncodableFieldValueTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EncodableFieldValueTests.swift; sourceTree = ""; }; 1235769422B86E65007DDFA9 /* FirestoreEncoderTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FirestoreEncoderTests.swift; sourceTree = ""; }; 124C932B22C1642C00CA8C2D /* CodableIntegrationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CodableIntegrationTests.swift; sourceTree = ""; }; @@ -1746,20 +1748,20 @@ 129A369928CA555B005AE7E2 /* FIRCountTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = FIRCountTests.mm; sourceTree = ""; }; 12F4357299652983A615F886 /* LICENSE */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text; name = LICENSE; path = ../LICENSE; sourceTree = ""; }; 132E32997D781B896672D30A /* reference_set_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = reference_set_test.cc; sourceTree = ""; }; + 15249D092D85B40EFC8A1459 /* pipeline.pb.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = pipeline.pb.h; sourceTree = ""; }; 166CE73C03AB4366AAC5201C /* leveldb_index_manager_test.cc */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; path = leveldb_index_manager_test.cc; sourceTree = ""; }; 1A7D48A017ECB54FD381D126 /* Validation_BloomFilterTest_MD5_5000_1_membership_test_result.json */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.json; name = Validation_BloomFilterTest_MD5_5000_1_membership_test_result.json; path = bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_5000_1_membership_test_result.json; sourceTree = ""; }; 1A8141230C7E3986EACEF0B6 /* thread_safe_memoizer_test.cc */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; path = thread_safe_memoizer_test.cc; sourceTree = ""; }; 1B342370EAE3AA02393E33EB /* cc_compilation_test.cc */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; name = cc_compilation_test.cc; path = api/cc_compilation_test.cc; sourceTree = ""; }; 1B9F95EC29FAD3F100EEC075 /* FIRAggregateQueryUnitTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = FIRAggregateQueryUnitTests.mm; sourceTree = ""; }; - 1BAFC713D2B1A2DBD55B2593 /* field_behavior.pb.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = field_behavior.pb.h; sourceTree = ""; }; 1C01D8CE367C56BB2624E299 /* index.pb.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = index.pb.h; path = admin/index.pb.h; sourceTree = ""; }; 1C3F7302BF4AE6CBC00ECDD0 /* resource.pb.cc */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; path = resource.pb.cc; sourceTree = ""; }; 1CA9800A53669EFBFFB824E3 /* memory_remote_document_cache_test.cc */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; path = memory_remote_document_cache_test.cc; sourceTree = ""; }; 1E0C7C0DCD2790019E66D8CC /* bloom_filter.pb.cc */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; path = bloom_filter.pb.cc; sourceTree = ""; }; 1F50E872B3F117A674DA8E94 /* index_backfiller_test.cc */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; path = index_backfiller_test.cc; sourceTree = ""; }; + 1F78CD3208A1D5885B4C134E /* field_behavior.pb.cc */ = {isa = PBXFileReference; includeInIndex = 1; path = field_behavior.pb.cc; sourceTree = ""; }; 214877F52A705012D6720CA0 /* object_value_test.cc */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; path = object_value_test.cc; sourceTree = ""; }; 2220F583583EFC28DE792ABE /* Pods_Firestore_IntegrationTests_tvOS.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Firestore_IntegrationTests_tvOS.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 2258E6EBCFB8E8B1693C1347 /* explain_stats.pb.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = explain_stats.pb.h; sourceTree = ""; }; 2286F308EFB0534B1BDE05B9 /* memory_target_cache_test.cc */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; path = memory_target_cache_test.cc; sourceTree = ""; }; 26DDBA115DEB88631B93F203 /* thread_safe_memoizer_testing.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = thread_safe_memoizer_testing.h; sourceTree = ""; }; 277EAACC4DD7C21332E8496A /* lru_garbage_collector_test.cc */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; path = lru_garbage_collector_test.cc; sourceTree = ""; }; @@ -1797,11 +1799,12 @@ 403DBF6EFB541DFD01582AA3 /* path_test.cc */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; path = path_test.cc; sourceTree = ""; }; 40F9D09063A07F710811A84F /* value_util_test.cc */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; path = value_util_test.cc; sourceTree = ""; }; 4132F30044D5DF1FB15B2A9D /* fake_credentials_provider.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = fake_credentials_provider.h; sourceTree = ""; }; + 428662F00938E9E21F7080D7 /* explain_stats.pb.cc */ = {isa = PBXFileReference; includeInIndex = 1; path = explain_stats.pb.cc; sourceTree = ""; }; 432C71959255C5DBDF522F52 /* byte_stream_test.cc */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; path = byte_stream_test.cc; sourceTree = ""; }; 4334F87873015E3763954578 /* status_testing.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = status_testing.h; sourceTree = ""; }; 4375BDCDBCA9938C7F086730 /* Validation_BloomFilterTest_MD5_5000_1_bloom_filter_proto.json */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.json; name = Validation_BloomFilterTest_MD5_5000_1_bloom_filter_proto.json; path = bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_5000_1_bloom_filter_proto.json; sourceTree = ""; }; 444B7AB3F5A2929070CB1363 /* hard_assert_test.cc */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; path = hard_assert_test.cc; sourceTree = ""; }; - 4564AD9C55EC39C080EB9476 /* globals_cache_test.cc */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; path = globals_cache_test.cc; sourceTree = ""; }; + 4564AD9C55EC39C080EB9476 /* globals_cache_test.cc */ = {isa = PBXFileReference; includeInIndex = 1; path = globals_cache_test.cc; sourceTree = ""; }; 478DC75A0DCA6249A616DD30 /* Validation_BloomFilterTest_MD5_500_0001_membership_test_result.json */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.json; name = Validation_BloomFilterTest_MD5_500_0001_membership_test_result.json; path = bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_500_0001_membership_test_result.json; sourceTree = ""; }; 48D0915834C3D234E5A875A9 /* grpc_stream_tester.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = grpc_stream_tester.h; sourceTree = ""; }; 4B3E4A77493524333133C5DC /* Validation_BloomFilterTest_MD5_50000_1_bloom_filter_proto.json */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.json; name = Validation_BloomFilterTest_MD5_50000_1_bloom_filter_proto.json; path = bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_50000_1_bloom_filter_proto.json; sourceTree = ""; }; @@ -1916,10 +1919,11 @@ 57F8EE51B5EFC9FAB185B66C /* Validation_BloomFilterTest_MD5_5000_01_bloom_filter_proto.json */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.json; name = Validation_BloomFilterTest_MD5_5000_01_bloom_filter_proto.json; path = bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_5000_01_bloom_filter_proto.json; sourceTree = ""; }; 584AE2C37A55B408541A6FF3 /* remote_event_test.cc */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; path = remote_event_test.cc; sourceTree = ""; }; 5918805E993304321A05E82B /* Pods_Firestore_Example_iOS.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Firestore_Example_iOS.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 59BF06E5A4988F9F949DD871 /* PipelineApiTests.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = PipelineApiTests.swift; sourceTree = ""; }; 5B5414D28802BC76FDADABD6 /* stream_test.cc */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; path = stream_test.cc; sourceTree = ""; }; 5B96CC29E9946508F022859C /* Validation_BloomFilterTest_MD5_50000_0001_membership_test_result.json */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.json; name = Validation_BloomFilterTest_MD5_50000_0001_membership_test_result.json; path = bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_50000_0001_membership_test_result.json; sourceTree = ""; }; 5C68EE4CB94C0DD6E333F546 /* Validation_BloomFilterTest_MD5_1_01_membership_test_result.json */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.json; name = Validation_BloomFilterTest_MD5_1_01_membership_test_result.json; path = bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_1_01_membership_test_result.json; sourceTree = ""; }; - 5C6DEA63FBDE19D841291723 /* memory_globals_cache_test.cc */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; path = memory_globals_cache_test.cc; sourceTree = ""; }; + 5C6DEA63FBDE19D841291723 /* memory_globals_cache_test.cc */ = {isa = PBXFileReference; includeInIndex = 1; path = memory_globals_cache_test.cc; sourceTree = ""; }; 5C7942B6244F4C416B11B86C /* leveldb_mutation_queue_test.cc */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; path = leveldb_mutation_queue_test.cc; sourceTree = ""; }; 5CAE131920FFFED600BE9A4A /* Firestore_Benchmarks_iOS.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = Firestore_Benchmarks_iOS.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 5CAE131D20FFFED600BE9A4A /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; @@ -1966,7 +1970,6 @@ 64AA92CFA356A2360F3C5646 /* filesystem_testing.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = filesystem_testing.h; sourceTree = ""; }; 65AF0AB593C3AD81A1F1A57E /* FIRCompositeIndexQueryTests.mm */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.objcpp; path = FIRCompositeIndexQueryTests.mm; sourceTree = ""; }; 67786C62C76A740AEDBD8CD3 /* FSTTestingHooks.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = FSTTestingHooks.h; sourceTree = ""; }; - 682582E5728F3F1C531990EA /* explain_stats.pb.cc */ = {isa = PBXFileReference; includeInIndex = 1; path = explain_stats.pb.cc; sourceTree = ""; }; 69E6C311558EC77729A16CF1 /* Pods-Firestore_Example_iOS-Firestore_SwiftTests_iOS.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Firestore_Example_iOS-Firestore_SwiftTests_iOS.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Firestore_Example_iOS-Firestore_SwiftTests_iOS/Pods-Firestore_Example_iOS-Firestore_SwiftTests_iOS.debug.xcconfig"; sourceTree = ""; }; 6A7A30A2DB3367E08939E789 /* bloom_filter.pb.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = bloom_filter.pb.h; sourceTree = ""; }; 6AE927CDFC7A72BF825BE4CB /* Pods-Firestore_Tests_tvOS.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Firestore_Tests_tvOS.release.xcconfig"; path = "Pods/Target Support Files/Pods-Firestore_Tests_tvOS/Pods-Firestore_Tests_tvOS.release.xcconfig"; sourceTree = ""; }; @@ -1983,7 +1986,6 @@ 6F57521E161450FAF89075ED /* event_manager_test.cc */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; path = event_manager_test.cc; sourceTree = ""; }; 6F5B6C1399F92FD60F2C582B /* nanopb_util_test.cc */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; name = nanopb_util_test.cc; path = nanopb/nanopb_util_test.cc; sourceTree = ""; }; 71140E5D09C6E76F7C71B2FC /* fake_target_metadata_provider.cc */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; path = fake_target_metadata_provider.cc; sourceTree = ""; }; - 7142B5EC46E88349FAB3384F /* pipeline.pb.cc */ = {isa = PBXFileReference; includeInIndex = 1; path = pipeline.pb.cc; sourceTree = ""; }; 71719F9E1E33DC2100824A3D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 728F617782600536F2561463 /* Validation_BloomFilterTest_MD5_5000_0001_bloom_filter_proto.json */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.json; name = Validation_BloomFilterTest_MD5_5000_0001_bloom_filter_proto.json; path = bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_5000_0001_bloom_filter_proto.json; sourceTree = ""; }; 731541602214AFFA0037F4DC /* query_spec_test.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = query_spec_test.json; sourceTree = ""; }; @@ -2009,6 +2011,8 @@ 7EB299CF85034F09CFD6F3FD /* remote_document_cache_test.cc */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; path = remote_document_cache_test.cc; sourceTree = ""; }; 84076EADF6872C78CDAC7291 /* bundle_builder.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = bundle_builder.h; sourceTree = ""; }; 84434E57CA72951015FC71BC /* Pods-Firestore_FuzzTests_iOS.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Firestore_FuzzTests_iOS.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Firestore_FuzzTests_iOS/Pods-Firestore_FuzzTests_iOS.debug.xcconfig"; sourceTree = ""; }; + 861684E49DAC993D153E60D0 /* PipelineTests.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = PipelineTests.swift; sourceTree = ""; }; + 86C7F725E6E1DA312807D8D3 /* explain_stats.pb.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = explain_stats.pb.h; sourceTree = ""; }; 872C92ABD71B12784A1C5520 /* async_testing.cc */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; path = async_testing.cc; sourceTree = ""; }; 873B8AEA1B1F5CCA007FD442 /* Main.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; name = Main.storyboard; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 87553338E42B8ECA05BA987E /* grpc_stream_tester.cc */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; path = grpc_stream_tester.cc; sourceTree = ""; }; @@ -2040,6 +2044,7 @@ A20BAA3D2F994384279727EC /* md5_testing.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = md5_testing.h; sourceTree = ""; }; A2E6F09AD1EE0A6A452E9A08 /* bloom_filter_test.cc */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; path = bloom_filter_test.cc; sourceTree = ""; }; A366F6AE1A5A77548485C091 /* bundle.pb.cc */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; path = bundle.pb.cc; sourceTree = ""; }; + A4192EB032E23129EF23605A /* field_behavior.pb.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = field_behavior.pb.h; sourceTree = ""; }; A5466E7809AD2871FFDE6C76 /* view_testing.cc */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; path = view_testing.cc; sourceTree = ""; }; A5D9044B72061CAF284BC9E4 /* Validation_BloomFilterTest_MD5_50000_0001_bloom_filter_proto.json */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.json; name = Validation_BloomFilterTest_MD5_50000_0001_bloom_filter_proto.json; path = bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_50000_0001_bloom_filter_proto.json; sourceTree = ""; }; A5FA86650A18F3B7A8162287 /* Pods-Firestore_Benchmarks_iOS.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Firestore_Benchmarks_iOS.release.xcconfig"; path = "Pods/Target Support Files/Pods-Firestore_Benchmarks_iOS/Pods-Firestore_Benchmarks_iOS.release.xcconfig"; sourceTree = ""; }; @@ -2114,13 +2119,13 @@ D0A6E9136804A41CEC9D55D4 /* delayed_constructor_test.cc */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; path = delayed_constructor_test.cc; sourceTree = ""; }; D22D4C211AC32E4F8B4883DA /* Validation_BloomFilterTest_MD5_500_0001_bloom_filter_proto.json */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.json; name = Validation_BloomFilterTest_MD5_500_0001_bloom_filter_proto.json; path = bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_500_0001_bloom_filter_proto.json; sourceTree = ""; }; D3CC3DC5338DCAF43A211155 /* README.md */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = net.daringfireball.markdown; name = README.md; path = ../README.md; sourceTree = ""; }; + D49E7AEE500651D25C5360C3 /* pipeline.pb.cc */ = {isa = PBXFileReference; includeInIndex = 1; path = pipeline.pb.cc; sourceTree = ""; }; D5B2593BCB52957D62F1C9D3 /* perf_spec_test.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = perf_spec_test.json; sourceTree = ""; }; D5B25E7E7D6873CBA4571841 /* FIRNumericTransformTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = FIRNumericTransformTests.mm; sourceTree = ""; }; D7DF4A6F740086A2D8C0E28E /* Pods_Firestore_Tests_tvOS.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Firestore_Tests_tvOS.framework; sourceTree = BUILT_PRODUCTS_DIR; }; D85AC18C55650ED230A71B82 /* FSTTestingHooks.mm */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.objcpp; path = FSTTestingHooks.mm; sourceTree = ""; }; D872D754B8AD88E28AF28B28 /* aggregation_result.pb.cc */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; path = aggregation_result.pb.cc; sourceTree = ""; }; D8A6D52723B1BABE1B7B8D8F /* leveldb_overlay_migration_manager_test.cc */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; path = leveldb_overlay_migration_manager_test.cc; sourceTree = ""; }; - D8DAE1269481D15A291E0B49 /* pipeline.pb.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = pipeline.pb.h; sourceTree = ""; }; D8E530B27D5641B9C26A452C /* Validation_BloomFilterTest_MD5_500_1_bloom_filter_proto.json */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.json; name = Validation_BloomFilterTest_MD5_500_1_bloom_filter_proto.json; path = bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_500_1_bloom_filter_proto.json; sourceTree = ""; }; D9D94300B9C02F7069523C00 /* leveldb_snappy_test.cc */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; path = leveldb_snappy_test.cc; sourceTree = ""; }; DAFF0CF521E64AC30062958F /* Firestore_Example_macOS.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Firestore_Example_macOS.app; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -2168,7 +2173,6 @@ F848C41C03A25C42AD5A4BC2 /* target_cache_test.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = target_cache_test.h; sourceTree = ""; }; F869D85E900E5AF6CD02E2FC /* firebase_auth_credentials_provider_test.mm */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.objcpp; name = firebase_auth_credentials_provider_test.mm; path = credentials/firebase_auth_credentials_provider_test.mm; sourceTree = ""; }; FA2E9952BA2B299C1156C43C /* Pods-Firestore_Benchmarks_iOS.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Firestore_Benchmarks_iOS.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Firestore_Benchmarks_iOS/Pods-Firestore_Benchmarks_iOS.debug.xcconfig"; sourceTree = ""; }; - FAAF1A69F4A315C38357BDC4 /* field_behavior.pb.cc */ = {isa = PBXFileReference; includeInIndex = 1; path = field_behavior.pb.cc; sourceTree = ""; }; FC44D934D4A52C790659C8D6 /* leveldb_globals_cache_test.cc */ = {isa = PBXFileReference; includeInIndex = 1; path = leveldb_globals_cache_test.cc; sourceTree = ""; }; FC738525340E594EBFAB121E /* Pods-Firestore_Example_tvOS.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Firestore_Example_tvOS.release.xcconfig"; path = "Pods/Target Support Files/Pods-Firestore_Example_tvOS/Pods-Firestore_Example_tvOS.release.xcconfig"; sourceTree = ""; }; FF73B39D04D1760190E6B84A /* FIRQueryUnitTests.mm */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.objcpp; path = FIRQueryUnitTests.mm; sourceTree = ""; }; @@ -2300,7 +2304,8 @@ 124C932B22C1642C00CA8C2D /* CodableIntegrationTests.swift */, 3355BE9391CC4857AF0BDAE3 /* DatabaseTests.swift */, 62E54B832A9E910A003347C8 /* IndexingTests.swift */, - 12260A292D56A3CE001766EB /* PipelineTests.swift */, + 59BF06E5A4988F9F949DD871 /* PipelineApiTests.swift */, + 861684E49DAC993D153E60D0 /* PipelineTests.swift */, 621D620928F9CE7400D2FA26 /* QueryIntegrationTests.swift */, 4D65F6E69993611D47DC8E7C /* SnapshotListenerSourceTests.swift */, EFF22EA92C5060A4009A369B /* VectorIntegrationTests.swift */, @@ -2339,12 +2344,12 @@ 544129D121C2DDC800EFB9CC /* common.pb.h */, 544129D821C2DDC800EFB9CC /* document.pb.cc */, 544129D721C2DDC800EFB9CC /* document.pb.h */, - 682582E5728F3F1C531990EA /* explain_stats.pb.cc */, - 2258E6EBCFB8E8B1693C1347 /* explain_stats.pb.h */, + 428662F00938E9E21F7080D7 /* explain_stats.pb.cc */, + 86C7F725E6E1DA312807D8D3 /* explain_stats.pb.h */, 544129D421C2DDC800EFB9CC /* firestore.pb.cc */, 544129D321C2DDC800EFB9CC /* firestore.pb.h */, - 7142B5EC46E88349FAB3384F /* pipeline.pb.cc */, - D8DAE1269481D15A291E0B49 /* pipeline.pb.h */, + D49E7AEE500651D25C5360C3 /* pipeline.pb.cc */, + 15249D092D85B40EFC8A1459 /* pipeline.pb.h */, 544129D621C2DDC800EFB9CC /* query.pb.cc */, 544129D021C2DDC800EFB9CC /* query.pb.h */, 544129D921C2DDC800EFB9CC /* write.pb.cc */, @@ -2811,8 +2816,8 @@ children = ( 618BBE9520B89AAC00B5BCE7 /* annotations.pb.cc */, 618BBE9620B89AAC00B5BCE7 /* annotations.pb.h */, - FAAF1A69F4A315C38357BDC4 /* field_behavior.pb.cc */, - 1BAFC713D2B1A2DBD55B2593 /* field_behavior.pb.h */, + 1F78CD3208A1D5885B4C134E /* field_behavior.pb.cc */, + A4192EB032E23129EF23605A /* field_behavior.pb.h */, 618BBE9720B89AAC00B5BCE7 /* http.pb.cc */, 618BBE9420B89AAC00B5BCE7 /* http.pb.h */, 1C3F7302BF4AE6CBC00ECDD0 /* resource.pb.cc */, @@ -4262,10 +4267,10 @@ AC6C1E57B18730428CB15E03 /* executor_libdispatch_test.mm in Sources */, E7D415B8717701B952C344E5 /* executor_std_test.cc in Sources */, 470A37727BBF516B05ED276A /* executor_test.cc in Sources */, - B280370F84393808250B28BC /* explain_stats.pb.cc in Sources */, + 2F72DBE2EC6E24A81C69DEF0 /* explain_stats.pb.cc in Sources */, 2E0BBA7E627EB240BA11B0D0 /* exponential_backoff_test.cc in Sources */, 9009C285F418EA80C46CF06B /* fake_target_metadata_provider.cc in Sources */, - A5301AA55748A11801E3EE47 /* field_behavior.pb.cc in Sources */, + 7B58861D0978827BC4CB1DFA /* field_behavior.pb.cc in Sources */, 2E373EA9D5FF8C6DE2507675 /* field_index_test.cc in Sources */, 07B1E8C62772758BC82FEBEE /* field_mask_test.cc in Sources */, D9366A834BFF13246DC3AF9E /* field_path_test.cc in Sources */, @@ -4341,7 +4346,7 @@ BE1D7C7E413449AFFBA21BCB /* overlay_test.cc in Sources */, DB7E9C5A59CCCDDB7F0C238A /* path_test.cc in Sources */, E30BF9E316316446371C956C /* persistence_testing.cc in Sources */, - 715A0E92C83AE4384A13B882 /* pipeline.pb.cc in Sources */, + 60DA778E447F9ACD402FDA2F /* pipeline.pb.cc in Sources */, 0455FC6E2A281BD755FD933A /* precondition_test.cc in Sources */, 5ECE040F87E9FCD0A5D215DB /* pretty_printing_test.cc in Sources */, 938F2AF6EC5CD0B839300DB0 /* query.pb.cc in Sources */, @@ -4488,10 +4493,10 @@ B220E091D8F4E6DE1EA44F57 /* executor_libdispatch_test.mm in Sources */, BAB43C839445782040657239 /* executor_std_test.cc in Sources */, 3A7CB01751697ED599F2D9A1 /* executor_test.cc in Sources */, - 8FE63980976481EBA001B789 /* explain_stats.pb.cc in Sources */, + 7CAF0E8C47FB2DD486240D47 /* explain_stats.pb.cc in Sources */, EF3518F84255BAF3EBD317F6 /* exponential_backoff_test.cc in Sources */, 4DAFC3A3FD5E96910A517320 /* fake_target_metadata_provider.cc in Sources */, - 86E73F6286E87834CF37D5D9 /* field_behavior.pb.cc in Sources */, + E9BC6A5BC2B209B1BA2F8BD6 /* field_behavior.pb.cc in Sources */, 69D3AD697D1A7BF803A08160 /* field_index_test.cc in Sources */, ED4E2AC80CAF2A8FDDAC3DEE /* field_mask_test.cc in Sources */, 41EAC526C543064B8F3F7EDA /* field_path_test.cc in Sources */, @@ -4567,7 +4572,7 @@ 2045517602D767BD01EA71D9 /* overlay_test.cc in Sources */, 0963F6D7B0F9AE1E24B82866 /* path_test.cc in Sources */, 92D7081085679497DC112EDB /* persistence_testing.cc in Sources */, - 9CD1E9301EC44ED10DAEA5FB /* pipeline.pb.cc in Sources */, + 8429E18EFBAF473209731E01 /* pipeline.pb.cc in Sources */, 152543FD706D5E8851C8DA92 /* precondition_test.cc in Sources */, 2639ABDA17EECEB7F62D1D83 /* pretty_printing_test.cc in Sources */, 5FA3DB52A478B01384D3A2ED /* query.pb.cc in Sources */, @@ -4690,7 +4695,8 @@ 432056C4D1259F76C80FC2A8 /* FSTUserDataReaderTests.mm in Sources */, 3B1E27D951407FD237E64D07 /* FirestoreEncoderTests.swift in Sources */, 62E54B862A9E910B003347C8 /* IndexingTests.swift in Sources */, - 12260A2C2D56A3CE001766EB /* PipelineTests.swift in Sources */, + 3D5F7AA7BB68529F47BE4B12 /* PipelineApiTests.swift in Sources */, + 655F8647F57E5F2155DFF7B5 /* PipelineTests.swift in Sources */, 621D620C28F9CE7400D2FA26 /* QueryIntegrationTests.swift in Sources */, 1CFBD4563960D8A20C4679A3 /* SnapshotListenerSourceTests.swift in Sources */, EFF22EAC2C5060A4009A369B /* VectorIntegrationTests.swift in Sources */, @@ -4739,10 +4745,10 @@ 5F6CE37B34C542704C5605A4 /* executor_libdispatch_test.mm in Sources */, AECCD9663BB3DC52199F954A /* executor_std_test.cc in Sources */, 18F644E6AA98E6D6F3F1F809 /* executor_test.cc in Sources */, - 0E7A39BD9C87CC33F91A672F /* explain_stats.pb.cc in Sources */, + ABE599C3BF9FB6AFF18AA901 /* explain_stats.pb.cc in Sources */, 6938575C8B5E6FE0D562547A /* exponential_backoff_test.cc in Sources */, 258B372CF33B7E7984BBA659 /* fake_target_metadata_provider.cc in Sources */, - D8F427680C3165DCD1A6BA2A /* field_behavior.pb.cc in Sources */, + 2FC2B732841BF2C425EB35DF /* field_behavior.pb.cc in Sources */, F8BD2F61EFA35C2D5120D9EB /* field_index_test.cc in Sources */, F272A8C41D2353700A11D1FB /* field_mask_test.cc in Sources */, AF6D6C47F9A25C65BFDCBBA0 /* field_path_test.cc in Sources */, @@ -4818,7 +4824,7 @@ A5583822218F9D5B1E86FCAC /* overlay_test.cc in Sources */, 70A171FC43BE328767D1B243 /* path_test.cc in Sources */, EECC1EC64CA963A8376FA55C /* persistence_testing.cc in Sources */, - 92B593DCD86543D8C90F64F9 /* pipeline.pb.cc in Sources */, + 5CDD24225992674A4D3E3D4E /* pipeline.pb.cc in Sources */, 34D69886DAD4A2029BFC5C63 /* precondition_test.cc in Sources */, F56E9334642C207D7D85D428 /* pretty_printing_test.cc in Sources */, 22A00AC39CAB3426A943E037 /* query.pb.cc in Sources */, @@ -4941,7 +4947,8 @@ 75A176239B37354588769206 /* FSTUserDataReaderTests.mm in Sources */, 5E89B1A5A5430713C79C4854 /* FirestoreEncoderTests.swift in Sources */, 62E54B852A9E910B003347C8 /* IndexingTests.swift in Sources */, - 12260A2B2D56A3CE001766EB /* PipelineTests.swift in Sources */, + DF6FBE5BBD578B0DD34CEFA1 /* PipelineApiTests.swift in Sources */, + C8C2B945D84DD98391145F3F /* PipelineTests.swift in Sources */, 621D620B28F9CE7400D2FA26 /* QueryIntegrationTests.swift in Sources */, A0BC30D482B0ABD1A3A24CDC /* SnapshotListenerSourceTests.swift in Sources */, EFF22EAB2C5060A4009A369B /* VectorIntegrationTests.swift in Sources */, @@ -4990,10 +4997,10 @@ 49C593017B5438B216FAF593 /* executor_libdispatch_test.mm in Sources */, 17DFF30CF61D87883986E8B6 /* executor_std_test.cc in Sources */, 814724DE70EFC3DDF439CD78 /* executor_test.cc in Sources */, - 7492C447277CDC8CB7A165CB /* explain_stats.pb.cc in Sources */, + A296B0110550890E1D8D59A3 /* explain_stats.pb.cc in Sources */, BD6CC8614970A3D7D2CF0D49 /* exponential_backoff_test.cc in Sources */, 4D2655C5675D83205C3749DC /* fake_target_metadata_provider.cc in Sources */, - DDABEDF95A5B44E590064EF7 /* field_behavior.pb.cc in Sources */, + FB462B2C6D3C167DF32BA0E1 /* field_behavior.pb.cc in Sources */, 50C852E08626CFA7DC889EEA /* field_index_test.cc in Sources */, A1563EFEB021936D3FFE07E3 /* field_mask_test.cc in Sources */, B235E260EA0DCB7BAC04F69B /* field_path_test.cc in Sources */, @@ -5069,7 +5076,7 @@ D1BCDAEACF6408200DFB9870 /* overlay_test.cc in Sources */, B3A309CCF5D75A555C7196E1 /* path_test.cc in Sources */, 46EAC2828CD942F27834F497 /* persistence_testing.cc in Sources */, - 3B4CFB45208A7EEF1EA58ADC /* pipeline.pb.cc in Sources */, + D64792BBFA130E26CB3D1028 /* pipeline.pb.cc in Sources */, 9EE1447AA8E68DF98D0590FF /* precondition_test.cc in Sources */, F6079BFC9460B190DA85C2E6 /* pretty_printing_test.cc in Sources */, 7B0F073BDB6D0D6E542E23D4 /* query.pb.cc in Sources */, @@ -5226,10 +5233,10 @@ B6FB468E208F9BAB00554BA2 /* executor_libdispatch_test.mm in Sources */, B6FB468F208F9BAE00554BA2 /* executor_std_test.cc in Sources */, B6FB4690208F9BB300554BA2 /* executor_test.cc in Sources */, - 50EA1F41D766C92894E9B078 /* explain_stats.pb.cc in Sources */, + DDC782CBA37AA9B0EA373B7A /* explain_stats.pb.cc in Sources */, B6D1B68520E2AB1B00B35856 /* exponential_backoff_test.cc in Sources */, FAE5DA6ED3E1842DC21453EE /* fake_target_metadata_provider.cc in Sources */, - 1F9FFAE375C88EFF88CBB6F8 /* field_behavior.pb.cc in Sources */, + F21A3E06BBEC807FADB43AAF /* field_behavior.pb.cc in Sources */, 03AEB9E07A605AE1B5827548 /* field_index_test.cc in Sources */, 549CCA5720A36E1F00BCEB75 /* field_mask_test.cc in Sources */, B686F2AF2023DDEE0028D6BE /* field_path_test.cc in Sources */, @@ -5305,7 +5312,7 @@ 4D20563D846FA0F3BEBFDE9D /* overlay_test.cc in Sources */, 5A080105CCBFDB6BF3F3772D /* path_test.cc in Sources */, 21C17F15579341289AD01051 /* persistence_testing.cc in Sources */, - F5BA649242983E2E54345BDD /* pipeline.pb.cc in Sources */, + C8889F3C37F1CC3E64558287 /* pipeline.pb.cc in Sources */, 549CCA5920A36E1F00BCEB75 /* precondition_test.cc in Sources */, 6A94393D83EB338DFAF6A0D2 /* pretty_printing_test.cc in Sources */, 544129DC21C2DDC800EFB9CC /* query.pb.cc in Sources */, @@ -5447,7 +5454,8 @@ F5BDECEB3B43BD1591EEADBD /* FSTUserDataReaderTests.mm in Sources */, 6F45846C159D3C063DBD3CBE /* FirestoreEncoderTests.swift in Sources */, 62E54B842A9E910B003347C8 /* IndexingTests.swift in Sources */, - 12260A2A2D56A3CE001766EB /* PipelineTests.swift in Sources */, + BD74B0E1FC752236A7376BC3 /* PipelineApiTests.swift in Sources */, + E04CB0D580980748D5DC453F /* PipelineTests.swift in Sources */, 621D620A28F9CE7400D2FA26 /* QueryIntegrationTests.swift in Sources */, B00F8D1819EE20C45B660940 /* SnapshotListenerSourceTests.swift in Sources */, EFF22EAA2C5060A4009A369B /* VectorIntegrationTests.swift in Sources */, @@ -5496,10 +5504,10 @@ B6BF6EFEF887B072068BA658 /* executor_libdispatch_test.mm in Sources */, 125B1048ECB755C2106802EB /* executor_std_test.cc in Sources */, DABB9FB61B1733F985CBF713 /* executor_test.cc in Sources */, - 676933F59F2F0A0D221A4F8F /* explain_stats.pb.cc in Sources */, + E9071BE412DC42300B936BAF /* explain_stats.pb.cc in Sources */, 7BCF050BA04537B0E7D44730 /* exponential_backoff_test.cc in Sources */, BA1C5EAE87393D8E60F5AE6D /* fake_target_metadata_provider.cc in Sources */, - 332E7D2D8489E6DA42947C59 /* field_behavior.pb.cc in Sources */, + 3A110ECBF96B6E44BA77011A /* field_behavior.pb.cc in Sources */, 84285C3F63D916A4786724A8 /* field_index_test.cc in Sources */, 6A40835DB2C02B9F07C02E88 /* field_mask_test.cc in Sources */, D00E69F7FDF2BE674115AD3F /* field_path_test.cc in Sources */, @@ -5575,7 +5583,7 @@ 4D7900401B1BF3D3C24DDC7E /* overlay_test.cc in Sources */, 6105A1365831B79A7DEEA4F3 /* path_test.cc in Sources */, CB8BEF34CC4A996C7BE85119 /* persistence_testing.cc in Sources */, - 2AD2CB51469AE35331C39258 /* pipeline.pb.cc in Sources */, + BC9966788F245D79A63C2E47 /* pipeline.pb.cc in Sources */, 4194B7BB8B0352E1AC5D69B9 /* precondition_test.cc in Sources */, 0EA40EDACC28F445F9A3F32F /* pretty_printing_test.cc in Sources */, 63B91FC476F3915A44F00796 /* query.pb.cc in Sources */, diff --git a/Firestore/Example/Tests/Util/FSTIntegrationTestCase.h b/Firestore/Example/Tests/Util/FSTIntegrationTestCase.h index faca06dee8c..5365f4696ff 100644 --- a/Firestore/Example/Tests/Util/FSTIntegrationTestCase.h +++ b/Firestore/Example/Tests/Util/FSTIntegrationTestCase.h @@ -51,6 +51,8 @@ extern "C" { /** Returns the default Firestore database ID for testing. */ + (NSString *)databaseID; ++ (void)switchToEnterpriseMode; + + (bool)isRunningAgainstEmulator; /** Returns a FirestoreSettings configured to use either hexa or the emulator. */ diff --git a/Firestore/Example/Tests/Util/FSTIntegrationTestCase.mm b/Firestore/Example/Tests/Util/FSTIntegrationTestCase.mm index c64b1e80706..9d69be35af4 100644 --- a/Firestore/Example/Tests/Util/FSTIntegrationTestCase.mm +++ b/Firestore/Example/Tests/Util/FSTIntegrationTestCase.mm @@ -86,6 +86,7 @@ static NSString *defaultProjectId; static NSString *defaultDatabaseId = @"(default)"; +static NSString *enterpriseDatabaseId = @"enterprise"; static FIRFirestoreSettings *defaultSettings; static bool runningAgainstEmulator = false; @@ -273,6 +274,10 @@ + (NSString *)databaseID { return defaultDatabaseId; } ++ (void)switchToEnterpriseMode { + defaultDatabaseId = enterpriseDatabaseId; +} + + (bool)isRunningAgainstEmulator { // The only way to determine whether or not we're running against the emulator is to figure out // which testing environment we're using. Essentially `setUpDefaults` determines diff --git a/Firestore/Source/API/FIRPipelineBridge+Internal.h b/Firestore/Source/API/FIRPipelineBridge+Internal.h index 30bee14aa02..603bc7b88ac 100644 --- a/Firestore/Source/API/FIRPipelineBridge+Internal.h +++ b/Firestore/Source/API/FIRPipelineBridge+Internal.h @@ -35,6 +35,12 @@ NS_ASSUME_NONNULL_BEGIN @end +@interface FIROrderingBridge (Internal) + +- (std::shared_ptr)cppOrderingWithReader:(FSTUserDataReader *)reader; + +@end + @interface FIRStageBridge (Internal) - (std::shared_ptr)cppStageWithReader:(FSTUserDataReader *)reader; @@ -53,4 +59,10 @@ NS_ASSUME_NONNULL_BEGIN @end +@interface FIRPipelineBridge (Internal) + +- (std::shared_ptr)cppPipelineWithReader:(FSTUserDataReader *)reader; + +@end + NS_ASSUME_NONNULL_END diff --git a/Firestore/Source/API/FIRPipelineBridge.mm b/Firestore/Source/API/FIRPipelineBridge.mm index c10a05f4d88..ac3091249e0 100644 --- a/Firestore/Source/API/FIRPipelineBridge.mm +++ b/Firestore/Source/API/FIRPipelineBridge.mm @@ -16,18 +16,25 @@ #import "FIRPipelineBridge.h" +#import + #include #import "Firestore/Source/API/FIRDocumentReference+Internal.h" +#import "Firestore/Source/API/FIRFieldPath+Internal.h" #import "Firestore/Source/API/FIRFirestore+Internal.h" #import "Firestore/Source/API/FIRPipelineBridge+Internal.h" #import "Firestore/Source/API/FSTUserDataReader.h" #import "Firestore/Source/API/FSTUserDataWriter.h" +#import "Firestore/Source/API/converters.h" +#import "Firestore/Source/Public/FirebaseFirestore/FIRVectorValue.h" #include "Firestore/Protos/nanopb/google/firestore/v1/document.nanopb.h" +#include "Firestore/core/src/api/aggregate_expressions.h" #include "Firestore/core/src/api/document_reference.h" #include "Firestore/core/src/api/expressions.h" +#include "Firestore/core/src/api/ordering.h" #include "Firestore/core/src/api/pipeline.h" #include "Firestore/core/src/api/pipeline_result.h" #include "Firestore/core/src/api/pipeline_snapshot.h" @@ -36,17 +43,40 @@ #include "Firestore/core/src/util/status.h" #include "Firestore/core/src/util/string_apple.h" +using firebase::firestore::api::AddFields; +using firebase::firestore::api::AggregateFunction; +using firebase::firestore::api::AggregateStage; +using firebase::firestore::api::CollectionGroupSource; using firebase::firestore::api::CollectionSource; using firebase::firestore::api::Constant; +using firebase::firestore::api::DatabaseSource; +using firebase::firestore::api::DistinctStage; using firebase::firestore::api::DocumentReference; +using firebase::firestore::api::DocumentsSource; using firebase::firestore::api::Expr; using firebase::firestore::api::Field; +using firebase::firestore::api::FindNearestStage; using firebase::firestore::api::FunctionExpr; +using firebase::firestore::api::GenericStage; +using firebase::firestore::api::LimitStage; +using firebase::firestore::api::MakeFIRTimestamp; +using firebase::firestore::api::OffsetStage; +using firebase::firestore::api::Ordering; using firebase::firestore::api::Pipeline; +using firebase::firestore::api::RemoveFieldsStage; +using firebase::firestore::api::ReplaceWith; +using firebase::firestore::api::Sample; +using firebase::firestore::api::SelectStage; +using firebase::firestore::api::SortStage; +using firebase::firestore::api::Union; +using firebase::firestore::api::Unnest; using firebase::firestore::api::Where; +using firebase::firestore::model::FieldPath; +using firebase::firestore::nanopb::SharedMessage; using firebase::firestore::util::MakeCallback; using firebase::firestore::util::MakeNSString; using firebase::firestore::util::MakeString; +using firebase::firestore::util::ThrowInvalidArgument; NS_ASSUME_NONNULL_BEGIN @@ -72,7 +102,7 @@ - (id)init:(NSString *)name { @end @implementation FIRConstantBridge { - std::shared_ptr constant; + std::shared_ptr cpp_constant; id _input; Boolean isUserDataRead; } @@ -85,17 +115,17 @@ - (id)init:(id)input { - (std::shared_ptr)cppExprWithReader:(FSTUserDataReader *)reader { if (!isUserDataRead) { - constant = std::make_shared([reader parsedQueryValue:_input]); + cpp_constant = std::make_shared([reader parsedQueryValue:_input]); } isUserDataRead = YES; - return constant; + return cpp_constant; } @end @implementation FIRFunctionExprBridge { - std::shared_ptr eq; + std::shared_ptr cpp_function; NSString *_name; NSArray *_args; Boolean isUserDataRead; @@ -115,11 +145,66 @@ - (nonnull id)initWithName:(NSString *)name Args:(nonnull NSArray(MakeString(_name), std::move(cpp_args)); + cpp_function = std::make_shared(MakeString(_name), std::move(cpp_args)); + } + + isUserDataRead = YES; + return cpp_function; +} + +@end + +@implementation FIRAggregateFunctionBridge { + std::shared_ptr cpp_function; + NSString *_name; + NSArray *_args; + Boolean isUserDataRead; +} + +- (nonnull id)initWithName:(NSString *)name Args:(nonnull NSArray *)args { + _name = name; + _args = args; + isUserDataRead = NO; + return self; +} + +- (std::shared_ptr)cppExprWithReader:(FSTUserDataReader *)reader { + if (!isUserDataRead) { + std::vector> cpp_args; + for (FIRExprBridge *arg in _args) { + cpp_args.push_back([arg cppExprWithReader:reader]); + } + cpp_function = std::make_shared(MakeString(_name), std::move(cpp_args)); } isUserDataRead = YES; - return eq; + return cpp_function; +} + +@end + +@implementation FIROrderingBridge { + std::shared_ptr cpp_ordering; + NSString *_direction; + FIRExprBridge *_expr; + Boolean isUserDataRead; +} + +- (nonnull id)initWithExpr:(FIRExprBridge *)expr Direction:(NSString *)direction { + _expr = expr; + _direction = direction; + isUserDataRead = NO; + return self; +} + +- (std::shared_ptr)cppOrderingWithReader:(FSTUserDataReader *)reader { + if (!isUserDataRead) { + cpp_ordering = std::make_shared( + [_expr cppExprWithReader:reader], Ordering::DirectionFromString(MakeString(_direction))); + } + + isUserDataRead = YES; + return cpp_ordering; } @end @@ -145,10 +230,68 @@ - (id)initWithPath:(NSString *)path { @end +@implementation FIRDatabaseSourceStageBridge { + std::shared_ptr cpp_database_source; +} + +- (id)init { + self = [super init]; + if (self) { + cpp_database_source = std::make_shared(); + } + return self; +} + +- (std::shared_ptr)cppStageWithReader:(FSTUserDataReader *)reader { + return cpp_database_source; +} + +@end + +@implementation FIRCollectionGroupSourceStageBridge { + std::shared_ptr cpp_collection_group_source; +} + +- (id)initWithCollectionId:(NSString *)id { + self = [super init]; + if (self) { + cpp_collection_group_source = std::make_shared(MakeString(id)); + } + return self; +} + +- (std::shared_ptr)cppStageWithReader:(FSTUserDataReader *)reader { + return cpp_collection_group_source; +} + +@end + +@implementation FIRDocumentsSourceStageBridge { + std::shared_ptr cpp_document_source; +} + +- (id)initWithDocuments:(NSArray *)documents { + self = [super init]; + if (self) { + std::vector cpp_documents; + for (NSString *doc in documents) { + cpp_documents.push_back(MakeString(doc)); + } + cpp_document_source = std::make_shared(std::move(cpp_documents)); + } + return self; +} + +- (std::shared_ptr)cppStageWithReader:(FSTUserDataReader *)reader { + return cpp_document_source; +} + +@end + @implementation FIRWhereStageBridge { FIRExprBridge *_exprBridge; Boolean isUserDataRead; - std::shared_ptr where; + std::shared_ptr cpp_where; } - (id)initWithExpr:(FIRExprBridge *)expr { @@ -162,18 +305,501 @@ - (id)initWithExpr:(FIRExprBridge *)expr { - (std::shared_ptr)cppStageWithReader:(FSTUserDataReader *)reader { if (!isUserDataRead) { - where = std::make_shared([_exprBridge cppExprWithReader:reader]); + cpp_where = std::make_shared([_exprBridge cppExprWithReader:reader]); + } + + isUserDataRead = YES; + return cpp_where; +} + +@end + +@implementation FIRLimitStageBridge { + Boolean isUserDataRead; + std::shared_ptr cpp_limit_stage; + int32_t limit; +} + +- (id)initWithLimit:(NSInteger)value { + self = [super init]; + if (self) { + isUserDataRead = NO; + limit = static_cast(value); + } + return self; +} + +- (std::shared_ptr)cppStageWithReader:(FSTUserDataReader *)reader { + if (!isUserDataRead) { + cpp_limit_stage = std::make_shared(limit); + } + + isUserDataRead = YES; + return cpp_limit_stage; +} + +@end + +@implementation FIROffsetStageBridge { + Boolean isUserDataRead; + std::shared_ptr cpp_offset_stage; + int32_t offset; +} + +- (id)initWithOffset:(NSInteger)value { + self = [super init]; + if (self) { + isUserDataRead = NO; + offset = static_cast(value); + } + return self; +} + +- (std::shared_ptr)cppStageWithReader:(FSTUserDataReader *)reader { + if (!isUserDataRead) { + cpp_offset_stage = std::make_shared(offset); + } + + isUserDataRead = YES; + return cpp_offset_stage; +} + +@end + +// TBD + +@implementation FIRAddFieldsStageBridge { + NSDictionary *_fields; + Boolean isUserDataRead; + std::shared_ptr cpp_add_fields; +} + +- (id)initWithFields:(NSDictionary *)fields { + self = [super init]; + if (self) { + _fields = fields; + isUserDataRead = NO; + } + return self; +} + +- (std::shared_ptr)cppStageWithReader:(FSTUserDataReader *)reader { + if (!isUserDataRead) { + std::unordered_map> cpp_fields; + for (NSString *key in _fields) { + cpp_fields[MakeString(key)] = [_fields[key] cppExprWithReader:reader]; + } + cpp_add_fields = std::make_shared(std::move(cpp_fields)); + } + + isUserDataRead = YES; + return cpp_add_fields; +} + +@end + +@implementation FIRRemoveFieldsStageBridge { + NSArray *_fields; + Boolean isUserDataRead; + std::shared_ptr cpp_remove_fields; +} + +- (id)initWithFields:(NSArray *)fields { + self = [super init]; + if (self) { + _fields = fields; + isUserDataRead = NO; + } + return self; +} + +- (std::shared_ptr)cppStageWithReader:(FSTUserDataReader *)reader { + if (!isUserDataRead) { + std::vector cpp_fields; + for (id field in _fields) { + cpp_fields.push_back(Field(MakeString(field))); + } + cpp_remove_fields = std::make_shared(std::move(cpp_fields)); + } + + isUserDataRead = YES; + return cpp_remove_fields; +} + +@end + +@implementation FIRSelectStageBridge { + NSDictionary *_selections; + Boolean isUserDataRead; + std::shared_ptr cpp_select; +} + +- (id)initWithSelections:(NSDictionary *)selections { + self = [super init]; + if (self) { + _selections = selections; + isUserDataRead = NO; + } + return self; +} + +- (std::shared_ptr)cppStageWithReader:(FSTUserDataReader *)reader { + if (!isUserDataRead) { + std::unordered_map> cpp_selections; + for (NSString *key in _selections) { + cpp_selections[MakeString(key)] = [_selections[key] cppExprWithReader:reader]; + } + cpp_select = std::make_shared(std::move(cpp_selections)); + } + + isUserDataRead = YES; + return cpp_select; +} + +@end + +@implementation FIRDistinctStageBridge { + NSDictionary *_groups; + Boolean isUserDataRead; + std::shared_ptr cpp_distinct; +} + +- (id)initWithGroups:(NSDictionary *)groups { + self = [super init]; + if (self) { + _groups = groups; + isUserDataRead = NO; + } + return self; +} + +- (std::shared_ptr)cppStageWithReader:(FSTUserDataReader *)reader { + if (!isUserDataRead) { + std::unordered_map> cpp_groups; + for (NSString *key in _groups) { + cpp_groups[MakeString(key)] = [_groups[key] cppExprWithReader:reader]; + } + cpp_distinct = std::make_shared(std::move(cpp_groups)); + } + + isUserDataRead = YES; + return cpp_distinct; +} + +@end + +@implementation FIRAggregateStageBridge { + NSDictionary *_accumulators; + NSDictionary *_groups; + Boolean isUserDataRead; + std::shared_ptr cpp_aggregate; +} + +- (id)initWithAccumulators:(NSDictionary *)accumulators + groups:(NSDictionary *)groups { + self = [super init]; + if (self) { + _accumulators = accumulators; + _groups = groups; + isUserDataRead = NO; + } + return self; +} + +- (std::shared_ptr)cppStageWithReader:(FSTUserDataReader *)reader { + if (!isUserDataRead) { + std::unordered_map> cpp_accumulators; + for (NSString *key in _accumulators) { + cpp_accumulators[MakeString(key)] = [_accumulators[key] cppExprWithReader:reader]; + } + + std::unordered_map> cpp_groups; + for (NSString *key in _groups) { + cpp_groups[MakeString(key)] = [_groups[key] cppExprWithReader:reader]; + } + cpp_aggregate = + std::make_shared(std::move(cpp_accumulators), std::move(cpp_groups)); } isUserDataRead = YES; - return where; + return cpp_aggregate; +} + +@end + +@implementation FIRFindNearestStageBridge { + FIRFieldBridge *_field; + FIRVectorValue *_vectorValue; + NSString *_distanceMeasure; + NSNumber *_limit; + NSString *_Nullable _distanceField; + Boolean isUserDataRead; + std::shared_ptr cpp_find_nearest; +} + +- (id)initWithField:(FIRFieldBridge *)field + vectorValue:(FIRVectorValue *)vectorValue + distanceMeasure:(NSString *)distanceMeasure + limit:(NSNumber *_Nullable)limit + distanceField:(NSString *_Nullable)distanceField { + self = [super init]; + if (self) { + _field = field; + _vectorValue = vectorValue; + _distanceMeasure = distanceMeasure; + _limit = limit; + _distanceField = distanceField; + isUserDataRead = NO; + } + return self; +} + +- (std::shared_ptr)cppStageWithReader:(FSTUserDataReader *)reader { + if (!isUserDataRead) { + std::unordered_map> + optional_value; + if (_limit) { + optional_value.emplace( + std::make_pair(std::string("limit"), + nanopb::SharedMessage( + [reader parsedQueryValue:_limit]))); + } + + if (_distanceField) { + optional_value.emplace( + std::make_pair(std::string("distance_field"), + nanopb::SharedMessage( + [reader parsedQueryValue:_distanceField]))); + } + + FindNearestStage::DistanceMeasure::Measure measure_enum; + if ([_distanceMeasure isEqualToString:@"cosine"]) { + measure_enum = FindNearestStage::DistanceMeasure::COSINE; + } else if ([_distanceMeasure isEqualToString:@"dot_product"]) { + measure_enum = FindNearestStage::DistanceMeasure::DOT_PRODUCT; + } else { + measure_enum = FindNearestStage::DistanceMeasure::EUCLIDEAN; + } + + cpp_find_nearest = std::make_shared( + [_field cppExprWithReader:reader], [reader parsedQueryValue:_vectorValue], + FindNearestStage::DistanceMeasure(measure_enum), optional_value); + } + + isUserDataRead = YES; + return cpp_find_nearest; +} + +@end + +@implementation FIRSorStageBridge { + NSArray *_orderings; + Boolean isUserDataRead; + std::shared_ptr cpp_sort; +} + +- (id)initWithOrderings:(NSArray *)orderings { + self = [super init]; + if (self) { + _orderings = orderings; + isUserDataRead = NO; + } + return self; +} + +- (std::shared_ptr)cppStageWithReader:(FSTUserDataReader *)reader { + if (!isUserDataRead) { + std::vector> cpp_orderings; + for (FIROrderingBridge *ordering in _orderings) { + cpp_orderings.push_back([ordering cppOrderingWithReader:reader]); + } + cpp_sort = std::make_shared(std::move(cpp_orderings)); + } + + isUserDataRead = YES; + return cpp_sort; +} + +@end + +@implementation FIRReplaceWithStageBridge { + FIRExprBridge *_expr; + Boolean isUserDataRead; + std::shared_ptr cpp_replace_with; +} + +- (id)initWithExpr:(FIRExprBridge *)expr { + self = [super init]; + if (self) { + _expr = expr; + isUserDataRead = NO; + } + return self; +} + +- (std::shared_ptr)cppStageWithReader:(FSTUserDataReader *)reader { + if (!isUserDataRead) { + cpp_replace_with = std::make_shared([_expr cppExprWithReader:reader]); + } + + isUserDataRead = YES; + return cpp_replace_with; +} + +@end + +@implementation FIRSampleStageBridge { + int64_t _count; + double _percentage; + Boolean isUserDataRead; + NSString *type; + std::shared_ptr cpp_sample; +} + +- (id)initWithCount:(int64_t)count { + self = [super init]; + if (self) { + _count = count; + _percentage = 0; + type = @"count"; + isUserDataRead = NO; + } + return self; +} + +- (id)initWithPercentage:(double)percentage { + self = [super init]; + if (self) { + _percentage = percentage; + _count = 0; + type = @"percentage"; + isUserDataRead = NO; + } + return self; +} + +- (std::shared_ptr)cppStageWithReader:(FSTUserDataReader *)reader { + if (!isUserDataRead) { + if ([type isEqualToString:@"count"]) { + cpp_sample = std::make_shared("count", _count, 0); + } else { + cpp_sample = std::make_shared("percentage", 0, _percentage); + } + } + + isUserDataRead = YES; + return cpp_sample; +} + +@end + +@implementation FIRUnionStageBridge { + FIRPipelineBridge *_other; + Boolean isUserDataRead; + std::shared_ptr cpp_union_stage; +} + +- (id)initWithOther:(FIRPipelineBridge *)other { + self = [super init]; + if (self) { + _other = other; + isUserDataRead = NO; + } + return self; +} + +- (std::shared_ptr)cppStageWithReader:(FSTUserDataReader *)reader { + if (!isUserDataRead) { + cpp_union_stage = std::make_shared([_other cppPipelineWithReader:reader]); + } + + isUserDataRead = YES; + return cpp_union_stage; +} + +@end + +@implementation FIRUnnestStageBridge { + FIRExprBridge *_field; + NSString *_Nullable _indexField; + Boolean isUserDataRead; + std::shared_ptr cpp_unnest; +} + +- (id)initWithField:(FIRExprBridge *)field indexField:(NSString *_Nullable)indexField { + self = [super init]; + if (self) { + _field = field; + _indexField = indexField; + isUserDataRead = NO; + } + return self; +} + +- (std::shared_ptr)cppStageWithReader:(FSTUserDataReader *)reader { + if (!isUserDataRead) { + absl::optional cpp_index_field; + if (_indexField != nil) { + cpp_index_field = MakeString(_indexField); + } else { + cpp_index_field = absl::nullopt; + } + cpp_unnest = std::make_shared([_field cppExprWithReader:reader], cpp_index_field); + } + + isUserDataRead = YES; + return cpp_unnest; +} + +@end + +@implementation FIRGenericStageBridge { + NSString *_name; + NSArray *_params; + NSDictionary *_Nullable _options; + Boolean isUserDataRead; + std::shared_ptr cpp_generic_stage; +} + +- (id)initWithName:(NSString *)name + params:(NSArray *)params + options:(NSDictionary *_Nullable)options { + self = [super init]; + if (self) { + _name = name; + _params = params; + _options = options; + isUserDataRead = NO; + } + return self; +} + +- (std::shared_ptr)cppStageWithReader:(FSTUserDataReader *)reader { + if (!isUserDataRead) { + std::vector> cpp_params; + for (FIRExprBridge *param in _params) { + cpp_params.push_back([param cppExprWithReader:reader]); + } + std::unordered_map> cpp_options; + if (_options) { + for (NSString *key in _options) { + cpp_options[MakeString(key)] = [_options[key] cppExprWithReader:reader]; + } + } + cpp_generic_stage = std::make_shared(MakeString(_name), std::move(cpp_params), + std::move(cpp_options)); + } + + isUserDataRead = YES; + return cpp_generic_stage; } @end @interface __FIRPipelineSnapshotBridge () -@property(nonatomic, strong, readwrite) NSArray<__FIRPipelineSnapshotBridge *> *results; +@property(nonatomic, strong, readwrite) NSArray<__FIRPipelineResultBridge *> *results; @end @@ -206,6 +832,14 @@ - (id)initWithCppSnapshot:(api::PipelineSnapshot)snapshot { return results_; } +- (FIRTimestamp *)execution_time { + if (!snapshot_.has_value()) { + return nil; + } else { + return MakeFIRTimestamp(snapshot_.value().execution_time().timestamp()); + } +} + @end @implementation __FIRPipelineResultBridge { @@ -213,13 +847,13 @@ @implementation __FIRPipelineResultBridge { std::shared_ptr _db; } -- (FIRDocumentReference *)reference { +- (nullable FIRDocumentReference *)reference { if (!_result.internal_key().has_value()) return nil; return [[FIRDocumentReference alloc] initWithKey:_result.internal_key().value() firestore:_db]; } -- (NSString *)documentID { +- (nullable NSString *)documentID { if (!_result.document_id().has_value()) { return nil; } @@ -227,6 +861,22 @@ - (NSString *)documentID { return MakeNSString(_result.document_id().value()); } +- (nullable FIRTimestamp *)create_time { + if (!_result.create_time().has_value()) { + return nil; + } + + return MakeFIRTimestamp(_result.create_time().value().timestamp()); +} + +- (nullable FIRTimestamp *)update_time { + if (!_result.update_time().has_value()) { + return nil; + } + + return MakeFIRTimestamp(_result.update_time().value().timestamp()); +} + - (id)initWithCppResult:(api::PipelineResult)result db:(std::shared_ptr)db { self = [super init]; if (self) { @@ -237,15 +887,15 @@ - (id)initWithCppResult:(api::PipelineResult)result db:(std::shared_ptr *)data { +- (NSDictionary *)data { return [self dataWithServerTimestampBehavior:FIRServerTimestampBehaviorNone]; } -- (nullable NSDictionary *)dataWithServerTimestampBehavior: +- (NSDictionary *)dataWithServerTimestampBehavior: (FIRServerTimestampBehavior)serverTimestampBehavior { absl::optional data = _result.internal_value()->Get(); - if (!data) return nil; + if (!data) return [NSDictionary dictionary]; FSTUserDataWriter *dataWriter = [[FSTUserDataWriter alloc] initWithFirestore:_db @@ -253,12 +903,35 @@ - (id)initWithCppResult:(api::PipelineResult)result db:(std::shared_ptr fieldValue = + _result.internal_value()->Get(fieldPath); + if (!fieldValue) return nil; + FSTUserDataWriter *dataWriter = + [[FSTUserDataWriter alloc] initWithFirestore:_db + serverTimestampBehavior:serverTimestampBehavior]; + return [dataWriter convertedValue:*fieldValue]; +} + @end @implementation FIRPipelineBridge { NSArray *_stages; FIRFirestore *firestore; - std::shared_ptr pipeline; + std::shared_ptr cpp_pipeline; } - (id)initWithStages:(NSArray *)stages db:(FIRFirestore *)db { @@ -273,9 +946,9 @@ - (void)executeWithCompletion:(void (^)(__FIRPipelineSnapshotBridge *_Nullable r for (FIRStageBridge *stage in _stages) { cpp_stages.push_back([stage cppStageWithReader:firestore.dataReader]); } - pipeline = std::make_shared(cpp_stages, firestore.wrapped); + cpp_pipeline = std::make_shared(cpp_stages, firestore.wrapped); - pipeline->execute([completion](StatusOr maybe_value) { + cpp_pipeline->execute([completion](StatusOr maybe_value) { if (maybe_value.ok()) { __FIRPipelineSnapshotBridge *bridge = [[__FIRPipelineSnapshotBridge alloc] initWithCppSnapshot:std::move(maybe_value).ValueOrDie()]; @@ -286,6 +959,10 @@ - (void)executeWithCompletion:(void (^)(__FIRPipelineSnapshotBridge *_Nullable r }); } +- (std::shared_ptr)cppPipelineWithReader:(FSTUserDataReader *)reader { + return cpp_pipeline; +} + @end NS_ASSUME_NONNULL_END diff --git a/Firestore/Source/Public/FirebaseFirestore/FIRPipelineBridge.h b/Firestore/Source/Public/FirebaseFirestore/FIRPipelineBridge.h index a27b2b7aa18..7b8ebf80e9b 100644 --- a/Firestore/Source/Public/FirebaseFirestore/FIRPipelineBridge.h +++ b/Firestore/Source/Public/FirebaseFirestore/FIRPipelineBridge.h @@ -20,31 +20,53 @@ #import "FIRDocumentSnapshot.h" +@class FIRTimestamp; +@class FIRVectorValue; +@class FIRPipelineBridge; + NS_ASSUME_NONNULL_BEGIN +NS_SWIFT_SENDABLE NS_SWIFT_NAME(ExprBridge) @interface FIRExprBridge : NSObject @end +NS_SWIFT_SENDABLE NS_SWIFT_NAME(FieldBridge) @interface FIRFieldBridge : FIRExprBridge - (id)init:(NSString *)name; @end +NS_SWIFT_SENDABLE NS_SWIFT_NAME(ConstantBridge) @interface FIRConstantBridge : FIRExprBridge - (id)init:(id)input; @end +NS_SWIFT_SENDABLE NS_SWIFT_NAME(FunctionExprBridge) @interface FIRFunctionExprBridge : FIRExprBridge - (id)initWithName:(NSString *)name Args:(NSArray *)args; @end +NS_SWIFT_SENDABLE +NS_SWIFT_NAME(AggregateFunctionBridge) +@interface FIRAggregateFunctionBridge : NSObject +- (id)initWithName:(NSString *)name Args:(NSArray *)args; +@end + +NS_SWIFT_SENDABLE +NS_SWIFT_NAME(OrderingBridge) +@interface FIROrderingBridge : NSObject +- (id)initWithExpr:(FIRExprBridge *)expr Direction:(NSString *)direction; +@end + +NS_SWIFT_SENDABLE NS_SWIFT_NAME(StageBridge) @interface FIRStageBridge : NSObject @end +NS_SWIFT_SENDABLE NS_SWIFT_NAME(CollectionSourceStageBridge) @interface FIRCollectionSourceStageBridge : FIRStageBridge @@ -52,6 +74,31 @@ NS_SWIFT_NAME(CollectionSourceStageBridge) @end +NS_SWIFT_SENDABLE +NS_SWIFT_NAME(DatabaseSourceStageBridge) +@interface FIRDatabaseSourceStageBridge : FIRStageBridge + +- (id)init; + +@end + +NS_SWIFT_SENDABLE +NS_SWIFT_NAME(CollectionGroupSourceStageBridge) +@interface FIRCollectionGroupSourceStageBridge : FIRStageBridge + +- (id)initWithCollectionId:(NSString *)id; + +@end + +NS_SWIFT_SENDABLE +NS_SWIFT_NAME(DocumentsSourceStageBridge) +@interface FIRDocumentsSourceStageBridge : FIRStageBridge + +- (id)initWithDocuments:(NSArray *)documents; + +@end + +NS_SWIFT_SENDABLE NS_SWIFT_NAME(WhereStageBridge) @interface FIRWhereStageBridge : FIRStageBridge @@ -59,26 +106,134 @@ NS_SWIFT_NAME(WhereStageBridge) @end -NS_SWIFT_NAME(__PipelineSnapshotBridge) -@interface __FIRPipelineSnapshotBridge : NSObject +NS_SWIFT_SENDABLE +NS_SWIFT_NAME(LimitStageBridge) +@interface FIRLimitStageBridge : FIRStageBridge + +- (id)initWithLimit:(NSInteger)value; + +@end + +NS_SWIFT_SENDABLE +NS_SWIFT_NAME(OffsetStageBridge) +@interface FIROffsetStageBridge : FIRStageBridge + +- (id)initWithOffset:(NSInteger)value; + +@end + +NS_SWIFT_SENDABLE +NS_SWIFT_NAME(AddFieldsStageBridge) +@interface FIRAddFieldsStageBridge : FIRStageBridge +- (id)initWithFields:(NSDictionary *)fields; +@end + +NS_SWIFT_SENDABLE +NS_SWIFT_NAME(RemoveFieldsStageBridge) +@interface FIRRemoveFieldsStageBridge : FIRStageBridge +- (id)initWithFields:(NSArray *)fields; +@end + +NS_SWIFT_SENDABLE +NS_SWIFT_NAME(SelectStageBridge) +@interface FIRSelectStageBridge : FIRStageBridge +- (id)initWithSelections:(NSDictionary *)selections; +@end + +NS_SWIFT_SENDABLE +NS_SWIFT_NAME(DistinctStageBridge) +@interface FIRDistinctStageBridge : FIRStageBridge +- (id)initWithGroups:(NSDictionary *)groups; +@end + +NS_SWIFT_SENDABLE +NS_SWIFT_NAME(AggregateStageBridge) +@interface FIRAggregateStageBridge : FIRStageBridge +- (id)initWithAccumulators:(NSDictionary *)accumulators + groups:(NSDictionary *)groups; +@end + +NS_SWIFT_SENDABLE +NS_SWIFT_NAME(FindNearestStageBridge) +@interface FIRFindNearestStageBridge : FIRStageBridge +- (id)initWithField:(FIRFieldBridge *)field + vectorValue:(FIRVectorValue *)vectorValue + distanceMeasure:(NSString *)distanceMeasure + limit:(NSNumber *_Nullable)limit + distanceField:(NSString *_Nullable)distanceField; +@end + +NS_SWIFT_SENDABLE +NS_SWIFT_NAME(SortStageBridge) +@interface FIRSorStageBridge : FIRStageBridge +- (id)initWithOrderings:(NSArray *)orderings; +@end + +NS_SWIFT_SENDABLE +NS_SWIFT_NAME(ReplaceWithStageBridge) +@interface FIRReplaceWithStageBridge : FIRStageBridge +- (id)initWithExpr:(FIRExprBridge *)expr; +@end + +NS_SWIFT_SENDABLE +NS_SWIFT_NAME(SampleStageBridge) +@interface FIRSampleStageBridge : FIRStageBridge +- (id)initWithCount:(int64_t)count; +- (id)initWithPercentage:(double)percentage; +@end + +NS_SWIFT_SENDABLE +NS_SWIFT_NAME(UnionStageBridge) +@interface FIRUnionStageBridge : FIRStageBridge +- (id)initWithOther:(FIRPipelineBridge *)other; +@end -@property(nonatomic, strong, readonly) NSArray<__FIRPipelineSnapshotBridge *> *results; +NS_SWIFT_SENDABLE +NS_SWIFT_NAME(UnnestStageBridge) +@interface FIRUnnestStageBridge : FIRStageBridge +- (id)initWithField:(FIRExprBridge *)field indexField:(NSString *_Nullable)indexField; +@end +NS_SWIFT_SENDABLE +NS_SWIFT_NAME(GenericStageBridge) +@interface FIRGenericStageBridge : FIRStageBridge +- (id)initWithName:(NSString *)name + params:(NSArray *)params + options:(NSDictionary *_Nullable)options; @end +NS_SWIFT_SENDABLE NS_SWIFT_NAME(__PipelineResultBridge) @interface __FIRPipelineResultBridge : NSObject -@property(nonatomic, strong, readonly) FIRDocumentReference *reference; +@property(nonatomic, strong, readonly, nullable) FIRDocumentReference *reference; -@property(nonatomic, copy, readonly) NSString *documentID; +@property(nonatomic, copy, readonly, nullable) NSString *documentID; -- (nullable NSDictionary *)data; -- (nullable NSDictionary *)dataWithServerTimestampBehavior: +@property(nonatomic, strong, readonly, nullable) FIRTimestamp *create_time; + +@property(nonatomic, strong, readonly, nullable) FIRTimestamp *update_time; + +- (NSDictionary *)data; + +- (NSDictionary *)dataWithServerTimestampBehavior: (FIRServerTimestampBehavior)serverTimestampBehavior; +- (nullable id)get:(id)field; + +@end + +NS_SWIFT_SENDABLE +NS_SWIFT_NAME(__PipelineSnapshotBridge) +@interface __FIRPipelineSnapshotBridge : NSObject + +@property(nonatomic, strong, readonly) NSArray<__FIRPipelineResultBridge *> *results; + +@property(nonatomic, strong, readonly) FIRTimestamp *execution_time; + @end +NS_SWIFT_SENDABLE NS_SWIFT_NAME(PipelineBridge) @interface FIRPipelineBridge : NSObject diff --git a/Firestore/Swift/Source/ExprImpl.swift b/Firestore/Swift/Source/ExprImpl.swift new file mode 100644 index 00000000000..6d55a7b479b --- /dev/null +++ b/Firestore/Swift/Source/ExprImpl.swift @@ -0,0 +1,607 @@ +// Copyright 2025 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. + +extension Expr { + func toBridge() -> ExprBridge { + return (self as! BridgeWrapper).bridge + } +} + +public extension Expr { + func `as`(_ name: String) -> ExprWithAlias { + return ExprWithAlias(self, name) + } + + // MARK: Arithmetic Operators + + func add(_ second: Expr, _ others: Expr...) -> FunctionExpr { + return FunctionExpr("add", [self, second] + others) + } + + func add(_ second: Sendable, _ others: Sendable...) -> FunctionExpr { + let exprs = [self] + [Helper.sendableToExpr(second)] + others + .map { Helper.sendableToExpr($0) } + return FunctionExpr("add", exprs) + } + + func subtract(_ other: Expr) -> FunctionExpr { + return FunctionExpr("subtract", [self, other]) + } + + func subtract(_ other: Sendable) -> FunctionExpr { + return FunctionExpr("subtract", [self, Helper.sendableToExpr(other)]) + } + + func multiply(_ second: Expr, _ others: Expr...) -> FunctionExpr { + return FunctionExpr("multiply", [self, second] + others) + } + + func multiply(_ second: Sendable, _ others: Sendable...) -> FunctionExpr { + let exprs = [self] + [Helper.sendableToExpr(second)] + others + .map { Helper.sendableToExpr($0) } + return FunctionExpr("multiply", exprs) + } + + func divide(_ other: Expr) -> FunctionExpr { + return FunctionExpr("divide", [self, other]) + } + + func divide(_ other: Sendable) -> FunctionExpr { + return FunctionExpr("divide", [self, Helper.sendableToExpr(other)]) + } + + func mod(_ other: Expr) -> FunctionExpr { + return FunctionExpr("mod", [self, other]) + } + + func mod(_ other: Sendable) -> FunctionExpr { + return FunctionExpr("mod", [self, Helper.sendableToExpr(other)]) + } + + // MARK: Array Operations + + func arrayConcat(_ secondArray: Expr, _ otherArrays: Expr...) -> FunctionExpr { + return FunctionExpr("array_concat", [self, secondArray] + otherArrays) + } + + func arrayConcat(_ secondArray: [Sendable], _ otherArrays: [Sendable]...) -> FunctionExpr { + let exprs = [self] + [Helper.sendableToExpr(secondArray)] + otherArrays + .map { Helper.sendableToExpr($0) } + return FunctionExpr("array_concat", exprs) + } + + func arrayContains(_ element: Expr) -> BooleanExpr { + return BooleanExpr("array_contains", [self, element]) + } + + func arrayContains(_ element: Sendable) -> BooleanExpr { + return BooleanExpr("array_contains", [self, Helper.sendableToExpr(element)]) + } + + func arrayContainsAll(_ values: Expr...) -> BooleanExpr { + return BooleanExpr("array_contains_all", [self] + values) + } + + func arrayContainsAll(_ values: Sendable...) -> BooleanExpr { + let exprValues = values.map { Helper.sendableToExpr($0) } + return BooleanExpr("array_contains_all", [self] + exprValues) + } + + func arrayContainsAny(_ values: Expr...) -> BooleanExpr { + return BooleanExpr("array_contains_any", [self] + values) + } + + func arrayContainsAny(_ values: Sendable...) -> BooleanExpr { + let exprValues = values.map { Helper.sendableToExpr($0) } + return BooleanExpr("array_contains_any", [self] + exprValues) + } + + func arrayLength() -> FunctionExpr { + return FunctionExpr("array_length", [self]) + } + + func arrayOffset(_ offset: Int) -> FunctionExpr { + return FunctionExpr("array_offset", [self, Helper.sendableToExpr(offset)]) + } + + func arrayOffset(_ offsetExpr: Expr) -> FunctionExpr { + return FunctionExpr("array_offset", [self, offsetExpr]) + } + + func gt(_ other: Expr) -> BooleanExpr { + return BooleanExpr("gt", [self, other]) + } + + func gt(_ other: Sendable) -> BooleanExpr { + let exprOther = Helper.sendableToExpr(other) + return BooleanExpr("gt", [self, exprOther]) + } + + // MARK: - Greater Than or Equal (gte) + + func gte(_ other: Expr) -> BooleanExpr { + return BooleanExpr("gte", [self, other]) + } + + func gte(_ other: Sendable) -> BooleanExpr { + let exprOther = Helper.sendableToExpr(other) + return BooleanExpr("gte", [self, exprOther]) + } + + // MARK: - Less Than (lt) + + func lt(_ other: Expr) -> BooleanExpr { + return BooleanExpr("lt", [self, other]) + } + + func lt(_ other: Sendable) -> BooleanExpr { + let exprOther = Helper.sendableToExpr(other) + return BooleanExpr("lt", [self, exprOther]) + } + + // MARK: - Less Than or Equal (lte) + + func lte(_ other: Expr) -> BooleanExpr { + return BooleanExpr("lte", [self, other]) + } + + func lte(_ other: Sendable) -> BooleanExpr { + let exprOther = Helper.sendableToExpr(other) + return BooleanExpr("lte", [self, exprOther]) + } + + // MARK: - Equal (eq) + + func eq(_ other: Expr) -> BooleanExpr { + return BooleanExpr("eq", [self, other]) + } + + func eq(_ other: Sendable) -> BooleanExpr { + let exprOther = Helper.sendableToExpr(other) + return BooleanExpr("eq", [self, exprOther]) + } + + func neq(_ others: Expr...) -> BooleanExpr { + return BooleanExpr("neq", [self] + others) + } + + func neq(_ others: Sendable...) -> BooleanExpr { + let exprOthers = others.map { Helper.sendableToExpr($0) } + return BooleanExpr("neq", [self] + exprOthers) + } + + func eqAny(_ others: Expr...) -> BooleanExpr { + return BooleanExpr("eq_any", [self] + others) + } + + func eqAny(_ others: Sendable...) -> BooleanExpr { + let exprOthers = others.map { Helper.sendableToExpr($0) } + return BooleanExpr("eq_any", [self] + exprOthers) + } + + func notEqAny(_ others: Expr...) -> BooleanExpr { + return BooleanExpr("not_eq_any", [self] + others) + } + + func notEqAny(_ others: Sendable...) -> BooleanExpr { + let exprOthers = others.map { Helper.sendableToExpr($0) } + return BooleanExpr("not_eq_any", [self] + exprOthers) + } + + // MARK: Checks + + // --- Added Type Check Operations --- + + func isNan() -> BooleanExpr { + return BooleanExpr("is_nan", [self]) + } + + func isNull() -> BooleanExpr { + return BooleanExpr("is_null", [self]) + } + + func exists() -> BooleanExpr { + return BooleanExpr("exists", [self]) + } + + func isError() -> BooleanExpr { + return BooleanExpr("is_error", [self]) + } + + func isAbsent() -> BooleanExpr { + return BooleanExpr("is_absent", [self]) + } + + func isNotNull() -> BooleanExpr { + return BooleanExpr("is_not_null", [self]) + } + + func isNotNan() -> BooleanExpr { + return BooleanExpr("is_not_nan", [self]) + } + + // --- Added String Operations --- + + func charLength() -> FunctionExpr { + return FunctionExpr("char_length", [self]) + } + + func like(_ pattern: String) -> FunctionExpr { + return FunctionExpr("like", [self, Helper.sendableToExpr(pattern)]) + } + + func like(_ pattern: Expr) -> FunctionExpr { + return FunctionExpr("like", [self, pattern]) + } + + func regexContains(_ pattern: String) -> BooleanExpr { + return BooleanExpr("regex_contains", [self, Helper.sendableToExpr(pattern)]) + } + + func regexContains(_ pattern: Expr) -> BooleanExpr { + return BooleanExpr("regex_contains", [self, pattern]) + } + + func regexMatch(_ pattern: String) -> BooleanExpr { + return BooleanExpr("regex_match", [self, Helper.sendableToExpr(pattern)]) + } + + func regexMatch(_ pattern: Expr) -> BooleanExpr { + return BooleanExpr("regex_match", [self, pattern]) + } + + func strContains(_ substring: String) -> BooleanExpr { + return BooleanExpr("str_contains", [self, Helper.sendableToExpr(substring)]) + } + + func strContains(_ expr: Expr) -> BooleanExpr { + return BooleanExpr("str_contains", [self, expr]) + } + + func startsWith(_ prefix: String) -> BooleanExpr { + return BooleanExpr("starts_with", [self, Helper.sendableToExpr(prefix)]) + } + + func startsWith(_ prefix: Expr) -> BooleanExpr { + return BooleanExpr("starts_with", [self, prefix]) + } + + func endsWith(_ suffix: String) -> BooleanExpr { + return BooleanExpr("ends_with", [self, Helper.sendableToExpr(suffix)]) + } + + func endsWith(_ suffix: Expr) -> BooleanExpr { + return BooleanExpr("ends_with", [self, suffix]) + } + + func lowercased() -> FunctionExpr { + return FunctionExpr("to_lower", [self]) + } + + func uppercased() -> FunctionExpr { + return FunctionExpr("to_upper", [self]) + } + + func trim() -> FunctionExpr { + return FunctionExpr("trim", [self]) + } + + func strConcat(_ secondString: Expr, _ otherStrings: Expr...) -> FunctionExpr { + return FunctionExpr("str_concat", [self, secondString] + otherStrings) + } + + func strConcat(_ secondString: String, _ otherStrings: String...) -> FunctionExpr { + let exprs = [self] + [Helper.sendableToExpr(secondString)] + otherStrings + .map { Helper.sendableToExpr($0) } + return FunctionExpr("str_concat", exprs) + } + + func reverse() -> FunctionExpr { + return FunctionExpr("reverse", [self]) + } + + func replaceFirst(_ find: String, _ replace: String) -> FunctionExpr { + return FunctionExpr( + "replace_first", + [self, Helper.sendableToExpr(find), Helper.sendableToExpr(replace)] + ) + } + + func replaceFirst(_ find: Expr, _ replace: Expr) -> FunctionExpr { + return FunctionExpr("replace_first", [self, find, replace]) + } + + func replaceAll(_ find: String, _ replace: String) -> FunctionExpr { + return FunctionExpr( + "replace_all", + [self, Helper.sendableToExpr(find), Helper.sendableToExpr(replace)] + ) + } + + func replaceAll(_ find: Expr, _ replace: Expr) -> FunctionExpr { + return FunctionExpr("replace_all", [self, find, replace]) + } + + func byteLength() -> FunctionExpr { + return FunctionExpr("byte_length", [self]) + } + + func substr(_ position: Int, _ length: Int? = nil) -> FunctionExpr { + let positionExpr = Helper.sendableToExpr(position) + if let length = length { + return FunctionExpr("substr", [self, positionExpr, Helper.sendableToExpr(length)]) + } else { + return FunctionExpr("substr", [self, positionExpr]) + } + } + + func substr(_ position: Expr, _ length: Expr? = nil) -> FunctionExpr { + if let length = length { + return FunctionExpr("substr", [self, position, length]) + } else { + return FunctionExpr("substr", [self, position]) + } + } + + // --- Added Map Operations --- + + func mapGet(_ subfield: String) -> FunctionExpr { + return FunctionExpr("map_get", [self, Constant(subfield)]) + } + + func mapRemove(_ key: String) -> FunctionExpr { + return FunctionExpr("map_remove", [self, Helper.sendableToExpr(key)]) + } + + func mapRemove(_ keyExpr: Expr) -> FunctionExpr { + return FunctionExpr("map_remove", [self, keyExpr]) + } + + func mapMerge(_ secondMap: [String: Sendable], + _ otherMaps: [String: Sendable]...) -> FunctionExpr { + let secondMapExpr = Helper.sendableToExpr(secondMap) + let otherMapExprs = otherMaps.map { Helper.sendableToExpr($0) } + return FunctionExpr("map_merge", [self, secondMapExpr] + otherMapExprs) + } + + func mapMerge(_ secondMap: Expr, _ otherMaps: Expr...) -> FunctionExpr { + return FunctionExpr("map_merge", [self, secondMap] + otherMaps) + } + + // --- Added Aggregate Operations (on Expr) --- + + func count() -> AggregateFunction { + return AggregateFunction("count", [self]) + } + + func sum() -> AggregateFunction { + return AggregateFunction("sum", [self]) + } + + func avg() -> AggregateFunction { + return AggregateFunction("avg", [self]) + } + + func minimum() -> AggregateFunction { + return AggregateFunction("minimum", [self]) + } + + func maximum() -> AggregateFunction { + return AggregateFunction("maximum", [self]) + } + + // MARK: Logical min/max + + func logicalMaximum(_ second: Expr, _ others: Expr...) -> FunctionExpr { + return FunctionExpr("logical_maximum", [self, second] + others) + } + + func logicalMaximum(_ second: Sendable, _ others: Sendable...) -> FunctionExpr { + let exprs = [self] + [Helper.sendableToExpr(second)] + others + .map { Helper.sendableToExpr($0) } + return FunctionExpr("logical_maximum", exprs) + } + + func logicalMinimum(_ second: Expr, _ others: Expr...) -> FunctionExpr { + return FunctionExpr("logical_min", [self, second] + others) + } + + func logicalMinimum(_ second: Sendable, _ others: Sendable...) -> FunctionExpr { + let exprs = [self] + [Helper.sendableToExpr(second)] + others + .map { Helper.sendableToExpr($0) } + return FunctionExpr("logical_min", exprs) + } + + // MARK: Vector Operations + + func vectorLength() -> FunctionExpr { + return FunctionExpr("vector_length", [self]) + } + + func cosineDistance(_ other: Expr) -> FunctionExpr { + return FunctionExpr("cosine_distance", [self, other]) + } + + func cosineDistance(_ other: VectorValue) -> FunctionExpr { + return FunctionExpr("cosine_distance", [self, Helper.sendableToExpr(other)]) + } + + func cosineDistance(_ other: [Double]) -> FunctionExpr { + return FunctionExpr("cosine_distance", [self, Helper.sendableToExpr(other)]) + } + + func dotProduct(_ other: Expr) -> FunctionExpr { + return FunctionExpr("dot_product", [self, other]) + } + + func dotProduct(_ other: VectorValue) -> FunctionExpr { + return FunctionExpr("dot_product", [self, Helper.sendableToExpr(other)]) + } + + func dotProduct(_ other: [Double]) -> FunctionExpr { + return FunctionExpr("dot_product", [self, Helper.sendableToExpr(other)]) + } + + func euclideanDistance(_ other: Expr) -> FunctionExpr { + return FunctionExpr("euclidean_distance", [self, other]) + } + + func euclideanDistance(_ other: VectorValue) -> FunctionExpr { + return FunctionExpr("euclidean_distance", [self, Helper.sendableToExpr(other)]) + } + + func euclideanDistance(_ other: [Double]) -> FunctionExpr { + return FunctionExpr("euclidean_distance", [self, Helper.sendableToExpr(other)]) + } + + func manhattanDistance(_ other: Expr) -> FunctionExpr { + return FunctionExpr("manhattan_distance", [self, other]) + } + + func manhattanDistance(_ other: VectorValue) -> FunctionExpr { + return FunctionExpr("manhattan_distance", [self, Helper.sendableToExpr(other)]) + } + + func manhattanDistance(_ other: [Double]) -> FunctionExpr { + return FunctionExpr("manhattan_distance", [self, Helper.sendableToExpr(other)]) + } + + // MARK: Timestamp operations + + func unixMicrosToTimestamp() -> FunctionExpr { + return FunctionExpr("unix_micros_to_timestamp", [self]) + } + + func timestampToUnixMicros() -> FunctionExpr { + return FunctionExpr("timestamp_to_unix_micros", [self]) + } + + func unixMillisToTimestamp() -> FunctionExpr { + return FunctionExpr("unix_millis_to_timestamp", [self]) + } + + func timestampToUnixMillis() -> FunctionExpr { + return FunctionExpr("timestamp_to_unix_millis", [self]) + } + + func unixSecondsToTimestamp() -> FunctionExpr { + return FunctionExpr("unix_seconds_to_timestamp", [self]) + } + + func timestampToUnixSeconds() -> FunctionExpr { + return FunctionExpr("timestamp_to_unix_seconds", [self]) + } + + func timestampAdd(_ unit: Expr, _ amount: Expr) -> FunctionExpr { + return FunctionExpr("timestamp_add", [self, unit, amount]) + } + + func timestampAdd(_ unit: TimeUnit, _ amount: Int) -> FunctionExpr { + return FunctionExpr( + "timestamp_add", + [self, Helper.sendableToExpr(unit), Helper.sendableToExpr(amount)] + ) + } + + func timestampSub(_ unit: Expr, _ amount: Expr) -> FunctionExpr { + return FunctionExpr("timestamp_sub", [self, unit, amount]) + } + + func timestampSub(_ unit: TimeUnit, _ amount: Int) -> FunctionExpr { + return FunctionExpr( + "timestamp_sub", + [self, Helper.sendableToExpr(unit), Helper.sendableToExpr(amount)] + ) + } + + // MARK: - Bitwise operations + + func bitAnd(_ otherBits: Int) -> FunctionExpr { + return FunctionExpr("bit_and", [self, Helper.sendableToExpr(otherBits)]) + } + + func bitAnd(_ otherBits: UInt8) -> FunctionExpr { + return FunctionExpr("bit_and", [self, Helper.sendableToExpr(otherBits)]) + } + + func bitAnd(_ bitsExpression: Expr) -> FunctionExpr { + return FunctionExpr("bit_and", [self, bitsExpression]) + } + + func bitOr(_ otherBits: Int) -> FunctionExpr { + return FunctionExpr("bit_or", [self, Helper.sendableToExpr(otherBits)]) + } + + func bitOr(_ otherBits: UInt8) -> FunctionExpr { + return FunctionExpr("bit_or", [self, Helper.sendableToExpr(otherBits)]) + } + + func bitOr(_ bitsExpression: Expr) -> FunctionExpr { + return FunctionExpr("bit_or", [self, bitsExpression]) + } + + func bitXor(_ otherBits: Int) -> FunctionExpr { + return FunctionExpr("bit_xor", [self, Helper.sendableToExpr(otherBits)]) + } + + func bitXor(_ otherBits: UInt8) -> FunctionExpr { + return FunctionExpr("bit_xor", [self, Helper.sendableToExpr(otherBits)]) + } + + func bitXor(_ bitsExpression: Expr) -> FunctionExpr { + return FunctionExpr("bit_xor", [self, bitsExpression]) + } + + func bitNot() -> FunctionExpr { + return FunctionExpr("bit_not", [self]) + } + + func bitLeftShift(_ y: Int) -> FunctionExpr { + return FunctionExpr("bit_left_shift", [self, Helper.sendableToExpr(y)]) + } + + func bitLeftShift(_ numberExpr: Expr) -> FunctionExpr { + return FunctionExpr("bit_left_shift", [self, numberExpr]) + } + + func bitRightShift(_ y: Int) -> FunctionExpr { + return FunctionExpr("bit_right_shift", [self, Helper.sendableToExpr(y)]) + } + + func bitRightShift(_ numberExpr: Expr) -> FunctionExpr { + return FunctionExpr("bit_right_shift", [self, numberExpr]) + } + + func documentId() -> FunctionExpr { + return FunctionExpr("document_id", [self]) + } + + func ifError(_ catchExpr: Expr) -> FunctionExpr { + return FunctionExpr("if_error", [self, catchExpr]) + } + + func ifError(_ catchValue: Sendable) -> FunctionExpr { + return FunctionExpr("if_error", [self, Helper.sendableToExpr(catchValue)]) + } + + // MARK: Sorting + + func ascending() -> Ordering { + return Ordering(expr: self, direction: .ascending) + } + + func descending() -> Ordering { + return Ordering(expr: self, direction: .descending) + } +} diff --git a/Firestore/Swift/Source/Helper/PipelineHelper.swift b/Firestore/Swift/Source/Helper/PipelineHelper.swift new file mode 100644 index 00000000000..582e90021b1 --- /dev/null +++ b/Firestore/Swift/Source/Helper/PipelineHelper.swift @@ -0,0 +1,51 @@ +// Copyright 2025 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. + +enum Helper { + static func sendableToExpr(_ value: Sendable) -> Expr { + if value is Expr { + return value as! Expr + } else if value is [String: Sendable] { + return map(value as! [String: Sendable]) + } else if value is [Sendable] { + return array(value as! [Sendable]) + } else { + return Constant(value) + } + } + + static func selectablesToMap(selectables: [Selectable]) -> [String: Expr] { + let exprMap = selectables.reduce(into: [String: Expr]()) { result, selectable in + let value = selectable as! SelectableWrapper + result[value.alias] = value.expr + } + return exprMap + } + + static func map(_ elements: [String: Sendable]) -> FunctionExpr { + var result: [Expr] = [] + for (key, value) in elements { + result.append(Constant(key)) + result.append(sendableToExpr(value)) + } + return FunctionExpr("map", result) + } + + static func array(_ elements: [Sendable]) -> FunctionExpr { + let transformedElements = elements.map { element in + sendableToExpr(element) + } + return FunctionExpr("array", transformedElements) + } +} diff --git a/Firestore/Swift/Source/PipelineWrapper.swift b/Firestore/Swift/Source/PipelineWrapper.swift new file mode 100644 index 00000000000..a057c2e4ea2 --- /dev/null +++ b/Firestore/Swift/Source/PipelineWrapper.swift @@ -0,0 +1,26 @@ +// Copyright 2025 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. + +protocol BridgeWrapper { + var bridge: ExprBridge { get } +} + +protocol AggregateBridgeWrapper { + var bridge: AggregateFunctionBridge { get } +} + +protocol SelectableWrapper: Sendable { + var alias: String { get } + var expr: Expr { get } +} diff --git a/Firestore/Swift/Source/SwiftAPI/Expressions.swift b/Firestore/Swift/Source/SwiftAPI/Expressions.swift deleted file mode 100644 index 22af7ae6471..00000000000 --- a/Firestore/Swift/Source/SwiftAPI/Expressions.swift +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright 2025 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 - -public protocol Expr {} - -protocol BridgeWrapper { - var bridge: ExprBridge { get } -} - -public struct Constant: Expr, BridgeWrapper { - var bridge: ExprBridge - - var value: Any - init(value: Any) { - self.value = value - bridge = ConstantBridge(value) - } -} - -public func constant(_ number: Any) -> Constant { - return Constant(value: number) -} - -public struct Field: Expr, BridgeWrapper { - var bridge: ExprBridge - - var name: String - init(name: String) { - self.name = name - bridge = FieldBridge(name) - } -} - -public func field(_ name: String) -> Field { - return Field(name: name) -} - -protocol Function: Expr { - var name: String { get } -} - -public struct FunctionExpr: Function, BridgeWrapper { - var bridge: ExprBridge - - var name: String - private var args: [Expr] - - init(name: String, args: [Expr]) { - self.name = name - self.args = args - bridge = FunctionExprBridge( - name: name, - args: args.map { ($0 as! (Expr & BridgeWrapper)).bridge - } - ) - } -} - -public func eq(_ left: Expr, _ right: Expr) -> FunctionExpr { - return FunctionExpr(name: "eq", args: [left, right]) -} diff --git a/Firestore/Swift/Source/SwiftAPI/Firestore+Pipeline.swift b/Firestore/Swift/Source/SwiftAPI/Firestore+Pipeline.swift index 0179ece4e04..e35a9bceac5 100644 --- a/Firestore/Swift/Source/SwiftAPI/Firestore+Pipeline.swift +++ b/Firestore/Swift/Source/SwiftAPI/Firestore+Pipeline.swift @@ -14,10 +14,16 @@ * limitations under the License. */ +#if SWIFT_PACKAGE + @_exported import FirebaseFirestoreInternalWrapper +#else + @_exported import FirebaseFirestoreInternal +#endif // SWIFT_PACKAGE import Foundation @objc public extension Firestore { + @available(iOS 13, tvOS 13, macOS 10.15, macCatalyst 13, watchOS 7, *) @nonobjc func pipeline() -> PipelineSource { - return PipelineSource(db: self) + return PipelineSource(self) } } diff --git a/Firestore/Swift/Source/SwiftAPI/Pipeline.swift b/Firestore/Swift/Source/SwiftAPI/Pipeline.swift deleted file mode 100644 index 8c8a4364d30..00000000000 --- a/Firestore/Swift/Source/SwiftAPI/Pipeline.swift +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright 2025 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 - -public struct Pipeline { - private var stages: [Stage] - private var bridge: PipelineBridge - private let db: Firestore - - init(stages: [Stage], db: Firestore) { - self.stages = stages - self.db = db - bridge = PipelineBridge(stages: stages.map { $0.bridge }, db: db) - } - - public func `where`(_ condition: Expr) -> Pipeline { - return Pipeline(stages: stages + [Where(condition: condition)], db: db) - } - - public func execute() async throws -> PipelineSnapshot { - return try await withCheckedThrowingContinuation { continuation in - self.bridge.execute { result, error in - if let error { - continuation.resume(throwing: error) - } else { - continuation.resume(returning: PipelineSnapshot(result!)) - } - } - } - } -} diff --git a/Firestore/Swift/Source/SwiftAPI/Pipeline/Aggregation/AggregateFunction.swift b/Firestore/Swift/Source/SwiftAPI/Pipeline/Aggregation/AggregateFunction.swift new file mode 100644 index 00000000000..ed7c25bd129 --- /dev/null +++ b/Firestore/Swift/Source/SwiftAPI/Pipeline/Aggregation/AggregateFunction.swift @@ -0,0 +1,34 @@ +// Copyright 2025 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. + +public class AggregateFunction: AggregateBridgeWrapper, @unchecked Sendable { + let bridge: AggregateFunctionBridge + + let functionName: String + let args: [Expr] + + public init(_ functionName: String, _ args: [Expr]) { + self.functionName = functionName + self.args = args + bridge = AggregateFunctionBridge( + name: functionName, + args: self.args.map { $0.toBridge() + } + ) + } + + public func `as`(_ name: String) -> AggregateWithAlias { + return AggregateWithAlias(aggregate: self, alias: name) + } +} diff --git a/Firestore/Swift/Source/SwiftAPI/Pipeline/Aggregation/AggregateWithAlias.swift b/Firestore/Swift/Source/SwiftAPI/Pipeline/Aggregation/AggregateWithAlias.swift new file mode 100644 index 00000000000..8a1871907c6 --- /dev/null +++ b/Firestore/Swift/Source/SwiftAPI/Pipeline/Aggregation/AggregateWithAlias.swift @@ -0,0 +1,18 @@ +// Copyright 2025 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. + +public struct AggregateWithAlias { + public let aggregate: AggregateFunction + public let alias: String +} diff --git a/Firestore/Swift/Source/SwiftAPI/Pipeline/Aggregation/CountAll.swift b/Firestore/Swift/Source/SwiftAPI/Pipeline/Aggregation/CountAll.swift new file mode 100644 index 00000000000..064eb6d99bc --- /dev/null +++ b/Firestore/Swift/Source/SwiftAPI/Pipeline/Aggregation/CountAll.swift @@ -0,0 +1,19 @@ +// Copyright 2025 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. + +public class CountAll: AggregateFunction, @unchecked Sendable { + public init() { + super.init("count", []) + } +} diff --git a/Firestore/Swift/Source/SwiftAPI/Pipeline/ArrayContains.swift b/Firestore/Swift/Source/SwiftAPI/Pipeline/ArrayContains.swift new file mode 100644 index 00000000000..7a70cfbc77b --- /dev/null +++ b/Firestore/Swift/Source/SwiftAPI/Pipeline/ArrayContains.swift @@ -0,0 +1,19 @@ +// Copyright 2025 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. + +public class ArrayContains: BooleanExpr, @unchecked Sendable { + public init(fieldName: String, values: Sendable...) { + super.init("array_contains", values.map { Helper.sendableToExpr($0) }) + } +} diff --git a/Firestore/Swift/Source/SwiftAPI/Pipeline/Ascending.swift b/Firestore/Swift/Source/SwiftAPI/Pipeline/Ascending.swift new file mode 100644 index 00000000000..e872b6e7f8a --- /dev/null +++ b/Firestore/Swift/Source/SwiftAPI/Pipeline/Ascending.swift @@ -0,0 +1,19 @@ +// Copyright 2025 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. + +public class Ascending: Ordering, @unchecked Sendable { + public init(_ fieldName: String) { + super.init(expr: Field(fieldName), direction: .ascending) + } +} diff --git a/Firestore/Swift/Source/SwiftAPI/Pipeline/Descending.swift b/Firestore/Swift/Source/SwiftAPI/Pipeline/Descending.swift new file mode 100644 index 00000000000..584d7b7ada3 --- /dev/null +++ b/Firestore/Swift/Source/SwiftAPI/Pipeline/Descending.swift @@ -0,0 +1,19 @@ +// Copyright 2025 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. + +public class Descending: Ordering, @unchecked Sendable { + public init(_ fieldName: String) { + super.init(expr: Field(fieldName), direction: .descending) + } +} diff --git a/Firestore/Swift/Source/SwiftAPI/Pipeline/DistanceMeasure.swift b/Firestore/Swift/Source/SwiftAPI/Pipeline/DistanceMeasure.swift new file mode 100644 index 00000000000..6bd54e9e71b --- /dev/null +++ b/Firestore/Swift/Source/SwiftAPI/Pipeline/DistanceMeasure.swift @@ -0,0 +1,47 @@ +// Copyright 2025 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 + +public struct DistanceMeasure: Sendable, Equatable, Hashable { + let kind: Kind + + enum Kind: String { + case euclidean + case cosine + case dotProduct = "dot_product" + } + + public static var euclidean: DistanceMeasure { + return self.init(kind: .euclidean) + } + + public static var cosine: DistanceMeasure { + return self.init(kind: .cosine) + } + + public static var dotProduct: DistanceMeasure { + return self.init(kind: .dotProduct) + } + + init(kind: Kind) { + self.kind = kind + } +} diff --git a/Firestore/Swift/Source/SwiftAPI/Pipeline/Expr.swift b/Firestore/Swift/Source/SwiftAPI/Pipeline/Expr.swift new file mode 100644 index 00000000000..7cd9b0d5adf --- /dev/null +++ b/Firestore/Swift/Source/SwiftAPI/Pipeline/Expr.swift @@ -0,0 +1,1558 @@ +// Copyright 2025 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 + +// TODO: the implementation of `Expr` is not complete +public protocol Expr: Sendable { + /// Assigns an alias to this expression. + /// + /// Aliases are useful for renaming fields in the output of a stage or for giving meaningful + /// names to calculated values. + /// + /// ```swift + /// // Calculate total price and alias it "totalPrice" + /// Field("price").multiply(Field("quantity")).`as`("totalPrice") + /// ``` + /// + /// - Parameter name: The alias to assign to this expression. + /// - Returns: A new `ExprWithAlias` wrapping this expression with the alias. + func `as`(_ name: String) -> ExprWithAlias + + // --- Added Mathematical Operations --- + + /// Creates an expression that adds this expression to one or more other expressions. + /// Assumes `self` and all parameters evaluate to compatible types for addition (e.g., numbers, or + /// string/array concatenation if supported by the specific "add" implementation). + /// + /// ```swift + /// // Add the value of the 'quantity' field and the 'reserve' field. + /// Field("quantity").add(Field("reserve")) + /// + /// // Add multiple numeric fields + /// Field("subtotal").add(Field("tax"), Field("shipping")) + /// ``` + /// + /// - Parameter second: An `Expr` to add to this expression. + /// - Parameter others: Optional additional `Expr` values to add. + /// - Returns: A new `FunctionExpr` representing the addition operation. + func add(_ second: Expr, _ others: Expr...) -> FunctionExpr + + /// Creates an expression that adds this expression to one or more literal values. + /// Assumes `self` and all parameters evaluate to compatible types for addition. + /// + /// ```swift + /// // Add 5 to the 'count' field + /// Field("count").add(5) + /// + /// // Add multiple literal numbers + /// Field("score").add(10, 20, -5) + /// ``` + /// + /// - Parameter second: A `Sendable` literal value to add to this expression. + /// - Parameter others: Optional additional `Sendable` literal values to add. + /// - Returns: A new `FunctionExpr` representing the addition operation. + func add(_ second: Sendable, _ others: Sendable...) -> FunctionExpr + + /// Creates an expression that subtracts another expression from this expression. + /// Assumes `self` and `other` evaluate to numeric types. + /// + /// ```swift + /// // Subtract the 'discount' field from the 'price' field + /// Field("price").subtract(Field("discount")) + /// ``` + /// + /// - Parameter other: The `Expr` (evaluating to a number) to subtract from this expression. + /// - Returns: A new `FunctionExpr` representing the subtraction operation. + func subtract(_ other: Expr) -> FunctionExpr + + /// Creates an expression that subtracts a literal value from this expression. + /// Assumes `self` evaluates to a numeric type. + /// + /// ```swift + /// // Subtract 20 from the value of the 'total' field + /// Field("total").subtract(20) + /// ``` + /// + /// - Parameter other: The `Sendable` literal (numeric) value to subtract from this expression. + /// - Returns: A new `FunctionExpr` representing the subtraction operation. + func subtract(_ other: Sendable) -> FunctionExpr + + /// Creates an expression that multiplies this expression by one or more other expressions. + /// Assumes `self` and all parameters evaluate to numeric types. + /// + /// ```swift + /// // Multiply the 'quantity' field by the 'price' field + /// Field("quantity").multiply(Field("price")) + /// + /// // Multiply 'rate' by 'time' and 'conversionFactor' fields + /// Field("rate").multiply(Field("time"), Field("conversionFactor")) + /// ``` + /// + /// - Parameter second: An `Expr` to multiply by. + /// - Parameter others: Optional additional `Expr` values to multiply by. + /// - Returns: A new `FunctionExpr` representing the multiplication operation. + func multiply(_ second: Expr, _ others: Expr...) -> FunctionExpr + + /// Creates an expression that multiplies this expression by one or more literal values. + /// Assumes `self` evaluates to a numeric type. + /// + /// ```swift + /// // Multiply the 'score' by 1.1 + /// Field("score").multiply(1.1) + /// + /// // Multiply 'base' by 2 and then by 3.0 + /// Field("base").multiply(2, 3.0) + /// ``` + /// + /// - Parameter second: A `Sendable` literal value to multiply by. + /// - Parameter others: Optional additional `Sendable` literal values to multiply by. + /// - Returns: A new `FunctionExpr` representing the multiplication operation. + func multiply(_ second: Sendable, _ others: Sendable...) -> FunctionExpr + + /// Creates an expression that divides this expression by another expression. + /// Assumes `self` and `other` evaluate to numeric types. + /// + /// ```swift + /// // Divide the 'total' field by the 'count' field + /// Field("total").divide(Field("count")) + /// ``` + /// + /// - Parameter other: The `Expr` (evaluating to a number) to divide by. + /// - Returns: A new `FunctionExpr` representing the division operation. + func divide(_ other: Expr) -> FunctionExpr + + /// Creates an expression that divides this expression by a literal value. + /// Assumes `self` evaluates to a numeric type. + /// + /// ```swift + /// // Divide the 'value' field by 10 + /// Field("value").divide(10) + /// ``` + /// + /// - Parameter other: The `Sendable` literal (numeric) value to divide by. + /// - Returns: A new `FunctionExpr` representing the division operation. + func divide(_ other: Sendable) -> FunctionExpr + + /// Creates an expression that calculates the modulo (remainder) of dividing this expression by + /// another expression. + /// Assumes `self` and `other` evaluate to numeric types. + /// + /// ```swift + /// // Calculate the remainder of dividing the 'value' field by the 'divisor' field + /// Field("value").mod(Field("divisor")) + /// ``` + /// + /// - Parameter other: The `Expr` (evaluating to a number) to use as the divisor. + /// - Returns: A new `FunctionExpr` representing the modulo operation. + func mod(_ other: Expr) -> FunctionExpr + + /// Creates an expression that calculates the modulo (remainder) of dividing this expression by a + /// literal value. + /// Assumes `self` evaluates to a numeric type. + /// + /// ```swift + /// // Calculate the remainder of dividing the 'value' field by 10 + /// Field("value").mod(10) + /// ``` + /// + /// - Parameter other: The `Sendable` literal (numeric) value to use as the divisor. + /// - Returns: A new `FunctionExpr` representing the modulo operation. + func mod(_ other: Sendable) -> FunctionExpr + + // --- Added Array Operations --- + + /// Creates an expression that concatenates an array expression (from `self`) with one or more + /// other array expressions. + /// Assumes `self` and all parameters evaluate to arrays. + /// + /// ```swift + /// // Combine the 'items' array with 'otherItems' and 'archiveItems' array fields. + /// Field("items").arrayConcat(Field("otherItems"), Field("archiveItems")) + /// ``` + /// - Parameter secondArray: An `Expr` (evaluating to an array) to concatenate. + /// - Parameter otherArrays: Optional additional `Expr` values (evaluating to arrays) to + /// concatenate. + /// - Returns: A new `FunctionExpr` representing the concatenated array. + func arrayConcat(_ secondArray: Expr, _ otherArrays: Expr...) -> FunctionExpr + + /// Creates an expression that concatenates an array expression (from `self`) with one or more + /// array literals. + /// Assumes `self` evaluates to an array. + /// + /// ```swift + /// // Combine 'tags' (an array field) with ["new", "featured"] and ["urgent"] + /// Field("tags").arrayConcat(["new", "featured"], ["urgent"]) + /// ``` + /// - Parameter secondArray: An array literal of `Sendable` values to concatenate. + /// - Parameter otherArrays: Optional additional array literals of `Sendable` values to + /// concatenate. + /// - Returns: A new `FunctionExpr` representing the concatenated array. + func arrayConcat(_ secondArray: [Sendable], _ otherArrays: [Sendable]...) -> FunctionExpr + + /// Creates an expression that checks if an array (from `self`) contains a specific element + /// expression. + /// Assumes `self` evaluates to an array. + /// + /// ```swift + /// // Check if 'sizes' contains the value from 'selectedSize' field + /// Field("sizes").arrayContains(Field("selectedSize")) + /// ``` + /// + /// - Parameter element: The `Expr` representing the element to search for in the array. + /// - Returns: A new `BooleanExpr` representing the 'array_contains' comparison. + func arrayContains(_ element: Expr) -> BooleanExpr + + /// Creates an expression that checks if an array (from `self`) contains a specific literal + /// element. + /// Assumes `self` evaluates to an array. + /// + /// ```swift + /// // Check if 'colors' array contains "red" + /// Field("colors").arrayContains("red") + /// ``` + /// + /// - Parameter element: The `Sendable` literal element to search for in the array. + /// - Returns: A new `BooleanExpr` representing the 'array_contains' comparison. + func arrayContains(_ element: Sendable) -> BooleanExpr + + /// Creates an expression that checks if an array (from `self`) contains all the specified element + /// expressions. + /// Assumes `self` evaluates to an array. + /// + /// ```swift + /// // Check if 'candidateSkills' contains all skills from 'requiredSkill1' and 'requiredSkill2' + /// fields + /// Field("candidateSkills").arrayContainsAll(Field("requiredSkill1"), Field("requiredSkill2")) + /// ``` + /// + /// - Parameter values: A variadic list of `Expr` elements to check for in the array represented + /// by `self`. + /// - Returns: A new `BooleanExpr` representing the 'array_contains_all' comparison. + func arrayContainsAll(_ values: Expr...) -> BooleanExpr + + /// Creates an expression that checks if an array (from `self`) contains all the specified literal + /// elements. + /// Assumes `self` evaluates to an array. + /// + /// ```swift + /// // Check if 'tags' contains both "urgent" and "review" + /// Field("tags").arrayContainsAll("urgent", "review") + /// ``` + /// + /// - Parameter values: A variadic list of `Sendable` literal elements to check for in the array + /// represented by `self`. + /// - Returns: A new `BooleanExpr` representing the 'array_contains_all' comparison. + func arrayContainsAll(_ values: Sendable...) -> BooleanExpr + + /// Creates an expression that checks if an array (from `self`) contains any of the specified + /// element expressions. + /// Assumes `self` evaluates to an array. + /// + /// ```swift + /// // Check if 'userGroups' contains any group from 'allowedGroup1' or 'allowedGroup2' fields + /// Field("userGroups").arrayContainsAny(Field("allowedGroup1"), Field("allowedGroup2")) + /// ``` + /// + /// - Parameter values: A variadic list of `Expr` elements to check for in the array represented + /// by `self`. + /// - Returns: A new `BooleanExpr` representing the 'array_contains_any' comparison. + func arrayContainsAny(_ values: Expr...) -> BooleanExpr + + /// Creates an expression that checks if an array (from `self`) contains any of the specified + /// literal elements. + /// Assumes `self` evaluates to an array. + /// + /// ```swift + /// // Check if 'categories' contains either "electronics" or "books" + /// Field("categories").arrayContainsAny("electronics", "books") + /// ``` + /// + /// - Parameter values: A variadic list of `Sendable` literal elements to check for in the array + /// represented by `self`. + /// - Returns: A new `BooleanExpr` representing the 'array_contains_any' comparison. + func arrayContainsAny(_ values: Sendable...) -> BooleanExpr + + /// Creates an expression that calculates the length of an array. + /// Assumes `self` evaluates to an array. + /// + /// ```swift + /// // Get the number of items in the 'cart' array + /// Field("cart").arrayLength() + /// ``` + /// + /// - Returns: A new `FunctionExpr` representing the length of the array. + func arrayLength() -> FunctionExpr + + /// Creates an expression that accesses an element in an array (from `self`) at the specified + /// integer offset. + /// A negative offset starts from the end. If the offset is out of bounds, an error may be + /// returned during evaluation. + /// Assumes `self` evaluates to an array. + /// + /// ```swift + /// // Return the value in the 'tags' field array at index 1. + /// Field("tags").arrayOffset(1) + /// // Return the last element in the 'tags' field array. + /// Field("tags").arrayOffset(-1) + /// ``` + /// + /// - Parameter offset: The literal `Int` offset of the element to return. + /// - Returns: A new `FunctionExpr` representing the 'arrayOffset' operation. + func arrayOffset(_ offset: Int) -> FunctionExpr + + /// Creates an expression that accesses an element in an array (from `self`) at the offset + /// specified by an expression. + /// A negative offset starts from the end. If the offset is out of bounds, an error may be + /// returned during evaluation. + /// Assumes `self` evaluates to an array and `offsetExpr` evaluates to an integer. + /// + /// ```swift + /// // Return the value in the tags field array at index specified by field 'favoriteTagIndex'. + /// Field("tags").arrayOffset(Field("favoriteTagIndex")) + /// ``` + /// + /// - Parameter offsetExpr: An `Expr` (evaluating to an Int) representing the offset of the + /// element to return. + /// - Returns: A new `FunctionExpr` representing the 'arrayOffset' operation. + func arrayOffset(_ offsetExpr: Expr) -> FunctionExpr + + // MARK: Equality with Sendable + + /// Creates an expression that checks if this expression is equal to any of the provided + /// expression values. + /// This is similar to an "IN" operator in SQL. + /// + /// ```swift + /// // Check if 'categoryID' field is equal to 'featuredCategory' or 'popularCategory' fields + /// Field("categoryID").eqAny(Field("featuredCategory"), Field("popularCategory")) + /// ``` + /// + /// - Parameter others: A variadic list of `Expr` values to check against. + /// - Returns: A new `BooleanExpr` representing the 'IN' comparison (eq_any). + func eqAny(_ others: Expr...) -> BooleanExpr + + /// Creates an expression that checks if this expression is equal to any of the provided literal + /// values. + /// This is similar to an "IN" operator in SQL. + /// + /// ```swift + /// // Check if 'category' is "Electronics", "Books", or "Home Goods" + /// Field("category").eqAny("Electronics", "Books", "Home Goods") + /// ``` + /// + /// - Parameter others: A variadic list of `Sendable` literal values to check against. + /// - Returns: A new `BooleanExpr` representing the 'IN' comparison (eq_any). + func eqAny(_ others: Sendable...) -> BooleanExpr + + /// Creates an expression that checks if this expression is not equal to any of the provided + /// expression values. + /// This is similar to a "NOT IN" operator in SQL. + /// + /// ```swift + /// // Check if 'statusValue' is not equal to 'archivedStatus' or 'deletedStatus' fields + /// Field("statusValue").notEqAny(Field("archivedStatus"), Field("deletedStatus")) + /// ``` + /// + /// - Parameter others: A variadic list of `Expr` values to check against. + /// - Returns: A new `BooleanExpr` representing the 'NOT IN' comparison (not_eq_any). + func notEqAny(_ others: Expr...) -> BooleanExpr + + /// Creates an expression that checks if this expression is not equal to any of the provided + /// literal values. + /// This is similar to a "NOT IN" operator in SQL. + /// + /// ```swift + /// // Check if 'status' is neither "pending" nor "archived" + /// Field("status").notEqAny("pending", "archived") + /// ``` + /// + /// - Parameter others: A variadic list of `Sendable` literal values to check against. + /// - Returns: A new `BooleanExpr` representing the 'NOT IN' comparison (not_eq_any). + func notEqAny(_ others: Sendable...) -> BooleanExpr + + // MARK: Checks + + /// Creates an expression that checks if this expression evaluates to 'NaN' (Not a Number). + /// Assumes `self` evaluates to a numeric type. + /// + /// ```swift + /// // Check if the result of a calculation is NaN + /// Field("value").divide(0).isNan() + /// ``` + /// + /// - Returns: A new `BooleanExpr` representing the 'isNaN' check. + func isNan() -> BooleanExpr + + /// Creates an expression that checks if this expression evaluates to 'Null'. + /// + /// ```swift + /// // Check if the 'optionalField' is null + /// Field("optionalField").isNull() + /// ``` + /// + /// - Returns: A new `BooleanExpr` representing the 'isNull' check. + func isNull() -> BooleanExpr + + /// Creates an expression that checks if a field exists in the document. + /// + /// - Note: This typically only makes sense when `self` is a `Field` expression. + /// + /// ```swift + /// // Check if the document has a field named "phoneNumber" + /// Field("phoneNumber").exists() + /// ``` + /// + /// - Returns: A new `BooleanExpr` representing the 'exists' check. + func exists() -> BooleanExpr + + /// Creates an expression that checks if this expression produces an error during evaluation. + /// + /// - Note: This API is in beta. + /// + /// ```swift + /// // Check if accessing a non-existent array index causes an error + /// Field("myArray").arrayOffset(100).isError() + /// ``` + /// + /// - Returns: A new `BooleanExpr` representing the 'isError' check. + func isError() -> BooleanExpr + + /// Creates an expression that returns `true` if the result of this expression + /// is absent (e.g., a field does not exist in a map). Otherwise, returns `false`, even if the + /// value is `null`. + /// + /// - Note: This API is in beta. + /// - Note: This typically only makes sense when `self` is a `Field` expression. + /// + /// ```swift + /// // Check if the field `value` is absent. + /// Field("value").isAbsent() + /// ``` + /// + /// - Returns: A new `BooleanExpr` representing the 'isAbsent' check. + func isAbsent() -> BooleanExpr + + /// Creates an expression that checks if the result of this expression is not null. + /// + /// ```swift + /// // Check if the value of the 'name' field is not null + /// Field("name").isNotNull() + /// ``` + /// + /// - Returns: A new `BooleanExpr` representing the 'isNotNull' check. + func isNotNull() -> BooleanExpr + + /// Creates an expression that checks if the results of this expression is NOT 'NaN' (Not a + /// Number). + /// Assumes `self` evaluates to a numeric type. + /// + /// ```swift + /// // Check if the result of a calculation is NOT NaN + /// Field("value").divide(Field("count")).isNotNan() // Assuming count might be 0 + /// ``` + /// + /// - Returns: A new `BooleanExpr` representing the 'isNotNaN' check. + func isNotNan() -> BooleanExpr + + // MARK: String Operations + + /// Creates an expression that calculates the character length of a string in UTF-8. + /// Assumes `self` evaluates to a string. + /// + /// ```swift + /// // Get the character length of the 'name' field in its UTF-8 form. + /// Field("name").charLength() + /// ``` + /// + /// - Returns: A new `FunctionExpr` representing the length of the string. + func charLength() -> FunctionExpr + + /// Creates an expression that performs a case-sensitive string comparison using wildcards against + /// a literal pattern. + /// Assumes `self` evaluates to a string. + /// + /// ```swift + /// // Check if the 'title' field contains the word "guide" (case-sensitive) + /// Field("title").like("%guide%") + /// ``` + /// + /// - Parameter pattern: The literal string pattern to search for. Use "%" as a wildcard. + /// - Returns: A new `FunctionExpr` representing the 'like' comparison. + func like(_ pattern: String) -> FunctionExpr + + /// Creates an expression that performs a case-sensitive string comparison using wildcards against + /// an expression pattern. + /// Assumes `self` evaluates to a string, and `pattern` evaluates to a string. + /// + /// ```swift + /// // Check if 'filename' matches a pattern stored in 'patternField' + /// Field("filename").like(Field("patternField")) + /// ``` + /// + /// - Parameter pattern: An `Expr` (evaluating to a string) representing the pattern to search + /// for. + /// - Returns: A new `FunctionExpr` representing the 'like' comparison. + func like(_ pattern: Expr) -> FunctionExpr + + /// Creates an expression that checks if a string (from `self`) contains a specified regular + /// expression literal as a substring. + /// Uses RE2 syntax. Assumes `self` evaluates to a string. + /// + /// ```swift + /// // Check if 'description' contains "example" (case-insensitive) + /// Field("description").regexContains("(?i)example") + /// ``` + /// + /// - Parameter pattern: The literal string regular expression to use for the search. + /// - Returns: A new `BooleanExpr` representing the 'regex_contains' comparison. + func regexContains(_ pattern: String) -> BooleanExpr + + /// Creates an expression that checks if a string (from `self`) contains a specified regular + /// expression (from an expression) as a substring. + /// Uses RE2 syntax. Assumes `self` evaluates to a string, and `pattern` evaluates to a string. + /// + /// ```swift + /// // Check if 'logEntry' contains a pattern from 'errorPattern' field + /// Field("logEntry").regexContains(Field("errorPattern")) + /// ``` + /// + /// - Parameter pattern: An `Expr` (evaluating to a string) representing the regular expression to + /// use for the search. + /// - Returns: A new `BooleanExpr` representing the 'regex_contains' comparison. + func regexContains(_ pattern: Expr) -> BooleanExpr + + /// Creates an expression that checks if a string (from `self`) matches a specified regular + /// expression literal entirely. + /// Uses RE2 syntax. Assumes `self` evaluates to a string. + /// + /// ```swift + /// // Check if the 'email' field matches a valid email pattern + /// Field("email").regexMatch("[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}") + /// ``` + /// + /// - Parameter pattern: The literal string regular expression to use for the match. + /// - Returns: A new `BooleanExpr` representing the regular expression match. + func regexMatch(_ pattern: String) -> BooleanExpr + + /// Creates an expression that checks if a string (from `self`) matches a specified regular + /// expression (from an expression) entirely. + /// Uses RE2 syntax. Assumes `self` evaluates to a string, and `pattern` evaluates to a string. + /// + /// ```swift + /// // Check if 'input' matches the regex stored in 'validationRegex' + /// Field("input").regexMatch(Field("validationRegex")) + /// ``` + /// + /// - Parameter pattern: An `Expr` (evaluating to a string) representing the regular expression to + /// use for the match. + /// - Returns: A new `BooleanExpr` representing the regular expression match. + func regexMatch(_ pattern: Expr) -> BooleanExpr + + /// Creates an expression that checks if a string (from `self`) contains a specified literal + /// substring (case-sensitive). + /// Assumes `self` evaluates to a string. + /// + /// ```swift + /// // Check if the 'description' field contains "example". + /// Field("description").strContains("example") + /// ``` + /// + /// - Parameter substring: The literal string substring to search for. + /// - Returns: A new `BooleanExpr` representing the 'str_contains' comparison. + func strContains(_ substring: String) -> BooleanExpr + + /// Creates an expression that checks if a string (from `self`) contains a specified substring + /// from an expression (case-sensitive). + /// Assumes `self` evaluates to a string, and `expr` evaluates to a string. + /// + /// ```swift + /// // Check if the 'message' field contains the value of the 'keyword' field. + /// Field("message").strContains(Field("keyword")) + /// ``` + /// + /// - Parameter expr: An `Expr` (evaluating to a string) representing the substring to search for. + /// - Returns: A new `BooleanExpr` representing the 'str_contains' comparison. + func strContains(_ expr: Expr) -> BooleanExpr + + /// Creates an expression that checks if a string (from `self`) starts with a given literal prefix + /// (case-sensitive). + /// Assumes `self` evaluates to a string. + /// + /// ```swift + /// // Check if the 'name' field starts with "Mr." + /// Field("name").startsWith("Mr.") + /// ``` + /// + /// - Parameter prefix: The literal string prefix to check for. + /// - Returns: A new `BooleanExpr` representing the 'starts_with' comparison. + func startsWith(_ prefix: String) -> BooleanExpr + + /// Creates an expression that checks if a string (from `self`) starts with a given prefix from an + /// expression (case-sensitive). + /// Assumes `self` evaluates to a string, and `prefix` evaluates to a string. + /// + /// ```swift + /// // Check if 'fullName' starts with the value of 'firstName' + /// Field("fullName").startsWith(Field("firstName")) + /// ``` + /// + /// - Parameter prefix: An `Expr` (evaluating to a string) representing the prefix to check for. + /// - Returns: A new `BooleanExpr` representing the 'starts_with' comparison. + func startsWith(_ prefix: Expr) -> BooleanExpr + + /// Creates an expression that checks if a string (from `self`) ends with a given literal suffix + /// (case-sensitive). + /// Assumes `self` evaluates to a string. + /// + /// ```swift + /// // Check if the 'filename' field ends with ".txt" + /// Field("filename").endsWith(".txt") + /// ``` + /// + /// - Parameter suffix: The literal string suffix to check for. + /// - Returns: A new `BooleanExpr` representing the 'ends_with' comparison. + func endsWith(_ suffix: String) -> BooleanExpr + + /// Creates an expression that checks if a string (from `self`) ends with a given suffix from an + /// expression (case-sensitive). + /// Assumes `self` evaluates to a string, and `suffix` evaluates to a string. + /// + /// ```swift + /// // Check if 'url' ends with the value of 'extension' field + /// Field("url").endsWith(Field("extension")) + /// ``` + /// + /// - Parameter suffix: An `Expr` (evaluating to a string) representing the suffix to check for. + /// - Returns: A new `BooleanExpr` representing the 'ends_with' comparison. + func endsWith(_ suffix: Expr) -> BooleanExpr + + /// Creates an expression that converts a string (from `self`) to lowercase. + /// Assumes `self` evaluates to a string. + /// + /// ```swift + /// // Convert the 'name' field to lowercase + /// Field("name").lowercased() + /// ``` + /// + /// - Returns: A new `FunctionExpr` representing the lowercase string. + func lowercased() -> FunctionExpr + + /// Creates an expression that converts a string (from `self`) to uppercase. + /// Assumes `self` evaluates to a string. + /// + /// ```swift + /// // Convert the 'title' field to uppercase + /// Field("title").uppercased() + /// ``` + /// + /// - Returns: A new `FunctionExpr` representing the uppercase string. + func uppercased() -> FunctionExpr + + /// Creates an expression that removes leading and trailing whitespace from a string (from + /// `self`). + /// Assumes `self` evaluates to a string. + /// + /// ```swift + /// // Trim whitespace from the 'userInput' field + /// Field("userInput").trim() + /// ``` + /// + /// - Returns: A new `FunctionExpr` representing the trimmed string. + func trim() -> FunctionExpr + + /// Creates an expression that concatenates this string expression with other string expressions. + /// Assumes `self` evaluates to a string. + /// + /// ```swift + /// // Combine 'part1', 'part2', and 'part3' fields + /// Field("part1").strConcat(Field("part2"), Field("part3")) + /// ``` + /// + /// - Parameter secondString: An `Expr` (evaluating to a string) to concatenate. + /// - Parameter otherStrings: Optional additional `Expr` (evaluating to strings) to concatenate. + /// - Returns: A new `FunctionExpr` representing the concatenated string. + func strConcat(_ secondString: Expr, _ otherStrings: Expr...) -> FunctionExpr + + /// Creates an expression that concatenates this string expression with other string literals. + /// Assumes `self` evaluates to a string. + /// + /// ```swift + /// // Combine 'firstName', " ", and 'lastName' + /// Field("firstName").strConcat(" ", "lastName") + /// ``` + /// + /// - Parameter secondString: A string literal to concatenate. + /// - Parameter otherStrings: Optional additional string literals to concatenate. + /// - Returns: A new `FunctionExpr` representing the concatenated string. + func strConcat(_ secondString: String, _ otherStrings: String...) -> FunctionExpr + + /// Creates an expression that reverses this string expression. + /// Assumes `self` evaluates to a string. + /// + /// ```swift + /// // Reverse the value of the 'myString' field. + /// Field("myString").reverse() + /// ``` + /// + /// - Returns: A new `FunctionExpr` representing the reversed string. + func reverse() -> FunctionExpr + + /// Creates an expression that replaces the first occurrence of a literal substring within this + /// string expression with another literal substring. + /// Assumes `self` evaluates to a string. + /// + /// ```swift + /// // Replace the first "hello" with "hi" in the 'message' field + /// Field("message").replaceFirst("hello", "hi") + /// ``` + /// + /// - Parameter find: The literal string substring to search for. + /// - Parameter replace: The literal string substring to replace the first occurrence with. + /// - Returns: A new `FunctionExpr` representing the string with the first occurrence replaced. + func replaceFirst(_ find: String, _ replace: String) -> FunctionExpr + + /// Creates an expression that replaces the first occurrence of a substring (from an expression) + /// within this string expression with another substring (from an expression). + /// Assumes `self` evaluates to a string, and `find`/`replace` evaluate to strings. + /// + /// ```swift + /// // Replace first occurrence of field 'findPattern' with field 'replacePattern' in 'text' + /// Field("text").replaceFirst(Field("findPattern"), Field("replacePattern")) + /// ``` + /// + /// - Parameter find: An `Expr` (evaluating to a string) for the substring to search for. + /// - Parameter replace: An `Expr` (evaluating to a string) for the substring to replace the first + /// occurrence with. + /// - Returns: A new `FunctionExpr` representing the string with the first occurrence replaced. + func replaceFirst(_ find: Expr, _ replace: Expr) -> FunctionExpr + + /// Creates an expression that replaces all occurrences of a literal substring within this string + /// expression with another literal substring. + /// Assumes `self` evaluates to a string. + /// + /// ```swift + /// // Replace all occurrences of " " with "_" in 'description' + /// Field("description").replaceAll(" ", "_") + /// ``` + /// + /// - Parameter find: The literal string substring to search for. + /// - Parameter replace: The literal string substring to replace all occurrences with. + /// - Returns: A new `FunctionExpr` representing the string with all occurrences replaced. + func replaceAll(_ find: String, _ replace: String) -> FunctionExpr + + /// Creates an expression that replaces all occurrences of a substring (from an expression) within + /// this string expression with another substring (from an expression). + /// Assumes `self` evaluates to a string, and `find`/`replace` evaluate to strings. + /// + /// ```swift + /// // Replace all occurrences of field 'target' with field 'replacement' in 'content' + /// Field("content").replaceAll(Field("target"), Field("replacement")) + /// ``` + /// + /// - Parameter find: An `Expr` (evaluating to a string) for the substring to search for. + /// - Parameter replace: An `Expr` (evaluating to a string) for the substring to replace all + /// occurrences with. + /// - Returns: A new `FunctionExpr` representing the string with all occurrences replaced. + func replaceAll(_ find: Expr, _ replace: Expr) -> FunctionExpr + + /// Creates an expression that calculates the length of this string or bytes expression in bytes. + /// Assumes `self` evaluates to a string or bytes. + /// + /// ```swift + /// // Calculate the length of the 'myString' field in bytes. + /// Field("myString").byteLength() + /// + /// // Calculate the size of the 'avatar' (Data/Bytes) field. + /// Field("avatar").byteLength() + /// ``` + /// + /// - Returns: A new `FunctionExpr` representing the length in bytes. + func byteLength() -> FunctionExpr + + /// Creates an expression that returns a substring of this expression (String or Bytes) using + /// literal integers for position and optional length. + /// Indexing is 0-based. Assumes `self` evaluates to a string or bytes. + /// + /// - Note: This API is in beta. + /// + /// ```swift + /// // Get substring from index 5 with length 10 + /// Field("myString").substr(5, 10) + /// + /// // Get substring from 'myString' starting at index 3 to the end + /// Field("myString").substr(3, nil) + /// ``` + /// + /// - Parameter position: Literal `Int` index of the first character/byte. + /// - Parameter length: Optional literal `Int` length of the substring. If `nil`, goes to the end. + /// - Returns: A new `FunctionExpr` representing the substring. + func substr(_ position: Int, _ length: Int?) -> FunctionExpr + + /// Creates an expression that returns a substring of this expression (String or Bytes) using + /// expressions for position and optional length. + /// Indexing is 0-based. Assumes `self` evaluates to a string or bytes, and parameters evaluate to + /// integers. + /// + /// - Note: This API is in beta. + /// + /// ```swift + /// // Get substring from index calculated by Field("start") with length from Field("len") + /// Field("myString").substr(Field("start"), Field("len")) + /// + /// // Get substring from index calculated by Field("start") to the end + /// Field("myString").substr(Field("start"), nil) // Passing nil for optional Expr length + /// ``` + /// + /// - Parameter position: An `Expr` (evaluating to an Int) for the index of the first + /// character/byte. + /// - Parameter length: Optional `Expr` (evaluating to an Int) for the length of the substring. If + /// `nil`, goes to the end. + /// - Returns: A new `FunctionExpr` representing the substring. + func substr(_ position: Expr, _ length: Expr?) -> FunctionExpr + + // MARK: Map Operations + + /// Accesses a value from a map (object) field using the provided literal string key. + /// Assumes `self` evaluates to a Map. + /// + /// ```swift + /// // Get the 'city' value from the 'address' map field + /// Field("address").mapGet("city") + /// ``` + /// + /// - Parameter subfield: The literal string key to access in the map. + /// - Returns: A new `FunctionExpr` representing the value associated with the given key. + func mapGet(_ subfield: String) -> FunctionExpr + + /// Creates an expression that removes a key (specified by a literal string) from the map produced + /// by evaluating this expression. + /// Assumes `self` evaluates to a Map. + /// + /// - Note: This API is in beta. + /// + /// ```swift + /// // Removes the key 'baz' from the map held in field 'myMap' + /// Field("myMap").mapRemove("baz") + /// ``` + /// + /// - Parameter key: The literal string key to remove from the map. + /// - Returns: A new `FunctionExpr` representing the 'map_remove' operation. + func mapRemove(_ key: String) -> FunctionExpr + + /// Creates an expression that removes a key (specified by an expression) from the map produced by + /// evaluating this expression. + /// Assumes `self` evaluates to a Map, and `keyExpr` evaluates to a string. + /// + /// - Note: This API is in beta. + /// + /// ```swift + /// // Removes the key specified by field 'keyToRemove' from the map in 'settings' + /// Field("settings").mapRemove(Field("keyToRemove")) + /// ``` + /// + /// - Parameter keyExpr: An `Expr` (evaluating to a string) representing the key to remove from + /// the map. + /// - Returns: A new `FunctionExpr` representing the 'map_remove' operation. + func mapRemove(_ keyExpr: Expr) -> FunctionExpr + + /// Creates an expression that merges this map with multiple other map literals. + /// Assumes `self` evaluates to a Map. Later maps overwrite keys from earlier maps. + /// + /// - Note: This API is in beta. + /// + /// ```swift + /// // Merge 'settings' field with { "enabled": true } and another map literal { "priority": 1 } + /// Field("settings").mapMerge(["enabled": true], ["priority": 1]) + /// ``` + /// + /// - Parameter secondMap: A required second map (dictionary literal with `Sendable` values) to + /// merge. + /// - Parameter otherMaps: Optional additional maps (dictionary literals with `Sendable` values) + /// to merge. + /// - Returns: A new `FunctionExpr` representing the 'map_merge' operation. + func mapMerge(_ secondMap: [String: Sendable], _ otherMaps: [String: Sendable]...) -> FunctionExpr + + /// Creates an expression that merges this map with multiple other map expressions. + /// Assumes `self` and other arguments evaluate to Maps. Later maps overwrite keys from earlier + /// maps. + /// + /// - Note: This API is in beta. + /// + /// ```swift + /// // Merge 'baseSettings' field with 'userOverrides' field and 'adminConfig' field + /// Field("baseSettings").mapMerge(Field("userOverrides"), Field("adminConfig")) + /// ``` + /// + /// - Parameter secondMap: A required second `Expr` (evaluating to a Map) to merge. + /// - Parameter otherMaps: Optional additional `Expr` (evaluating to Maps) to merge. + /// - Returns: A new `FunctionExpr` representing the 'map_merge' operation. + func mapMerge(_ secondMap: Expr, _ otherMaps: Expr...) -> FunctionExpr + + // MARK: Aggregations + + /// Creates an aggregation that counts the number of stage inputs where this expression evaluates + /// to a valid, non-null value. + /// + /// ```swift + /// // Count the total number of products with a 'productId' + /// Field("productId").count().alias("totalProducts") + /// ``` + /// + /// - Returns: A new `AggregateFunction` representing the 'count' aggregation on this expression. + func count() -> AggregateFunction + + /// Creates an aggregation that calculates the sum of this numeric expression across multiple + /// stage inputs. + /// Assumes `self` evaluates to a numeric type. + /// + /// ```swift + /// // Calculate the total revenue from a set of orders + /// Field("orderAmount").sum().alias("totalRevenue") + /// ``` + /// + /// - Returns: A new `AggregateFunction` representing the 'sum' aggregation. + func sum() -> AggregateFunction + + /// Creates an aggregation that calculates the average (mean) of this numeric expression across + /// multiple stage inputs. + /// Assumes `self` evaluates to a numeric type. + /// + /// ```swift + /// // Calculate the average age of users + /// Field("age").avg().alias("averageAge") + /// ``` + /// + /// - Returns: A new `AggregateFunction` representing the 'avg' aggregation. + func avg() -> AggregateFunction + + /// Creates an aggregation that finds the minimum value of this expression across multiple stage + /// inputs. + /// + /// ```swift + /// // Find the lowest price of all products + /// Field("price").minimum().alias("lowestPrice") + /// ``` + /// + /// - Returns: A new `AggregateFunction` representing the 'min' aggregation. + func minimum() -> AggregateFunction + + /// Creates an aggregation that finds the maximum value of this expression across multiple stage + /// inputs. + /// + /// ```swift + /// // Find the highest score in a leaderboard + /// Field("score").maximum().alias("highestScore") + /// ``` + /// + /// - Returns: A new `AggregateFunction` representing the 'max' aggregation. + func maximum() -> AggregateFunction + + // MARK: Logical min/max + + /// Creates an expression that returns the larger value between this expression and other + /// expressions, based on Firestore's value type ordering. + /// + /// ```swift + /// // Returns the largest of 'val1', 'val2', and 'val3' fields + /// Field("val1").logicalMaximum(Field("val2"), Field("val3")) + /// ``` + /// + /// - Parameter second: The second `Expr` to compare with. + /// - Parameter others: Optional additional `Expr` values to compare with. + /// - Returns: A new `FunctionExpr` representing the logical max operation. + func logicalMaximum(_ second: Expr, _ others: Expr...) -> FunctionExpr + + /// Creates an expression that returns the larger value between this expression and other literal + /// values, based on Firestore's value type ordering. + /// + /// ```swift + /// // Returns the largest of 'val1' (a field), 100, and 200.0 + /// Field("val1").logicalMaximum(100, 200.0) + /// ``` + /// + /// - Parameter second: The second literal `Sendable` value to compare with. + /// - Parameter others: Optional additional literal `Sendable` values to compare with. + /// - Returns: A new `FunctionExpr` representing the logical max operation. + func logicalMaximum(_ second: Sendable, _ others: Sendable...) -> FunctionExpr + + /// Creates an expression that returns the smaller value between this expression and other + /// expressions, based on Firestore's value type ordering. + /// + /// ```swift + /// // Returns the smallest of 'val1', 'val2', and 'val3' fields + /// Field("val1").logicalMinimum(Field("val2"), Field("val3")) + /// ``` + /// + /// - Parameter second: The second `Expr` to compare with. + /// - Parameter others: Optional additional `Expr` values to compare with. + /// - Returns: A new `FunctionExpr` representing the logical min operation. + func logicalMinimum(_ second: Expr, _ others: Expr...) -> FunctionExpr + + /// Creates an expression that returns the smaller value between this expression and other literal + /// values, based on Firestore's value type ordering. + /// + /// ```swift + /// // Returns the smallest of 'val1' (a field), 0, and -5.5 + /// Field("val1").logicalMinimum(0, -5.5) + /// ``` + /// + /// - Parameter second: The second literal `Sendable` value to compare with. + /// - Parameter others: Optional additional literal `Sendable` values to compare with. + /// - Returns: A new `FunctionExpr` representing the logical min operation. + func logicalMinimum(_ second: Sendable, _ others: Sendable...) -> FunctionExpr + + // MARK: Vector Operations + + /// Creates an expression that calculates the length (number of dimensions) of this Firestore + /// Vector expression. + /// Assumes `self` evaluates to a Vector. + /// + /// ```swift + /// // Get the vector length (dimension) of the field 'embedding'. + /// Field("embedding").vectorLength() + /// ``` + /// + /// - Returns: A new `FunctionExpr` representing the length of the vector. + func vectorLength() -> FunctionExpr + + /// Calculates the cosine distance between this vector expression and another vector expression. + /// Assumes both `self` and `other` evaluate to Vectors. + /// + /// ```swift + /// // Cosine distance between 'userVector' field and 'itemVector' field + /// Field("userVector").cosineDistance(Field("itemVector")) + /// ``` + /// + /// - Parameter other: The other vector as an `Expr` to compare against. + /// - Returns: A new `FunctionExpr` representing the cosine distance. + func cosineDistance(_ other: Expr) -> FunctionExpr + + /// Calculates the cosine distance between this vector expression and another vector literal + /// (`VectorValue`). + /// Assumes `self` evaluates to a Vector. + /// + /// ```swift + /// // Cosine distance with a VectorValue + /// let targetVector = VectorValue(vector: [0.1, 0.2, 0.3]) + /// Field("docVector").cosineDistance(targetVector) + /// ``` + /// - Parameter other: The other vector as a `VectorValue` to compare against. + /// - Returns: A new `FunctionExpr` representing the cosine distance. + func cosineDistance(_ other: VectorValue) -> FunctionExpr + + /// Calculates the cosine distance between this vector expression and another vector literal + /// (`[Double]`). + /// Assumes `self` evaluates to a Vector. + /// + /// ```swift + /// // Cosine distance between 'location' field and a target location + /// Field("location").cosineDistance([37.7749, -122.4194]) + /// ``` + /// - Parameter other: The other vector as `[Double]` to compare against. + /// - Returns: A new `FunctionExpr` representing the cosine distance. + func cosineDistance(_ other: [Double]) -> FunctionExpr + + /// Calculates the dot product between this vector expression and another vector expression. + /// Assumes both `self` and `other` evaluate to Vectors. + /// + /// ```swift + /// // Dot product between 'vectorA' and 'vectorB' fields + /// Field("vectorA").dotProduct(Field("vectorB")) + /// ``` + /// + /// - Parameter other: The other vector as an `Expr` to calculate with. + /// - Returns: A new `FunctionExpr` representing the dot product. + func dotProduct(_ other: Expr) -> FunctionExpr + + /// Calculates the dot product between this vector expression and another vector literal + /// (`VectorValue`). + /// Assumes `self` evaluates to a Vector. + /// + /// ```swift + /// // Dot product with a VectorValue + /// let weightVector = VectorValue(vector: [0.5, -0.5]) + /// Field("features").dotProduct(weightVector) + /// ``` + /// - Parameter other: The other vector as a `VectorValue` to calculate with. + /// - Returns: A new `FunctionExpr` representing the dot product. + func dotProduct(_ other: VectorValue) -> FunctionExpr + + /// Calculates the dot product between this vector expression and another vector literal + /// (`[Double]`). + /// Assumes `self` evaluates to a Vector. + /// + /// ```swift + /// // Dot product between a feature vector and a target vector literal + /// Field("features").dotProduct([0.5, 0.8, 0.2]) + /// ``` + /// - Parameter other: The other vector as `[Double]` to calculate with. + /// - Returns: A new `FunctionExpr` representing the dot product. + func dotProduct(_ other: [Double]) -> FunctionExpr + + /// Calculates the Euclidean distance between this vector expression and another vector + /// expression. + /// Assumes both `self` and `other` evaluate to Vectors. + /// + /// ```swift + /// // Euclidean distance between 'pointA' and 'pointB' fields + /// Field("pointA").euclideanDistance(Field("pointB")) + /// ``` + /// + /// - Parameter other: The other vector as an `Expr` to compare against. + /// - Returns: A new `FunctionExpr` representing the Euclidean distance. + func euclideanDistance(_ other: Expr) -> FunctionExpr + + /// Calculates the Euclidean distance between this vector expression and another vector literal + /// (`VectorValue`). + /// Assumes `self` evaluates to a Vector. + /// + /// ```swift + /// let targetPoint = VectorValue(vector: [1.0, 2.0]) + /// Field("currentLocation").euclideanDistance(targetPoint) + /// ``` + /// - Parameter other: The other vector as a `VectorValue` to compare against. + /// - Returns: A new `FunctionExpr` representing the Euclidean distance. + func euclideanDistance(_ other: VectorValue) -> FunctionExpr + + /// Calculates the Euclidean distance between this vector expression and another vector literal + /// (`[Double]`). + /// Assumes `self` evaluates to a Vector. + /// + /// ```swift + /// // Euclidean distance between 'location' field and a target location literal + /// Field("location").euclideanDistance([37.7749, -122.4194]) + /// ``` + /// - Parameter other: The other vector as `[Double]` to compare against. + /// - Returns: A new `FunctionExpr` representing the Euclidean distance. + func euclideanDistance(_ other: [Double]) -> FunctionExpr + + /// Calculates the Manhattan (L1) distance between this vector expression and another vector + /// expression. + /// Assumes both `self` and `other` evaluate to Vectors. + /// + /// - Note: This API is in beta. + /// + /// ```swift + /// // Manhattan distance between 'vector1' field and 'vector2' field + /// Field("vector1").manhattanDistance(Field("vector2")) + /// ``` + /// + /// - Parameter other: The other vector as an `Expr` to compare against. + /// - Returns: A new `FunctionExpr` representing the Manhattan distance. + func manhattanDistance(_ other: Expr) -> FunctionExpr + + /// Calculates the Manhattan (L1) distance between this vector expression and another vector + /// literal (`VectorValue`). + /// Assumes `self` evaluates to a Vector. + /// - Note: This API is in beta. + /// ```swift + /// let referencePoint = VectorValue(vector: [5.0, 10.0]) + /// Field("dataPoint").manhattanDistance(referencePoint) + /// ``` + /// - Parameter other: The other vector as a `VectorValue` to compare against. + /// - Returns: A new `FunctionExpr` representing the Manhattan distance. + func manhattanDistance(_ other: VectorValue) -> FunctionExpr + + /// Calculates the Manhattan (L1) distance between this vector expression and another vector + /// literal (`[Double]`). + /// Assumes `self` evaluates to a Vector. + /// - Note: This API is in beta. + /// + /// ```swift + /// // Manhattan distance between 'point' field and a target point + /// Field("point").manhattanDistance([10.0, 20.0]) + /// ``` + /// - Parameter other: The other vector as `[Double]` to compare against. + /// - Returns: A new `FunctionExpr` representing the Manhattan distance. + func manhattanDistance(_ other: [Double]) -> FunctionExpr + + // MARK: Timestamp operations + + /// Creates an expression that interprets this expression (evaluating to a number) as microseconds + /// since the Unix epoch and returns a timestamp. + /// Assumes `self` evaluates to a number. + /// + /// ```swift + /// // Interpret 'microseconds' field as microseconds since epoch. + /// Field("microseconds").unixMicrosToTimestamp() + /// ``` + /// + /// - Returns: A new `FunctionExpr` representing the timestamp. + func unixMicrosToTimestamp() -> FunctionExpr + + /// Creates an expression that converts this timestamp expression to the number of microseconds + /// since the Unix epoch. Assumes `self` evaluates to a Timestamp. + /// + /// ```swift + /// // Convert 'timestamp' field to microseconds since epoch. + /// Field("timestamp").timestampToUnixMicros() + /// ``` + /// + /// - Returns: A new `FunctionExpr` representing the number of microseconds. + func timestampToUnixMicros() -> FunctionExpr + + /// Creates an expression that interprets this expression (evaluating to a number) as milliseconds + /// since the Unix epoch and returns a timestamp. + /// Assumes `self` evaluates to a number. + /// + /// ```swift + /// // Interpret 'milliseconds' field as milliseconds since epoch. + /// Field("milliseconds").unixMillisToTimestamp() + /// ``` + /// + /// - Returns: A new `FunctionExpr` representing the timestamp. + func unixMillisToTimestamp() -> FunctionExpr + + /// Creates an expression that converts this timestamp expression to the number of milliseconds + /// since the Unix epoch. Assumes `self` evaluates to a Timestamp. + /// + /// ```swift + /// // Convert 'timestamp' field to milliseconds since epoch. + /// Field("timestamp").timestampToUnixMillis() + /// ``` + /// + /// - Returns: A new `FunctionExpr` representing the number of milliseconds. + func timestampToUnixMillis() -> FunctionExpr + + /// Creates an expression that interprets this expression (evaluating to a number) as seconds + /// since the Unix epoch and returns a timestamp. + /// Assumes `self` evaluates to a number. + /// + /// ```swift + /// // Interpret 'seconds' field as seconds since epoch. + /// Field("seconds").unixSecondsToTimestamp() + /// ``` + /// + /// - Returns: A new `FunctionExpr` representing the timestamp. + func unixSecondsToTimestamp() -> FunctionExpr + + /// Creates an expression that converts this timestamp expression to the number of seconds + /// since the Unix epoch. Assumes `self` evaluates to a Timestamp. + /// + /// ```swift + /// // Convert 'timestamp' field to seconds since epoch. + /// Field("timestamp").timestampToUnixSeconds() + /// ``` + /// + /// - Returns: A new `FunctionExpr` representing the number of seconds. + func timestampToUnixSeconds() -> FunctionExpr + + /// Creates an expression that adds a specified amount of time to this timestamp expression, + /// where unit and amount are provided as expressions. + /// Assumes `self` evaluates to a Timestamp, `unit` evaluates to a unit string, and `amount` + /// evaluates to an integer. + /// + /// ```swift + /// // Add duration from 'unitField'/'amountField' to 'timestamp' + /// Field("timestamp").timestampAdd(Field("unitField"), Field("amountField")) + /// ``` + /// + /// - Parameter unit: An `Expr` evaluating to the unit of time string (e.g., "day", "hour"). + /// Valid units are 'microsecond', 'millisecond', 'second', 'minute', 'hour', + /// 'day'. + /// - Parameter amount: An `Expr` evaluating to the amount (Int) of the unit to add. + /// - Returns: A new `FunctionExpr` representing the resulting timestamp. + func timestampAdd(_ unit: Expr, _ amount: Expr) -> FunctionExpr + + /// Creates an expression that adds a specified amount of time to this timestamp expression, + /// where unit and amount are provided as literals. + /// Assumes `self` evaluates to a Timestamp. + /// + /// ```swift + /// // Add 1 day to the 'timestamp' field. + /// Field("timestamp").timestampAdd(.day, 1) + /// ``` + /// + /// - Parameter unit: The `TimeUnit` enum representing the unit of time. + /// - Parameter amount: The literal `Int` amount of the unit to add. + /// - Returns: A new `FunctionExpr` representing the resulting timestamp. + func timestampAdd(_ unit: TimeUnit, _ amount: Int) -> FunctionExpr + + /// Creates an expression that subtracts a specified amount of time from this timestamp + /// expression, + /// where unit and amount are provided as expressions. + /// Assumes `self` evaluates to a Timestamp, `unit` evaluates to a unit string, and `amount` + /// evaluates to an integer. + /// + /// ```swift + /// // Subtract duration from 'unitField'/'amountField' from 'timestamp' + /// Field("timestamp").timestampSub(Field("unitField"), Field("amountField")) + /// ``` + /// + /// - Parameter unit: An `Expr` evaluating to the unit of time string (e.g., "day", "hour"). + /// Valid units are 'microsecond', 'millisecond', 'second', 'minute', 'hour', + /// 'day'. + /// - Parameter amount: An `Expr` evaluating to the amount (Int) of the unit to subtract. + /// - Returns: A new `FunctionExpr` representing the resulting timestamp. + func timestampSub(_ unit: Expr, _ amount: Expr) -> FunctionExpr + + /// Creates an expression that subtracts a specified amount of time from this timestamp + /// expression, + /// where unit and amount are provided as literals. + /// Assumes `self` evaluates to a Timestamp. + /// + /// ```swift + /// // Subtract 1 day from the 'timestamp' field. + /// Field("timestamp").timestampSub(.day, 1) + /// ``` + /// + /// - Parameter unit: The `TimeUnit` enum representing the unit of time. + /// - Parameter amount: The literal `Int` amount of the unit to subtract. + /// - Returns: A new `FunctionExpr` representing the resulting timestamp. + func timestampSub(_ unit: TimeUnit, _ amount: Int) -> FunctionExpr + + // MARK: - Bitwise operations + + /// Creates an expression applying bitwise AND between this expression and an integer literal. + /// Assumes `self` evaluates to an Integer or Bytes. + /// + /// - Note: This API is in beta. + /// + /// ```swift + /// // Bitwise AND of 'flags' field and 0xFF + /// Field("flags").bitAnd(0xFF) + /// ``` + /// + /// - Parameter otherBits: The integer literal operand. + /// - Returns: A new `FunctionExpr` representing the bitwise AND operation. + func bitAnd(_ otherBits: Int) -> FunctionExpr + + /// Creates an expression applying bitwise AND between this expression and a UInt8 literal (often + /// for byte masks). + /// Assumes `self` evaluates to an Integer or Bytes. + /// - Note: This API is in beta. + /// ```swift + /// // Bitwise AND of 'byteFlags' field and a byte mask + /// Field("byteFlags").bitAnd(0b00001111 as UInt8) + /// ``` + /// - Parameter otherBits: The UInt8 literal operand. + /// - Returns: A new `FunctionExpr` representing the bitwise AND operation. + func bitAnd(_ otherBits: UInt8) -> FunctionExpr + + /// Creates an expression applying bitwise AND between this expression and another expression. + /// Assumes `self` and `bitsExpression` evaluate to Integer or Bytes. + /// - Note: This API is in beta. + /// + /// ```swift + /// // Bitwise AND of 'mask1' and 'mask2' fields + /// Field("mask1").bitAnd(Field("mask2")) + /// ``` + /// - Parameter bitsExpression: The other `Expr` operand. + /// - Returns: A new `FunctionExpr` representing the bitwise AND operation. + func bitAnd(_ bitsExpression: Expr) -> FunctionExpr + + /// Creates an expression applying bitwise OR between this expression and an integer literal. + /// Assumes `self` evaluates to an Integer or Bytes. + /// + /// - Note: This API is in beta. + /// + /// ```swift + /// // Bitwise OR of 'flags' field and 0x01 + /// Field("flags").bitOr(0x01) + /// ``` + /// + /// - Parameter otherBits: The integer literal operand. + /// - Returns: A new `FunctionExpr` representing the bitwise OR operation. + func bitOr(_ otherBits: Int) -> FunctionExpr + + /// Creates an expression applying bitwise OR between this expression and a UInt8 literal. + /// Assumes `self` evaluates to an Integer or Bytes. + /// - Note: This API is in beta. + /// ```swift + /// // Set specific bits in 'controlByte' + /// Field("controlByte").bitOr(0b10000001 as UInt8) + /// ``` + /// - Parameter otherBits: The UInt8 literal operand. + /// - Returns: A new `FunctionExpr` representing the bitwise OR operation. + func bitOr(_ otherBits: UInt8) -> FunctionExpr + + /// Creates an expression applying bitwise OR between this expression and another expression. + /// Assumes `self` and `bitsExpression` evaluate to Integer or Bytes. + /// - Note: This API is in beta. + /// + /// ```swift + /// // Bitwise OR of 'permissionSet1' and 'permissionSet2' fields + /// Field("permissionSet1").bitOr(Field("permissionSet2")) + /// ``` + /// - Parameter bitsExpression: The other `Expr` operand. + /// - Returns: A new `FunctionExpr` representing the bitwise OR operation. + func bitOr(_ bitsExpression: Expr) -> FunctionExpr + + /// Creates an expression applying bitwise XOR between this expression and an integer literal. + /// Assumes `self` evaluates to an Integer or Bytes. + /// + /// - Note: This API is in beta. + /// + /// ```swift + /// // Bitwise XOR of 'toggle' field and 0xFFFF + /// Field("toggle").bitXor(0xFFFF) + /// ``` + /// + /// - Parameter otherBits: The integer literal operand. + /// - Returns: A new `FunctionExpr` representing the bitwise XOR operation. + func bitXor(_ otherBits: Int) -> FunctionExpr + + /// Creates an expression applying bitwise XOR between this expression and a UInt8 literal. + /// Assumes `self` evaluates to an Integer or Bytes. + /// - Note: This API is in beta. + /// ```swift + /// // Toggle bits in 'statusByte' using a XOR mask + /// Field("statusByte").bitXor(0b01010101 as UInt8) + /// ``` + /// - Parameter otherBits: The UInt8 literal operand. + /// - Returns: A new `FunctionExpr` representing the bitwise XOR operation. + func bitXor(_ otherBits: UInt8) -> FunctionExpr + + /// Creates an expression applying bitwise XOR between this expression and another expression. + /// Assumes `self` and `bitsExpression` evaluate to Integer or Bytes. + /// - Note: This API is in beta. + /// + /// ```swift + /// // Bitwise XOR of 'key1' and 'key2' fields (assuming Bytes) + /// Field("key1").bitXor(Field("key2")) + /// ``` + /// - Parameter bitsExpression: The other `Expr` operand. + /// - Returns: A new `FunctionExpr` representing the bitwise XOR operation. + func bitXor(_ bitsExpression: Expr) -> FunctionExpr + + /// Creates an expression applying bitwise NOT to this expression. + /// Assumes `self` evaluates to an Integer or Bytes. + /// + /// - Note: This API is in beta. + /// + /// ```swift + /// // Bitwise NOT of 'mask' field + /// Field("mask").bitNot() + /// ``` + /// + /// - Returns: A new `FunctionExpr` representing the bitwise NOT operation. + func bitNot() -> FunctionExpr + + /// Creates an expression applying bitwise left shift to this expression by a literal number of + /// bits. + /// Assumes `self` evaluates to Integer or Bytes. + /// + /// - Note: This API is in beta. + /// + /// ```swift + /// // Left shift 'value' field by 2 bits + /// Field("value").bitLeftShift(2) + /// ``` + /// + /// - Parameter y: The number of bits (Int literal) to shift by. + /// - Returns: A new `FunctionExpr` representing the bitwise left shift operation. + func bitLeftShift(_ y: Int) -> FunctionExpr + + /// Creates an expression applying bitwise left shift to this expression by a number of bits + /// specified by an expression. + /// Assumes `self` evaluates to Integer or Bytes, and `numberExpr` evaluates to an Integer. + /// - Note: This API is in beta. + /// + /// ```swift + /// // Left shift 'data' by number of bits in 'shiftCount' field + /// Field("data").bitLeftShift(Field("shiftCount")) + /// ``` + /// - Parameter numberExpr: An `Expr` (evaluating to an Int) for the number of bits to shift by. + /// - Returns: A new `FunctionExpr` representing the bitwise left shift operation. + func bitLeftShift(_ numberExpr: Expr) -> FunctionExpr + + /// Creates an expression applying bitwise right shift to this expression by a literal number of + /// bits. + /// Assumes `self` evaluates to Integer or Bytes. + /// + /// - Note: This API is in beta. + /// + /// ```swift + /// // Right shift 'value' field by 4 bits + /// Field("value").bitRightShift(4) + /// ``` + /// + /// - Parameter y: The number of bits (Int literal) to shift by. + /// - Returns: A new `FunctionExpr` representing the bitwise right shift operation. + func bitRightShift(_ y: Int) -> FunctionExpr + + /// Creates an expression applying bitwise right shift to this expression by a number of bits + /// specified by an expression. + /// Assumes `self` evaluates to Integer or Bytes, and `numberExpr` evaluates to an Integer. + /// - Note: This API is in beta. + /// + /// ```swift + /// // Right shift 'data' by number of bits in 'shiftCount' field + /// Field("data").bitRightShift(Field("shiftCount")) + /// ``` + /// - Parameter numberExpr: An `Expr` (evaluating to an Int) for the number of bits to shift by. + /// - Returns: A new `FunctionExpr` representing the bitwise right shift operation. + func bitRightShift(_ numberExpr: Expr) -> FunctionExpr + + /// Creates an expression that returns the result of `catchExpr` if this expression produces an + /// error during evaluation, + /// otherwise returns the result of this expression. + /// + /// - Note: This API is in beta. + /// + /// ```swift + /// // Try dividing 'a' by 'b', return field 'fallbackValue' on error (e.g., division by zero) + /// Field("a").divide(Field("b")).ifError(Field("fallbackValue")) + /// ``` + /// + /// - Parameter catchExpr: The `Expr` to evaluate and return if this expression errors. + /// - Returns: A new `FunctionExpr` representing the 'ifError' operation. + func ifError(_ catchExpr: Expr) -> FunctionExpr + + /// Creates an expression that returns the literal `catchValue` if this expression produces an + /// error during evaluation, + /// otherwise returns the result of this expression. + /// + /// - Note: This API is in beta. + /// + /// ```swift + /// // Get first item in 'title' array, or return "Default Title" if error (e.g., empty array) + /// Field("title").arrayOffset(0).ifError("Default Title") + /// ``` + /// + /// - Parameter catchValue: The literal `Sendable` value to return if this expression errors. + /// - Returns: A new `FunctionExpr` representing the 'ifError' operation. + func ifError(_ catchValue: Sendable) -> FunctionExpr + + // MARK: Sorting + + /// Creates an `Ordering` object that sorts documents in ascending order based on this expression. + /// + /// ```swift + /// // Sort documents by the 'name' field in ascending order + /// firestore.pipeline().collection("users") + /// .sort(Field("name").ascending()) + /// ``` + /// + /// - Returns: A new `Ordering` instance for ascending sorting. + func ascending() -> Ordering + + /// Creates an `Ordering` object that sorts documents in descending order based on this + /// expression. + /// + /// ```swift + /// // Sort documents by the 'createdAt' field in descending order + /// firestore.pipeline().collection("users") + /// .sort(Field("createdAt").descending()) + /// ``` + /// + /// - Returns: A new `Ordering` instance for descending sorting. + func descending() -> Ordering +} diff --git a/Firestore/Swift/Source/SwiftAPI/Pipeline/Expr/Constant.swift b/Firestore/Swift/Source/SwiftAPI/Pipeline/Expr/Constant.swift new file mode 100644 index 00000000000..0d4f30fe463 --- /dev/null +++ b/Firestore/Swift/Source/SwiftAPI/Pipeline/Expr/Constant.swift @@ -0,0 +1,77 @@ +// Copyright 2025 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 + +public struct Constant: Expr, BridgeWrapper, @unchecked Sendable { + let bridge: ExprBridge + + let value: Any? + + // Initializer for optional values (including nil) + init(_ value: Any?) { + self.value = value + if value == nil { + bridge = ConstantBridge(NSNull()) + } else { + bridge = ConstantBridge(value!) + } + } + + // Initializer for numbers + public init(_ value: Double) { + self.init(value as Any) + } + + // Initializer for strings + public init(_ value: String) { + self.init(value as Any) + } + + // Initializer for boolean values + public init(_ value: Bool) { + self.init(value as Any) + } + + // Initializer for GeoPoint values + public init(_ value: GeoPoint) { + self.init(value as Any) + } + + // Initializer for Timestamp values + public init(_ value: Timestamp) { + self.init(value as Any) + } + + // Initializer for Date values + public init(_ value: Date) { + self.init(value as Any) + } + + // Initializer for DocumentReference + public init(_ value: DocumentReference) { + self.init(value as Any) + } + + // Initializer for vector values + public init(_ value: VectorValue) { + self.init(value as Any) + } + + public static let `nil` = Constant(nil) +} diff --git a/Firestore/Swift/Source/SwiftAPI/Pipeline/Expr/DocumentId.swift b/Firestore/Swift/Source/SwiftAPI/Pipeline/Expr/DocumentId.swift new file mode 100644 index 00000000000..70c621d8cbd --- /dev/null +++ b/Firestore/Swift/Source/SwiftAPI/Pipeline/Expr/DocumentId.swift @@ -0,0 +1,19 @@ +// Copyright 2025 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. + +public class DocumentId: Field, @unchecked Sendable { + public init() { + super.init("__name__") + } +} diff --git a/Firestore/Swift/Source/SwiftAPI/Pipeline/Expr/Field.swift b/Firestore/Swift/Source/SwiftAPI/Pipeline/Expr/Field.swift new file mode 100644 index 00000000000..fa1dc7d7510 --- /dev/null +++ b/Firestore/Swift/Source/SwiftAPI/Pipeline/Expr/Field.swift @@ -0,0 +1,32 @@ +// Copyright 2025 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. + +public class Field: ExprBridge, Expr, Selectable, BridgeWrapper, SelectableWrapper, + @unchecked Sendable { + let bridge: ExprBridge + + var alias: String + + var expr: Expr { + return self + } + + public let fieldName: String + + public init(_ fieldName: String) { + self.fieldName = fieldName + alias = fieldName + bridge = FieldBridge(alias) + } +} diff --git a/Firestore/Swift/Source/SwiftAPI/Pipeline/Expr/FunctionExpr.swift b/Firestore/Swift/Source/SwiftAPI/Pipeline/Expr/FunctionExpr.swift new file mode 100644 index 00000000000..533f6a5ef51 --- /dev/null +++ b/Firestore/Swift/Source/SwiftAPI/Pipeline/Expr/FunctionExpr.swift @@ -0,0 +1,30 @@ +// Copyright 2025 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. + +public class FunctionExpr: Expr, BridgeWrapper, @unchecked Sendable { + let bridge: ExprBridge + + let functionName: String + let agrs: [Expr] + + public init(_ functionName: String, _ agrs: [Expr]) { + self.functionName = functionName + self.agrs = agrs + bridge = FunctionExprBridge( + name: functionName, + args: self.agrs.map { $0.toBridge() + } + ) + } +} diff --git a/Firestore/Swift/Source/SwiftAPI/Pipeline/Expr/FunctionExpr/BooleanExpr.swift b/Firestore/Swift/Source/SwiftAPI/Pipeline/Expr/FunctionExpr/BooleanExpr.swift new file mode 100644 index 00000000000..9826d1698c0 --- /dev/null +++ b/Firestore/Swift/Source/SwiftAPI/Pipeline/Expr/FunctionExpr/BooleanExpr.swift @@ -0,0 +1,33 @@ +// Copyright 2025 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. + +public class BooleanExpr: FunctionExpr, @unchecked Sendable { + override public init(_ functionName: String, _ agrs: [Expr]) { + super.init(functionName, agrs) + } + + public static func && (lhs: BooleanExpr, + rhs: @autoclosure () throws -> BooleanExpr) rethrows -> BooleanExpr { + try BooleanExpr("and", [lhs, rhs()]) + } + + public static func || (lhs: BooleanExpr, + rhs: @autoclosure () throws -> BooleanExpr) rethrows -> BooleanExpr { + try BooleanExpr("or", [lhs, rhs()]) + } + + public static prefix func ! (lhs: BooleanExpr) -> BooleanExpr { + return BooleanExpr("not", [lhs]) + } +} diff --git a/Firestore/Swift/Source/SwiftAPI/Pipeline/ExprWithAlias.swift b/Firestore/Swift/Source/SwiftAPI/Pipeline/ExprWithAlias.swift new file mode 100644 index 00000000000..247427f2fd8 --- /dev/null +++ b/Firestore/Swift/Source/SwiftAPI/Pipeline/ExprWithAlias.swift @@ -0,0 +1,24 @@ +// Copyright 2025 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. + +public struct ExprWithAlias: Selectable, SelectableWrapper, Sendable { + public var alias: String + + public var expr: Expr + + init(_ expr: Expr, _ alias: String) { + self.alias = alias + self.expr = expr + } +} diff --git a/Firestore/Swift/Source/SwiftAPI/Pipeline/Ordering.swift b/Firestore/Swift/Source/SwiftAPI/Pipeline/Ordering.swift new file mode 100644 index 00000000000..9659e95e682 --- /dev/null +++ b/Firestore/Swift/Source/SwiftAPI/Pipeline/Ordering.swift @@ -0,0 +1,50 @@ +/* + * 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. + */ + +public class Ordering: @unchecked Sendable { + let expr: Expr + let direction: Direction + let bridge: OrderingBridge + + init(expr: Expr, direction: Direction) { + self.expr = expr + self.direction = direction + bridge = OrderingBridge(expr: expr.toBridge(), direction: direction.rawValue) + } +} + +public struct Direction: Sendable, Equatable, Hashable { + let kind: Kind + let rawValue: String + + enum Kind: String { + case ascending + case descending + } + + public static var ascending: Direction { + return self.init(kind: .ascending, rawValue: "ascending") + } + + public static var descending: Direction { + return self.init(kind: .descending, rawValue: "descending") + } + + init(kind: Kind, rawValue: String) { + self.kind = kind + self.rawValue = rawValue + } +} diff --git a/Firestore/Swift/Source/SwiftAPI/Pipeline/Pipeline.swift b/Firestore/Swift/Source/SwiftAPI/Pipeline/Pipeline.swift new file mode 100644 index 00000000000..4e49c97301b --- /dev/null +++ b/Firestore/Swift/Source/SwiftAPI/Pipeline/Pipeline.swift @@ -0,0 +1,722 @@ +// Copyright 2025 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 + +/// The `Pipeline` class provides a flexible and expressive framework for building complex data +/// transformation and query pipelines for Firestore. +/// +/// A pipeline takes data sources, such as Firestore collections or collection groups, and applies +/// a series of stages that are chained together. Each stage takes the output from the previous +/// stage +/// (or the data source) and produces an output for the next stage (or as the final output of the +/// pipeline). +/// +/// Expressions can be used within each stage to filter and transform data through the stage. +/// +/// NOTE: The chained stages do not prescribe exactly how Firestore will execute the pipeline. +/// Instead, Firestore only guarantees that the result is the same as if the chained stages were +/// executed in order. +/// +/// ## Usage Examples +/// +/// The following examples assume you have a `Firestore` instance named `db`. +/// +/// ```swift +/// import FirebaseFirestore +/// +/// // Example 1: Select specific fields and rename 'rating' to 'bookRating'. +/// // Assumes `Field("rating").as("bookRating")` is a valid `Selectable` expression. +/// do { +/// let results1 = try await db.pipeline().collection("books") +/// .select(Field("title"), Field("author"), Field("rating").as("bookRating")) +/// .execute() +/// print("Results 1: \(results1.documents)") +/// } catch { +/// print("Error in example 1: \(error)") +/// } +/// +/// // Example 2: Filter documents where 'genre' is "Science Fiction" and 'published' is after 1950. +/// // Assumes `Function.eq`, `Function.gt`, and `Function.and` create `BooleanExpr`. +/// do { +/// let results2 = try await db.pipeline().collection("books") +/// .where(Function.and( +/// Function.eq(Field("genre"), "Science Fiction"), +/// Function.gt(Field("published"), 1950) +/// )) +/// .execute() +/// print("Results 2: \(results2.documents)") +/// } catch { +/// print("Error in example 2: \(error)") +/// } +/// +/// // Example 3: Calculate the average rating of books published after 1980. +/// // Assumes `avg()` creates an `Accumulator` and `AggregateWithAlias` is used correctly. +/// do { +/// let results3 = try await db.pipeline().collection("books") +/// .where(Function.gt(Field("published"), 1980)) +/// .aggregate(AggregateWithas(avg(Field("rating")), alias: "averageRating")) +/// .execute() +/// print("Results 3: \(results3.documents)") +/// } catch { +/// print("Error in example 3: \(error)") +/// } +/// ``` +@available(iOS 13, tvOS 13, macOS 10.15, macCatalyst 13, watchOS 7, *) +public struct Pipeline: @unchecked Sendable { + private var stages: [Stage] + let bridge: PipelineBridge + let db: Firestore + + init(stages: [Stage], db: Firestore) { + self.stages = stages + self.db = db + bridge = PipelineBridge(stages: stages.map { $0.bridge }, db: db) + } + + /// Executes the defined pipeline and returns a `PipelineSnapshot` containing the results. + /// + /// This method asynchronously sends the pipeline definition to Firestore for execution. + /// The resulting documents, transformed and filtered by the pipeline stages, are returned + /// within a `PipelineSnapshot`. + /// + /// ```swift + /// // let pipeline: Pipeline = ... // Assume a pipeline is already configured. + /// do { + /// let snapshot = try await pipeline.execute() + /// // Process snapshot.documents + /// print("Pipeline executed successfully: \(snapshot.documents)") + /// } catch { + /// print("Pipeline execution failed: \(error)") + /// } + /// ``` + /// + /// - Throws: An error if the pipeline execution fails on the backend. + /// - Returns: A `PipelineSnapshot` containing the result of the pipeline execution. + public func execute() async throws -> PipelineSnapshot { + return try await withCheckedThrowingContinuation { continuation in + self.bridge.execute { result, error in + if let error { + continuation.resume(throwing: error) + } else { + continuation.resume(returning: PipelineSnapshot(result!, pipeline: self)) + } + } + } + } + + /// Adds new fields to outputs from previous stages. + /// + /// This stage allows you to compute values on-the-fly based on existing data from previous + /// stages or constants. You can use this to create new fields or overwrite existing ones + /// (if there is a name overlap). + /// + /// The added fields are defined using `Selectable`s, which can be: + /// - `Field`: References an existing document field. + /// - `Function`: Performs a calculation using functions like `Function.add` or + /// `Function.multiply`, + /// typically with an assigned alias (e.g., `Function.multiply(Field("price"), + /// 1.1).as("priceWithTax")`). + /// + /// ```swift + /// // let pipeline: Pipeline = ... // Assume initial pipeline from a collection. + /// let updatedPipeline = pipeline.addFields( + /// Field("rating").as("bookRating"), // Rename 'rating' to 'bookRating'. + /// Function.add(5, Field("quantity")).as("totalQuantityPlusFive") // Calculate + /// 'totalQuantityPlusFive'. + /// ) + /// // let results = try await updatedPipeline.execute() + /// ``` + /// + /// - Parameter field: The first field to add to the documents, specified as a `Selectable`. + /// - Parameter additionalFields: Optional additional fields to add, specified as `Selectable`s. + /// - Returns: A new `Pipeline` object with this stage appended. + public func addFields(_ field: Selectable, _ additionalFields: Selectable...) -> Pipeline { + let fields = [field] + additionalFields + return Pipeline(stages: stages + [AddFields(fields: fields)], db: db) + } + + /// Removes fields from outputs of previous stages. + /// + /// ```swift + /// // let pipeline: Pipeline = ... // Assume initial pipeline. + /// let updatedPipeline = pipeline.removeFields(Field("confidentialData"), Field("internalNotes")) + /// // let results = try await updatedPipeline.execute() + /// ``` + /// + /// - Parameter field: The first field to remove, specified as a `Field` instance. + /// - Parameter additionalFields: Optional additional fields to remove. + /// - Returns: A new `Pipeline` object with this stage appended. + public func removeFields(_ field: Field, _ additionalFields: Field...) -> Pipeline { + return Pipeline( + stages: stages + [RemoveFieldsStage(fields: [field] + additionalFields)], + db: db + ) + } + + /// Removes fields from outputs of previous stages using field names. + /// + /// ```swift + /// // let pipeline: Pipeline = ... // Assume initial pipeline. + /// // Removes fields 'rating' and 'cost' from the previous stage outputs. + /// let updatedPipeline = pipeline.removeFields("rating", "cost") + /// // let results = try await updatedPipeline.execute() + /// ``` + /// + /// - Parameter field: The name of the first field to remove. + /// - Parameter additionalFields: Optional additional field names to remove. + /// - Returns: A new `Pipeline` object with this stage appended. + public func removeFields(_ field: String, _ additionalFields: String...) -> Pipeline { + return Pipeline( + stages: stages + [RemoveFieldsStage(fields: [field] + additionalFields)], + db: db + ) + } + + /// Selects or creates a set of fields from the outputs of previous stages. + /// + /// The selected fields are defined using `Selectable` expressions, which can be: + /// - `String`: Name of an existing field (implicitly converted to `Field`). + /// - `Field`: References an existing field. + /// - `Function`: Represents the result of a function with an assigned alias + /// (e.g., `Function.toUppercase(Field("address")).as("upperAddress")`). + /// + /// If no selections are provided, the output of this stage is typically empty. + /// Use `addFields` if only additions are desired without replacing the existing document + /// structure. + /// + /// ```swift + /// // let pipeline: Pipeline = ... // Assume initial pipeline. + /// let projectedPipeline = pipeline.select( + /// Field("firstName"), + /// Field("lastName"), + /// Function.toUppercase(Field("address")).as("upperAddress") + /// ) + /// // let results = try await projectedPipeline.execute() + /// ``` + /// + /// - Parameter selection: The first field to include in the output documents, specified as a + /// `Selectable`. + /// - Parameter additionalSelections: Optional additional fields to include, specified as + /// `Selectable`s. + /// - Returns: A new `Pipeline` object with this stage appended. + public func select(_ selection: Selectable, _ additionalSelections: Selectable...) -> Pipeline { + let selections = [selection] + additionalSelections + return Pipeline( + stages: stages + [Select(selections: selections)], + db: db + ) + } + + /// Selects a set of fields from the outputs of previous stages using field names. + /// + /// The selected fields are specified by their names. If no selections are provided, + /// the output of this stage is typically empty. Use `addFields` if only additions are desired. + /// + /// ```swift + /// // let pipeline: Pipeline = ... // Assume initial pipeline. + /// let projectedPipeline = pipeline.select("title", "author", "yearPublished") + /// // let results = try await projectedPipeline.execute() + /// ``` + /// + /// - Parameter selection: The name of the first field to include in the output documents. + /// - Parameter additionalSelections: Optional additional field names to include. + /// - Returns: A new `Pipeline` object with this stage appended. + public func select(_ selection: String, _ additionalSelections: String...) -> Pipeline { + let selections = ([selection] + additionalSelections).map { Field($0) } + return Pipeline( + stages: stages + [Select(selections: selections)], + db: db + ) + } + + /// Filters documents from previous stages, including only those matching the specified + /// `BooleanExpr`. + /// + /// This stage applies conditions similar to a "WHERE" clause in SQL. + /// Filter documents based on field values using `BooleanExpr` implementations, such as: + /// - Field comparators: `Function.eq`, `Function.lt` (less than), `Function.gt` (greater than). + /// - Logical operators: `Function.and`, `Function.or`, `Function.not`. + /// - Advanced functions: `Function.regexMatch`, `Function.arrayContains`. + /// + /// ```swift + /// // let pipeline: Pipeline = ... // Assume initial pipeline. + /// let filteredPipeline = pipeline.where( + /// Field("rating").gt(4.0) // Rating greater than 4.0. + /// && Field("genre").eq("Science Fiction") // Genre is "Science Fiction". + /// ) + /// // let results = try await filteredPipeline.execute() + /// ``` + /// + /// - Parameter condition: The `BooleanExpr` to apply. + /// - Returns: A new `Pipeline` object with this stage appended. + public func `where`(_ condition: BooleanExpr) -> Pipeline { + return Pipeline(stages: stages + [Where(condition: condition)], db: db) + } + + /// Skips the first `offset` number of documents from the results of previous stages. + /// + /// A negative input number might count back from the end of the result set, + /// depending on backend behavior. This stage is useful for pagination, + /// typically used with `limit` to control page size. + /// + /// ```swift + /// // let pipeline: Pipeline = ... // Assume initial pipeline, possibly sorted. + /// // Retrieve the second page of 20 results (skip first 20, limit to next 20). + /// let pagedPipeline = pipeline + /// .sort(Ascending("published")) // Example sort. + /// .offset(20) // Skip the first 20 results. + /// .limit(20) // Take the next 20 results. + /// // let results = try await pagedPipeline.execute() + /// ``` + /// + /// - Parameter offset: The number of documents to skip (a `Int32` value). + /// - Returns: A new `Pipeline` object with this stage appended. + public func offset(_ offset: Int32) -> Pipeline { + return Pipeline(stages: stages + [Offset(offset)], db: db) + } + + /// Limits the maximum number of documents returned by previous stages to `limit`. + /// + /// A negative input number might count back from the end of the result set, + /// depending on backend behavior. This stage helps retrieve a controlled subset of data. + /// It's often used for: + /// - **Pagination:** With `offset` to retrieve specific pages. + /// - **Limiting Data Retrieval:** To improve performance with large collections. + /// + /// ```swift + /// // let pipeline: Pipeline = ... // Assume initial pipeline. + /// // Limit results to the top 10 highest-rated books. + /// let topTenPipeline = pipeline + /// .sort(Descending(Field("rating"))) + /// .limit(10) + /// // let results = try await topTenPipeline.execute() + /// ``` + /// + /// - Parameter limit: The maximum number of documents to return (a `Int32` value). + /// - Returns: A new `Pipeline` object with this stage appended. + public func limit(_ limit: Int32) -> Pipeline { + return Pipeline(stages: stages + [Limit(limit)], db: db) + } + + /// Returns a set of distinct documents based on specified grouping field names. + /// + /// This stage ensures that only unique combinations of values for the specified + /// group fields are included from the previous stage's output. + /// + /// ```swift + /// // let pipeline: Pipeline = ... // Assume initial pipeline. + /// // Get a list of unique author and genre combinations. + /// let distinctAuthorsGenresPipeline = pipeline.distinct("author", "genre") + /// // To further select only the author: + /// // .select("author") + /// // let results = try await distinctAuthorsGenresPipeline.execute() + /// ``` + /// + /// - Parameter group: The name of the first field for distinct value combinations. + /// - Parameter additionalGroups: Optional additional field names. + /// - Returns: A new `Pipeline` object with this stage appended. + public func distinct(_ group: String, _ additionalGroups: String...) -> Pipeline { + let selections = ([group] + additionalGroups).map { Field($0) } + return Pipeline(stages: stages + [Distinct(groups: selections)], db: db) + } + + /// Returns a set of distinct documents based on specified `Selectable` expressions. + /// + /// This stage ensures unique combinations of values from evaluated `Selectable` + /// expressions (e.g., `Field` or `Function` results). + /// + /// `Selectable` expressions can be: + /// - `Field`: A reference to an existing document field. + /// - `Function`: The result of a function with an alias (e.g., + /// `Function.toUppercase(Field("author")).as("authorName")`). + /// + /// ```swift + /// // let pipeline: Pipeline = ... // Assume initial pipeline. + /// // Get unique uppercase author names and genre combinations. + /// let distinctPipeline = pipeline.distinct( + /// Field("author").uppercased().as("authorName"), + /// Field("genre") + /// ) + /// // To select only the transformed author name: + /// // .select(Field("authorName")) + /// // let results = try await distinctPipeline.execute() + /// ``` + /// + /// - Parameter group: The first `Selectable` expression to consider. + /// - Parameter additionalGroups: Optional additional `Selectable` expressions. + /// - Returns: A new `Pipeline` object with this stage appended. + public func distinct(_ group: Selectable, _ additionalGroups: Selectable...) -> Pipeline { + let groups = [group] + additionalGroups + return Pipeline(stages: stages + [Distinct(groups: groups)], db: db) + } + + /// Performs aggregation operations on all documents from previous stages. + /// + /// Computes aggregate values (e.g., sum, average, count) over the entire set of documents + /// from the previous stage. Aggregations are defined using `AggregateWithAlias`, + /// which pairs an `Accumulator` (e.g., `avg(Field("price"))`) with a result field name. + /// + /// ```swift + /// // let pipeline: Pipeline = ... // Assume pipeline from a "books" collection. + /// // Calculate the average rating and total number of books. + /// let aggregatedPipeline = pipeline.aggregate( + /// AggregateWithas(aggregate: avg(Field("rating")), alias: "averageRating"), + /// AggregateWithas(aggregate: countAll(), alias: "totalBooks") + /// ) + /// // let results = try await aggregatedPipeline.execute() + /// // results.documents might be: [["averageRating": 4.2, "totalBooks": 150]] + /// ``` + /// + /// - Parameter accumulator: The first `AggregateWithAlias` expression. + /// - Parameter additionalAccumulators: Optional additional `AggregateWithAlias` expressions. + /// - Returns: A new `Pipeline` object with this stage appended. + public func aggregate(_ accumulator: AggregateWithAlias, + _ additionalAccumulators: AggregateWithAlias...) -> Pipeline { + return Pipeline( + stages: stages + [Aggregate( + accumulators: [accumulator] + additionalAccumulators, + groups: nil // No grouping: aggregate over all documents. + )], + db: db + ) + } + + /// Performs optionally grouped aggregation operations on documents from previous stages. + /// + /// Calculates aggregate values, optionally grouping documents by fields or `Selectable` + /// expressions. + /// - **Grouping:** Defined by the `groups` parameter. Each unique combination of values + /// from these `Selectable`s forms a group. If `groups` is `nil` or empty, + /// all documents form a single group. + /// - **Accumulators:** An array of `AggregateWithAlias` defining operations + /// (e.g., sum, average) within each group. + /// + /// ```swift + /// // let pipeline: Pipeline = ... // Assume pipeline from "books" collection. + /// // Calculate the average rating for each genre. + /// let groupedAggregationPipeline = pipeline.aggregate( + /// [AggregateWithas(aggregate: avg(Field("rating")), alias: "avg_rating")], + /// groups: [Field("genre")] // Group by the "genre" field. + /// ) + /// // let results = try await groupedAggregationPipeline.execute() + /// // results.documents might be: + /// // [ + /// // ["genre": "SciFi", "avg_rating": 4.5], + /// // ["genre": "Fantasy", "avg_rating": 4.2] + /// // ] + /// ``` + /// + /// - Parameters: + /// - accumulator: An array of `AggregateWithAlias` expressions for calculations. + /// - groups: Optional array of `Selectable` expressions for grouping. If `nil` or empty, + /// aggregates across all documents. + /// - Returns: A new `Pipeline` object with this stage appended. + public func aggregate(_ accumulator: [AggregateWithAlias], + groups: [Selectable]? = nil) -> Pipeline { + return Pipeline(stages: stages + [Aggregate(accumulators: accumulator, groups: groups)], db: db) + } + + /// Performs optionally grouped aggregation operations using field names for grouping. + /// + /// Similar to the other `aggregate` method, but `groups` are specified as an array of `String` + /// field names. + /// + /// ```swift + /// // let pipeline: Pipeline = ... // Assume pipeline from "books" collection. + /// // Count books for each publisher. + /// let groupedByPublisherPipeline = pipeline.aggregate( + /// [AggregateWithas(aggregate: countAll(), alias: "book_count")], + /// groups: ["publisher"] // Group by the "publisher" field name. + /// ) + /// // let results = try await groupedByPublisherPipeline.execute() + /// // results.documents might be: + /// // [ + /// // ["publisher": "Penguin", "book_count": 50], + /// // ["publisher": "HarperCollins", "book_count": 35] + /// // ] + /// ``` + /// + /// - Parameters: + /// - accumulator: An array of `AggregateWithAlias` expressions. + /// - groups: An optional array of `String` field names for grouping. + /// - Returns: A new `Pipeline` object with this stage appended. + public func aggregate(_ accumulator: [AggregateWithAlias], + groups: [String]? = nil) -> Pipeline { + let selectables = groups?.map { Field($0) } + return Pipeline( + stages: stages + [Aggregate(accumulators: accumulator, groups: selectables)], + db: db + ) + } + + /// Performs a vector similarity search, ordering results by similarity. + /// + /// Returns up to `limit` documents, from most to least similar based on vector embeddings. + /// The distance can optionally be included in a specified field. + /// + /// ```swift + /// // let pipeline: Pipeline = ... // Assume pipeline from a collection with vector embeddings. + /// let queryVector: [Double] = [0.1, 0.2, ..., 0.8] // Example query vector. + /// let nearestNeighborsPipeline = pipeline.findNearest( + /// field: Field("embedding_field"), // Field containing the vector. + /// vectorValue: queryVector, // Query vector for comparison. + /// distanceMeasure: .COSINE, // Distance metric. + /// limit: 10, // Return top 10 nearest neighbors. + /// distanceField: "similarityScore" // Optional: field for distance score. + /// ) + /// // let results = try await nearestNeighborsPipeline.execute() + /// ``` + /// + /// - Parameters: + /// - field: The `Field` containing vector embeddings. + /// - vectorValue: An array of `Double` representing the query vector. + /// - distanceMeasure: The `DistanceMeasure` (e.g., `.EUCLIDEAN`, `.COSINE`) for comparison. + /// - limit: Optional. Maximum number of similar documents to return. + /// - distanceField: Optional. Name for a new field to store the calculated distance. + /// - Returns: A new `Pipeline` object with this stage appended. + public func findNearest(field: Field, + vectorValue: [Double], + distanceMeasure: DistanceMeasure, + limit: Int? = nil, + distanceField: String? = nil) -> Pipeline { + return Pipeline( + stages: stages + [ + FindNearest( + field: field, + vectorValue: vectorValue, + distanceMeasure: distanceMeasure, + limit: limit, + distanceField: distanceField + ), + ], + db: db + ) + } + + /// Sorts documents from previous stages based on one or more `Ordering` criteria. + /// + /// Specify multiple `Ordering` instances for multi-field sorting (ascending/descending). + /// If documents are equal by one criterion, the next is used. If all are equal, + /// relative order is unspecified. + /// + /// ```swift + /// // let pipeline: Pipeline = ... // Assume initial pipeline. + /// // Sort books by rating (descending), then by title (ascending). + /// let sortedPipeline = pipeline.sort( + /// Ascending("rating"), + /// Descending("title") // or Field("title").ascending() for ascending. + /// ) + /// // let results = try await sortedPipeline.execute() + /// ``` + /// + /// - Parameter ordering: The primary `Ordering` criterion. + /// - Parameter additionalOrdering: Optional additional `Ordering` criteria for secondary sorting, + /// etc. + /// - Returns: A new `Pipeline` object with this stage appended. + public func sort(_ ordering: Ordering, _ additionalOrdering: Ordering...) -> Pipeline { + let orderings = [ordering] + additionalOrdering + return Pipeline(stages: stages + [Sort(orderings: orderings)], db: db) + } + + /// Fully overwrites document fields with those from a nested map identified by an `Expr`. + /// + /// "Promotes" a map value (dictionary) from a field to become the new root document. + /// Each key-value pair from the map specified by `expr` becomes a field-value pair + /// in the output document, discarding original document fields. + /// + /// ```swift + /// // Assume input document: + /// // { "id": "user123", "profile": { "name": "Alex", "age": 30 }, "status": "active" } + /// // let pipeline: Pipeline = ... + /// + /// // Replace document with the contents of the 'profile' map. + /// let replacedPipeline = pipeline.replace(with: Field("profile")) + /// + /// // let results = try await replacedPipeline.execute() + /// // Output document would be: { "name": "Alex", "age": 30 } + /// ``` + /// + /// - Parameter expr: The `Expr` (typically a `Field`) that resolves to the nested map. + /// - Returns: A new `Pipeline` object with this stage appended. + public func replace(with expr: Expr) -> Pipeline { + return Pipeline(stages: stages + [ReplaceWith(expr: expr)], db: db) + } + + /// Fully overwrites document fields with those from a nested map identified by a field name. + /// + /// "Promotes" a map value (dictionary) from a field to become the new root document. + /// Each key-value pair from the map in `fieldName` becomes a field-value pair + /// in the output document, discarding original document fields. + /// + /// ```swift + /// // Assume input document: + /// // { "id": "user123", "details": { "role": "admin", "department": "tech" }, "joined": + /// "2023-01-15" } + /// // let pipeline: Pipeline = ... + /// + /// // Replace document with the contents of the 'details' map. + /// let replacedPipeline = pipeline.replace(with: "details") + /// + /// // let results = try await replacedPipeline.execute() + /// // Output document would be: { "role": "admin", "department": "tech" } + /// ``` + /// + /// - Parameter fieldName: The name of the field containing the nested map. + /// - Returns: A new `Pipeline` object with this stage appended. + public func replace(with fieldName: String) -> Pipeline { + return Pipeline(stages: stages + [ReplaceWith(expr: Field(fieldName))], db: db) + } + + /// Performs pseudo-random sampling of input documents, returning a specific count. + /// + /// Filters documents pseudo-randomly. `count` specifies the approximate number + /// to return. The actual number may vary and isn't guaranteed if the input set + /// is smaller than `count`. + /// + /// ```swift + /// // let pipeline: Pipeline = ... // Assume pipeline from a large collection. + /// // Sample 25 books, if available. + /// let sampledPipeline = pipeline.sample(count: 25) + /// // let results = try await sampledPipeline.execute() + /// ``` + /// + /// - Parameter count: The target number of documents to sample (a `Int64` value). + /// - Returns: A new `Pipeline` object with this stage appended. + public func sample(count: Int64) -> Pipeline { + return Pipeline(stages: stages + [Sample(count: count)], db: db) + } + + /// Performs pseudo-random sampling of input documents, returning a percentage. + /// + /// Filters documents pseudo-randomly. `percentage` (0.0 to 1.0) specifies + /// the approximate fraction of documents to return from the input set. + /// + /// ```swift + /// // let pipeline: Pipeline = ... // Assume initial pipeline. + /// // Sample 50% of books. + /// let sampledPipeline = pipeline.sample(percentage: 0.5) + /// // let results = try await sampledPipeline.execute() + /// ``` + /// + /// - Parameter percentage: The percentage of documents to sample (e.g., 0.5 for 50%; a `Double` + /// value). + /// - Returns: A new `Pipeline` object with this stage appended. + public func sample(percentage: Double) -> Pipeline { + return Pipeline(stages: stages + [Sample(percentage: percentage)], db: db) + } + + /// Performs a union of all documents from this pipeline and another, including duplicates. + /// + /// Passes through documents from this pipeline's previous stage and also those from + /// the `other` pipeline's previous stage. The order of emitted documents is undefined. + /// Both pipelines should ideally have compatible document structures. + /// + /// ```swift + /// // let db: Firestore = ... + /// // let booksPipeline = db.collection("books").pipeline().select("title", "category") + /// // let magazinesPipeline = db.collection("magazines").pipeline().select("title", + /// Field("topic").as("category")) + /// + /// // Emit documents from both "books" and "magazines" collections. + /// let combinedPipeline = booksPipeline.union(magazinesPipeline) + /// // let results = try await combinedPipeline.execute() + /// ``` + /// + /// - Parameter other: The other `Pipeline` whose documents will be unioned. + /// - Returns: A new `Pipeline` object with this stage appended. + public func union(_ other: Pipeline) -> Pipeline { + return Pipeline(stages: stages + [Union(other: other)], db: db) + } + + /// Takes an array field from input documents and outputs a new document for each element. + /// + /// For each input document, this stage emits zero or more augmented documents based on + /// an array field specified by `field` (a `Selectable`). The `Selectable` for `field` + /// **must** have an alias; this alias becomes the field name in the output document + /// containing the unnested element. + /// + /// The original field containing the array is effectively replaced by the array element + /// under the new alias name in each output document. Other fields from the original document + /// are typically preserved. + /// + /// If `indexField` is provided, a new field with this name is added, containing the + /// zero-based index of the element within its original array. + /// + /// Behavior for non-array values or empty arrays depends on the backend. + /// + /// ```swift + /// // Assume input document: + /// // { "title": "The Hitchhiker's Guide", "authors": ["Douglas Adams", "Eoin Colfer"] } + /// // let pipeline: Pipeline = ... + /// + /// // Unnest 'authors'. Each author becomes a new document with the author in a "authorName" + /// field. + /// let unnestedPipeline = pipeline.unnest(Field("authors").as("authorName"), indexField: + /// "authorIndex") + /// + /// // let results = try await unnestedPipeline.execute() + /// // Possible Output (other fields like "title" are preserved): + /// // { "title": "The Hitchhiker's Guide", "authorName": "Douglas Adams", "authorIndex": 0 } + /// // { "title": "The Hitchhiker's Guide", "authorName": "Eoin Colfer", "authorIndex": 1 } + /// ``` + /// + /// - Parameters: + /// - field: A `Selectable` resolving to an array field. **Must include an alias** + /// (e.g., `Field("myArray").as("arrayElement")`) to name the output field. + /// - indexField: Optional. If provided, this string names a new field for the element's + /// zero-based index from the original array. + /// - Returns: A new `Pipeline` object with this stage appended. + public func unnest(_ field: Selectable, indexField: String? = nil) -> Pipeline { + return Pipeline(stages: stages + [Unnest(field: field, indexField: indexField)], db: db) + } + + /// Adds a generic stage to the pipeline by specifying its name and parameters. + /// + /// Use this to call backend-supported stages not yet strongly-typed in the SDK. + /// This method does not offer compile-time type safety for stage parameters; + /// the caller must ensure correct name, order, and types. + /// + /// Parameters in `params` and `options` are typically primitive types, `Field`, + /// `Function`, `Expr`, or arrays/dictionaries thereof. + /// + /// ```swift + /// // let pipeline: Pipeline = ... + /// // Example: Assuming a hypothetical backend stage "customFilterV2". + /// let genericPipeline = pipeline.genericStage( + /// name: "customFilterV2", + /// params: [Field("userScore"), 80], // Ordered parameters. + /// options: ["mode": "strict", "logLevel": 2] // Optional named parameters. + /// ) + /// // let results = try await genericPipeline.execute() + /// ``` + /// + /// - Parameters: + /// - name: The unique name of the stage (as recognized by the backend). + /// - params: An array of ordered, `Sendable` parameters for the stage. + /// - options: Optional dictionary of named, `Sendable` parameters. + /// - Returns: A new `Pipeline` object with this stage appended. + public func genericStage(name: String, params: [Sendable], + options: [String: Sendable]? = nil) -> Pipeline { + return Pipeline( + stages: stages + [GenericStage(name: name, params: params, options: options)], + db: db + ) + } +} diff --git a/Firestore/Swift/Source/SwiftAPI/Pipeline/PipelineResult.swift b/Firestore/Swift/Source/SwiftAPI/Pipeline/PipelineResult.swift new file mode 100644 index 00000000000..6e1d892f3cb --- /dev/null +++ b/Firestore/Swift/Source/SwiftAPI/Pipeline/PipelineResult.swift @@ -0,0 +1,70 @@ +// Copyright 2025 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 struct PipelineResult: @unchecked Sendable { + let bridge: __PipelineResultBridge + + init(_ bridge: __PipelineResultBridge) { + self.bridge = bridge + ref = self.bridge.reference + id = self.bridge.documentID + data = self.bridge.data() + createTime = self.bridge.create_time + updateTime = self.bridge.update_time + } + + /// The reference of the document, if the query returns the `__name__` field. + public let ref: DocumentReference? + + /// The ID of the document for which this `PipelineResult` contains data, if available. + public let id: String? + + /// The time the document was created, if available. + public let createTime: Timestamp? + + /// The time the document was last updated when the snapshot was generated. + public let updateTime: Timestamp? + + /// Retrieves all fields in the result as a dictionary. + public let data: [String: Sendable] + + /// Retrieves the field specified by `fieldPath`. + /// - Parameter fieldPath: The field path (e.g., "foo" or "foo.bar"). + /// - Returns: The data at the specified field location or `nil` if no such field exists. + public func get(_ fieldName: String) -> Sendable? { + return bridge.get(fieldName) + } + + /// Retrieves the field specified by `fieldPath`. + /// - Parameter fieldPath: The field path (e.g., "foo" or "foo.bar"). + /// - Returns: The data at the specified field location or `nil` if no such field exists. + public func get(_ fieldPath: FieldPath) -> Sendable? { + return bridge.get(fieldPath) + } + + /// Retrieves the field specified by `fieldPath`. + /// - Parameter fieldPath: The field path (e.g., "foo" or "foo.bar"). + /// - Returns: The data at the specified field location or `nil` if no such field exists. + public func get(_ field: Field) -> Sendable? { + return bridge.get(field.fieldName) + } +} diff --git a/Firestore/Swift/Source/SwiftAPI/Pipeline/PipelineSnapshot.swift b/Firestore/Swift/Source/SwiftAPI/Pipeline/PipelineSnapshot.swift new file mode 100644 index 00000000000..e25191b8ad2 --- /dev/null +++ b/Firestore/Swift/Source/SwiftAPI/Pipeline/PipelineSnapshot.swift @@ -0,0 +1,45 @@ +// Copyright 2025 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 struct PipelineSnapshot: Sendable { + /// The Pipeline on which `execute()` was called to obtain this `PipelineSnapshot`. + public let pipeline: Pipeline + + /// An array of all the results in the `PipelineSnapshot`. + let results_cache: [PipelineResult] + + /// The time at which the pipeline producing this result was executed. + public let executionTime: Timestamp + + let bridge: __PipelineSnapshotBridge + + init(_ bridge: __PipelineSnapshotBridge, pipeline: Pipeline) { + self.bridge = bridge + self.pipeline = pipeline + executionTime = self.bridge.execution_time + results_cache = self.bridge.results.map { PipelineResult($0) } + } + + public func results() -> [PipelineResult] { + return results_cache + } +} diff --git a/Firestore/Swift/Source/SwiftAPI/Pipeline/PipelineSource.swift b/Firestore/Swift/Source/SwiftAPI/Pipeline/PipelineSource.swift new file mode 100644 index 00000000000..da0b5b5b1b4 --- /dev/null +++ b/Firestore/Swift/Source/SwiftAPI/Pipeline/PipelineSource.swift @@ -0,0 +1,56 @@ +// Copyright 2025 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. + +@available(iOS 13, tvOS 13, macOS 10.15, macCatalyst 13, watchOS 7, *) +public struct PipelineSource: @unchecked Sendable { + let db: Firestore + + init(_ db: Firestore) { + self.db = db + } + + public func collection(_ path: String) -> Pipeline { + let normalizedPath = path.hasPrefix("/") ? path : "/" + path + return Pipeline(stages: [CollectionSource(collection: normalizedPath)], db: db) + } + + public func collectionGroup(_ collectionId: String) -> Pipeline { + return Pipeline( + stages: [CollectionGroupSource(collectionId: collectionId)], + db: db + ) + } + + public func database() -> Pipeline { + return Pipeline(stages: [DatabaseSource()], db: db) + } + + public func documents(_ docs: [DocumentReference]) -> Pipeline { + let paths = docs.map { $0.path.hasPrefix("/") ? $0.path : "/" + $0.path } + return Pipeline(stages: [DocumentsSource(paths: paths)], db: db) + } + + public func documents(_ paths: [String]) -> Pipeline { + let normalizedPaths = paths.map { $0.hasPrefix("/") ? $0 : "/" + $0 } + return Pipeline(stages: [DocumentsSource(paths: normalizedPaths)], db: db) + } + + public func create(from query: Query) -> Pipeline { + return Pipeline(stages: [QuerySource(query: query)], db: db) + } + + public func create(from aggregateQuery: AggregateQuery) -> Pipeline { + return Pipeline(stages: [AggregateQuerySource(aggregateQuery: aggregateQuery)], db: db) + } +} diff --git a/Firestore/Swift/Source/SwiftAPI/Pipeline/RealtimePipeline.swift b/Firestore/Swift/Source/SwiftAPI/Pipeline/RealtimePipeline.swift new file mode 100644 index 00000000000..de1a709d44d --- /dev/null +++ b/Firestore/Swift/Source/SwiftAPI/Pipeline/RealtimePipeline.swift @@ -0,0 +1,15 @@ +// Copyright 2025 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. + +public struct RealtimePipeline: @unchecked Sendable {} diff --git a/Firestore/Swift/Source/SwiftAPI/Pipeline/Selectable.swift b/Firestore/Swift/Source/SwiftAPI/Pipeline/Selectable.swift new file mode 100644 index 00000000000..a9c655f4e6a --- /dev/null +++ b/Firestore/Swift/Source/SwiftAPI/Pipeline/Selectable.swift @@ -0,0 +1,15 @@ +// Copyright 2025 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. + +public protocol Selectable: Sendable {} diff --git a/Firestore/Swift/Source/SwiftAPI/Pipeline/TimeUnit.swift b/Firestore/Swift/Source/SwiftAPI/Pipeline/TimeUnit.swift new file mode 100644 index 00000000000..0b8aa112db8 --- /dev/null +++ b/Firestore/Swift/Source/SwiftAPI/Pipeline/TimeUnit.swift @@ -0,0 +1,37 @@ +// Copyright 2025 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. + +public struct TimeUnit: Sendable, Equatable, Hashable { + enum Kind: String { + case microsecond + case millisecond + case second + case minute + case hour + case day + } + + public static let microsecond = TimeUnit(kind: .microsecond) + public static let millisecond = TimeUnit(kind: .millisecond) + public static let second = TimeUnit(kind: .second) + public static let minute = TimeUnit(kind: .minute) + public static let hour = TimeUnit(kind: .hour) + public static let day = TimeUnit(kind: .day) + + public let rawValue: String + + init(kind: Kind) { + rawValue = kind.rawValue + } +} diff --git a/Firestore/Swift/Source/SwiftAPI/PipelineSnapshot.swift b/Firestore/Swift/Source/SwiftAPI/PipelineSnapshot.swift deleted file mode 100644 index 00386d0c6dc..00000000000 --- a/Firestore/Swift/Source/SwiftAPI/PipelineSnapshot.swift +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright 2025 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 - -public struct PipelineSnapshot { - private let bridge: __PipelineSnapshotBridge - - init(_ bridge: __PipelineSnapshotBridge) { - self.bridge = bridge - } -} diff --git a/Firestore/Swift/Source/SwiftAPI/PipelineSource.swift b/Firestore/Swift/Source/SwiftAPI/PipelineSource.swift deleted file mode 100644 index ce84c0356ac..00000000000 --- a/Firestore/Swift/Source/SwiftAPI/PipelineSource.swift +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright 2025 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 - -public class PipelineSource { - private let db: Firestore - public init(db: Firestore) { - self.db = db - } - - public func collection(path: String) -> Pipeline { - return Pipeline(stages: [CollectionSource(collection: path)], db: db) - } -} diff --git a/Firestore/Swift/Source/SwiftAPI/Stages.swift b/Firestore/Swift/Source/SwiftAPI/Stages.swift index c5de0c00e52..65796af8471 100644 --- a/Firestore/Swift/Source/SwiftAPI/Stages.swift +++ b/Firestore/Swift/Source/SwiftAPI/Stages.swift @@ -14,18 +14,25 @@ * limitations under the License. */ -import FirebaseFirestoreInternal import Foundation +#if SWIFT_PACKAGE + @_exported import FirebaseFirestoreInternalWrapper +#else + @_exported import FirebaseFirestoreInternal +#endif // SWIFT_PACKAGE + +@available(iOS 13, tvOS 13, macOS 10.15, macCatalyst 13, watchOS 7, *) protocol Stage { var name: String { get } var bridge: StageBridge { get } } +@available(iOS 13, tvOS 13, macOS 10.15, macCatalyst 13, watchOS 7, *) class CollectionSource: Stage { - var name: String = "collection" + let name: String = "collection" - var bridge: StageBridge + let bridge: StageBridge private var collection: String init(collection: String) { @@ -34,14 +41,314 @@ class CollectionSource: Stage { } } +@available(iOS 13, tvOS 13, macOS 10.15, macCatalyst 13, watchOS 7, *) +class CollectionGroupSource: Stage { + let name: String = "collectionId" + + let bridge: StageBridge + private var collectionId: String + + init(collectionId: String) { + self.collectionId = collectionId + bridge = CollectionGroupSourceStageBridge(collectionId: collectionId) + } +} + +// Represents the entire database as a source. +@available(iOS 13, tvOS 13, macOS 10.15, macCatalyst 13, watchOS 7, *) +class DatabaseSource: Stage { + let name: String = "database" + let bridge: StageBridge + + init() { + bridge = DatabaseSourceStageBridge() + } +} + +// Represents a list of document references as a source. +@available(iOS 13, tvOS 13, macOS 10.15, macCatalyst 13, watchOS 7, *) +class DocumentsSource: Stage { + let name: String = "documents" + let bridge: StageBridge + private var references: [String] + + // Initialize with an array of String paths + init(paths: [String]) { + references = paths + bridge = DocumentsSourceStageBridge(documents: paths) + } +} + +// Represents an existing Query as a source. +@available(iOS 13, tvOS 13, macOS 10.15, macCatalyst 13, watchOS 7, *) +class QuerySource: Stage { + let name: String = "query" + let bridge: StageBridge + private var query: Query + + init(query: Query) { + self.query = query + bridge = DatabaseSourceStageBridge() + // TODO: bridge = QuerySourceStageBridge(query: query.query) + } +} + +// Represents an existing AggregateQuery as a source. +@available(iOS 13, tvOS 13, macOS 10.15, macCatalyst 13, watchOS 7, *) +class AggregateQuerySource: Stage { + let name: String = "aggregateQuery" + let bridge: StageBridge + private var aggregateQuery: AggregateQuery + + init(aggregateQuery: AggregateQuery) { + self.aggregateQuery = aggregateQuery + bridge = DatabaseSourceStageBridge() + // TODO: bridge = AggregateQuerySourceStageBridge(aggregateQuery: aggregateQuery.query) + } +} + +@available(iOS 13, tvOS 13, macOS 10.15, macCatalyst 13, watchOS 7, *) class Where: Stage { - var name: String = "where" + let name: String = "where" - var bridge: StageBridge - private var condition: Expr // TODO: should be FilterCondition + let bridge: StageBridge + private var condition: BooleanExpr - init(condition: Expr) { + init(condition: BooleanExpr) { self.condition = condition - bridge = WhereStageBridge(expr: (condition as! (Expr & BridgeWrapper)).bridge) + bridge = WhereStageBridge(expr: condition.toBridge()) + } +} + +@available(iOS 13, tvOS 13, macOS 10.15, macCatalyst 13, watchOS 7, *) +class Limit: Stage { + let name: String = "limit" + + let bridge: StageBridge + private var limit: Int32 + + init(_ limit: Int32) { + self.limit = limit + bridge = LimitStageBridge(limit: NSInteger(limit)) + } +} + +@available(iOS 13, tvOS 13, macOS 10.15, macCatalyst 13, watchOS 7, *) +class Offset: Stage { + let name: String = "offset" + + let bridge: StageBridge + private var offset: Int32 + + init(_ offset: Int32) { + self.offset = offset + bridge = OffsetStageBridge(offset: NSInteger(offset)) + } +} + +@available(iOS 13, tvOS 13, macOS 10.15, macCatalyst 13, watchOS 7, *) +class AddFields: Stage { + let name: String = "addFields" + let bridge: StageBridge + private var fields: [Selectable] + + init(fields: [Selectable]) { + self.fields = fields + let objc_accumulators = fields.reduce(into: [String: ExprBridge]()) { + result, + field + in + let seletable = field as! SelectableWrapper + result[seletable.alias] = seletable.expr.toBridge() + } + bridge = AddFieldsStageBridge(fields: objc_accumulators) + } +} + +@available(iOS 13, tvOS 13, macOS 10.15, macCatalyst 13, watchOS 7, *) +class RemoveFieldsStage: Stage { + let name: String = "removeFields" + let bridge: StageBridge + private var fields: [String] + + init(fields: [String]) { + self.fields = fields + bridge = RemoveFieldsStageBridge(fields: fields) + } + + init(fields: [Field]) { + self.fields = fields.map { $0.fieldName } + bridge = RemoveFieldsStageBridge(fields: self.fields) + } +} + +@available(iOS 13, tvOS 13, macOS 10.15, macCatalyst 13, watchOS 7, *) +class Select: Stage { + let name: String = "select" + let bridge: StageBridge + private var selections: [Selectable] + + init(selections: [Selectable]) { + self.selections = selections + let map = Helper.selectablesToMap(selectables: selections) + bridge = SelectStageBridge(selections: map + .mapValues { Helper.sendableToExpr($0).toBridge() }) + } +} + +@available(iOS 13, tvOS 13, macOS 10.15, macCatalyst 13, watchOS 7, *) +class Distinct: Stage { + let name: String = "distinct" + let bridge: StageBridge + private var groups: [Selectable] + + init(groups: [Selectable]) { + self.groups = groups + let map = Helper.selectablesToMap(selectables: groups) + bridge = DistinctStageBridge(groups: map + .mapValues { Helper.sendableToExpr($0).toBridge() }) + } +} + +@available(iOS 13, tvOS 13, macOS 10.15, macCatalyst 13, watchOS 7, *) +class Aggregate: Stage { + let name: String = "aggregate" + let bridge: StageBridge + private var accumulators: [AggregateWithAlias] + private var groups: [String: Expr] = [:] + + init(accumulators: [AggregateWithAlias], groups: [Selectable]?) { + self.accumulators = accumulators + if groups != nil { + self.groups = Helper.selectablesToMap(selectables: groups!) + } + let map = accumulators + .reduce(into: [String: AggregateFunctionBridge]()) { result, accumulator in + result[accumulator.alias] = accumulator.aggregate.bridge + } + bridge = AggregateStageBridge( + accumulators: map, + groups: self.groups.mapValues { Helper.sendableToExpr($0).toBridge() } + ) + } +} + +@available(iOS 13, tvOS 13, macOS 10.15, macCatalyst 13, watchOS 7, *) +class FindNearest: Stage { + let name: String = "findNearest" + let bridge: StageBridge + private var field: Field + private var vectorValue: [Double] + private var distanceMeasure: DistanceMeasure + private var limit: Int? + private var distanceField: String? + + init(field: Field, + vectorValue: [Double], + distanceMeasure: DistanceMeasure, + limit: Int? = nil, + distanceField: String? = nil) { + self.field = field + self.vectorValue = vectorValue + self.distanceMeasure = distanceMeasure + self.limit = limit + self.distanceField = distanceField + bridge = FindNearestStageBridge( + field: field.bridge as! FieldBridge, + vectorValue: VectorValue(vectorValue), + distanceMeasure: distanceMeasure.kind.rawValue, + limit: limit as NSNumber?, + distanceField: distanceField + ) + } +} + +@available(iOS 13, tvOS 13, macOS 10.15, macCatalyst 13, watchOS 7, *) +class Sort: Stage { + let name: String = "sort" + let bridge: StageBridge + private var orderings: [Ordering] + + init(orderings: [Ordering]) { + self.orderings = orderings + bridge = SortStageBridge(orderings: orderings.map { $0.bridge }) + } +} + +@available(iOS 13, tvOS 13, macOS 10.15, macCatalyst 13, watchOS 7, *) +class ReplaceWith: Stage { + let name: String = "replaceWith" + let bridge: StageBridge + private var expr: Expr + + init(expr: Expr) { + self.expr = expr + bridge = ReplaceWithStageBridge(expr: expr.toBridge()) + } +} + +@available(iOS 13, tvOS 13, macOS 10.15, macCatalyst 13, watchOS 7, *) +class Sample: Stage { + let name: String = "sample" + let bridge: StageBridge + private var count: Int64? + private var percentage: Double? + + init(count: Int64) { + self.count = count + percentage = nil + bridge = SampleStageBridge(count: count) + } + + init(percentage: Double) { + self.percentage = percentage + count = nil + bridge = SampleStageBridge(percentage: percentage) + } +} + +@available(iOS 13, tvOS 13, macOS 10.15, macCatalyst 13, watchOS 7, *) +class Union: Stage { + let name: String = "union" + let bridge: StageBridge + private var other: Pipeline + + init(other: Pipeline) { + self.other = other + bridge = UnionStageBridge(other: other.bridge) + } +} + +@available(iOS 13, tvOS 13, macOS 10.15, macCatalyst 13, watchOS 7, *) +class Unnest: Stage { + let name: String = "unnest" + let bridge: StageBridge + private var field: Selectable + private var indexField: String? + + init(field: Selectable, indexField: String? = nil) { + self.field = field + self.indexField = indexField + bridge = UnnestStageBridge( + field: Helper.sendableToExpr(field).toBridge(), + indexField: indexField + ) + } +} + +@available(iOS 13, tvOS 13, macOS 10.15, macCatalyst 13, watchOS 7, *) +class GenericStage: Stage { + let name: String + let bridge: StageBridge + private var params: [Sendable] + private var options: [String: Sendable]? + + init(name: String, params: [Sendable], options: [String: Sendable]? = nil) { + self.name = name + self.params = params + self.options = options + let bridgeParams = params.map { Helper.sendableToExpr($0).toBridge() } + let bridgeOptions = options?.mapValues { Helper.sendableToExpr($0).toBridge() } + bridge = GenericStageBridge(name: name, params: bridgeParams, options: bridgeOptions) } } diff --git a/Firestore/Swift/Tests/Integration/PipelineApiTests.swift b/Firestore/Swift/Tests/Integration/PipelineApiTests.swift new file mode 100644 index 00000000000..25ca1f09a6d --- /dev/null +++ b/Firestore/Swift/Tests/Integration/PipelineApiTests.swift @@ -0,0 +1,404 @@ +// Copyright 2025 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 +import XCTest + +import FirebaseFirestore + +final class PipelineTests: FSTIntegrationTestCase { + override func setUp() { + FSTIntegrationTestCase.switchToEnterpriseMode() + super.setUp() + } + + func testCreatePipeline() async throws { + let pipelineSource: PipelineSource = db.pipeline() + + let pipeline: Pipeline = pipelineSource.documents( + [db.collection("foo").document("bar"), db.document("foo/baz")] + ) + let _: Pipeline = pipelineSource.collection("foo") + let _: Pipeline = pipelineSource.collectionGroup("foo") + let _: Pipeline = pipelineSource.database() + + let query: Query = db.collection("foo").limit(to: 2) + let _: Pipeline = pipelineSource.create(from: query) + + let aggregateQuery = db.collection("foo").count + let _: Pipeline = pipelineSource.create(from: aggregateQuery) + + let _: PipelineSnapshot = try await pipeline.execute() + } + + func testWhereStage() async throws { + _ = db.pipeline().collection("books") + .where( + Field("rating").gt(4.0) && Field("genre").eq("Science Fiction") || ArrayContains( + fieldName: "fieldName", + values: "rating" + ) + ) + } + + func testAddFieldStage() async throws { + // Input + // { title: 'title1', price: 10, discount: 0.8 }, + // { title: 'title2', price: 12, discount: 1.0 }, + // { title: 'title3', price: 5, discount: 0.66 } + + // An expression that will compute price from the value of msrp field and discount field + let priceExpr: FunctionExpr = Field("msrp").multiply(Field("discount")) + + // An expression becomes a Selectable when given an alias. In this case + // the alias is 'salePrice' + let priceSelectableExpr: Selectable = priceExpr.as("salePrice") + + _ = db.pipeline().collection("books") + .addFields( + priceSelectableExpr // Add field `salePrice` based computed from msrp and discount + ) + + // We don't expect customers to separate the Expression definition from the + // Pipeline definition. This was shown above so readers of this doc can see + // the different types involved. The cleaner way to write the code above + // is to inline the Expr definition + _ = db.pipeline().collection("books") + .addFields( + Field("msrp").multiply(Field("discount")).as("salePrice"), + Field("author") + ) + + // Output + // { title: 'title1', price: 10, discount: 0.8, salePrice: 8.0}, + // { title: 'title2', price: 12, discount: 1.0, salePrice: 12.0 }, + // { title: 'title3', price: 5, discount: 0.66, salePrice: 3.30 } + } + + func testRemoveFieldsStage() async throws { + // removes field 'rating' and 'cost' from the previous stage outputs. + _ = db.pipeline().collection("books").removeFields("rating", "cost") + + // removes field 'rating'. + _ = db.pipeline().collection("books").removeFields(Field("rating")) + } + + func testSelectStage() async throws { + // Input + // { title: 'title1', price: 10, discount: 0.8 }, + // { title: 'title2', price: 12, discount: 1.0 }, + // { title: 'title3', price: 5, discount: 0.66 } + + // Overload for string and Selectable + _ = db.pipeline().collection("books") + .select( + Field("title"), // Field class inheritates Selectable + Field("msrp").multiply(Field("discount")).as("salePrice") + ) + + _ = db.pipeline().collection("books").select("title", "author") + + // Output + // { title: 'title1', salePrice: 8.0}, + // { title: 'title2', salePrice: 12.0 }, + // { title: 'title3', salePrice: 3.30 } + } + + func testSortStage() async throws { + // Sort books by rating in descending order, and then by title in ascending order for books + // with the same rating + _ = db.pipeline().collection("books") + .sort( + Field("rating").descending(), + Ascending("title") // alternative API offered + ) + } + + func testLimitStage() async throws { + // Limit the results to the top 10 highest-rated books + _ = db.pipeline().collection("books") + .sort(Field("rating").descending()) + .limit(10) + } + + func testOffsetStage() async throws { + // Retrieve the second page of 20 results + _ = db.pipeline().collection("books") + .sort(Field("published").descending()) + .offset(20) // Skip the first 20 results. Note that this must come + // before .limit(...) unlike in Query where the order did not matter. + .limit(20) // Take the next 20 results + } + + func testDistinctStage() async throws { + // Input + // { author: 'authorA', genre: 'genreA', title: 'title1' }, + // { author: 'authorb', genre: 'genreB', title: 'title2' }, + // { author: 'authorB', genre: 'genreB', title: 'title3' } + + // Get a list of unique author names in uppercase and genre combinations. + _ = db.pipeline().collection("books") + .distinct( + Field("author").uppercased().as("authorName"), + Field("genre") + ) + + // Output + // { authorName: 'AUTHORA', genre: 'genreA' }, + // { authorName: 'AUTHORB', genre: 'genreB' } + } + + func testAggregateStage() async throws { + // Input + // { genre: 'genreA', title: 'title1', rating: 5.0 }, + // { genre: 'genreB', title: 'title2', rating: 1.5 }, + // { genre: 'genreB', title: 'title3', rating: 2.5 } + + // Calculate the average rating and the total number of books + _ = db.pipeline().collection("books") + .aggregate( + Field("rating").avg().as("averageRating"), + CountAll().as("totalBooks") + ) + + // Output + // { totalBooks: 3, averageRating: 3.0 } + + // Input + // { genre: 'genreA', title: 'title1', rating: 5.0 }, + // { genre: 'genreB', title: 'title2', rating: 1.5 }, + // { genre: 'genreB', title: 'title3', rating: 2.5 } + + // Calculate the average rating and the total number of books and group by field 'genre' + _ = db.pipeline().collection("books") + .aggregate([ + Field("rating").avg().as("averageRating"), + CountAll().as("totalBooks"), + ], + groups: ["genre"]) + + // Output + // { genre: 'genreA', totalBooks: 1, averageRating: 5.0 } + // { genre: 'genreB', totalBooks: 2, averageRating: 2.0 } + } + + func testFindNearestStage() async throws { + _ = db.pipeline().collection("books").findNearest( + field: Field("embedding"), + vectorValue: [5.0], + distanceMeasure: .cosine, + limit: 3) + } + + func testReplaceStage() async throws { + // Input. + // { +// "name": "John Doe Jr.", +// "parents": { +// "father": "John Doe Sr.", +// "mother": "Jane Doe" +// } + // } + + // Emit field parents as the document. + _ = db.pipeline().collection("people") + .replace(with: Field("parents")) + + // Output + // { +// "father": "John Doe Sr.", +// "mother": "Jane Doe" + // } + } + + func testSampleStage() async throws { + // Sample 25 books, if the collection contains at least 25 documents + _ = db.pipeline().collection("books").sample(count: 10) + + // Sample 10 percent of the collection of books + _ = db.pipeline().collection("books").sample(percentage: 10) + } + + func testUnionStage() async throws { + // Emit documents from books collection and magazines collection. + _ = db.pipeline().collection("books") + .union(db.pipeline().collection("magazines")) + } + + func testUnnestStage() async throws { + // Input: + // { "title": "The Hitchhiker's Guide to the Galaxy", "tags": [ "comedy", "space", "adventure" + // ], ... } + + // Emit a book document for each tag of the book. + _ = db.pipeline().collection("books") + .unnest(Field("tags").as("tag")) + + // Output: + // { "title": "The Hitchhiker's Guide to the Galaxy", "tag": "comedy", tags: [...], ... } + // { "title": "The Hitchhiker's Guide to the Galaxy", "tag": "space", tags: [...], ... } + // { "title": "The Hitchhiker's Guide to the Galaxy", "tag": "adventure", tags: [...], ... } + + // Emit a book document for each tag of the book mapped to its' index in the array. + _ = db.pipeline().collection("books") + .unnest(Field("tags").as("tag"), indexField: "index") + + // Output: + // { "title": "The Hitchhiker's Guide to the Galaxy", "tag": "comedy", index: 0, tags: [...], + // ... } + // { "title": "The Hitchhiker's Guide to the Galaxy", "tag": "space", index: 1, tags: [...], ... + // } + // { "title": "The Hitchhiker's Guide to the Galaxy", "tag": "adventure", index: 2, tags: [...], + // ... } + } + + func testGenericStage() async throws { + // Assume we don't have a built-in "where" stage, the customer could still + // add this stage by calling genericStage, passing the name of the stage "where", + // and providing positional argument values. + _ = db.pipeline().collection("books") + .genericStage(name: "where", + params: [Field("published").lt(1900)]) + .select("title", "author") + + // In cases where the stage also supports named argument values, then these can be + // provided with a third argument that maps the argument name to value. + // Note that these named arguments are always optional in the stage definition. + _ = db.pipeline().collection("books") + .genericStage(name: "where", + params: [Field("published").lt(1900)], + options: ["someOptionalParamName": "the argument value for this param"]) + .select("title", "author") + } + + func testField() async throws { + // An expression that will return the value of the field `name` in the document + let nameField = Field("name") + + // An expression that will return the value of the field `description` in the document + // Field is a sub-type of Expr, so we can also declare our var of type Expr + let descriptionField: Expr = Field("description") + + // USAGE: anywhere an Expr type is accepted + // Use a field in a pipeline + _ = db.pipeline().collection("books") + .addFields( + Field("rating").as("bookRating") // Duplicate field 'rating' as 'bookRating' + ) + + // One special Field value is conveniently exposed as static function to help the user reference + // reserved field values of __name__. + _ = db.pipeline().collection("books") + .addFields( + DocumentId() + ) + } + + func testConstant() async throws { + // A constant for a number + let three = Constant(3) + + // A constant for a string + let name = Constant("Expressions API") + + // Const is a sub-type of Expr, so we can also declare our var of type Expr + let nothing: Expr = Constant.nil + + // USAGE: Anywhere an Expr type is accepted + // Add field `fromTheLibraryOf: 'Rafi'` to every document in the collection. + _ = db.pipeline().collection("books") + .addFields(Constant("Rafi").as("fromTheLibraryOf")) + } + + func testFunctionExpr() async throws { + let secondsField = Field("seconds") + + // Create a FunctionExpr using the multiply function to compute milliseconds + let milliseconds: FunctionExpr = secondsField.multiply(1000) + + // A firestore function is also a sub-type of Expr + let myExpr: Expr = milliseconds + } + + func testBooleanExpr() async throws { + let isApple: BooleanExpr = Field("type").eq("apple") + + // USAGE: stage where requires an expression of type BooleanExpr + let allAppleOptions: Pipeline = db.pipeline().collection("fruitOptions").where(isApple) + } + + func testSelectableExpr() async throws { + let secondsField = Field("seconds") + + // Create a selectable from our milliseconds expression. + let millisecondsSelectable: Selectable = secondsField.multiply(1000).as("milliseconds") + + // USAGE: stages addFields and select accept expressions of type Selectable + // Add (or overwrite) the 'milliseconds` field to each of our documents using the + // `.addFields(...)` stage. + _ = db.pipeline().collection("lapTimes") + .addFields(secondsField.multiply(1000).as("milliseconds")) + + // NOTE: Field implements Selectable, the alias is the same as the name + let secondsSelectable: Selectable = secondsField + } + + func testAggregateExpr() async throws { + let lapTimeSum: AggregateFunction = Field("seconds").sum() + + let lapTimeSumTarget: AggregateWithAlias = lapTimeSum.as("totalTrackTime") + + // USAGE: stage aggregate accepts expressions of type AggregateWithAlias + // A pipeline that will return one document with one field `totalTrackTime` that + // is the sum of all laps ever taken on the track. + _ = db.pipeline().collection("lapTimes") + .aggregate(lapTimeSum.as("totalTrackTime")) + } + + func testOrdering() async throws { + let fastestToSlowest: Ordering = Field("seconds").ascending() + + // USAGE: stage sort accepts objects of type Ordering + // Use this ordering to sort our lap times collection from fastest to slowest + _ = db.pipeline().collection("lapTimes").sort(fastestToSlowest) + } + + func testExpr() async throws { + // An expression that computes the area of a circle + // by chaining together two calls to the multiply function + let radiusField: Expr = Field("radius") + let radiusSq: Expr = radiusField.multiply(Field("radius")) + let areaExpr: Expr = radiusSq.multiply(3.14) + + // Or define this expression in one clean, fluent statement + let areaOfCircle: Selectable = Field("radius") + .multiply(Field("radius")) + .multiply(3.14) + .as("area") + + // And pass the expression to a Pipeline for evaluation + _ = db.pipeline().collection("circles").addFields(areaOfCircle) + } + + func testGeneric() async throws { + // This is the same of the logicalMin('price', 0)', if it did not exist + let myLm = FunctionExpr("logicalMin", [Field("price"), Constant(0)]) + + // Create a generic BooleanExpr for use where BooleanExpr is required + let myEq = BooleanExpr("eq", [Field("price"), Constant(10)]) + + // Create a generic AggregateFunction for use where AggregateFunction is required + let mySum = AggregateFunction("sum", [Field("price")]) + } +} diff --git a/Firestore/Swift/Tests/Integration/PipelineTests.swift b/Firestore/Swift/Tests/Integration/PipelineTests.swift index a2252488312..7bfdc8525a1 100644 --- a/Firestore/Swift/Tests/Integration/PipelineTests.swift +++ b/Firestore/Swift/Tests/Integration/PipelineTests.swift @@ -17,16 +17,152 @@ import FirebaseFirestore import Foundation +private let bookDocs: [String: [String: Any]] = [ + "book1": [ + "title": "The Hitchhiker's Guide to the Galaxy", + "author": "Douglas Adams", + "genre": "Science Fiction", + "published": 1979, + "rating": 4.2, + "tags": ["comedy", "space", "adventure"], // Array literal + "awards": ["hugo": true, "nebula": false], // Dictionary literal + "nestedField": ["level.1": ["level.2": true]], // Nested dictionary literal + ], + "book2": [ + "title": "Pride and Prejudice", + "author": "Jane Austen", + "genre": "Romance", + "published": 1813, + "rating": 4.5, + "tags": ["classic", "social commentary", "love"], + "awards": ["none": true], + ], + "book3": [ + "title": "One Hundred Years of Solitude", + "author": "Gabriel García Márquez", + "genre": "Magical Realism", + "published": 1967, + "rating": 4.3, + "tags": ["family", "history", "fantasy"], + "awards": ["nobel": true, "nebula": false], + ], + "book4": [ + "title": "The Lord of the Rings", + "author": "J.R.R. Tolkien", + "genre": "Fantasy", + "published": 1954, + "rating": 4.7, + "tags": ["adventure", "magic", "epic"], + "awards": ["hugo": false, "nebula": false], + ], + "book5": [ + "title": "The Handmaid's Tale", + "author": "Margaret Atwood", + "genre": "Dystopian", + "published": 1985, + "rating": 4.1, + "tags": ["feminism", "totalitarianism", "resistance"], + "awards": ["arthur c. clarke": true, "booker prize": false], + ], + "book6": [ + "title": "Crime and Punishment", + "author": "Fyodor Dostoevsky", + "genre": "Psychological Thriller", + "published": 1866, + "rating": 4.3, + "tags": ["philosophy", "crime", "redemption"], + "awards": ["none": true], + ], + "book7": [ + "title": "To Kill a Mockingbird", + "author": "Harper Lee", + "genre": "Southern Gothic", + "published": 1960, + "rating": 4.2, + "tags": ["racism", "injustice", "coming-of-age"], + "awards": ["pulitzer": true], + ], + "book8": [ + "title": "1984", + "author": "George Orwell", + "genre": "Dystopian", + "published": 1949, + "rating": 4.2, + "tags": ["surveillance", "totalitarianism", "propaganda"], + "awards": ["prometheus": true], + ], + "book9": [ + "title": "The Great Gatsby", + "author": "F. Scott Fitzgerald", + "genre": "Modernist", + "published": 1925, + "rating": 4.0, + "tags": ["wealth", "american dream", "love"], + "awards": ["none": true], + ], + "book10": [ + "title": "Dune", + "author": "Frank Herbert", + "genre": "Science Fiction", + "published": 1965, + "rating": 4.6, + "tags": ["politics", "desert", "ecology"], + "awards": ["hugo": true, "nebula": true], + ], +] + @available(iOS 13, tvOS 13, macOS 10.15, macCatalyst 13, watchOS 7, *) class PipelineIntegrationTests: FSTIntegrationTestCase { + override func setUp() { + FSTIntegrationTestCase.switchToEnterpriseMode() + super.setUp() + } + func testCount() async throws { try await firestore().collection("foo").document("bar").setData(["foo": "bar", "x": 42]) let snapshot = try await firestore() .pipeline() - .collection(path: "/foo") - .where(eq(field("foo"), constant("bar"))) + .collection("/foo") + .where(Field("foo").eq(Constant("bar"))) .execute() print(snapshot) } + + func testEmptyResults() async throws { + let collRef = collectionRef( + withDocuments: bookDocs + ) + let db = collRef.firestore + + let snapshot = try await db + .pipeline() + .collection(collRef.path) + .limit(0) + .execute() + + XCTAssertTrue(snapshot.results().isEmpty) + } + + func testFullResults() async throws { + let collRef = collectionRef( + withDocuments: bookDocs + ) + let db = collRef.firestore + + let snapshot = try await db + .pipeline() + .collection(collRef.path) + .execute() + + let results = snapshot.results() + XCTAssertEqual(results.count, 10) + + let actualIDs = Set(results.map { $0.id }) + let expectedIDs = Set([ + "book1", "book2", "book3", "book4", "book5", + "book6", "book7", "book8", "book9", "book10", + ]) + XCTAssertEqual(actualIDs, expectedIDs) + } } diff --git a/Firestore/core/src/api/aggregate_expressions.cc b/Firestore/core/src/api/aggregate_expressions.cc index 87fc69c368a..fb58918833c 100644 --- a/Firestore/core/src/api/aggregate_expressions.cc +++ b/Firestore/core/src/api/aggregate_expressions.cc @@ -22,7 +22,7 @@ namespace firebase { namespace firestore { namespace api { -google_firestore_v1_Value AggregateExpr::to_proto() const { +google_firestore_v1_Value AggregateFunction::to_proto() const { google_firestore_v1_Value result; result.which_value_type = google_firestore_v1_Value_function_value_tag; diff --git a/Firestore/core/src/api/aggregate_expressions.h b/Firestore/core/src/api/aggregate_expressions.h index 119198b2abd..fc19eacb0a5 100644 --- a/Firestore/core/src/api/aggregate_expressions.h +++ b/Firestore/core/src/api/aggregate_expressions.h @@ -29,12 +29,12 @@ namespace firebase { namespace firestore { namespace api { -class AggregateExpr { +class AggregateFunction { public: - AggregateExpr(std::string name, std::vector> params) + AggregateFunction(std::string name, std::vector> params) : name_(std::move(name)), params_(std::move(params)) { } - ~AggregateExpr() = default; + ~AggregateFunction() = default; google_firestore_v1_Value to_proto() const; diff --git a/Firestore/core/src/api/expressions.h b/Firestore/core/src/api/expressions.h index 5b08a277e3b..fe6f4fde9c8 100644 --- a/Firestore/core/src/api/expressions.h +++ b/Firestore/core/src/api/expressions.h @@ -36,18 +36,12 @@ class Expr { virtual google_firestore_v1_Value to_proto() const = 0; }; -class Selectable : public Expr { - public: - virtual ~Selectable() = default; - virtual const std::string& alias() const = 0; -}; - -class Field : public Selectable { +class Field : public Expr { public: explicit Field(std::string name) : name_(std::move(name)) { } google_firestore_v1_Value to_proto() const override; - const std::string& alias() const override { + const std::string& alias() const { return name_; } diff --git a/Firestore/core/src/api/ordering.cc b/Firestore/core/src/api/ordering.cc index 6520cea5b6f..388280b532a 100644 --- a/Firestore/core/src/api/ordering.cc +++ b/Firestore/core/src/api/ordering.cc @@ -31,7 +31,7 @@ google_firestore_v1_Value Ordering::to_proto() const { result.map_value.fields = nanopb::MakeArray(2); result.map_value.fields[0].key = nanopb::MakeBytesArray("expression"); - result.map_value.fields[0].value = field_.to_proto(); + result.map_value.fields[0].value = expr_->to_proto(); result.map_value.fields[1].key = nanopb::MakeBytesArray("direction"); google_firestore_v1_Value direction; direction.which_value_type = google_firestore_v1_Value_string_value_tag; diff --git a/Firestore/core/src/api/ordering.h b/Firestore/core/src/api/ordering.h index 130dda12b19..2e4709d2af0 100644 --- a/Firestore/core/src/api/ordering.h +++ b/Firestore/core/src/api/ordering.h @@ -17,16 +17,17 @@ #ifndef FIRESTORE_CORE_SRC_API_ORDERING_H_ #define FIRESTORE_CORE_SRC_API_ORDERING_H_ +#include +#include #include #include "Firestore/core/src/api/expressions.h" +#include "Firestore/core/src/util/exception.h" namespace firebase { namespace firestore { namespace api { -class UserDataReader; // forward declaration - class Ordering { public: enum Direction { @@ -34,14 +35,20 @@ class Ordering { DESCENDING, }; - Ordering(Field field, Direction direction) - : field_(std::move(field)), direction_(direction) { + static Direction DirectionFromString(const std::string& str) { + if (str == "ascending") return ASCENDING; + if (str == "descending") return DESCENDING; + util::ThrowInvalidArgument("Unknown direction: '%s' ", str); + } + + Ordering(std::shared_ptr expr, Direction direction) + : expr_(expr), direction_(direction) { } google_firestore_v1_Value to_proto() const; private: - Field field_; + std::shared_ptr expr_; Direction direction_; }; diff --git a/Firestore/core/src/api/pipeline.cc b/Firestore/core/src/api/pipeline.cc index 24c5109bd95..53d332f3259 100644 --- a/Firestore/core/src/api/pipeline.cc +++ b/Firestore/core/src/api/pipeline.cc @@ -40,6 +40,20 @@ void Pipeline::execute(util::StatusOrCallback callback) { this->firestore_->RunPipeline(*this, std::move(callback)); } +google_firestore_v1_Value Pipeline::to_proto() const { + google_firestore_v1_Value result; + + result.which_value_type = google_firestore_v1_Value_pipeline_value_tag; + result.pipeline_value = google_firestore_v1_Pipeline{}; + result.pipeline_value.stages_count = this->stages_.size(); + nanopb::SetRepeatedField( + &result.pipeline_value.stages, &result.pipeline_value.stages_count, + stages_, + [](const std::shared_ptr& arg) { return arg->to_proto(); }); + + return result; +} + } // namespace api } // namespace firestore } // namespace firebase diff --git a/Firestore/core/src/api/pipeline.h b/Firestore/core/src/api/pipeline.h index 6103f366eda..edea35dce6d 100644 --- a/Firestore/core/src/api/pipeline.h +++ b/Firestore/core/src/api/pipeline.h @@ -47,6 +47,8 @@ class Pipeline { void execute(util::StatusOrCallback callback); + google_firestore_v1_Value to_proto() const; + private: std::vector> stages_; std::shared_ptr firestore_; diff --git a/Firestore/core/src/api/pipeline_result.h b/Firestore/core/src/api/pipeline_result.h index 53761752cdc..662ea721c6b 100644 --- a/Firestore/core/src/api/pipeline_result.h +++ b/Firestore/core/src/api/pipeline_result.h @@ -53,6 +53,14 @@ class PipelineResult { std::shared_ptr internal_value() const; absl::optional document_id() const; + absl::optional create_time() const { + return create_time_; + } + + absl::optional update_time() const { + return update_time_; + } + const absl::optional& internal_key() const { return internal_key_; } diff --git a/Firestore/core/src/api/pipeline_snapshot.h b/Firestore/core/src/api/pipeline_snapshot.h index 079f2d57375..2bb0a1e94d2 100644 --- a/Firestore/core/src/api/pipeline_snapshot.h +++ b/Firestore/core/src/api/pipeline_snapshot.h @@ -41,6 +41,10 @@ class PipelineSnapshot { return results_; } + model::SnapshotVersion execution_time() const { + return execution_time_; + } + const std::shared_ptr firestore() const { return firestore_; } diff --git a/Firestore/core/src/api/stages.cc b/Firestore/core/src/api/stages.cc index eaa19cb03bd..afa943c8cb0 100644 --- a/Firestore/core/src/api/stages.cc +++ b/Firestore/core/src/api/stages.cc @@ -20,6 +20,7 @@ #include #include "Firestore/Protos/nanopb/google/firestore/v1/document.nanopb.h" +#include "Firestore/core/src/api/pipeline.h" #include "Firestore/core/src/nanopb/message.h" #include "Firestore/core/src/nanopb/nanopb_util.h" @@ -88,8 +89,8 @@ google_firestore_v1_Pipeline_Stage DocumentsSource::to_proto() const { for (size_t i = 0; i < documents_.size(); ++i) { result.args[i].which_value_type = - google_firestore_v1_Value_string_value_tag; - result.args[i].string_value = nanopb::MakeBytesArray(documents_[i]); + google_firestore_v1_Value_reference_value_tag; + result.args[i].reference_value = nanopb::MakeBytesArray(documents_[i]); } result.options_count = 0; @@ -108,9 +109,9 @@ google_firestore_v1_Pipeline_Stage AddFields::to_proto() const { result.args[0].which_value_type = google_firestore_v1_Value_map_value_tag; nanopb::SetRepeatedField( &result.args[0].map_value.fields, &result.args[0].map_value.fields_count, - fields_, [](const std::shared_ptr& entry) { + fields_, [](const std::pair>& entry) { return _google_firestore_v1_MapValue_FieldsEntry{ - nanopb::MakeBytesArray(entry->alias()), entry->to_proto()}; + nanopb::MakeBytesArray(entry.first), entry.second->to_proto()}; }); result.options_count = 0; @@ -130,7 +131,8 @@ google_firestore_v1_Pipeline_Stage AggregateStage::to_proto() const { nanopb::SetRepeatedField( &result.args[0].map_value.fields, &result.args[0].map_value.fields_count, this->accumulators_, - [](const std::pair>& entry) { + [](const std::pair>& + entry) { return _google_firestore_v1_MapValue_FieldsEntry{ nanopb::MakeBytesArray(entry.first), entry.second->to_proto()}; }); @@ -242,9 +244,9 @@ google_firestore_v1_Pipeline_Stage SelectStage::to_proto() const { result.args[0].which_value_type = google_firestore_v1_Value_map_value_tag; nanopb::SetRepeatedField( &result.args[0].map_value.fields, &result.args[0].map_value.fields_count, - fields_, [](const std::shared_ptr& entry) { + fields_, [](const std::pair>& entry) { return _google_firestore_v1_MapValue_FieldsEntry{ - nanopb::MakeBytesArray(entry->alias()), entry->to_proto()}; + nanopb::MakeBytesArray(entry.first), entry.second->to_proto()}; }); result.options_count = 0; @@ -260,7 +262,7 @@ google_firestore_v1_Pipeline_Stage SortStage::to_proto() const { result.args = nanopb::MakeArray(result.args_count); for (size_t i = 0; i < orders_.size(); ++i) { - result.args[i] = orders_[i].to_proto(); + result.args[i] = orders_[i]->to_proto(); } result.options_count = 0; @@ -278,9 +280,9 @@ google_firestore_v1_Pipeline_Stage DistinctStage::to_proto() const { result.args[0].which_value_type = google_firestore_v1_Value_map_value_tag; nanopb::SetRepeatedField( &result.args[0].map_value.fields, &result.args[0].map_value.fields_count, - groups_, [](const std::shared_ptr& entry) { + groups_, [](const std::pair>& entry) { return _google_firestore_v1_MapValue_FieldsEntry{ - nanopb::MakeBytesArray(entry->alias()), entry->to_proto()}; + nanopb::MakeBytesArray(entry.first), entry.second->to_proto()}; }); result.options_count = 0; @@ -304,6 +306,123 @@ google_firestore_v1_Pipeline_Stage RemoveFieldsStage::to_proto() const { return result; } +google_firestore_v1_Pipeline_Stage ReplaceWith::to_proto() const { + google_firestore_v1_Pipeline_Stage result; + result.name = nanopb::MakeBytesArray("replace_with"); + + result.args_count = 1; + result.args = nanopb::MakeArray(1); + result.args[0] = expr_->to_proto(); + + result.options_count = 0; + result.options = nullptr; + return result; +} + +ReplaceWith::ReplaceWith(std::shared_ptr expr) : expr_(std::move(expr)) { +} + +Sample::Sample(std::string type, int64_t count, double percentage) + : type_(type), count_(count), percentage_(percentage) { +} + +google_firestore_v1_Pipeline_Stage Sample::to_proto() const { + google_firestore_v1_Pipeline_Stage result; + result.name = nanopb::MakeBytesArray("sample"); + + result.args_count = 1; + result.args = nanopb::MakeArray(1); + if (type_ == "count") { + result.args[0].which_value_type = + google_firestore_v1_Value_integer_value_tag; + result.args[0].integer_value = count_; + } else { + result.args[0].which_value_type = + google_firestore_v1_Value_double_value_tag; + result.args[0].double_value = percentage_; + } + + result.options_count = 0; + result.options = nullptr; + return result; +} + +Union::Union(std::shared_ptr other) : other_(std::move(other)) { +} + +google_firestore_v1_Pipeline_Stage Union::to_proto() const { + google_firestore_v1_Pipeline_Stage result; + result.name = nanopb::MakeBytesArray("union"); + + result.args_count = 1; + result.args = nanopb::MakeArray(1); + result.args[0] = other_->to_proto(); + + result.options_count = 0; + result.options = nullptr; + return result; +} + +Unnest::Unnest(std::shared_ptr field, + absl::optional index_field) + : field_(std::move(field)), index_field_(std::move(index_field)) { +} + +google_firestore_v1_Pipeline_Stage Unnest::to_proto() const { + google_firestore_v1_Pipeline_Stage result; + result.name = nanopb::MakeBytesArray("unnest"); + + result.args_count = 1; + result.args = nanopb::MakeArray(1); + result.args[0] = field_->to_proto(); + + if (index_field_.has_value()) { + result.options_count = 1; + result.options = + nanopb::MakeArray(1); + result.options[0].key = nanopb::MakeBytesArray("index_field"); + result.options[0].value.which_value_type = + google_firestore_v1_Value_string_value_tag; + result.options[0].value.string_value = + nanopb::MakeBytesArray(index_field_.value()); + } else { + result.options_count = 0; + result.options = nullptr; + } + + return result; +} + +GenericStage::GenericStage( + std::string name, + std::vector> params, + std::unordered_map> options) + : name_(std::move(name)), + params_(std::move(params)), + options_(std::move(options)) { +} + +google_firestore_v1_Pipeline_Stage GenericStage::to_proto() const { + google_firestore_v1_Pipeline_Stage result; + result.name = nanopb::MakeBytesArray(name_); + + result.args_count = static_cast(params_.size()); + result.args = nanopb::MakeArray(result.args_count); + + for (size_t i = 0; i < result.args_count; i++) { + result.args[i] = params_[i]->to_proto(); + } + + nanopb::SetRepeatedField( + &result.options, &result.options_count, options_, + [](const std::pair>& entry) { + return _google_firestore_v1_Pipeline_Stage_OptionsEntry{ + nanopb::MakeBytesArray(entry.first), entry.second->to_proto()}; + }); + + return result; +} + } // namespace api } // namespace firestore } // namespace firebase diff --git a/Firestore/core/src/api/stages.h b/Firestore/core/src/api/stages.h index 11534278002..a3c7303ae92 100644 --- a/Firestore/core/src/api/stages.h +++ b/Firestore/core/src/api/stages.h @@ -25,9 +25,11 @@ #include "Firestore/Protos/nanopb/google/firestore/v1/document.nanopb.h" #include "Firestore/core/src/api/aggregate_expressions.h" +#include "Firestore/core/src/api/api_fwd.h" #include "Firestore/core/src/api/expressions.h" #include "Firestore/core/src/api/ordering.h" #include "Firestore/core/src/nanopb/message.h" +#include "absl/types/optional.h" namespace firebase { namespace firestore { @@ -89,7 +91,8 @@ class DocumentsSource : public Stage { class AddFields : public Stage { public: - explicit AddFields(std::vector> fields) + explicit AddFields( + std::unordered_map> fields) : fields_(std::move(fields)) { } ~AddFields() override = default; @@ -97,27 +100,29 @@ class AddFields : public Stage { google_firestore_v1_Pipeline_Stage to_proto() const override; private: - std::vector> fields_; + std::unordered_map> fields_; }; class AggregateStage : public Stage { public: - AggregateStage(std::unordered_map> - accumulators, - std::unordered_map> groups) + AggregateStage( + std::unordered_map> + accumulators, + std::unordered_map> groups) : accumulators_(std::move(accumulators)), groups_(std::move(groups)) { } google_firestore_v1_Pipeline_Stage to_proto() const override; private: - std::unordered_map> accumulators_; + std::unordered_map> + accumulators_; std::unordered_map> groups_; }; class Where : public Stage { public: - explicit Where(std::shared_ptr expr) : expr_(std::move(expr)) { + explicit Where(std::shared_ptr expr) : expr_(expr) { } ~Where() override = default; @@ -169,14 +174,14 @@ class FindNearestStage : public Stage { class LimitStage : public Stage { public: - explicit LimitStage(int64_t limit) : limit_(limit) { + explicit LimitStage(int32_t limit) : limit_(limit) { } ~LimitStage() override = default; google_firestore_v1_Pipeline_Stage to_proto() const override; private: - int64_t limit_; + int32_t limit_; }; class OffsetStage : public Stage { @@ -193,7 +198,8 @@ class OffsetStage : public Stage { class SelectStage : public Stage { public: - explicit SelectStage(std::vector> fields) + explicit SelectStage( + std::unordered_map> fields) : fields_(std::move(fields)) { } ~SelectStage() override = default; @@ -201,12 +207,12 @@ class SelectStage : public Stage { google_firestore_v1_Pipeline_Stage to_proto() const override; private: - std::vector> fields_; + std::unordered_map> fields_; }; class SortStage : public Stage { public: - explicit SortStage(std::vector orders) + explicit SortStage(std::vector> orders) : orders_(std::move(orders)) { } ~SortStage() override = default; @@ -214,12 +220,13 @@ class SortStage : public Stage { google_firestore_v1_Pipeline_Stage to_proto() const override; private: - std::vector orders_; + std::vector> orders_; }; class DistinctStage : public Stage { public: - explicit DistinctStage(std::vector> groups) + explicit DistinctStage( + std::unordered_map> groups) : groups_(std::move(groups)) { } ~DistinctStage() override = default; @@ -227,7 +234,7 @@ class DistinctStage : public Stage { google_firestore_v1_Pipeline_Stage to_proto() const override; private: - std::vector> groups_; + std::unordered_map> groups_; }; class RemoveFieldsStage : public Stage { @@ -243,6 +250,63 @@ class RemoveFieldsStage : public Stage { std::vector fields_; }; +class ReplaceWith : public Stage { + public: + explicit ReplaceWith(std::shared_ptr expr); + ~ReplaceWith() override = default; + google_firestore_v1_Pipeline_Stage to_proto() const override; + + private: + std::shared_ptr expr_; +}; + +class Sample : public Stage { + public: + Sample(std::string type, int64_t count, double percentage); + ~Sample() override = default; + google_firestore_v1_Pipeline_Stage to_proto() const override; + + private: + std::string type_; + int64_t count_; + double percentage_; +}; + +class Union : public Stage { + public: + explicit Union(std::shared_ptr other); + ~Union() override = default; + google_firestore_v1_Pipeline_Stage to_proto() const override; + + private: + std::shared_ptr other_; +}; + +class Unnest : public Stage { + public: + Unnest(std::shared_ptr field, absl::optional index_field); + ~Unnest() override = default; + google_firestore_v1_Pipeline_Stage to_proto() const override; + + private: + std::shared_ptr field_; + absl::optional index_field_; +}; + +class GenericStage : public Stage { + public: + GenericStage(std::string name, + std::vector> params, + std::unordered_map> options); + ~GenericStage() override = default; + google_firestore_v1_Pipeline_Stage to_proto() const override; + + private: + std::string name_; + std::vector> params_; + std::unordered_map> options_; +}; + } // namespace api } // namespace firestore } // namespace firebase diff --git a/Firestore/core/src/remote/serializer.cc b/Firestore/core/src/remote/serializer.cc index 2985f86d623..889767b84ee 100644 --- a/Firestore/core/src/remote/serializer.cc +++ b/Firestore/core/src/remote/serializer.cc @@ -1209,16 +1209,8 @@ Serializer::DecodeCursorValue(google_firestore_v1_Cursor& cursor) const { google_firestore_v1_StructuredPipeline Serializer::EncodePipeline( const api::Pipeline& pipeline) const { google_firestore_v1_StructuredPipeline result; - auto* stages = - MakeArray(pipeline.stages().size()); - size_t i = 0; - for (const auto& stage : pipeline.stages()) { - stages[i++] = stage->to_proto(); - } - - result.pipeline.stages_count = pipeline.stages().size(); - result.pipeline.stages = stages; + result.pipeline = pipeline.to_proto().pipeline_value; result.options_count = 0; result.options = nullptr; @@ -1514,7 +1506,8 @@ api::PipelineSnapshot Serializer::DecodePipelineResponse( const { auto execution_time = DecodeVersion(context, message->execution_time); - std::vector results(message->results_count); + std::vector results; + results.reserve(message->results_count); for (pb_size_t i = 0; i < message->results_count; ++i) { absl::optional key; From 7cafce471f92564abf23c0089e4e03dd1dc31a8d Mon Sep 17 00:00:00 2001 From: cherylEnkidu <96084918+cherylEnkidu@users.noreply.github.com> Date: Tue, 17 Jun 2025 14:28:49 -0400 Subject: [PATCH 009/113] Pipeline tests part 1 (#14885) Co-authored-by: wu-hui Co-authored-by: Nick Cooke <36927374+ncooke3@users.noreply.github.com> --- Firestore/Source/API/FIRPipelineBridge.mm | 48 ++- .../FirebaseFirestore/FIRPipelineBridge.h | 8 +- .../Source/SwiftAPI/Pipeline/Pipeline.swift | 8 +- .../SwiftAPI/Pipeline/PipelineSnapshot.swift | 8 +- .../SwiftAPI/Pipeline/PipelineSource.swift | 16 +- Firestore/Swift/Source/SwiftAPI/Stages.swift | 22 +- .../Tests/Integration/PipelineApiTests.swift | 14 +- .../Tests/Integration/PipelineTests.swift | 368 ++++++++++++++++-- .../core/src/api/aggregate_expressions.cc | 2 +- Firestore/core/src/api/pipeline.cc | 4 +- Firestore/core/src/api/stages.cc | 6 +- Firestore/core/src/api/stages.h | 10 +- 12 files changed, 436 insertions(+), 78 deletions(-) diff --git a/Firestore/Source/API/FIRPipelineBridge.mm b/Firestore/Source/API/FIRPipelineBridge.mm index ac3091249e0..ef09a86e1da 100644 --- a/Firestore/Source/API/FIRPipelineBridge.mm +++ b/Firestore/Source/API/FIRPipelineBridge.mm @@ -20,6 +20,7 @@ #include +#import "Firestore/Source/API/FIRCollectionReference+Internal.h" #import "Firestore/Source/API/FIRDocumentReference+Internal.h" #import "Firestore/Source/API/FIRFieldPath+Internal.h" #import "Firestore/Source/API/FIRFirestore+Internal.h" @@ -39,6 +40,7 @@ #include "Firestore/core/src/api/pipeline_result.h" #include "Firestore/core/src/api/pipeline_snapshot.h" #include "Firestore/core/src/api/stages.h" +#include "Firestore/core/src/util/comparison.h" #include "Firestore/core/src/util/error_apple.h" #include "Firestore/core/src/util/status.h" #include "Firestore/core/src/util/string_apple.h" @@ -57,12 +59,12 @@ using firebase::firestore::api::Field; using firebase::firestore::api::FindNearestStage; using firebase::firestore::api::FunctionExpr; -using firebase::firestore::api::GenericStage; using firebase::firestore::api::LimitStage; using firebase::firestore::api::MakeFIRTimestamp; using firebase::firestore::api::OffsetStage; using firebase::firestore::api::Ordering; using firebase::firestore::api::Pipeline; +using firebase::firestore::api::RawStage; using firebase::firestore::api::RemoveFieldsStage; using firebase::firestore::api::ReplaceWith; using firebase::firestore::api::Sample; @@ -73,6 +75,7 @@ using firebase::firestore::api::Where; using firebase::firestore::model::FieldPath; using firebase::firestore::nanopb::SharedMessage; +using firebase::firestore::util::ComparisonResult; using firebase::firestore::util::MakeCallback; using firebase::firestore::util::MakeNSString; using firebase::firestore::util::MakeString; @@ -80,6 +83,13 @@ NS_ASSUME_NONNULL_BEGIN +inline std::string EnsureLeadingSlash(const std::string &path) { + if (!path.empty() && path[0] == '/') { + return path; + } + return "/" + path; +} + @implementation FIRExprBridge @end @@ -216,10 +226,19 @@ @implementation FIRCollectionSourceStageBridge { std::shared_ptr collection_source; } -- (id)initWithPath:(NSString *)path { +- (id)initWithRef:(FIRCollectionReference *)ref firestore:(FIRFirestore *)db { self = [super init]; if (self) { - collection_source = std::make_shared(MakeString(path)); + if (ref.firestore.databaseID.CompareTo(db.databaseID) != ComparisonResult::Same) { + ThrowInvalidArgument( + "Invalid CollectionReference. The project ID (\"%s\") or the database (\"%s\") does not " + "match " + "the project ID (\"%s\") and database (\"%s\") of the target database of this Pipeline.", + ref.firestore.databaseID.project_id(), ref.firestore.databaseID.database_id(), + db.databaseID.project_id(), db.databaseID.project_id()); + } + collection_source = + std::make_shared(EnsureLeadingSlash(MakeString(ref.path))); } return self; } @@ -270,12 +289,21 @@ @implementation FIRDocumentsSourceStageBridge { std::shared_ptr cpp_document_source; } -- (id)initWithDocuments:(NSArray *)documents { +- (id)initWithDocuments:(NSArray *)documents firestore:(FIRFirestore *)db { self = [super init]; if (self) { std::vector cpp_documents; - for (NSString *doc in documents) { - cpp_documents.push_back(MakeString(doc)); + for (FIRDocumentReference *doc in documents) { + if (doc.firestore.databaseID.CompareTo(db.databaseID) != ComparisonResult::Same) { + ThrowInvalidArgument("Invalid DocumentReference. The project ID (\"%s\") or the database " + "(\"%s\") does not match " + "the project ID (\"%s\") and database (\"%s\") of the target database " + "of this Pipeline.", + doc.firestore.databaseID.project_id(), + doc.firestore.databaseID.database_id(), db.databaseID.project_id(), + db.databaseID.project_id()); + } + cpp_documents.push_back(EnsureLeadingSlash(MakeString(doc.path))); } cpp_document_source = std::make_shared(std::move(cpp_documents)); } @@ -754,12 +782,12 @@ - (id)initWithField:(FIRExprBridge *)field indexField:(NSString *_Nullable)index @end -@implementation FIRGenericStageBridge { +@implementation FIRRawStageBridge { NSString *_name; NSArray *_params; NSDictionary *_Nullable _options; Boolean isUserDataRead; - std::shared_ptr cpp_generic_stage; + std::shared_ptr cpp_generic_stage; } - (id)initWithName:(NSString *)name @@ -787,8 +815,8 @@ - (id)initWithName:(NSString *)name cpp_options[MakeString(key)] = [_options[key] cppExprWithReader:reader]; } } - cpp_generic_stage = std::make_shared(MakeString(_name), std::move(cpp_params), - std::move(cpp_options)); + cpp_generic_stage = std::make_shared(MakeString(_name), std::move(cpp_params), + std::move(cpp_options)); } isUserDataRead = YES; diff --git a/Firestore/Source/Public/FirebaseFirestore/FIRPipelineBridge.h b/Firestore/Source/Public/FirebaseFirestore/FIRPipelineBridge.h index 7b8ebf80e9b..58cf3237194 100644 --- a/Firestore/Source/Public/FirebaseFirestore/FIRPipelineBridge.h +++ b/Firestore/Source/Public/FirebaseFirestore/FIRPipelineBridge.h @@ -70,7 +70,7 @@ NS_SWIFT_SENDABLE NS_SWIFT_NAME(CollectionSourceStageBridge) @interface FIRCollectionSourceStageBridge : FIRStageBridge -- (id)initWithPath:(NSString *)path; +- (id)initWithRef:(FIRCollectionReference *)ref firestore:(FIRFirestore *)db; @end @@ -94,7 +94,7 @@ NS_SWIFT_SENDABLE NS_SWIFT_NAME(DocumentsSourceStageBridge) @interface FIRDocumentsSourceStageBridge : FIRStageBridge -- (id)initWithDocuments:(NSArray *)documents; +- (id)initWithDocuments:(NSArray *)documents firestore:(FIRFirestore *)db; @end @@ -195,8 +195,8 @@ NS_SWIFT_NAME(UnnestStageBridge) @end NS_SWIFT_SENDABLE -NS_SWIFT_NAME(GenericStageBridge) -@interface FIRGenericStageBridge : FIRStageBridge +NS_SWIFT_NAME(RawStageBridge) +@interface FIRRawStageBridge : FIRStageBridge - (id)initWithName:(NSString *)name params:(NSArray *)params options:(NSDictionary *_Nullable)options; diff --git a/Firestore/Swift/Source/SwiftAPI/Pipeline/Pipeline.swift b/Firestore/Swift/Source/SwiftAPI/Pipeline/Pipeline.swift index 4e49c97301b..cb839239994 100644 --- a/Firestore/Swift/Source/SwiftAPI/Pipeline/Pipeline.swift +++ b/Firestore/Swift/Source/SwiftAPI/Pipeline/Pipeline.swift @@ -699,7 +699,7 @@ public struct Pipeline: @unchecked Sendable { /// ```swift /// // let pipeline: Pipeline = ... /// // Example: Assuming a hypothetical backend stage "customFilterV2". - /// let genericPipeline = pipeline.genericStage( + /// let genericPipeline = pipeline.rawStage( /// name: "customFilterV2", /// params: [Field("userScore"), 80], // Ordered parameters. /// options: ["mode": "strict", "logLevel": 2] // Optional named parameters. @@ -712,10 +712,10 @@ public struct Pipeline: @unchecked Sendable { /// - params: An array of ordered, `Sendable` parameters for the stage. /// - options: Optional dictionary of named, `Sendable` parameters. /// - Returns: A new `Pipeline` object with this stage appended. - public func genericStage(name: String, params: [Sendable], - options: [String: Sendable]? = nil) -> Pipeline { + public func rawStage(name: String, params: [Sendable], + options: [String: Sendable]? = nil) -> Pipeline { return Pipeline( - stages: stages + [GenericStage(name: name, params: params, options: options)], + stages: stages + [RawStage(name: name, params: params, options: options)], db: db ) } diff --git a/Firestore/Swift/Source/SwiftAPI/Pipeline/PipelineSnapshot.swift b/Firestore/Swift/Source/SwiftAPI/Pipeline/PipelineSnapshot.swift index e25191b8ad2..a260cc55cee 100644 --- a/Firestore/Swift/Source/SwiftAPI/Pipeline/PipelineSnapshot.swift +++ b/Firestore/Swift/Source/SwiftAPI/Pipeline/PipelineSnapshot.swift @@ -25,7 +25,7 @@ public struct PipelineSnapshot: Sendable { public let pipeline: Pipeline /// An array of all the results in the `PipelineSnapshot`. - let results_cache: [PipelineResult] + public let results: [PipelineResult] /// The time at which the pipeline producing this result was executed. public let executionTime: Timestamp @@ -36,10 +36,6 @@ public struct PipelineSnapshot: Sendable { self.bridge = bridge self.pipeline = pipeline executionTime = self.bridge.execution_time - results_cache = self.bridge.results.map { PipelineResult($0) } - } - - public func results() -> [PipelineResult] { - return results_cache + results = self.bridge.results.map { PipelineResult($0) } } } diff --git a/Firestore/Swift/Source/SwiftAPI/Pipeline/PipelineSource.swift b/Firestore/Swift/Source/SwiftAPI/Pipeline/PipelineSource.swift index da0b5b5b1b4..6a0026340a2 100644 --- a/Firestore/Swift/Source/SwiftAPI/Pipeline/PipelineSource.swift +++ b/Firestore/Swift/Source/SwiftAPI/Pipeline/PipelineSource.swift @@ -21,8 +21,12 @@ public struct PipelineSource: @unchecked Sendable { } public func collection(_ path: String) -> Pipeline { - let normalizedPath = path.hasPrefix("/") ? path : "/" + path - return Pipeline(stages: [CollectionSource(collection: normalizedPath)], db: db) + return Pipeline(stages: [CollectionSource(collection: db.collection(path), db: db)], db: db) + } + + public func collection(_ ref: CollectionReference) -> Pipeline { + let collectionStage = CollectionSource(collection: ref, db: db) + return Pipeline(stages: [collectionStage], db: db) } public func collectionGroup(_ collectionId: String) -> Pipeline { @@ -37,13 +41,13 @@ public struct PipelineSource: @unchecked Sendable { } public func documents(_ docs: [DocumentReference]) -> Pipeline { - let paths = docs.map { $0.path.hasPrefix("/") ? $0.path : "/" + $0.path } - return Pipeline(stages: [DocumentsSource(paths: paths)], db: db) + return Pipeline(stages: [DocumentsSource(docs: docs, db: db)], db: db) } public func documents(_ paths: [String]) -> Pipeline { - let normalizedPaths = paths.map { $0.hasPrefix("/") ? $0 : "/" + $0 } - return Pipeline(stages: [DocumentsSource(paths: normalizedPaths)], db: db) + let docs = paths.map { db.document($0) } + let documentsStage = DocumentsSource(docs: docs, db: db) + return Pipeline(stages: [documentsStage], db: db) } public func create(from query: Query) -> Pipeline { diff --git a/Firestore/Swift/Source/SwiftAPI/Stages.swift b/Firestore/Swift/Source/SwiftAPI/Stages.swift index 65796af8471..13079a3148b 100644 --- a/Firestore/Swift/Source/SwiftAPI/Stages.swift +++ b/Firestore/Swift/Source/SwiftAPI/Stages.swift @@ -33,11 +33,13 @@ class CollectionSource: Stage { let name: String = "collection" let bridge: StageBridge - private var collection: String + private var collection: CollectionReference + private let db: Firestore - init(collection: String) { + init(collection: CollectionReference, db: Firestore) { self.collection = collection - bridge = CollectionSourceStageBridge(path: collection) + self.db = db + bridge = CollectionSourceStageBridge(ref: collection, firestore: db) } } @@ -70,12 +72,14 @@ class DatabaseSource: Stage { class DocumentsSource: Stage { let name: String = "documents" let bridge: StageBridge - private var references: [String] + private var docs: [DocumentReference] + private let db: Firestore // Initialize with an array of String paths - init(paths: [String]) { - references = paths - bridge = DocumentsSourceStageBridge(documents: paths) + init(docs: [DocumentReference], db: Firestore) { + self.docs = docs + self.db = db + bridge = DocumentsSourceStageBridge(documents: docs, firestore: db) } } @@ -337,7 +341,7 @@ class Unnest: Stage { } @available(iOS 13, tvOS 13, macOS 10.15, macCatalyst 13, watchOS 7, *) -class GenericStage: Stage { +class RawStage: Stage { let name: String let bridge: StageBridge private var params: [Sendable] @@ -349,6 +353,6 @@ class GenericStage: Stage { self.options = options let bridgeParams = params.map { Helper.sendableToExpr($0).toBridge() } let bridgeOptions = options?.mapValues { Helper.sendableToExpr($0).toBridge() } - bridge = GenericStageBridge(name: name, params: bridgeParams, options: bridgeOptions) + bridge = RawStageBridge(name: name, params: bridgeParams, options: bridgeOptions) } } diff --git a/Firestore/Swift/Tests/Integration/PipelineApiTests.swift b/Firestore/Swift/Tests/Integration/PipelineApiTests.swift index 25ca1f09a6d..f712cceca1f 100644 --- a/Firestore/Swift/Tests/Integration/PipelineApiTests.swift +++ b/Firestore/Swift/Tests/Integration/PipelineApiTests.swift @@ -263,22 +263,22 @@ final class PipelineTests: FSTIntegrationTestCase { // ... } } - func testGenericStage() async throws { + func testRawStage() async throws { // Assume we don't have a built-in "where" stage, the customer could still - // add this stage by calling genericStage, passing the name of the stage "where", + // add this stage by calling rawStage, passing the name of the stage "where", // and providing positional argument values. _ = db.pipeline().collection("books") - .genericStage(name: "where", - params: [Field("published").lt(1900)]) + .rawStage(name: "where", + params: [Field("published").lt(1900)]) .select("title", "author") // In cases where the stage also supports named argument values, then these can be // provided with a third argument that maps the argument name to value. // Note that these named arguments are always optional in the stage definition. _ = db.pipeline().collection("books") - .genericStage(name: "where", - params: [Field("published").lt(1900)], - options: ["someOptionalParamName": "the argument value for this param"]) + .rawStage(name: "where", + params: [Field("published").lt(1900)], + options: ["someOptionalParamName": "the argument value for this param"]) .select("title", "author") } diff --git a/Firestore/Swift/Tests/Integration/PipelineTests.swift b/Firestore/Swift/Tests/Integration/PipelineTests.swift index 7bfdc8525a1..9816716a1e9 100644 --- a/Firestore/Swift/Tests/Integration/PipelineTests.swift +++ b/Firestore/Swift/Tests/Integration/PipelineTests.swift @@ -14,8 +14,10 @@ * limitations under the License. */ +import FirebaseCore // For FirebaseApp management import FirebaseFirestore import Foundation +import XCTest // For XCTFail, XCTAssertEqual etc. private let bookDocs: [String: [String: Any]] = [ "book1": [ @@ -24,9 +26,10 @@ private let bookDocs: [String: [String: Any]] = [ "genre": "Science Fiction", "published": 1979, "rating": 4.2, - "tags": ["comedy", "space", "adventure"], // Array literal - "awards": ["hugo": true, "nebula": false], // Dictionary literal - "nestedField": ["level.1": ["level.2": true]], // Nested dictionary literal + "tags": ["comedy", "space", "adventure"], + "awards": ["hugo": true, "nebula": false, "others": ["unknown": ["year": 1980]]], // Corrected + "nestedField": ["level.1": ["level.2": true]], + "embedding": VectorValue([10, 1, 1, 1, 1, 1, 1, 1, 1, 1]), ], "book2": [ "title": "Pride and Prejudice", @@ -36,6 +39,7 @@ private let bookDocs: [String: [String: Any]] = [ "rating": 4.5, "tags": ["classic", "social commentary", "love"], "awards": ["none": true], + "embedding": VectorValue([1, 10, 1, 1, 1, 1, 1, 1, 1, 1]), // Added ], "book3": [ "title": "One Hundred Years of Solitude", @@ -45,6 +49,7 @@ private let bookDocs: [String: [String: Any]] = [ "rating": 4.3, "tags": ["family", "history", "fantasy"], "awards": ["nobel": true, "nebula": false], + "embedding": VectorValue([1, 1, 10, 1, 1, 1, 1, 1, 1, 1]), ], "book4": [ "title": "The Lord of the Rings", @@ -54,6 +59,9 @@ private let bookDocs: [String: [String: Any]] = [ "rating": 4.7, "tags": ["adventure", "magic", "epic"], "awards": ["hugo": false, "nebula": false], + "remarks": NSNull(), // Added + "cost": Double.nan, // Added + "embedding": VectorValue([1, 1, 1, 10, 1, 1, 1, 1, 1, 1]), // Added ], "book5": [ "title": "The Handmaid's Tale", @@ -63,6 +71,7 @@ private let bookDocs: [String: [String: Any]] = [ "rating": 4.1, "tags": ["feminism", "totalitarianism", "resistance"], "awards": ["arthur c. clarke": true, "booker prize": false], + "embedding": VectorValue([1, 1, 1, 1, 10, 1, 1, 1, 1, 1]), // Added ], "book6": [ "title": "Crime and Punishment", @@ -72,6 +81,7 @@ private let bookDocs: [String: [String: Any]] = [ "rating": 4.3, "tags": ["philosophy", "crime", "redemption"], "awards": ["none": true], + "embedding": VectorValue([1, 1, 1, 1, 1, 10, 1, 1, 1, 1]), // Added ], "book7": [ "title": "To Kill a Mockingbird", @@ -81,6 +91,7 @@ private let bookDocs: [String: [String: Any]] = [ "rating": 4.2, "tags": ["racism", "injustice", "coming-of-age"], "awards": ["pulitzer": true], + "embedding": VectorValue([1, 1, 1, 1, 1, 1, 10, 1, 1, 1]), // Added ], "book8": [ "title": "1984", @@ -90,6 +101,7 @@ private let bookDocs: [String: [String: Any]] = [ "rating": 4.2, "tags": ["surveillance", "totalitarianism", "propaganda"], "awards": ["prometheus": true], + "embedding": VectorValue([1, 1, 1, 1, 1, 1, 1, 10, 1, 1]), // Added ], "book9": [ "title": "The Great Gatsby", @@ -99,6 +111,7 @@ private let bookDocs: [String: [String: Any]] = [ "rating": 4.0, "tags": ["wealth", "american dream", "love"], "awards": ["none": true], + "embedding": VectorValue([1, 1, 1, 1, 1, 1, 1, 1, 10, 1]), // Added ], "book10": [ "title": "Dune", @@ -108,9 +121,46 @@ private let bookDocs: [String: [String: Any]] = [ "rating": 4.6, "tags": ["politics", "desert", "ecology"], "awards": ["hugo": true, "nebula": true], + "embedding": VectorValue([1, 1, 1, 1, 1, 1, 1, 1, 1, 10]), // Added ], ] +func expectResults(_ snapshot: PipelineSnapshot, + expectedCount: Int, + file: StaticString = #file, + line: UInt = #line) { + XCTAssertEqual( + snapshot.results.count, + expectedCount, + "Snapshot results count mismatch", + file: file, + line: line + ) +} + +func expectResults(_ snapshot: PipelineSnapshot, + expectedIDs: [String], + file: StaticString = #file, + line: UInt = #line) { + let results = snapshot.results + XCTAssertEqual( + results.count, + expectedIDs.count, + "Snapshot document IDs count mismatch. Expected \(expectedIDs.count), got \(results.count). Actual IDs: \(results.map { $0.id })", + file: file, + line: line + ) + + let actualIDs = results.map { $0.id! }.sorted() + XCTAssertEqual( + actualIDs, + expectedIDs.sorted(), + "Snapshot document IDs mismatch. Expected (sorted): \(expectedIDs.sorted()), got (sorted): \(actualIDs)", + file: file, + line: line + ) +} + @available(iOS 13, tvOS 13, macOS 10.15, macCatalyst 13, watchOS 7, *) class PipelineIntegrationTests: FSTIntegrationTestCase { override func setUp() { @@ -118,17 +168,6 @@ class PipelineIntegrationTests: FSTIntegrationTestCase { super.setUp() } - func testCount() async throws { - try await firestore().collection("foo").document("bar").setData(["foo": "bar", "x": 42]) - let snapshot = try await firestore() - .pipeline() - .collection("/foo") - .where(Field("foo").eq(Constant("bar"))) - .execute() - - print(snapshot) - } - func testEmptyResults() async throws { let collRef = collectionRef( withDocuments: bookDocs @@ -141,7 +180,7 @@ class PipelineIntegrationTests: FSTIntegrationTestCase { .limit(0) .execute() - XCTAssertTrue(snapshot.results().isEmpty) + expectResults(snapshot, expectedCount: 0) } func testFullResults() async throws { @@ -155,14 +194,299 @@ class PipelineIntegrationTests: FSTIntegrationTestCase { .collection(collRef.path) .execute() - let results = snapshot.results() - XCTAssertEqual(results.count, 10) + // expectResults(snapshot, expectedCount: 10) // This is implicitly checked by expectedIDs + // version + expectResults( + snapshot, + expectedIDs: [ + "book1", "book10", "book2", "book3", "book4", + "book5", "book6", "book7", "book8", "book9", + ] + ) + } + + func testReturnsExecutionTime() async throws { + let collRef = collectionRef(withDocuments: bookDocs) + let db = collRef.firestore + + let pipeline = db.pipeline().collection(collRef.path) + let snapshot = try await pipeline.execute() + + XCTAssertEqual(snapshot.results.count, bookDocs.count, "Should fetch all documents") + + let executionTimeValue = snapshot.executionTime.dateValue().timeIntervalSince1970 + + XCTAssertGreaterThan(executionTimeValue, 0, "Execution time should be positive and not zero") + } + + func testReturnsExecutionTimeForEmptyQuery() async throws { + let collRef = + collectionRef(withDocuments: bookDocs) // Using bookDocs is fine, limit(0) makes it empty + let db = collRef.firestore + + let pipeline = db.pipeline().collection(collRef.path).limit(0) + let snapshot = try await pipeline.execute() + + expectResults(snapshot, expectedCount: 0) + + let executionTimeValue = snapshot.executionTime.dateValue().timeIntervalSince1970 + XCTAssertGreaterThan(executionTimeValue, 0, "Execution time should be positive and not zero") + } + + func testReturnsCreateAndUpdateTimeForEachDocument() async throws { + let collRef = collectionRef(withDocuments: bookDocs) + let db = collRef.firestore + let pipeline = db.pipeline().collection(collRef.path) + var snapshot = try await pipeline.execute() + + XCTAssertEqual( + snapshot.results.count, + bookDocs.count, + "Initial fetch should return all documents" + ) + for doc in snapshot.results { + XCTAssertNotNil( + doc.createTime, + "Document \(String(describing: doc.id)) should have createTime" + ) + XCTAssertNotNil( + doc.updateTime, + "Document \(String(describing: doc.id)) should have updateTime" + ) + if let createTime = doc.createTime, let updateTime = doc.updateTime { + let createTimestamp = createTime.dateValue().timeIntervalSince1970 + let updateTimestamp = updateTime.dateValue().timeIntervalSince1970 + + XCTAssertEqual(createTimestamp, + updateTimestamp, + "Initial createTime and updateTime should be equal for \(String(describing: doc.id))") + } + } + + // Update documents + let batch = db.batch() + for doc in snapshot.results { + batch + .updateData( + ["newField": "value"], + forDocument: doc.ref! + ) + } + + try await batch.commit() + + snapshot = try await pipeline.execute() + XCTAssertEqual( + snapshot.results.count, + bookDocs.count, + "Fetch after update should return all documents" + ) + + for doc in snapshot.results { + XCTAssertNotNil( + doc.createTime, + "Document \(String(describing: doc.id)) should still have createTime after update" + ) + XCTAssertNotNil( + doc.updateTime, + "Document \(String(describing: doc.id)) should still have updateTime after update" + ) + if let createTime = doc.createTime, let updateTime = doc.updateTime { + let createTimestamp = createTime.dateValue().timeIntervalSince1970 + let updateTimestamp = updateTime.dateValue().timeIntervalSince1970 + + XCTAssertLessThan(createTimestamp, + updateTimestamp, + "updateTime (\(updateTimestamp)) should be after createTime (\(createTimestamp)) for \(String(describing: doc.id))") + } + } + } + + func testReturnsExecutionTimeForAggregateQuery() async throws { + let collRef = collectionRef(withDocuments: bookDocs) + let db = collRef.firestore + + let pipeline = db.pipeline() + .collection(collRef.path) + .aggregate(Field("rating").avg().as("avgRating")) + let snapshot = try await pipeline.execute() + + XCTAssertEqual(snapshot.results.count, 1, "Aggregate query should return a single result") + + let executionTimeValue = snapshot.executionTime.dateValue().timeIntervalSince1970 + XCTAssertGreaterThan(executionTimeValue, 0, "Execution time should be positive") + } + + func testTimestampsAreNilForAggregateQueryResults() async throws { + let collRef = collectionRef(withDocuments: bookDocs) + let db = collRef.firestore + + let pipeline = db.pipeline() + .collection(collRef.path) + .aggregate( + [Field("rating").avg().as("avgRating")], + groups: ["genre"] + ) // Make sure 'groupBy' and 'average' are correct + let snapshot = try await pipeline.execute() + + // There are 8 unique genres in bookDocs + XCTAssertEqual(snapshot.results.count, 8, "Should return one result per genre") + + for doc in snapshot.results { + XCTAssertNil( + doc.createTime, + "createTime should be nil for aggregate result (docID: \(String(describing: doc.id)), data: \(doc.data))" + ) + XCTAssertNil( + doc.updateTime, + "updateTime should be nil for aggregate result (docID: \(String(describing: doc.id)), data: \(doc.data))" + ) + } + } + + func testSupportsCollectionReferenceAsSource() async throws { + let collRef = collectionRef(withDocuments: bookDocs) + let db = collRef.firestore + + let pipeline = db.pipeline().collection(collRef) + let snapshot = try await pipeline.execute() + + expectResults(snapshot, expectedCount: bookDocs.count) + } + + func testSupportsListOfDocumentReferencesAsSource() async throws { + let collRef = collectionRef(withDocuments: bookDocs) + let db = collRef.firestore + + let docRefs: [DocumentReference] = [ + collRef.document("book1"), + collRef.document("book2"), + collRef.document("book3"), + ] + let pipeline = db.pipeline().documents(docRefs) + let snapshot = try await pipeline.execute() + + expectResults(snapshot, expectedIDs: ["book1", "book2", "book3"]) + } + + func testSupportsListOfDocumentPathsAsSource() async throws { + let collRef = collectionRef(withDocuments: bookDocs) + let db = collRef.firestore + + let docPaths: [String] = [ + collRef.document("book1").path, + collRef.document("book2").path, + collRef.document("book3").path, + ] + let pipeline = db.pipeline().documents(docPaths) + let snapshot = try await pipeline.execute() + + expectResults(snapshot, expectedIDs: ["book1", "book2", "book3"]) + } + + func testRejectsCollectionReferenceFromAnotherDB() async throws { + let db1 = firestore() // Primary DB + + let db2 = Firestore.firestore(app: db1.app, database: "db2") + + let collRefDb2 = db2.collection("foo") + + XCTAssertTrue(FSTNSExceptionUtil.testForException({ + _ = db1.pipeline().collection(collRefDb2) + }, reasonContains: "Invalid CollectionReference")) + } + + func testRejectsDocumentReferenceFromAnotherDB() async throws { + let db1 = firestore() // Primary DB - let actualIDs = Set(results.map { $0.id }) - let expectedIDs = Set([ - "book1", "book2", "book3", "book4", "book5", - "book6", "book7", "book8", "book9", "book10", + let db2 = Firestore.firestore(app: db1.app, database: "db2") + + let docRefDb2 = db2.collection("foo").document("bar") + + XCTAssertTrue(FSTNSExceptionUtil.testForException({ + _ = db1.pipeline().documents([docRefDb2]) + }, reasonContains: "Invalid DocumentReference")) + } + + func testSupportsCollectionGroupAsSource() async throws { + let db = firestore() + + let rootCollForTest = collectionRef() + + let randomSubCollectionId = String(UUID().uuidString.prefix(8)) + + // Create parent documents first to ensure they exist before creating subcollections. + let doc1Ref = rootCollForTest.document("book1").collection(randomSubCollectionId) + .document("translation") + try await doc1Ref.setData(["order": 1]) + + let doc2Ref = rootCollForTest.document("book2").collection(randomSubCollectionId) + .document("translation") + try await doc2Ref.setData(["order": 2]) + + let pipeline = db.pipeline() + .collectionGroup(randomSubCollectionId) + .sort(Field("order").ascending()) + + let snapshot = try await pipeline.execute() + + // Assert that only the two documents from the targeted subCollectionId are fetched, in the + // correct order. + expectResults(snapshot, expectedIDs: [doc1Ref.documentID, doc2Ref.documentID]) + } + + func testSupportsDatabaseAsSource() async throws { + let db = firestore() + let testRootCol = collectionRef() // Provides a unique root path for this test + + let randomIDValue = UUID().uuidString.prefix(8) + + // Document 1 + let collADocRef = testRootCol.document("docA") // Using specific IDs for clarity in debugging + try await collADocRef.setData(["order": 1, "randomId": randomIDValue, "name": "DocInCollA"]) + + // Document 2 + let collBDocRef = testRootCol.document("docB") // Using specific IDs for clarity in debugging + try await collBDocRef.setData(["order": 2, "randomId": randomIDValue, "name": "DocInCollB"]) + + // Document 3 (control, should not be fetched by the main query due to different randomId) + let collCDocRef = testRootCol.document("docC") + try await collCDocRef.setData([ + "order": 3, + "randomId": "\(UUID().uuidString)", + "name": "DocInCollC", + ]) + + // Document 4 (control, no randomId, should not be fetched) + let collDDocRef = testRootCol.document("docD") + try await collDDocRef.setData(["order": 4, "name": "DocInCollDNoRandomId"]) + + // Document 5 (control, correct randomId but in a sub-sub-collection to test depth) + // This also helps ensure the database() query scans deeply. + let subSubCollDocRef = testRootCol.document("parentForSubSub").collection("subSubColl") + .document("docE") + try await subSubCollDocRef.setData([ + "order": 0, + "randomId": randomIDValue, + "name": "DocInSubSubColl", ]) - XCTAssertEqual(actualIDs, expectedIDs) + + let pipeline = db.pipeline() + .database() // Source is the entire database + .where(Field("randomId").eq(randomIDValue)) + .sort(Ascending("order")) + let snapshot = try await pipeline.execute() + + // We expect 3 documents: docA, docB, and docE (from sub-sub-collection) + XCTAssertEqual( + snapshot.results.count, + 3, + "Should fetch the three documents with the correct randomId" + ) + // Order should be docE (order 0), docA (order 1), docB (order 2) + expectResults( + snapshot, + expectedIDs: [subSubCollDocRef.documentID, collADocRef.documentID, collBDocRef.documentID] + ) } } diff --git a/Firestore/core/src/api/aggregate_expressions.cc b/Firestore/core/src/api/aggregate_expressions.cc index fb58918833c..8509dfda59a 100644 --- a/Firestore/core/src/api/aggregate_expressions.cc +++ b/Firestore/core/src/api/aggregate_expressions.cc @@ -25,7 +25,7 @@ namespace api { google_firestore_v1_Value AggregateFunction::to_proto() const { google_firestore_v1_Value result; result.which_value_type = google_firestore_v1_Value_function_value_tag; - + result.function_value = google_firestore_v1_Function{}; result.function_value.name = nanopb::MakeBytesArray(name_); result.function_value.args_count = static_cast(params_.size()); result.function_value.args = nanopb::MakeArray( diff --git a/Firestore/core/src/api/pipeline.cc b/Firestore/core/src/api/pipeline.cc index 53d332f3259..8f92d65465e 100644 --- a/Firestore/core/src/api/pipeline.cc +++ b/Firestore/core/src/api/pipeline.cc @@ -25,6 +25,8 @@ namespace firebase { namespace firestore { namespace api { +using nanopb::CheckedSize; + Pipeline Pipeline::AddingStage(std::shared_ptr stage) { auto copy = std::vector>(this->stages_); copy.push_back(stage); @@ -45,7 +47,7 @@ google_firestore_v1_Value Pipeline::to_proto() const { result.which_value_type = google_firestore_v1_Value_pipeline_value_tag; result.pipeline_value = google_firestore_v1_Pipeline{}; - result.pipeline_value.stages_count = this->stages_.size(); + result.pipeline_value.stages_count = CheckedSize(this->stages_.size()); nanopb::SetRepeatedField( &result.pipeline_value.stages, &result.pipeline_value.stages_count, stages_, diff --git a/Firestore/core/src/api/stages.cc b/Firestore/core/src/api/stages.cc index afa943c8cb0..b3dfd2c55a8 100644 --- a/Firestore/core/src/api/stages.cc +++ b/Firestore/core/src/api/stages.cc @@ -84,7 +84,7 @@ google_firestore_v1_Pipeline_Stage DocumentsSource::to_proto() const { result.name = nanopb::MakeBytesArray("documents"); - result.args_count = documents_.size(); + result.args_count = static_cast(documents_.size()); result.args = nanopb::MakeArray(result.args_count); for (size_t i = 0; i < documents_.size(); ++i) { @@ -393,7 +393,7 @@ google_firestore_v1_Pipeline_Stage Unnest::to_proto() const { return result; } -GenericStage::GenericStage( +RawStage::RawStage( std::string name, std::vector> params, std::unordered_map> options) @@ -402,7 +402,7 @@ GenericStage::GenericStage( options_(std::move(options)) { } -google_firestore_v1_Pipeline_Stage GenericStage::to_proto() const { +google_firestore_v1_Pipeline_Stage RawStage::to_proto() const { google_firestore_v1_Pipeline_Stage result; result.name = nanopb::MakeBytesArray(name_); diff --git a/Firestore/core/src/api/stages.h b/Firestore/core/src/api/stages.h index a3c7303ae92..7af3683e99b 100644 --- a/Firestore/core/src/api/stages.h +++ b/Firestore/core/src/api/stages.h @@ -293,12 +293,12 @@ class Unnest : public Stage { absl::optional index_field_; }; -class GenericStage : public Stage { +class RawStage : public Stage { public: - GenericStage(std::string name, - std::vector> params, - std::unordered_map> options); - ~GenericStage() override = default; + RawStage(std::string name, + std::vector> params, + std::unordered_map> options); + ~RawStage() override = default; google_firestore_v1_Pipeline_Stage to_proto() const override; private: From 432064a297874a971dd3c091f10f569b04d4abfb Mon Sep 17 00:00:00 2001 From: cherylEnkidu <96084918+cherylEnkidu@users.noreply.github.com> Date: Mon, 30 Jun 2025 13:51:10 -0400 Subject: [PATCH 010/113] Pipeline tests part 2 (#14951) Co-authored-by: wu-hui Co-authored-by: Nick Cooke <36927374+ncooke3@users.noreply.github.com> --- .../Firestore.xcodeproj/project.pbxproj | 16 + Firestore/Source/API/FIRPipelineBridge.mm | 114 +- .../FirebaseFirestore/FIRPipelineBridge.h | 6 +- .../Swift/Source/Helper/PipelineHelper.swift | 45 +- .../Aggregation/AggregateFunction.swift | 6 + .../Pipeline/Expr/ArrayExpression.swift | 24 + .../SwiftAPI/Pipeline/Expr/Constant.swift | 5 + .../Expr/FunctionExpr/BooleanExpr.swift | 9 + .../Pipeline/Expr/MapExpression.swift | 25 + .../Source/SwiftAPI/Pipeline/Pipeline.swift | 9 +- .../SwiftAPI/Pipeline/PipelineResult.swift | 2 +- Firestore/Swift/Source/SwiftAPI/Stages.swift | 19 +- .../Tests/Integration/PipelineTests.swift | 1139 ++++++++++++++++- .../Swift/Tests/TestHelper/TestHelper.swift | 227 ++++ Firestore/core/src/api/ordering.cc | 10 +- Firestore/core/src/api/stages.cc | 88 +- Firestore/core/src/api/stages.h | 53 +- 17 files changed, 1653 insertions(+), 144 deletions(-) create mode 100644 Firestore/Swift/Source/SwiftAPI/Pipeline/Expr/ArrayExpression.swift create mode 100644 Firestore/Swift/Source/SwiftAPI/Pipeline/Expr/MapExpression.swift create mode 100644 Firestore/Swift/Tests/TestHelper/TestHelper.swift diff --git a/Firestore/Example/Firestore.xcodeproj/project.pbxproj b/Firestore/Example/Firestore.xcodeproj/project.pbxproj index abba41a6f55..d106d804805 100644 --- a/Firestore/Example/Firestore.xcodeproj/project.pbxproj +++ b/Firestore/Example/Firestore.xcodeproj/project.pbxproj @@ -1133,6 +1133,7 @@ A7309DAD4A3B5334536ECA46 /* remote_event_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 584AE2C37A55B408541A6FF3 /* remote_event_test.cc */; }; A7399FB3BEC50BBFF08EC9BA /* mutation_queue_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 3068AA9DFBBA86C1FE2A946E /* mutation_queue_test.cc */; }; A7669E72BCED7FBADA4B1314 /* thread_safe_memoizer_testing_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = EA10515F99A42D71DA2D2841 /* thread_safe_memoizer_testing_test.cc */; }; + A78366DBE0BFDE42474A728A /* TestHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E73D03B9C02CAC7BEBAFA86 /* TestHelper.swift */; }; A80D38096052F928B17E1504 /* user_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = CCC9BD953F121B9E29F9AA42 /* user_test.cc */; }; A833A216988ADFD4876763CD /* Validation_BloomFilterTest_MD5_50000_01_membership_test_result.json in Resources */ = {isa = PBXBuildFile; fileRef = C8FB22BCB9F454DA44BA80C8 /* Validation_BloomFilterTest_MD5_50000_01_membership_test_result.json */; }; A841EEB5A94A271523EAE459 /* Validation_BloomFilterTest_MD5_50000_0001_bloom_filter_proto.json in Resources */ = {isa = PBXBuildFile; fileRef = A5D9044B72061CAF284BC9E4 /* Validation_BloomFilterTest_MD5_50000_0001_bloom_filter_proto.json */; }; @@ -1172,6 +1173,7 @@ ACC9369843F5ED3BD2284078 /* timestamp_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = ABF6506B201131F8005F2C74 /* timestamp_test.cc */; }; AD00D000A63837FB47291BFE /* Validation_BloomFilterTest_MD5_1_0001_bloom_filter_proto.json in Resources */ = {isa = PBXBuildFile; fileRef = 4B59C0A7B2A4548496ED4E7D /* Validation_BloomFilterTest_MD5_1_0001_bloom_filter_proto.json */; }; AD12205540893CEB48647937 /* filesystem_testing.cc in Sources */ = {isa = PBXBuildFile; fileRef = BA02DA2FCD0001CFC6EB08DA /* filesystem_testing.cc */; }; + AD34726BFD3461FF64BBD56D /* TestHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E73D03B9C02CAC7BEBAFA86 /* TestHelper.swift */; }; AD35AA07F973934BA30C9000 /* remote_event_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 584AE2C37A55B408541A6FF3 /* remote_event_test.cc */; }; AD3C26630E33BE59C49BEB0D /* grpc_unary_call_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = B6D964942163E63900EB9CFB /* grpc_unary_call_test.cc */; }; AD74843082C6465A676F16A7 /* async_queue_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = B6FB467B208E9A8200554BA2 /* async_queue_test.cc */; }; @@ -1572,6 +1574,7 @@ ED9DF1EB20025227B38736EC /* message_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = CE37875365497FFA8687B745 /* message_test.cc */; }; EDF35B147B116F659D0D2CA8 /* Validation_BloomFilterTest_MD5_1_0001_membership_test_result.json in Resources */ = {isa = PBXBuildFile; fileRef = C939D1789E38C09F9A0C1157 /* Validation_BloomFilterTest_MD5_1_0001_membership_test_result.json */; }; EE470CC3C8FBCDA5F70A8466 /* local_store_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 307FF03D0297024D59348EBD /* local_store_test.cc */; }; + EE4C4BE7F93366AE6368EE02 /* TestHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E73D03B9C02CAC7BEBAFA86 /* TestHelper.swift */; }; EE6DBFB0874A50578CE97A7F /* leveldb_remote_document_cache_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 0840319686A223CC4AD3FAB1 /* leveldb_remote_document_cache_test.cc */; }; EECC1EC64CA963A8376FA55C /* persistence_testing.cc in Sources */ = {isa = PBXBuildFile; fileRef = 9113B6F513D0473AEABBAF1F /* persistence_testing.cc */; }; EF3518F84255BAF3EBD317F6 /* exponential_backoff_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = B6D1B68420E2AB1A00B35856 /* exponential_backoff_test.cc */; }; @@ -1739,6 +1742,7 @@ 062072B62773A055001655D7 /* AsyncAwaitIntegrationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AsyncAwaitIntegrationTests.swift; sourceTree = ""; }; 0840319686A223CC4AD3FAB1 /* leveldb_remote_document_cache_test.cc */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; path = leveldb_remote_document_cache_test.cc; sourceTree = ""; }; 0D964D4936953635AC7E0834 /* Validation_BloomFilterTest_MD5_1_01_bloom_filter_proto.json */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.json; name = Validation_BloomFilterTest_MD5_1_01_bloom_filter_proto.json; path = bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_1_01_bloom_filter_proto.json; sourceTree = ""; }; + 0E73D03B9C02CAC7BEBAFA86 /* TestHelper.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = TestHelper.swift; path = TestHelper/TestHelper.swift; sourceTree = ""; }; 0EE5300F8233D14025EF0456 /* string_apple_test.mm */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.objcpp; path = string_apple_test.mm; sourceTree = ""; }; 11984BA0A99D7A7ABA5B0D90 /* Pods-Firestore_Example_iOS-Firestore_SwiftTests_iOS.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Firestore_Example_iOS-Firestore_SwiftTests_iOS.release.xcconfig"; path = "Pods/Target Support Files/Pods-Firestore_Example_iOS-Firestore_SwiftTests_iOS/Pods-Firestore_Example_iOS-Firestore_SwiftTests_iOS.release.xcconfig"; sourceTree = ""; }; 1235769122B7E915007DDFA9 /* EncodableFieldValueTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EncodableFieldValueTests.swift; sourceTree = ""; }; @@ -2599,6 +2603,7 @@ 544A20ED20F6C046004E52CD /* API */, 5495EB012040E90200EBA509 /* Codable */, 124C932A22C1635300CA8C2D /* Integration */, + C7D3D622BB13EB3C3301DA4F /* TestHelper */, 620C1427763BA5D3CCFB5A1F /* BridgingHeader.h */, 54C9EDF52040E16300A969CD /* Info.plist */, ); @@ -2978,6 +2983,14 @@ path = core; sourceTree = ""; }; + C7D3D622BB13EB3C3301DA4F /* TestHelper */ = { + isa = PBXGroup; + children = ( + 0E73D03B9C02CAC7BEBAFA86 /* TestHelper.swift */, + ); + name = TestHelper; + sourceTree = ""; + }; DAFF0CF621E64AC30062958F /* macOS */ = { isa = PBXGroup; children = ( @@ -4699,6 +4712,7 @@ 655F8647F57E5F2155DFF7B5 /* PipelineTests.swift in Sources */, 621D620C28F9CE7400D2FA26 /* QueryIntegrationTests.swift in Sources */, 1CFBD4563960D8A20C4679A3 /* SnapshotListenerSourceTests.swift in Sources */, + EE4C4BE7F93366AE6368EE02 /* TestHelper.swift in Sources */, EFF22EAC2C5060A4009A369B /* VectorIntegrationTests.swift in Sources */, 4D42E5C756229C08560DD731 /* XCTestCase+Await.mm in Sources */, 09BE8C01EC33D1FD82262D5D /* aggregate_query_test.cc in Sources */, @@ -4951,6 +4965,7 @@ C8C2B945D84DD98391145F3F /* PipelineTests.swift in Sources */, 621D620B28F9CE7400D2FA26 /* QueryIntegrationTests.swift in Sources */, A0BC30D482B0ABD1A3A24CDC /* SnapshotListenerSourceTests.swift in Sources */, + A78366DBE0BFDE42474A728A /* TestHelper.swift in Sources */, EFF22EAB2C5060A4009A369B /* VectorIntegrationTests.swift in Sources */, 736C4E82689F1CA1859C4A3F /* XCTestCase+Await.mm in Sources */, 412BE974741729A6683C386F /* aggregate_query_test.cc in Sources */, @@ -5458,6 +5473,7 @@ E04CB0D580980748D5DC453F /* PipelineTests.swift in Sources */, 621D620A28F9CE7400D2FA26 /* QueryIntegrationTests.swift in Sources */, B00F8D1819EE20C45B660940 /* SnapshotListenerSourceTests.swift in Sources */, + AD34726BFD3461FF64BBD56D /* TestHelper.swift in Sources */, EFF22EAA2C5060A4009A369B /* VectorIntegrationTests.swift in Sources */, 5492E0442021457E00B64F25 /* XCTestCase+Await.mm in Sources */, B04E4FE20930384DF3A402F9 /* aggregate_query_test.cc in Sources */, diff --git a/Firestore/Source/API/FIRPipelineBridge.mm b/Firestore/Source/API/FIRPipelineBridge.mm index ef09a86e1da..11f3f4c56d5 100644 --- a/Firestore/Source/API/FIRPipelineBridge.mm +++ b/Firestore/Source/API/FIRPipelineBridge.mm @@ -710,9 +710,11 @@ - (id)initWithPercentage:(double)percentage { - (std::shared_ptr)cppStageWithReader:(FSTUserDataReader *)reader { if (!isUserDataRead) { if ([type isEqualToString:@"count"]) { - cpp_sample = std::make_shared("count", _count, 0); + cpp_sample = + std::make_shared(Sample::SampleMode(Sample::SampleMode::DOCUMENTS), _count, 0); } else { - cpp_sample = std::make_shared("percentage", 0, _percentage); + cpp_sample = + std::make_shared(Sample::SampleMode(Sample::SampleMode::PERCENT), 0, _percentage); } } @@ -750,16 +752,20 @@ - (id)initWithOther:(FIRPipelineBridge *)other { @implementation FIRUnnestStageBridge { FIRExprBridge *_field; - NSString *_Nullable _indexField; + FIRExprBridge *_Nullable _index_field; + FIRExprBridge *_alias; Boolean isUserDataRead; std::shared_ptr cpp_unnest; } -- (id)initWithField:(FIRExprBridge *)field indexField:(NSString *_Nullable)indexField { +- (id)initWithField:(FIRExprBridge *)field + alias:(FIRExprBridge *)alias + indexField:(FIRExprBridge *_Nullable)index_field { self = [super init]; if (self) { _field = field; - _indexField = indexField; + _alias = alias; + _index_field = index_field; isUserDataRead = NO; } return self; @@ -767,13 +773,14 @@ - (id)initWithField:(FIRExprBridge *)field indexField:(NSString *_Nullable)index - (std::shared_ptr)cppStageWithReader:(FSTUserDataReader *)reader { if (!isUserDataRead) { - absl::optional cpp_index_field; - if (_indexField != nil) { - cpp_index_field = MakeString(_indexField); + absl::optional> cpp_index_field; + if (_index_field != nil) { + cpp_index_field = [_index_field cppExprWithReader:reader]; } else { cpp_index_field = absl::nullopt; } - cpp_unnest = std::make_shared([_field cppExprWithReader:reader], cpp_index_field); + cpp_unnest = std::make_shared([_field cppExprWithReader:reader], + [_alias cppExprWithReader:reader], cpp_index_field); } isUserDataRead = YES; @@ -784,14 +791,14 @@ - (id)initWithField:(FIRExprBridge *)field indexField:(NSString *_Nullable)index @implementation FIRRawStageBridge { NSString *_name; - NSArray *_params; + NSArray *_params; NSDictionary *_Nullable _options; Boolean isUserDataRead; std::shared_ptr cpp_generic_stage; } - (id)initWithName:(NSString *)name - params:(NSArray *)params + params:(NSArray *)params options:(NSDictionary *_Nullable)options { self = [super init]; if (self) { @@ -803,12 +810,51 @@ - (id)initWithName:(NSString *)name return self; } +- (firebase::firestore::google_firestore_v1_Value)convertIdToV1Value:(id)value + reader:(FSTUserDataReader *)reader { + if ([value isKindOfClass:[FIRExprBridge class]]) { + return [((FIRExprBridge *)value) cppExprWithReader:reader]->to_proto(); + } else if ([value isKindOfClass:[FIRAggregateFunctionBridge class]]) { + return [((FIRAggregateFunctionBridge *)value) cppExprWithReader:reader]->to_proto(); + } else if ([value isKindOfClass:[NSDictionary class]]) { + NSDictionary *dictionary = (NSDictionary *)value; + + std::unordered_map cpp_dictionary; + for (NSString *key in dictionary) { + if ([dictionary[key] isKindOfClass:[FIRExprBridge class]]) { + cpp_dictionary[MakeString(key)] = + [((FIRExprBridge *)dictionary[key]) cppExprWithReader:reader]->to_proto(); + } else if ([dictionary[key] isKindOfClass:[FIRAggregateFunctionBridge class]]) { + cpp_dictionary[MakeString(key)] = + [((FIRAggregateFunctionBridge *)dictionary[key]) cppExprWithReader:reader]->to_proto(); + } else { + ThrowInvalidArgument( + "Dictionary value must be an FIRExprBridge or FIRAggregateFunctionBridge."); + } + } + + firebase::firestore::google_firestore_v1_Value result; + result.which_value_type = google_firestore_v1_Value_map_value_tag; + + nanopb::SetRepeatedField( + &result.map_value.fields, &result.map_value.fields_count, cpp_dictionary, + [](const std::pair &entry) { + return firebase::firestore::_google_firestore_v1_MapValue_FieldsEntry{ + nanopb::MakeBytesArray(entry.first), entry.second}; + }); + return result; + } else { + ThrowInvalidArgument("Invalid value to convert to google_firestore_v1_Value."); + } +} + - (std::shared_ptr)cppStageWithReader:(FSTUserDataReader *)reader { if (!isUserDataRead) { - std::vector> cpp_params; - for (FIRExprBridge *param in _params) { - cpp_params.push_back([param cppExprWithReader:reader]); + std::vector cpp_params; + for (id param in _params) { + cpp_params.push_back([self convertIdToV1Value:param reader:reader]); } + std::unordered_map> cpp_options; if (_options) { for (NSString *key in _options) { @@ -928,7 +974,9 @@ - (id)initWithCppResult:(api::PipelineResult)result db:(std::shared_ptr *dictionary = [dataWriter convertedValue:*data]; + NSLog(@"Dictionary contents: %@", dictionary); + return dictionary; } - (nullable id)get:(id)field { @@ -959,35 +1007,41 @@ - (nullable id)get:(id)field @implementation FIRPipelineBridge { NSArray *_stages; FIRFirestore *firestore; + Boolean isUserDataRead; std::shared_ptr cpp_pipeline; } - (id)initWithStages:(NSArray *)stages db:(FIRFirestore *)db { _stages = stages; firestore = db; + isUserDataRead = NO; return [super init]; } - (void)executeWithCompletion:(void (^)(__FIRPipelineSnapshotBridge *_Nullable result, NSError *_Nullable error))completion { - std::vector> cpp_stages; - for (FIRStageBridge *stage in _stages) { - cpp_stages.push_back([stage cppStageWithReader:firestore.dataReader]); - } - cpp_pipeline = std::make_shared(cpp_stages, firestore.wrapped); - - cpp_pipeline->execute([completion](StatusOr maybe_value) { - if (maybe_value.ok()) { - __FIRPipelineSnapshotBridge *bridge = [[__FIRPipelineSnapshotBridge alloc] - initWithCppSnapshot:std::move(maybe_value).ValueOrDie()]; - completion(bridge, nil); - } else { - completion(nil, MakeNSError(std::move(maybe_value).status())); - } - }); + [self cppPipelineWithReader:firestore.dataReader]->execute( + [completion](StatusOr maybe_value) { + if (maybe_value.ok()) { + __FIRPipelineSnapshotBridge *bridge = [[__FIRPipelineSnapshotBridge alloc] + initWithCppSnapshot:std::move(maybe_value).ValueOrDie()]; + completion(bridge, nil); + } else { + completion(nil, MakeNSError(std::move(maybe_value).status())); + } + }); } - (std::shared_ptr)cppPipelineWithReader:(FSTUserDataReader *)reader { + if (!isUserDataRead) { + std::vector> cpp_stages; + for (FIRStageBridge *stage in _stages) { + cpp_stages.push_back([stage cppStageWithReader:firestore.dataReader]); + } + cpp_pipeline = std::make_shared(cpp_stages, firestore.wrapped); + } + + isUserDataRead = YES; return cpp_pipeline; } diff --git a/Firestore/Source/Public/FirebaseFirestore/FIRPipelineBridge.h b/Firestore/Source/Public/FirebaseFirestore/FIRPipelineBridge.h index 58cf3237194..cf72c897f3b 100644 --- a/Firestore/Source/Public/FirebaseFirestore/FIRPipelineBridge.h +++ b/Firestore/Source/Public/FirebaseFirestore/FIRPipelineBridge.h @@ -191,14 +191,16 @@ NS_SWIFT_NAME(UnionStageBridge) NS_SWIFT_SENDABLE NS_SWIFT_NAME(UnnestStageBridge) @interface FIRUnnestStageBridge : FIRStageBridge -- (id)initWithField:(FIRExprBridge *)field indexField:(NSString *_Nullable)indexField; +- (id)initWithField:(FIRExprBridge *)field + alias:(FIRExprBridge *)alias + indexField:(FIRExprBridge *_Nullable)index_field; @end NS_SWIFT_SENDABLE NS_SWIFT_NAME(RawStageBridge) @interface FIRRawStageBridge : FIRStageBridge - (id)initWithName:(NSString *)name - params:(NSArray *)params + params:(NSArray *)params options:(NSDictionary *_Nullable)options; @end diff --git a/Firestore/Swift/Source/Helper/PipelineHelper.swift b/Firestore/Swift/Source/Helper/PipelineHelper.swift index 582e90021b1..cde334b7ae8 100644 --- a/Firestore/Swift/Source/Helper/PipelineHelper.swift +++ b/Firestore/Swift/Source/Helper/PipelineHelper.swift @@ -13,13 +13,17 @@ // limitations under the License. enum Helper { - static func sendableToExpr(_ value: Sendable) -> Expr { + static func sendableToExpr(_ value: Sendable?) -> Expr { + guard let value = value else { + return Constant.nil + } + if value is Expr { return value as! Expr - } else if value is [String: Sendable] { - return map(value as! [String: Sendable]) - } else if value is [Sendable] { - return array(value as! [Sendable]) + } else if value is [String: Sendable?] { + return map(value as! [String: Sendable?]) + } else if value is [Sendable?] { + return array(value as! [Sendable?]) } else { return Constant(value) } @@ -33,7 +37,7 @@ enum Helper { return exprMap } - static func map(_ elements: [String: Sendable]) -> FunctionExpr { + static func map(_ elements: [String: Sendable?]) -> FunctionExpr { var result: [Expr] = [] for (key, value) in elements { result.append(Constant(key)) @@ -42,10 +46,37 @@ enum Helper { return FunctionExpr("map", result) } - static func array(_ elements: [Sendable]) -> FunctionExpr { + static func array(_ elements: [Sendable?]) -> FunctionExpr { let transformedElements = elements.map { element in sendableToExpr(element) } return FunctionExpr("array", transformedElements) } + + // This function is used to convert Swift type into Objective-C type. + static func sendableToAnyObjectForRawStage(_ value: Sendable?) -> AnyObject { + guard let value = value else { + return Constant.nil.bridge + } + + guard !(value is NSNull) else { + return Constant.nil.bridge + } + + if value is Expr { + return (value as! Expr).toBridge() + } else if value is AggregateFunction { + return (value as! AggregateFunction).toBridge() + } else if value is [String: Sendable?] { + let mappedValue: [String: Sendable?] = (value as! [String: Sendable?]).mapValues { + if $0 is AggregateFunction { + return ($0 as! AggregateFunction).toBridge() + } + return sendableToExpr($0).toBridge() + } + return mappedValue as NSDictionary + } else { + return Constant(value).bridge + } + } } diff --git a/Firestore/Swift/Source/SwiftAPI/Pipeline/Aggregation/AggregateFunction.swift b/Firestore/Swift/Source/SwiftAPI/Pipeline/Aggregation/AggregateFunction.swift index ed7c25bd129..6d7e05098a9 100644 --- a/Firestore/Swift/Source/SwiftAPI/Pipeline/Aggregation/AggregateFunction.swift +++ b/Firestore/Swift/Source/SwiftAPI/Pipeline/Aggregation/AggregateFunction.swift @@ -12,6 +12,12 @@ // See the License for the specific language governing permissions and // limitations under the License. +extension AggregateFunction { + func toBridge() -> AggregateFunctionBridge { + return (self as AggregateBridgeWrapper).bridge + } +} + public class AggregateFunction: AggregateBridgeWrapper, @unchecked Sendable { let bridge: AggregateFunctionBridge diff --git a/Firestore/Swift/Source/SwiftAPI/Pipeline/Expr/ArrayExpression.swift b/Firestore/Swift/Source/SwiftAPI/Pipeline/Expr/ArrayExpression.swift new file mode 100644 index 00000000000..e1f5d749c5f --- /dev/null +++ b/Firestore/Swift/Source/SwiftAPI/Pipeline/Expr/ArrayExpression.swift @@ -0,0 +1,24 @@ +// Copyright 2025 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. + +public class ArrayExpression: FunctionExpr, @unchecked Sendable { + var result: [Expr] = [] + public init(_ elements: [Sendable]) { + for element in elements { + result.append(Helper.sendableToExpr(element)) + } + + super.init("array", result) + } +} diff --git a/Firestore/Swift/Source/SwiftAPI/Pipeline/Expr/Constant.swift b/Firestore/Swift/Source/SwiftAPI/Pipeline/Expr/Constant.swift index 0d4f30fe463..bfb958b468c 100644 --- a/Firestore/Swift/Source/SwiftAPI/Pipeline/Expr/Constant.swift +++ b/Firestore/Swift/Source/SwiftAPI/Pipeline/Expr/Constant.swift @@ -48,6 +48,11 @@ public struct Constant: Expr, BridgeWrapper, @unchecked Sendable { self.init(value as Any) } + // Initializer for Bytes + public init(_ value: [UInt8]) { + self.init(value as Any) + } + // Initializer for GeoPoint values public init(_ value: GeoPoint) { self.init(value as Any) diff --git a/Firestore/Swift/Source/SwiftAPI/Pipeline/Expr/FunctionExpr/BooleanExpr.swift b/Firestore/Swift/Source/SwiftAPI/Pipeline/Expr/FunctionExpr/BooleanExpr.swift index 9826d1698c0..8b4bfe23b80 100644 --- a/Firestore/Swift/Source/SwiftAPI/Pipeline/Expr/FunctionExpr/BooleanExpr.swift +++ b/Firestore/Swift/Source/SwiftAPI/Pipeline/Expr/FunctionExpr/BooleanExpr.swift @@ -17,6 +17,10 @@ public class BooleanExpr: FunctionExpr, @unchecked Sendable { super.init(functionName, agrs) } + public func countIf() -> AggregateFunction { + return AggregateFunction("count_if", [self]) + } + public static func && (lhs: BooleanExpr, rhs: @autoclosure () throws -> BooleanExpr) rethrows -> BooleanExpr { try BooleanExpr("and", [lhs, rhs()]) @@ -27,6 +31,11 @@ public class BooleanExpr: FunctionExpr, @unchecked Sendable { try BooleanExpr("or", [lhs, rhs()]) } + public static func ^ (lhs: BooleanExpr, + rhs: @autoclosure () throws -> BooleanExpr) rethrows -> BooleanExpr { + try BooleanExpr("xor", [lhs, rhs()]) + } + public static prefix func ! (lhs: BooleanExpr) -> BooleanExpr { return BooleanExpr("not", [lhs]) } diff --git a/Firestore/Swift/Source/SwiftAPI/Pipeline/Expr/MapExpression.swift b/Firestore/Swift/Source/SwiftAPI/Pipeline/Expr/MapExpression.swift new file mode 100644 index 00000000000..93d9bb4859b --- /dev/null +++ b/Firestore/Swift/Source/SwiftAPI/Pipeline/Expr/MapExpression.swift @@ -0,0 +1,25 @@ +// Copyright 2025 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. + +public class MapExpression: FunctionExpr, @unchecked Sendable { + var result: [Expr] = [] + public init(_ elements: [String: Sendable]) { + for element in elements { + result.append(Constant(element.key)) + result.append(Helper.sendableToExpr(element.value)) + } + + super.init("map", result) + } +} diff --git a/Firestore/Swift/Source/SwiftAPI/Pipeline/Pipeline.swift b/Firestore/Swift/Source/SwiftAPI/Pipeline/Pipeline.swift index cb839239994..6c2a6e34053 100644 --- a/Firestore/Swift/Source/SwiftAPI/Pipeline/Pipeline.swift +++ b/Firestore/Swift/Source/SwiftAPI/Pipeline/Pipeline.swift @@ -246,6 +246,13 @@ public struct Pipeline: @unchecked Sendable { ) } + public func select(_ selections: [Selectable]) -> Pipeline { + return Pipeline( + stages: stages + [Select(selections: selections)], + db: db + ) + } + /// Filters documents from previous stages, including only those matching the specified /// `BooleanExpr`. /// @@ -712,7 +719,7 @@ public struct Pipeline: @unchecked Sendable { /// - params: An array of ordered, `Sendable` parameters for the stage. /// - options: Optional dictionary of named, `Sendable` parameters. /// - Returns: A new `Pipeline` object with this stage appended. - public func rawStage(name: String, params: [Sendable], + public func rawStage(name: String, params: [Sendable?], options: [String: Sendable]? = nil) -> Pipeline { return Pipeline( stages: stages + [RawStage(name: name, params: params, options: options)], diff --git a/Firestore/Swift/Source/SwiftAPI/Pipeline/PipelineResult.swift b/Firestore/Swift/Source/SwiftAPI/Pipeline/PipelineResult.swift index 6e1d892f3cb..e5728d44409 100644 --- a/Firestore/Swift/Source/SwiftAPI/Pipeline/PipelineResult.swift +++ b/Firestore/Swift/Source/SwiftAPI/Pipeline/PipelineResult.swift @@ -45,7 +45,7 @@ public struct PipelineResult: @unchecked Sendable { public let updateTime: Timestamp? /// Retrieves all fields in the result as a dictionary. - public let data: [String: Sendable] + public let data: [String: Sendable?] /// Retrieves the field specified by `fieldPath`. /// - Parameter fieldPath: The field path (e.g., "foo" or "foo.bar"). diff --git a/Firestore/Swift/Source/SwiftAPI/Stages.swift b/Firestore/Swift/Source/SwiftAPI/Stages.swift index 13079a3148b..9ecab6945f4 100644 --- a/Firestore/Swift/Source/SwiftAPI/Stages.swift +++ b/Firestore/Swift/Source/SwiftAPI/Stages.swift @@ -327,15 +327,20 @@ class Union: Stage { class Unnest: Stage { let name: String = "unnest" let bridge: StageBridge - private var field: Selectable + private var alias: Expr + private var field: Expr private var indexField: String? init(field: Selectable, indexField: String? = nil) { - self.field = field + let seletable = field as! SelectableWrapper + self.field = seletable.expr + alias = Field(seletable.alias) self.indexField = indexField + bridge = UnnestStageBridge( - field: Helper.sendableToExpr(field).toBridge(), - indexField: indexField + field: self.field.toBridge(), + alias: alias.toBridge(), + indexField: indexField.map { Field($0).toBridge() } ?? nil ) } } @@ -344,14 +349,14 @@ class Unnest: Stage { class RawStage: Stage { let name: String let bridge: StageBridge - private var params: [Sendable] + private var params: [Sendable?] private var options: [String: Sendable]? - init(name: String, params: [Sendable], options: [String: Sendable]? = nil) { + init(name: String, params: [Sendable?], options: [String: Sendable]? = nil) { self.name = name self.params = params self.options = options - let bridgeParams = params.map { Helper.sendableToExpr($0).toBridge() } + let bridgeParams = params.map { Helper.sendableToAnyObjectForRawStage($0) } let bridgeOptions = options?.mapValues { Helper.sendableToExpr($0).toBridge() } bridge = RawStageBridge(name: name, params: bridgeParams, options: bridgeOptions) } diff --git a/Firestore/Swift/Tests/Integration/PipelineTests.swift b/Firestore/Swift/Tests/Integration/PipelineTests.swift index 9816716a1e9..cf522b9e1f1 100644 --- a/Firestore/Swift/Tests/Integration/PipelineTests.swift +++ b/Firestore/Swift/Tests/Integration/PipelineTests.swift @@ -14,12 +14,12 @@ * limitations under the License. */ -import FirebaseCore // For FirebaseApp management +import FirebaseCore import FirebaseFirestore import Foundation -import XCTest // For XCTFail, XCTAssertEqual etc. +import XCTest -private let bookDocs: [String: [String: Any]] = [ +private let bookDocs: [String: [String: Sendable]] = [ "book1": [ "title": "The Hitchhiker's Guide to the Galaxy", "author": "Douglas Adams", @@ -125,42 +125,6 @@ private let bookDocs: [String: [String: Any]] = [ ], ] -func expectResults(_ snapshot: PipelineSnapshot, - expectedCount: Int, - file: StaticString = #file, - line: UInt = #line) { - XCTAssertEqual( - snapshot.results.count, - expectedCount, - "Snapshot results count mismatch", - file: file, - line: line - ) -} - -func expectResults(_ snapshot: PipelineSnapshot, - expectedIDs: [String], - file: StaticString = #file, - line: UInt = #line) { - let results = snapshot.results - XCTAssertEqual( - results.count, - expectedIDs.count, - "Snapshot document IDs count mismatch. Expected \(expectedIDs.count), got \(results.count). Actual IDs: \(results.map { $0.id })", - file: file, - line: line - ) - - let actualIDs = results.map { $0.id! }.sorted() - XCTAssertEqual( - actualIDs, - expectedIDs.sorted(), - "Snapshot document IDs mismatch. Expected (sorted): \(expectedIDs.sorted()), got (sorted): \(actualIDs)", - file: file, - line: line - ) -} - @available(iOS 13, tvOS 13, macOS 10.15, macCatalyst 13, watchOS 7, *) class PipelineIntegrationTests: FSTIntegrationTestCase { override func setUp() { @@ -180,7 +144,7 @@ class PipelineIntegrationTests: FSTIntegrationTestCase { .limit(0) .execute() - expectResults(snapshot, expectedCount: 0) + TestHelper.compare(pipelineSnapshot: snapshot, expectedCount: 0) } func testFullResults() async throws { @@ -194,15 +158,10 @@ class PipelineIntegrationTests: FSTIntegrationTestCase { .collection(collRef.path) .execute() - // expectResults(snapshot, expectedCount: 10) // This is implicitly checked by expectedIDs - // version - expectResults( - snapshot, - expectedIDs: [ - "book1", "book10", "book2", "book3", "book4", - "book5", "book6", "book7", "book8", "book9", - ] - ) + TestHelper.compare(pipelineSnapshot: snapshot, expectedIDs: [ + "book1", "book10", "book2", "book3", "book4", + "book5", "book6", "book7", "book8", "book9", + ], enforceOrder: false) } func testReturnsExecutionTime() async throws { @@ -221,13 +180,13 @@ class PipelineIntegrationTests: FSTIntegrationTestCase { func testReturnsExecutionTimeForEmptyQuery() async throws { let collRef = - collectionRef(withDocuments: bookDocs) // Using bookDocs is fine, limit(0) makes it empty + collectionRef(withDocuments: bookDocs) let db = collRef.firestore let pipeline = db.pipeline().collection(collRef.path).limit(0) let snapshot = try await pipeline.execute() - expectResults(snapshot, expectedCount: 0) + TestHelper.compare(pipelineSnapshot: snapshot, expectedCount: 0) let executionTimeValue = snapshot.executionTime.dateValue().timeIntervalSince1970 XCTAssertGreaterThan(executionTimeValue, 0, "Execution time should be positive and not zero") @@ -351,7 +310,7 @@ class PipelineIntegrationTests: FSTIntegrationTestCase { let pipeline = db.pipeline().collection(collRef) let snapshot = try await pipeline.execute() - expectResults(snapshot, expectedCount: bookDocs.count) + TestHelper.compare(pipelineSnapshot: snapshot, expectedCount: bookDocs.count) } func testSupportsListOfDocumentReferencesAsSource() async throws { @@ -366,7 +325,12 @@ class PipelineIntegrationTests: FSTIntegrationTestCase { let pipeline = db.pipeline().documents(docRefs) let snapshot = try await pipeline.execute() - expectResults(snapshot, expectedIDs: ["book1", "book2", "book3"]) + TestHelper + .compare( + pipelineSnapshot: snapshot, + expectedIDs: ["book1", "book2", "book3"], + enforceOrder: false + ) } func testSupportsListOfDocumentPathsAsSource() async throws { @@ -381,11 +345,16 @@ class PipelineIntegrationTests: FSTIntegrationTestCase { let pipeline = db.pipeline().documents(docPaths) let snapshot = try await pipeline.execute() - expectResults(snapshot, expectedIDs: ["book1", "book2", "book3"]) + TestHelper + .compare( + pipelineSnapshot: snapshot, + expectedIDs: ["book1", "book2", "book3"], + enforceOrder: false + ) } func testRejectsCollectionReferenceFromAnotherDB() async throws { - let db1 = firestore() // Primary DB + let db1 = firestore() let db2 = Firestore.firestore(app: db1.app, database: "db2") @@ -397,7 +366,7 @@ class PipelineIntegrationTests: FSTIntegrationTestCase { } func testRejectsDocumentReferenceFromAnotherDB() async throws { - let db1 = firestore() // Primary DB + let db1 = firestore() let db2 = Firestore.firestore(app: db1.app, database: "db2") @@ -432,7 +401,12 @@ class PipelineIntegrationTests: FSTIntegrationTestCase { // Assert that only the two documents from the targeted subCollectionId are fetched, in the // correct order. - expectResults(snapshot, expectedIDs: [doc1Ref.documentID, doc2Ref.documentID]) + TestHelper + .compare( + pipelineSnapshot: snapshot, + expectedIDs: [doc1Ref.documentID, doc2Ref.documentID], + enforceOrder: true + ) } func testSupportsDatabaseAsSource() async throws { @@ -484,9 +458,1054 @@ class PipelineIntegrationTests: FSTIntegrationTestCase { "Should fetch the three documents with the correct randomId" ) // Order should be docE (order 0), docA (order 1), docB (order 2) - expectResults( - snapshot, - expectedIDs: [subSubCollDocRef.documentID, collADocRef.documentID, collBDocRef.documentID] + TestHelper + .compare( + pipelineSnapshot: snapshot, + expectedIDs: [subSubCollDocRef.documentID, collADocRef.documentID, collBDocRef.documentID], + enforceOrder: true + ) + } + + func testAcceptsAndReturnsAllSupportedDataTypes() async throws { + let db = firestore() + let randomCol = collectionRef() // Ensure a unique collection for the test + + // Add a dummy document to the collection. + // A pipeline query with .select against an empty collection might not behave as expected. + try await randomCol.document("dummyDoc").setData(["field": "value"]) + + let refDate = Date(timeIntervalSince1970: 1_678_886_400) + let refTimestamp = Timestamp(date: refDate) + + let constantsFirst: [Selectable] = [ + Constant(1).as("number"), + Constant("a string").as("string"), + Constant(true).as("boolean"), + Constant.nil.as("nil"), + Constant(GeoPoint(latitude: 0.1, longitude: 0.2)).as("geoPoint"), + Constant(refTimestamp).as("timestamp"), + Constant(refDate).as("date"), // Firestore will convert this to a Timestamp + Constant([1, 2, 3, 4, 5, 6, 7, 0] as [UInt8]).as("bytes"), + Constant(db.document("foo/bar")).as("documentReference"), + Constant(VectorValue([1, 2, 3])).as("vectorValue"), + Constant([1, 2, 3]).as("arrayValue"), // Treated as an array of numbers + ] + + let constantsSecond: [Selectable] = [ + MapExpression([ + "number": 1, + "string": "a string", + "boolean": true, + "nil": Constant.nil, + "geoPoint": GeoPoint(latitude: 0.1, longitude: 0.2), + "timestamp": refTimestamp, + "date": refDate, + "uint8Array": Data([1, 2, 3, 4, 5, 6, 7, 0]), + "documentReference": Constant(db.document("foo/bar")), + "vectorValue": VectorValue([1, 2, 3]), + "map": [ + "number": 2, + "string": "b string", + ], + "array": [1, "c string"], + ]).as("map"), + ArrayExpression([ + 1000, + "another string", + false, + Constant.nil, + GeoPoint(latitude: 10.1, longitude: 20.2), + Timestamp(date: Date(timeIntervalSince1970: 1_700_000_000)), // Different timestamp + Date(timeIntervalSince1970: 1_700_000_000), // Different date + [11, 22, 33] as [UInt8], + db.document("another/doc"), + VectorValue([7, 8, 9]), + [ + "nestedInArrayMapKey": "value", + "anotherNestedKey": refTimestamp, + ], + [2000, "deep nested array string"], + ]).as("array"), + ] + + let expectedResultsMap: [String: Sendable?] = [ + "number": 1, + "string": "a string", + "boolean": true, + "nil": nil, + "geoPoint": GeoPoint(latitude: 0.1, longitude: 0.2), + "timestamp": refTimestamp, + "date": refTimestamp, // Dates are converted to Timestamps + "bytes": [1, 2, 3, 4, 5, 6, 7, 0] as [UInt8], + "documentReference": db.document("foo/bar"), + "vectorValue": VectorValue([1, 2, 3]), + "arrayValue": [1, 2, 3], + "map": [ + "number": 1, + "string": "a string", + "boolean": true, + "nil": nil, + "geoPoint": GeoPoint(latitude: 0.1, longitude: 0.2), + "timestamp": refTimestamp, + "date": refTimestamp, + "uint8Array": Data([1, 2, 3, 4, 5, 6, 7, 0]), + "documentReference": db.document("foo/bar"), + "vectorValue": VectorValue([1, 2, 3]), + "map": [ + "number": 2, + "string": "b string", + ], + "array": [1, "c string"], + ], + "array": [ + 1000, + "another string", + false, + nil, + GeoPoint(latitude: 10.1, longitude: 20.2), + Timestamp(date: Date(timeIntervalSince1970: 1_700_000_000)), + Timestamp(date: Date(timeIntervalSince1970: 1_700_000_000)), // Dates are converted + [11, 22, 33] as [UInt8], + db.document("another/doc"), + VectorValue([7, 8, 9]), + [ + "nestedInArrayMapKey": "value", + "anotherNestedKey": refTimestamp, + ], + [2000, "deep nested array string"], + ], + ] + + let pipeline = db.pipeline() + .collection(randomCol.path) + .limit(1) + .select( + constantsFirst + constantsSecond + ) + let snapshot = try await pipeline.execute() + + TestHelper.compare(pipelineResult: snapshot.results.first!, expected: expectedResultsMap) + } + + func testAcceptsAndReturnsNil() async throws { + let db = firestore() + let randomCol = collectionRef() // Ensure a unique collection for the test + + // Add a dummy document to the collection. + // A pipeline query with .select against an empty collection might not behave as expected. + try await randomCol.document("dummyDoc").setData(["field": "value"]) + + let refDate = Date(timeIntervalSince1970: 1_678_886_400) + let refTimestamp = Timestamp(date: refDate) + + let constantsFirst: [Selectable] = [ + Constant.nil.as("nil"), + ] + + let expectedResultsMap: [String: Sendable?] = [ + "nil": nil, + ] + + let pipeline = db.pipeline() + .collection(randomCol.path) + .limit(1) + .select( + constantsFirst + ) + let snapshot = try await pipeline.execute() + + XCTAssertEqual(snapshot.results.count, 1) + TestHelper.compare(pipelineResult: snapshot.results.first!, expected: expectedResultsMap) + } + + func testConvertsArraysAndPlainObjectsToFunctionValues() async throws { + let collRef = collectionRef(withDocuments: bookDocs) // Uses existing bookDocs + let db = collRef.firestore + + // Expected data for "The Lord of the Rings" + let expectedTitle = "The Lord of the Rings" + let expectedAuthor = "J.R.R. Tolkien" + let expectedGenre = "Fantasy" + let expectedPublished = 1954 + let expectedRating = 4.7 + let expectedTags = ["adventure", "magic", "epic"] + let expectedAwards: [String: Sendable] = ["hugo": false, "nebula": false] + + let metadataArrayElements: [Sendable] = [ + 1, + 2, + expectedGenre, + expectedRating * 10, + [expectedTitle], + ["published": expectedPublished], + ] + + let metadataMapElements: [String: Sendable] = [ + "genre": expectedGenre, + "rating": expectedRating * 10, + "nestedArray": [expectedTitle], + "nestedMap": ["published": expectedPublished], + ] + + let pipeline = db.pipeline() + .collection(collRef.path) + .sort(Field("rating").descending()) + .limit(1) // This should pick "The Lord of the Rings" (rating 4.7) + .select( + Field("title"), + Field("author"), + Field("genre"), + Field("rating"), + Field("published"), + Field("tags"), + Field("awards") + ) + .addFields( + ArrayExpression([ + 1, + 2, + Field("genre"), + Field("rating").multiply(10), + ArrayExpression([Field("title")]), + MapExpression(["published": Field("published")]), + ]).as("metadataArray"), + MapExpression([ + "genre": Field("genre"), + "rating": Field("rating").multiply(10), + "nestedArray": ArrayExpression([Field("title")]), + "nestedMap": MapExpression(["published": Field("published")]), + ]).as("metadata") + ) + .where( + Field("metadataArray").eq(metadataArrayElements) && + Field("metadata").eq(metadataMapElements) + ) + + let snapshot = try await pipeline.execute() + + XCTAssertEqual(snapshot.results.count, 1, "Should retrieve one document") + + if let resultDoc = snapshot.results.first { + let expectedFullDoc: [String: Sendable?] = [ + "title": expectedTitle, + "author": expectedAuthor, + "genre": expectedGenre, + "published": expectedPublished, + "rating": expectedRating, + "tags": expectedTags, + "awards": expectedAwards, + "metadataArray": metadataArrayElements, + "metadata": metadataMapElements, + ] + + TestHelper.compare(pipelineResult: resultDoc, expected: expectedFullDoc) + } else { + XCTFail("No document retrieved") + } + } + + func testSupportsAggregate() async throws { + let collRef = collectionRef(withDocuments: bookDocs) + let db = collRef.firestore + + var pipeline = db.pipeline() + .collection(collRef.path) + .aggregate(CountAll().as("count")) + var snapshot = try await pipeline.execute() + + XCTAssertEqual(snapshot.results.count, 1, "Count all should return a single aggregate document") + if let result = snapshot.results.first { + TestHelper.compare(pipelineResult: result, expected: ["count": bookDocs.count]) + } else { + XCTFail("No result for count all aggregation") + } + + pipeline = db.pipeline() + .collection(collRef.path) + .where(Field("genre").eq("Science Fiction")) + .aggregate( + CountAll().as("count"), + Field("rating").avg().as("avgRating"), + Field("rating").maximum().as("maxRating") + ) + snapshot = try await pipeline.execute() + + XCTAssertEqual(snapshot.results.count, 1, "Filtered aggregate should return a single document") + if let result = snapshot.results.first { + let expectedAggValues: [String: Sendable] = [ + "count": 2, + "avgRating": 4.4, + "maxRating": 4.6, + ] + TestHelper.compare(pipelineResult: result, expected: expectedAggValues) + } else { + XCTFail("No result for filtered aggregation") + } + } + + func testRejectsGroupsWithoutAccumulators() async throws { + let collRef = collectionRef(withDocuments: bookDocs) + let db = collRef.firestore + + let dummyDocRef = collRef.document("dummyDocForRejectTest") + try await dummyDocRef.setData(["field": "value"]) + + do { + _ = try await db.pipeline() + .collection(collRef.path) + .where(Field("published").lt(1900)) + .aggregate([], groups: ["genre"]) + .execute() + + XCTFail( + "The pipeline should have thrown an error for groups without accumulators, but it did not." + ) + + } catch { + XCTAssert(true, "Successfully caught expected error for groups without accumulators.") + } + } + + func testReturnsGroupAndAccumulateResults() async throws { + let collRef = collectionRef(withDocuments: bookDocs) + let db = collRef.firestore + + let pipeline = db.pipeline() + .collection(collRef.path) + .where(Field("published").lt(1984)) + .aggregate( + [Field("rating").avg().as("avgRating")], + groups: ["genre"] + ) + .where(Field("avgRating").gt(4.3)) + .sort(Field("avgRating").descending()) + + let snapshot = try await pipeline.execute() + + XCTAssertEqual( + snapshot.results.count, + 3, + "Should return 3 documents after grouping and filtering." ) + + let expectedResultsArray: [[String: Sendable]] = [ + ["avgRating": 4.7, "genre": "Fantasy"], + ["avgRating": 4.5, "genre": "Romance"], + ["avgRating": 4.4, "genre": "Science Fiction"], + ] + + TestHelper + .compare(pipelineSnapshot: snapshot, expected: expectedResultsArray, enforceOrder: true) + } + + func testReturnsMinMaxCountAndCountAllAccumulations() async throws { + let collRef = collectionRef(withDocuments: bookDocs) + let db = collRef.firestore + + let pipeline = db.pipeline() + .collection(collRef.path) + .aggregate( + Field("cost").count().as("booksWithCost"), + CountAll().as("count"), + Field("rating").maximum().as("maxRating"), + Field("published").minimum().as("minPublished") + ) + + let snapshot = try await pipeline.execute() + + XCTAssertEqual(snapshot.results.count, 1, "Aggregate should return a single document") + + let expectedValues: [String: Sendable] = [ + "booksWithCost": 1, + "count": bookDocs.count, + "maxRating": 4.7, + "minPublished": 1813, + ] + + if let result = snapshot.results.first { + TestHelper.compare(pipelineResult: result, expected: expectedValues) + } else { + XCTFail("No result for min/max/count/countAll aggregation") + } + } + + func testReturnsCountIfAccumulation() async throws { + let collRef = collectionRef(withDocuments: bookDocs) + let db = collRef.firestore + + let expectedCount = 3 + let expectedResults: [String: Sendable] = ["count": expectedCount] + let condition = Field("rating").gt(4.3) + + var pipeline = db.pipeline() + .collection(collRef.path) + .aggregate(condition.countIf().as("count")) + var snapshot = try await pipeline.execute() + + XCTAssertEqual(snapshot.results.count, 1, "countIf aggregate should return a single document") + if let result = snapshot.results.first { + TestHelper.compare(pipelineResult: result, expected: expectedResults) + } else { + XCTFail("No result for countIf aggregation") + } + } + + func testDistinctStage() async throws { + let collRef = collectionRef(withDocuments: bookDocs) + let db = collRef.firestore + + let pipeline = db.pipeline() + .collection(collRef.path) + .distinct(Field("genre"), Field("author")) + .sort(Field("genre").ascending(), Field("author").ascending()) + + let snapshot = try await pipeline.execute() + + let expectedResults: [[String: Sendable]] = [ + ["genre": "Dystopian", "author": "George Orwell"], + ["genre": "Dystopian", "author": "Margaret Atwood"], + ["genre": "Fantasy", "author": "J.R.R. Tolkien"], + ["genre": "Magical Realism", "author": "Gabriel García Márquez"], + ["genre": "Modernist", "author": "F. Scott Fitzgerald"], + ["genre": "Psychological Thriller", "author": "Fyodor Dostoevsky"], + ["genre": "Romance", "author": "Jane Austen"], + ["genre": "Science Fiction", "author": "Douglas Adams"], + ["genre": "Science Fiction", "author": "Frank Herbert"], + ["genre": "Southern Gothic", "author": "Harper Lee"], + ] + + XCTAssertEqual(snapshot.results.count, expectedResults.count, "Snapshot results count mismatch") + + TestHelper.compare(pipelineSnapshot: snapshot, expected: expectedResults, enforceOrder: true) + } + + func testSelectStage() async throws { + let collRef = collectionRef(withDocuments: bookDocs) + let db = collRef.firestore + + let pipeline = db.pipeline() + .collection(collRef.path) + .select(Field("title"), Field("author")) + .sort(Field("author").ascending()) + + let snapshot = try await pipeline.execute() + + let expectedResults: [[String: Sendable]] = [ + ["title": "The Hitchhiker's Guide to the Galaxy", "author": "Douglas Adams"], + ["title": "The Great Gatsby", "author": "F. Scott Fitzgerald"], + ["title": "Dune", "author": "Frank Herbert"], + ["title": "Crime and Punishment", "author": "Fyodor Dostoevsky"], + ["title": "One Hundred Years of Solitude", "author": "Gabriel García Márquez"], + ["title": "1984", "author": "George Orwell"], + ["title": "To Kill a Mockingbird", "author": "Harper Lee"], + ["title": "The Lord of the Rings", "author": "J.R.R. Tolkien"], + ["title": "Pride and Prejudice", "author": "Jane Austen"], + ["title": "The Handmaid's Tale", "author": "Margaret Atwood"], + ] + + XCTAssertEqual( + snapshot.results.count, + expectedResults.count, + "Snapshot results count mismatch for select stage." + ) + + TestHelper.compare(pipelineSnapshot: snapshot, expected: expectedResults, enforceOrder: true) + } + + func testAddFieldStage() async throws { + let collRef = collectionRef(withDocuments: bookDocs) + let db = collRef.firestore + + let pipeline = db.pipeline() + .collection(collRef.path) + .select(Field("title"), Field("author")) + .addFields(Constant("bar").as("foo")) + .sort(Field("author").ascending()) + + let snapshot = try await pipeline.execute() + + let expectedResults: [[String: Sendable]] = [ + ["title": "The Hitchhiker's Guide to the Galaxy", "author": "Douglas Adams", "foo": "bar"], + ["title": "The Great Gatsby", "author": "F. Scott Fitzgerald", "foo": "bar"], + ["title": "Dune", "author": "Frank Herbert", "foo": "bar"], + ["title": "Crime and Punishment", "author": "Fyodor Dostoevsky", "foo": "bar"], + ["title": "One Hundred Years of Solitude", "author": "Gabriel García Márquez", "foo": "bar"], + ["title": "1984", "author": "George Orwell", "foo": "bar"], + ["title": "To Kill a Mockingbird", "author": "Harper Lee", "foo": "bar"], + ["title": "The Lord of the Rings", "author": "J.R.R. Tolkien", "foo": "bar"], + ["title": "Pride and Prejudice", "author": "Jane Austen", "foo": "bar"], + ["title": "The Handmaid's Tale", "author": "Margaret Atwood", "foo": "bar"], + ] + + XCTAssertEqual( + snapshot.results.count, + expectedResults.count, + "Snapshot results count mismatch for addField stage." + ) + + TestHelper.compare(pipelineSnapshot: snapshot, expected: expectedResults, enforceOrder: true) + } + + func testRemoveFieldsStage() async throws { + let collRef = collectionRef(withDocuments: bookDocs) + let db = collRef.firestore + + let pipeline = db.pipeline() + .collection(collRef.path) + .select(Field("title"), Field("author")) + .sort(Field("author").ascending()) // Sort before removing the 'author' field + .removeFields(Field("author")) + + let snapshot = try await pipeline.execute() + + // Expected results are sorted by author, but only contain the title + let expectedResults: [[String: Sendable]] = [ + ["title": "The Hitchhiker's Guide to the Galaxy"], // Douglas Adams + ["title": "The Great Gatsby"], // F. Scott Fitzgerald + ["title": "Dune"], // Frank Herbert + ["title": "Crime and Punishment"], // Fyodor Dostoevsky + ["title": "One Hundred Years of Solitude"], // Gabriel García Márquez + ["title": "1984"], // George Orwell + ["title": "To Kill a Mockingbird"], // Harper Lee + ["title": "The Lord of the Rings"], // J.R.R. Tolkien + ["title": "Pride and Prejudice"], // Jane Austen + ["title": "The Handmaid's Tale"], // Margaret Atwood + ] + + XCTAssertEqual( + snapshot.results.count, + expectedResults.count, + "Snapshot results count mismatch for removeFields stage." + ) + + TestHelper.compare(pipelineSnapshot: snapshot, expected: expectedResults, enforceOrder: true) + } + + func testWhereStageWithAndConditions() async throws { + let collRef = collectionRef(withDocuments: bookDocs) + let db = collRef.firestore + + // Test Case 1: Two AND conditions + var pipeline = db.pipeline() + .collection(collRef.path) + .where(Field("rating").gt(4.5) + && Field("genre").eqAny(["Science Fiction", "Romance", "Fantasy"])) + var snapshot = try await pipeline.execute() + var expectedIDs = ["book10", "book4"] // Dune (SF, 4.6), LOTR (Fantasy, 4.7) + TestHelper.compare(pipelineSnapshot: snapshot, expectedIDs: expectedIDs, enforceOrder: false) + + // Test Case 2: Three AND conditions + pipeline = db.pipeline() + .collection(collRef.path) + .where( + Field("rating").gt(4.5) + && Field("genre").eqAny(["Science Fiction", "Romance", "Fantasy"]) + && Field("published").lt(1965) + ) + snapshot = try await pipeline.execute() + expectedIDs = ["book4"] // LOTR (Fantasy, 4.7, published 1954) + TestHelper.compare(pipelineSnapshot: snapshot, expectedIDs: expectedIDs, enforceOrder: false) + } + + func testWhereStageWithOrAndXorConditions() async throws { + let collRef = collectionRef(withDocuments: bookDocs) + let db = collRef.firestore + + // Test Case 1: OR conditions + var pipeline = db.pipeline() + .collection(collRef.path) + .where( + Field("genre").eq("Romance") + || Field("genre").eq("Dystopian") + || Field("genre").eq("Fantasy") + ) + .select(Field("title")) + .sort(Field("title").ascending()) + + var snapshot = try await pipeline.execute() + var expectedResults: [[String: Sendable]] = [ + ["title": "1984"], // Dystopian + ["title": "Pride and Prejudice"], // Romance + ["title": "The Handmaid's Tale"], // Dystopian + ["title": "The Lord of the Rings"], // Fantasy + ] + + XCTAssertEqual( + snapshot.results.count, + expectedResults.count, + "Snapshot results count mismatch for OR conditions." + ) + TestHelper.compare(pipelineSnapshot: snapshot, expected: expectedResults, enforceOrder: true) + + // Test Case 2: XOR conditions + // XOR is true if an odd number of its arguments are true. + pipeline = db.pipeline() + .collection(collRef.path) + .where( + Field("genre").eq("Romance") // Book2 (T), Book5 (F), Book4 (F), Book8 (F) + ^ Field("genre").eq("Dystopian") // Book2 (F), Book5 (T), Book4 (F), Book8 (T) + ^ Field("genre").eq("Fantasy") // Book2 (F), Book5 (F), Book4 (T), Book8 (F) + ^ Field("published").eq(1949) // Book2 (F), Book5 (F), Book4 (F), Book8 (T) + ) + .select(Field("title")) + .sort(Field("title").ascending()) + + snapshot = try await pipeline.execute() + + expectedResults = [ + ["title": "Pride and Prejudice"], + ["title": "The Handmaid's Tale"], + ["title": "The Lord of the Rings"], + ] + + XCTAssertEqual( + snapshot.results.count, + expectedResults.count, + "Snapshot results count mismatch for XOR conditions." + ) + TestHelper.compare(pipelineSnapshot: snapshot, expected: expectedResults, enforceOrder: true) + } + + func testSortOffsetAndLimitStages() async throws { + let collRef = collectionRef(withDocuments: bookDocs) + let db = collRef.firestore + + let pipeline = db.pipeline() + .collection(collRef.path) + .sort(Field("author").ascending()) + .offset(5) + .limit(3) + .select("title", "author") + + let snapshot = try await pipeline.execute() + + let expectedResults: [[String: Sendable]] = [ + ["title": "1984", "author": "George Orwell"], + ["title": "To Kill a Mockingbird", "author": "Harper Lee"], + ["title": "The Lord of the Rings", "author": "J.R.R. Tolkien"], + ] + TestHelper.compare(pipelineSnapshot: snapshot, expected: expectedResults, enforceOrder: true) + } + + // MARK: - Generic Stage Tests + + func testRawStageSelectFields() async throws { + let collRef = collectionRef(withDocuments: bookDocs) + let db = collRef.firestore + + let expectedSelectedData: [String: Sendable] = [ + "title": "1984", + "metadata": ["author": "George Orwell"], + ] + + let selectParameters: [Sendable] = + [ + [ + "title": Field("title"), + "metadata": ["author": Field("author")], + ], + ] + + let pipeline = db.pipeline() + .collection(collRef.path) + .rawStage(name: "select", params: selectParameters) + .sort(Field("title").ascending()) + .limit(1) + + let snapshot = try await pipeline.execute() + + XCTAssertEqual(snapshot.results.count, 1, "Should retrieve one document") + TestHelper.compare( + pipelineSnapshot: snapshot, + expected: [expectedSelectedData], + enforceOrder: true + ) + } + + func testCanAddFields() async throws { + let collRef = collectionRef(withDocuments: bookDocs) + let db = collRef.firestore + + let pipeline = db.pipeline() + .collection(collRef.path) + .sort(Field("author").ascending()) + .limit(1) + .select("title", "author") + .rawStage( + name: "add_fields", + params: [ + [ + "display": Field("title").strConcat( + Constant(" - "), + Field("author") + ), + ], + ] + ) + + let snapshot = try await pipeline.execute() + + TestHelper.compare( + pipelineSnapshot: snapshot, + expected: [ + [ + "title": "The Hitchhiker's Guide to the Galaxy", + "author": "Douglas Adams", + "display": "The Hitchhiker's Guide to the Galaxy - Douglas Adams", + ], + ], + enforceOrder: false + ) + } + + func testCanPerformDistinctQuery() async throws { + let collRef = collectionRef(withDocuments: bookDocs) + let db = collRef.firestore + + let pipeline = db.pipeline() + .collection(collRef.path) + .select("title", "author", "rating") + .rawStage( + name: "distinct", + params: [ + ["rating": Field("rating")], + ] + ) + .sort(Field("rating").descending()) + + let snapshot = try await pipeline.execute() + + TestHelper.compare( + pipelineSnapshot: snapshot, + expected: [ + ["rating": 4.7], + ["rating": 4.6], + ["rating": 4.5], + ["rating": 4.3], + ["rating": 4.2], + ["rating": 4.1], + ["rating": 4.0], + ], + enforceOrder: true + ) + } + + func testCanPerformAggregateQuery() async throws { + let collRef = collectionRef(withDocuments: bookDocs) + let db = collRef.firestore + + let emptySendableDictionary: [String: Sendable?] = [:] + + let pipeline = db.pipeline() + .collection(collRef.path) + .select("title", "author", "rating") + .rawStage( + name: "aggregate", + params: [ + [ + "averageRating": Field("rating").avg(), + ], + emptySendableDictionary, + ] + ) + + let snapshot = try await pipeline.execute() + + TestHelper.compare( + pipelineSnapshot: snapshot, + expected: [ + [ + "averageRating": 4.3100000000000005, + ], + ], + enforceOrder: true + ) + } + + func testCanFilterWithWhere() async throws { + let collRef = collectionRef(withDocuments: bookDocs) + let db = collRef.firestore + + let pipeline = db.pipeline() + .collection(collRef.path) + .select("title", "author") + .rawStage( + name: "where", + params: [Field("author").eq("Douglas Adams")] + ) + + let snapshot = try await pipeline.execute() + + TestHelper.compare( + pipelineSnapshot: snapshot, + expected: [ + [ + "title": "The Hitchhiker's Guide to the Galaxy", + "author": "Douglas Adams", + ], + ], + enforceOrder: false + ) + } + + func testCanLimitOffsetAndSort() async throws { + let collRef = collectionRef(withDocuments: bookDocs) + let db = collRef.firestore + + let pipeline = db.pipeline() + .collection(collRef.path) + .select("title", "author") + .rawStage( + name: "sort", + params: [ + [ + "direction": "ascending", + "expression": Field("author"), + ], + ] + ) + .rawStage(name: "offset", params: [3]) + .rawStage(name: "limit", params: [1]) + + let snapshot = try await pipeline.execute() + + TestHelper.compare( + pipelineSnapshot: snapshot, + expected: [ + [ + "author": "Fyodor Dostoevsky", + "title": "Crime and Punishment", + ], + ], + enforceOrder: false + ) + } + + // MARK: - Replace Stage Test + + func testReplaceStagePromoteAwardsAndAddFlag() async throws { + let collRef = collectionRef(withDocuments: bookDocs) + let db = collRef.firestore + + let pipeline = db.pipeline() + .collection(collRef.path) + .where(Field("title").eq("The Hitchhiker's Guide to the Galaxy")) + .replace(with: "awards") + + let snapshot = try await pipeline.execute() + + TestHelper.compare(pipelineSnapshot: snapshot, expectedCount: 1) + + let expectedBook1Transformed: [String: Sendable?] = [ + "hugo": true, + "nebula": false, + "others": ["unknown": ["year": 1980]], + ] + + TestHelper + .compare( + pipelineSnapshot: snapshot, + expected: [expectedBook1Transformed], + enforceOrder: false + ) + } + + func testReplaceWithExprResult() async throws { + let collRef = collectionRef(withDocuments: bookDocs) + let db = collRef.firestore + + let pipeline = db.pipeline() + .collection(collRef.path) + .where(Field("title").eq("The Hitchhiker's Guide to the Galaxy")) + .replace(with: + MapExpression([ + "foo": "bar", + "baz": MapExpression([ + "title": Field("title"), + ]), + ])) + + let snapshot = try await pipeline.execute() + + let expectedResults: [String: Sendable?] = [ + "foo": "bar", + "baz": ["title": "The Hitchhiker's Guide to the Galaxy"], + ] + + TestHelper.compare(pipelineSnapshot: snapshot, expected: [expectedResults], enforceOrder: false) + } + + // MARK: - Sample Stage Tests + + func testSampleStageLimit3() async throws { + let collRef = collectionRef(withDocuments: bookDocs) + let db = collRef.firestore + + let pipeline = db.pipeline() + .collection(collRef.path) + .sample(count: 3) + + let snapshot = try await pipeline.execute() + + TestHelper + .compare(pipelineSnapshot: snapshot, expectedCount: 3) + } + + func testSampleStageLimitPercentage60Average() async throws { + let collRef = collectionRef(withDocuments: bookDocs) + let db = collRef.firestore + + var avgSize = 0.0 + let numIterations = 20 + for _ in 0 ..< numIterations { + let snapshot = try await db + .pipeline() + .collection(collRef.path) + .sample(percentage: 0.6) + .execute() + avgSize += Double(snapshot.results.count) + } + avgSize /= Double(numIterations) + XCTAssertEqual(avgSize, 6.0, accuracy: 1.0, "Average size should be close to 6") + } + + // MARK: - Union Stage Test + + func testUnionStageCombineAuthors() async throws { + let collRef = collectionRef(withDocuments: bookDocs) + let db = collRef.firestore + + let pipeline = db.pipeline() + .collection(collRef.path) + .union(db.pipeline() + .collection(collRef.path)) + + let snapshot = try await pipeline.execute() + + let bookSequence = (1 ... 10).map { "book\($0)" } + let repeatedIDs = bookSequence + bookSequence + TestHelper.compare(pipelineSnapshot: snapshot, expectedIDs: repeatedIDs, enforceOrder: false) + } + + func testUnnestStage() async throws { + let collRef = collectionRef(withDocuments: bookDocs) + let db = collRef.firestore + + let pipeline = db.pipeline() + .collection(collRef.path) + .where(Field("title").eq("The Hitchhiker's Guide to the Galaxy")) + .unnest(Field("tags").as("tag"), indexField: "tagsIndex") + .select( + "title", + "author", + "genre", + "published", + "rating", + "tags", + "tag", + "awards", + "nestedField" + ) + + let snapshot = try await pipeline.execute() + + let expectedResults: [[String: Sendable?]] = [ + [ + "title": "The Hitchhiker's Guide to the Galaxy", + "author": "Douglas Adams", + "genre": "Science Fiction", + "published": 1979, + "rating": 4.2, + "tags": ["comedy", "space", "adventure"], + "tag": "comedy", + "awards": ["hugo": true, "nebula": false, "others": ["unknown": ["year": 1980]]], + "nestedField": ["level.1": ["level.2": true]], + ], + [ + "title": "The Hitchhiker's Guide to the Galaxy", + "author": "Douglas Adams", + "genre": "Science Fiction", + "published": 1979, + "rating": 4.2, + "tags": ["comedy", "space", "adventure"], + "tag": "space", + "awards": ["hugo": true, "nebula": false, "others": ["unknown": ["year": 1980]]], + "nestedField": ["level.1": ["level.2": true]], + ], + [ + "title": "The Hitchhiker's Guide to the Galaxy", + "author": "Douglas Adams", + "genre": "Science Fiction", + "published": 1979, + "rating": 4.2, + "tags": ["comedy", "space", "adventure"], + "tag": "adventure", + "awards": ["hugo": true, "nebula": false, "others": ["unknown": ["year": 1980]]], + "nestedField": ["level.1": ["level.2": true]], + ], + ] + + TestHelper.compare(pipelineSnapshot: snapshot, expected: expectedResults, enforceOrder: false) + } + + func testUnnestExpr() async throws { + let collRef = collectionRef(withDocuments: bookDocs) + let db = collRef.firestore + + let pipeline = db.pipeline() + .collection(collRef.path) + .where(Field("title").eq("The Hitchhiker's Guide to the Galaxy")) + .unnest(ArrayExpression([1, 2, 3]).as("copy")) + .select( + "title", + "author", + "genre", + "published", + "rating", + "tags", + "copy", + "awards", + "nestedField" + ) + + let snapshot = try await pipeline.execute() + + let expectedResults: [[String: Sendable?]] = [ + [ + "title": "The Hitchhiker's Guide to the Galaxy", + "author": "Douglas Adams", + "genre": "Science Fiction", + "published": 1979, + "rating": 4.2, + "tags": ["comedy", "space", "adventure"], + "copy": 1, + "awards": ["hugo": true, "nebula": false, "others": ["unknown": ["year": 1980]]], + "nestedField": ["level.1": ["level.2": true]], + ], + [ + "title": "The Hitchhiker's Guide to the Galaxy", + "author": "Douglas Adams", + "genre": "Science Fiction", + "published": 1979, + "rating": 4.2, + "tags": ["comedy", "space", "adventure"], + "copy": 2, + "awards": ["hugo": true, "nebula": false, "others": ["unknown": ["year": 1980]]], + "nestedField": ["level.1": ["level.2": true]], + ], + [ + "title": "The Hitchhiker's Guide to the Galaxy", + "author": "Douglas Adams", + "genre": "Science Fiction", + "published": 1979, + "rating": 4.2, + "tags": ["comedy", "space", "adventure"], + "copy": 3, + "awards": ["hugo": true, "nebula": false, "others": ["unknown": ["year": 1980]]], + "nestedField": ["level.1": ["level.2": true]], + ], + ] + + TestHelper.compare(pipelineSnapshot: snapshot, expected: expectedResults, enforceOrder: false) } } diff --git a/Firestore/Swift/Tests/TestHelper/TestHelper.swift b/Firestore/Swift/Tests/TestHelper/TestHelper.swift new file mode 100644 index 00000000000..e65d3960176 --- /dev/null +++ b/Firestore/Swift/Tests/TestHelper/TestHelper.swift @@ -0,0 +1,227 @@ +/* + * Copyright 2025 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 FirebaseCore +import FirebaseFirestore +import Foundation +import XCTest + +public enum TestHelper { + public static func compare(pipelineSnapshot snapshot: PipelineSnapshot, + expectedCount: Int, + file: StaticString = #file, + line: UInt = #line) { + XCTAssertEqual( + snapshot.results.count, + expectedCount, + "Snapshot results count mismatch", + file: file, + line: line + ) + } + + static func compare(pipelineSnapshot snapshot: PipelineSnapshot, + expectedIDs: [String], + enforceOrder: Bool, + file: StaticString = #file, + line: UInt = #line) { + let results = snapshot.results + XCTAssertEqual( + results.count, + expectedIDs.count, + "Snapshot document IDs count mismatch. Expected \(expectedIDs.count), got \(results.count). Actual IDs: \(results.map { $0.id })", + file: file, + line: line + ) + + if enforceOrder { + let actualIDs = results.map { $0.id! } + XCTAssertEqual( + actualIDs, + expectedIDs, + "Snapshot document IDs mismatch. Expected: \(expectedIDs.sorted()), got: \(actualIDs)", + file: file, + line: line + ) + } else { + let actualIDs = results.map { $0.id! }.sorted() + XCTAssertEqual( + actualIDs, + expectedIDs.sorted(), + "Snapshot document IDs mismatch. Expected (sorted): \(expectedIDs.sorted()), got (sorted): \(actualIDs)", + file: file, + line: line + ) + } + } + + static func compare(pipelineSnapshot snapshot: PipelineSnapshot, + expected: [[String: Sendable?]], + enforceOrder: Bool, + file: StaticString = #file, + line: UInt = #line) { + guard snapshot.results.count == expected.count else { + XCTFail("Mismatch in expected results count and actual results count.") + return + } + + if enforceOrder { + for i in 0 ..< expected.count { + compare(pipelineResult: snapshot.results[i], expected: expected[i]) + } + } else { + let result = snapshot.results.map { $0.data } + XCTAssertTrue(areArraysOfDictionariesEqualRegardlessOfOrder(result, expected), + "PipelineSnapshot mismatch. Expected \(expected), got \(result)") + } + } + + static func compare(pipelineResult result: PipelineResult, + expected: [String: Sendable?], + file: StaticString = #file, + line: UInt = #line) { + XCTAssertTrue(areDictionariesEqual(result.data, expected), + "Document data mismatch. Expected \(expected), got \(result.data)") + } + + // MARK: - Internal helper + + private static func isNilOrNSNull(_ value: Sendable?) -> Bool { + // First, use a `guard` to safely unwrap the optional. + // If it's nil, we can immediately return true. + guard let unwrappedValue = value else { + return true + } + + // If it wasn't nil, we now check if the unwrapped value is the NSNull object. + return unwrappedValue is NSNull + } + + // A custom function to compare two values of type 'Sendable' + private static func areEqual(_ value1: Sendable?, _ value2: Sendable?) -> Bool { + if isNilOrNSNull(value1) || isNilOrNSNull(value2) { + return isNilOrNSNull(value1) && isNilOrNSNull(value2) + } + + switch (value1!, value2!) { + case let (v1 as [String: Sendable?], v2 as [String: Sendable?]): + return areDictionariesEqual(v1, v2) + case let (v1 as [Sendable?], v2 as [Sendable?]): + return areArraysEqual(v1, v2) + case let (v1 as Timestamp, v2 as Timestamp): + return v1 == v2 + case let (v1 as Date, v2 as Timestamp): + // Firestore converts Dates to Timestamps + return Timestamp(date: v1) == v2 + case let (v1 as GeoPoint, v2 as GeoPoint): + return v1.latitude == v2.latitude && v1.longitude == v2.longitude + case let (v1 as DocumentReference, v2 as DocumentReference): + return v1.path == v2.path + case let (v1 as VectorValue, v2 as VectorValue): + return v1.array == v2.array + case let (v1 as Data, v2 as Data): + return v1 == v2 + case let (v1 as Int, v2 as Int): + return v1 == v2 + case let (v1 as Double, v2 as Double): + let doubleEpsilon = 0.000001 + return abs(v1 - v2) <= doubleEpsilon + case let (v1 as Float, v2 as Float): + let floatEpsilon: Float = 0.00001 + return abs(v1 - v2) <= floatEpsilon + case let (v1 as String, v2 as String): + return v1 == v2 + case let (v1 as Bool, v2 as Bool): + return v1 == v2 + case let (v1 as UInt8, v2 as UInt8): + return v1 == v2 + default: + // Fallback for any other types, might need more specific checks + return false + } + } + + // A function to compare two dictionaries + private static func areDictionariesEqual(_ dict1: [String: Sendable?], + _ dict2: [String: Sendable?]) -> Bool { + guard dict1.count == dict2.count else { return false } + + for (key, value1) in dict1 { + guard let value2 = dict2[key], areEqual(value1, value2) else { + XCTFail(""" + Dictionary value mismatch for key: '\(key)' + Expected value: '\(String(describing: value1))' (from dict1) + Actual value: '\(String(describing: dict2[key]))' (from dict2) + Full dict1: \(String(describing: dict1)) + Full dict2: \(String(describing: dict2)) + """) + return false + } + } + return true + } + + private static func areArraysEqual(_ array1: [Sendable?], _ array2: [Sendable?]) -> Bool { + guard array1.count == array2.count else { return false } + + for (index, value1) in array1.enumerated() { + let value2 = array2[index] + if !areEqual(value1, value2) { + XCTFail(""" + Array value mismatch. + Expected array value: '\(String(describing: value1))' + Actual array value: '\(String(describing: value2))' + """) + return false + } + } + return true + } + + private static func areArraysOfDictionariesEqualRegardlessOfOrder(_ array1: [[String: Sendable?]], + _ array2: [[String: Sendable?]]) + -> Bool { + // 1. Check if the arrays have the same number of dictionaries. + guard array1.count == array2.count else { + return false + } + + // Create a mutable copy of array2 to remove matched dictionaries + var mutableArray2 = array2 + + // Iterate through each dictionary in array1 + for dict1 in array1 { + var foundMatch = false + // Try to find an equivalent dictionary in mutableArray2 + if let index = mutableArray2.firstIndex(where: { dict2 in + areDictionariesEqual(dict1, dict2) // Use our deep comparison function + }) { + // If a match is found, remove it from mutableArray2 to handle duplicates + mutableArray2.remove(at: index) + foundMatch = true + } + + // If no match was found for the current dictionary from array1, arrays are not equal + if !foundMatch { + return false + } + } + + // If we've iterated through all of array1 and mutableArray2 is empty, + // it means all dictionaries found a unique match. + return mutableArray2.isEmpty + } +} diff --git a/Firestore/core/src/api/ordering.cc b/Firestore/core/src/api/ordering.cc index 388280b532a..47d5ad6013b 100644 --- a/Firestore/core/src/api/ordering.cc +++ b/Firestore/core/src/api/ordering.cc @@ -30,14 +30,16 @@ google_firestore_v1_Value Ordering::to_proto() const { result.map_value.fields_count = 2; result.map_value.fields = nanopb::MakeArray(2); - result.map_value.fields[0].key = nanopb::MakeBytesArray("expression"); - result.map_value.fields[0].value = expr_->to_proto(); - result.map_value.fields[1].key = nanopb::MakeBytesArray("direction"); + + result.map_value.fields[0].key = nanopb::MakeBytesArray("direction"); google_firestore_v1_Value direction; direction.which_value_type = google_firestore_v1_Value_string_value_tag; direction.string_value = nanopb::MakeBytesArray( this->direction_ == ASCENDING ? "ascending" : "descending"); - result.map_value.fields[1].value = direction; + result.map_value.fields[0].value = direction; + + result.map_value.fields[1].key = nanopb::MakeBytesArray("expression"); + result.map_value.fields[1].value = expr_->to_proto(); return result; } diff --git a/Firestore/core/src/api/stages.cc b/Firestore/core/src/api/stages.cc index b3dfd2c55a8..0c514fe0ee6 100644 --- a/Firestore/core/src/api/stages.cc +++ b/Firestore/core/src/api/stages.cc @@ -306,42 +306,79 @@ google_firestore_v1_Pipeline_Stage RemoveFieldsStage::to_proto() const { return result; } +google_firestore_v1_Value ReplaceWith::ReplaceMode::to_proto() const { + google_firestore_v1_Value result; + result.which_value_type = google_firestore_v1_Value_string_value_tag; + switch (mode_) { + case FULL_REPLACE: + result.string_value = nanopb::MakeBytesArray("full_replace"); + break; + case MERGE_PREFER_NEST: + result.string_value = nanopb::MakeBytesArray("merge_prefer_nest"); + break; + } + return result; +} + google_firestore_v1_Pipeline_Stage ReplaceWith::to_proto() const { google_firestore_v1_Pipeline_Stage result; result.name = nanopb::MakeBytesArray("replace_with"); - result.args_count = 1; - result.args = nanopb::MakeArray(1); + result.args_count = 2; + result.args = nanopb::MakeArray(2); result.args[0] = expr_->to_proto(); + result.args[1] = mode_.to_proto(); + result.options_count = 0; result.options = nullptr; return result; } -ReplaceWith::ReplaceWith(std::shared_ptr expr) : expr_(std::move(expr)) { +ReplaceWith::ReplaceWith(std::shared_ptr expr, ReplaceMode mode) + : expr_(std::move(expr)), mode_(mode) { +} + +google_firestore_v1_Value Sample::SampleMode::to_proto() const { + google_firestore_v1_Value result; + result.which_value_type = google_firestore_v1_Value_string_value_tag; + switch (mode_) { + case DOCUMENTS: + result.string_value = nanopb::MakeBytesArray("documents"); + break; + case PERCENT: + result.string_value = nanopb::MakeBytesArray("percent"); + break; + } + return result; } -Sample::Sample(std::string type, int64_t count, double percentage) - : type_(type), count_(count), percentage_(percentage) { +Sample::Sample(SampleMode mode, int64_t count, double percentage) + : mode_(mode), count_(count), percentage_(percentage) { } google_firestore_v1_Pipeline_Stage Sample::to_proto() const { google_firestore_v1_Pipeline_Stage result; result.name = nanopb::MakeBytesArray("sample"); - result.args_count = 1; - result.args = nanopb::MakeArray(1); - if (type_ == "count") { - result.args[0].which_value_type = - google_firestore_v1_Value_integer_value_tag; - result.args[0].integer_value = count_; - } else { - result.args[0].which_value_type = - google_firestore_v1_Value_double_value_tag; - result.args[0].double_value = percentage_; + result.args_count = 2; + result.args = nanopb::MakeArray(2); + + switch (mode_.mode()) { + case SampleMode::Mode::DOCUMENTS: + result.args[0].which_value_type = + google_firestore_v1_Value_integer_value_tag; + result.args[0].integer_value = count_; + break; + case SampleMode::Mode::PERCENT: + result.args[0].which_value_type = + google_firestore_v1_Value_double_value_tag; + result.args[0].double_value = percentage_; + break; } + result.args[1] = mode_.to_proto(); + result.options_count = 0; result.options = nullptr; return result; @@ -364,27 +401,28 @@ google_firestore_v1_Pipeline_Stage Union::to_proto() const { } Unnest::Unnest(std::shared_ptr field, - absl::optional index_field) - : field_(std::move(field)), index_field_(std::move(index_field)) { + std::shared_ptr alias, + absl::optional> index_field) + : field_(std::move(field)), + alias_(alias), + index_field_(std::move(index_field)) { } google_firestore_v1_Pipeline_Stage Unnest::to_proto() const { google_firestore_v1_Pipeline_Stage result; result.name = nanopb::MakeBytesArray("unnest"); - result.args_count = 1; - result.args = nanopb::MakeArray(1); + result.args_count = 2; + result.args = nanopb::MakeArray(2); result.args[0] = field_->to_proto(); + result.args[1] = alias_->to_proto(); if (index_field_.has_value()) { result.options_count = 1; result.options = nanopb::MakeArray(1); result.options[0].key = nanopb::MakeBytesArray("index_field"); - result.options[0].value.which_value_type = - google_firestore_v1_Value_string_value_tag; - result.options[0].value.string_value = - nanopb::MakeBytesArray(index_field_.value()); + result.options[0].value = index_field_.value()->to_proto(); } else { result.options_count = 0; result.options = nullptr; @@ -395,7 +433,7 @@ google_firestore_v1_Pipeline_Stage Unnest::to_proto() const { RawStage::RawStage( std::string name, - std::vector> params, + std::vector params, std::unordered_map> options) : name_(std::move(name)), params_(std::move(params)), @@ -410,7 +448,7 @@ google_firestore_v1_Pipeline_Stage RawStage::to_proto() const { result.args = nanopb::MakeArray(result.args_count); for (size_t i = 0; i < result.args_count; i++) { - result.args[i] = params_[i]->to_proto(); + result.args[i] = params_[i]; } nanopb::SetRepeatedField( diff --git a/Firestore/core/src/api/stages.h b/Firestore/core/src/api/stages.h index 7af3683e99b..e8bf34ac70a 100644 --- a/Firestore/core/src/api/stages.h +++ b/Firestore/core/src/api/stages.h @@ -252,22 +252,58 @@ class RemoveFieldsStage : public Stage { class ReplaceWith : public Stage { public: - explicit ReplaceWith(std::shared_ptr expr); + class ReplaceMode { + public: + enum Mode { + FULL_REPLACE, + MERGE_PREFER_NEST, + MERGE_PREFER_PARENT = FULL_REPLACE + }; + + explicit ReplaceMode(Mode mode) : mode_(mode) { + } + google_firestore_v1_Value to_proto() const; + + private: + Mode mode_; + }; + + explicit ReplaceWith( + std::shared_ptr expr, + ReplaceMode mode = ReplaceMode(ReplaceMode::Mode::FULL_REPLACE)); ~ReplaceWith() override = default; google_firestore_v1_Pipeline_Stage to_proto() const override; private: std::shared_ptr expr_; + ReplaceMode mode_; }; class Sample : public Stage { public: - Sample(std::string type, int64_t count, double percentage); + class SampleMode { + public: + enum Mode { DOCUMENTS = 0, PERCENT }; + + explicit SampleMode(Mode mode) : mode_(mode) { + } + + Mode mode() const { + return mode_; + } + + google_firestore_v1_Value to_proto() const; + + private: + Mode mode_; + }; + + Sample(SampleMode mode, int64_t count, double percentage); ~Sample() override = default; google_firestore_v1_Pipeline_Stage to_proto() const override; private: - std::string type_; + SampleMode mode_; int64_t count_; double percentage_; }; @@ -284,26 +320,29 @@ class Union : public Stage { class Unnest : public Stage { public: - Unnest(std::shared_ptr field, absl::optional index_field); + Unnest(std::shared_ptr field, + std::shared_ptr alias, + absl::optional> index_field); ~Unnest() override = default; google_firestore_v1_Pipeline_Stage to_proto() const override; private: std::shared_ptr field_; - absl::optional index_field_; + std::shared_ptr alias_; + absl::optional> index_field_; }; class RawStage : public Stage { public: RawStage(std::string name, - std::vector> params, + std::vector params, std::unordered_map> options); ~RawStage() override = default; google_firestore_v1_Pipeline_Stage to_proto() const override; private: std::string name_; - std::vector> params_; + std::vector params_; std::unordered_map> options_; }; From bc5865245b9d6412fe4541dcedacb23b83c4efed Mon Sep 17 00:00:00 2001 From: cherylEnkidu <96084918+cherylEnkidu@users.noreply.github.com> Date: Tue, 6 May 2025 14:50:27 -0400 Subject: [PATCH 011/113] Fix type warnings for size_t use in Firestore (#14790) --- Firestore/core/src/local/local_store.cc | 2 +- Firestore/core/src/local/local_store.h | 2 +- .../test/unit/local/index_backfiller_test.cc | 66 +++++++++---------- 3 files changed, 35 insertions(+), 35 deletions(-) diff --git a/Firestore/core/src/local/local_store.cc b/Firestore/core/src/local/local_store.cc index 5a054a31a67..155ff5a7232 100644 --- a/Firestore/core/src/local/local_store.cc +++ b/Firestore/core/src/local/local_store.cc @@ -585,7 +585,7 @@ LruResults LocalStore::CollectGarbage(LruGarbageCollector* garbage_collector) { }); } -int LocalStore::Backfill() const { +size_t LocalStore::Backfill() const { return persistence_->Run("Backfill Indexes", [&] { return index_backfiller_->WriteIndexEntries(this); }); diff --git a/Firestore/core/src/local/local_store.h b/Firestore/core/src/local/local_store.h index 8f2a0872f52..f3b61affa5a 100644 --- a/Firestore/core/src/local/local_store.h +++ b/Firestore/core/src/local/local_store.h @@ -254,7 +254,7 @@ class LocalStore : public bundle::BundleCallback { * Runs a single backfill operation and returns the number of documents * processed. */ - int Backfill() const; + size_t Backfill() const; /** * Returns whether the given bundle has already been loaded and its create diff --git a/Firestore/core/test/unit/local/index_backfiller_test.cc b/Firestore/core/test/unit/local/index_backfiller_test.cc index bee0c1c9f81..e0ee1499bb6 100644 --- a/Firestore/core/test/unit/local/index_backfiller_test.cc +++ b/Firestore/core/test/unit/local/index_backfiller_test.cc @@ -176,7 +176,7 @@ TEST_F(IndexBackfillerTest, WritesLatestReadTimeToFieldIndexOnCompletion) { AddFieldIndex("coll2", "bar"); AddDoc("coll1/docA", Version(10), "foo", 1); AddDoc("coll2/docA", Version(20), "bar", 1); - int documents_processed = local_store_.Backfill(); + int documents_processed = static_cast(local_store_.Backfill()); ASSERT_EQ(2, documents_processed); auto field_index1 = index_manager_->GetFieldIndexes("coll1").at(0); @@ -189,7 +189,7 @@ TEST_F(IndexBackfillerTest, WritesLatestReadTimeToFieldIndexOnCompletion) { AddDoc("coll2/docB", Version(60), "bar", 1); AddDoc("coll2/docC", Version(60, 10), "bar", 1); - documents_processed = local_store_.Backfill(); + documents_processed = static_cast(local_store_.Backfill()); ASSERT_EQ(4, documents_processed); field_index1 = index_manager_->GetFieldIndexes("coll1").at(0); @@ -205,7 +205,7 @@ TEST_F(IndexBackfillerTest, FetchesDocumentsAfterEarliestReadTime) { // Documents before read time should not be fetched. AddDoc("coll1/docA", Version(9), "foo", 1); - int documents_processed = local_store_.Backfill(); + int documents_processed = static_cast(local_store_.Backfill()); ASSERT_EQ(0, documents_processed); // Read time should be the highest read time from the cache. @@ -217,7 +217,7 @@ TEST_F(IndexBackfillerTest, FetchesDocumentsAfterEarliestReadTime) { // Documents that are after the earliest read time // but before field index read time are fetched. AddDoc("coll1/docB", Version(19), "boo", 1); - documents_processed = local_store_.Backfill(); + documents_processed = static_cast(local_store_.Backfill()); ASSERT_EQ(1, documents_processed); // Field indexes should now hold the latest read time @@ -233,7 +233,7 @@ TEST_F(IndexBackfillerTest, WritesIndexEntries) { AddDoc("coll2/docA", Version(10), "bar", 1); AddDoc("coll2/docB", Version(10), "car", 1); - int documents_processed = local_store_.Backfill(); + int documents_processed = static_cast(local_store_.Backfill()); ASSERT_EQ(4, documents_processed); } @@ -245,12 +245,12 @@ TEST_F(IndexBackfillerTest, WritesOldestDocumentFirst) { AddDoc("coll1/docB", Version(3), "foo", 1); AddDoc("coll1/docC", Version(10), "foo", 1); - int documents_processed = local_store_.Backfill(); + int documents_processed = static_cast(local_store_.Backfill()); ASSERT_EQ(2, documents_processed); VerifyQueryResults("coll1", {"coll1/docA", "coll1/docB"}); - documents_processed = local_store_.Backfill(); + documents_processed = static_cast(local_store_.Backfill()); ASSERT_EQ(1, documents_processed); VerifyQueryResults("coll1", {"coll1/docA", "coll1/docB", "coll1/docC"}); @@ -264,12 +264,12 @@ TEST_F(IndexBackfillerTest, UsesDocumentKeyOffsetForLargeSnapshots) { AddDoc("coll1/docB", Version(1), "foo", 1); AddDoc("coll1/docC", Version(1), "foo", 1); - int documents_processed = local_store_.Backfill(); + int documents_processed = static_cast(local_store_.Backfill()); ASSERT_EQ(2, documents_processed); VerifyQueryResults("coll1", {"coll1/docA", "coll1/docB"}); - documents_processed = local_store_.Backfill(); + documents_processed = static_cast(local_store_.Backfill()); ASSERT_EQ(1, documents_processed); VerifyQueryResults("coll1", {"coll1/docA", "coll1/docB", "coll1/docC"}); @@ -290,7 +290,7 @@ TEST_F(IndexBackfillerTest, UpdatesCollectionGroups) { ASSERT_TRUE(collection_group.has_value()); ASSERT_EQ("coll1", collection_group.value()); - int documents_processed = local_store_.Backfill(); + int documents_processed = static_cast(local_store_.Backfill()); ASSERT_EQ(2, documents_processed); // Check that coll1 was backfilled and that coll2 is next @@ -318,7 +318,7 @@ TEST_F(IndexBackfillerTest, PrioritizesNewCollectionGroups) { ASSERT_TRUE(collection_group.has_value()); ASSERT_EQ("coll3", collection_group.value()); - int documents_processed = local_store_.Backfill(); + int documents_processed = static_cast(local_store_.Backfill()); ASSERT_EQ(1, documents_processed); VerifyQueryResults("coll3", {"coll3/doc"}); @@ -334,7 +334,7 @@ TEST_F(IndexBackfillerTest, WritesUntilCap) { AddDoc("coll2/docA", Version(30), "foo", 1); AddDoc("coll2/docA", Version(40), "foo", 1); - int documents_processed = local_store_.Backfill(); + int documents_processed = static_cast(local_store_.Backfill()); ASSERT_EQ(3, documents_processed); VerifyQueryResults("coll1", {"coll1/docA", "coll1/docB"}); @@ -345,13 +345,13 @@ TEST_F(IndexBackfillerTest, UsesLatestReadTimeForEmptyCollections) { AddFieldIndex("coll", "foo", Version(1)); AddDoc("readtime/doc", Version(1), "foo", 1); - int documents_processed = local_store_.Backfill(); + int documents_processed = static_cast(local_store_.Backfill()); ASSERT_EQ(0, documents_processed); AddDoc("coll/ignored", Version(2), "foo", 1); AddDoc("coll/added", Version(3), "foo", 1); - documents_processed = local_store_.Backfill(); + documents_processed = static_cast(local_store_.Backfill()); ASSERT_EQ(2, documents_processed); } @@ -364,11 +364,11 @@ TEST_F(IndexBackfillerTest, HandlesLocalMutationsAfterRemoteDocs) { AddDoc("coll1/docC", Version(30), "foo", 1); AddSetMutationsToOverlay(1, {"coll1/docD"}); - int documents_processed = local_store_.Backfill(); + int documents_processed = static_cast(local_store_.Backfill()); ASSERT_EQ(2, documents_processed); VerifyQueryResults("coll1", {"coll1/docA", "coll1/docB"}); - documents_processed = local_store_.Backfill(); + documents_processed = static_cast(local_store_.Backfill()); ASSERT_EQ(2, documents_processed); VerifyQueryResults("coll1", {"coll1/docA", "coll1/docB", "coll1/docC", "coll1/docD"}); @@ -383,13 +383,13 @@ TEST_F(IndexBackfillerTest, AddSetMutationsToOverlay(3, {"coll1/docC"}); AddSetMutationsToOverlay(4, {"coll1/docD"}); - int documents_processed = local_store_.Backfill(); + int documents_processed = static_cast(local_store_.Backfill()); ASSERT_EQ(2, documents_processed); VerifyQueryResults("coll1", {"coll1/docA", "coll1/docB"}); auto field_index = index_manager_->GetFieldIndexes("coll1").at(0); ASSERT_EQ(2, field_index.index_state().index_offset().largest_batch_id()); - documents_processed = local_store_.Backfill(); + documents_processed = static_cast(local_store_.Backfill()); ASSERT_EQ(2, documents_processed); VerifyQueryResults("coll1", {"coll1/docA", "coll1/docB", "coll1/docC", "coll1/docD"}); @@ -404,7 +404,7 @@ TEST_F(IndexBackfillerTest, MutationFinishesMutationBatchEvenIfItExceedsLimit) { AddSetMutationsToOverlay(2, {"coll1/docB", "coll1/docC", "coll1/docD"}); AddSetMutationsToOverlay(3, {"coll1/docE"}); - int documents_processed = local_store_.Backfill(); + int documents_processed = static_cast(local_store_.Backfill()); ASSERT_EQ(4, documents_processed); VerifyQueryResults("coll1", {"coll1/docA", "coll1/docB", "coll1/docC", "coll1/docD"}); @@ -416,13 +416,13 @@ TEST_F(IndexBackfillerTest, MutationsFromHighWaterMark) { AddDoc("coll1/docA", Version(10), "foo", 1); AddSetMutationsToOverlay(3, {"coll1/docB"}); - int documents_processed = local_store_.Backfill(); + int documents_processed = static_cast(local_store_.Backfill()); ASSERT_EQ(2, documents_processed); VerifyQueryResults("coll1", {"coll1/docA", "coll1/docB"}); AddSetMutationsToOverlay(1, {"coll1/docC"}); AddSetMutationsToOverlay(2, {"coll1/docD"}); - documents_processed = local_store_.Backfill(); + documents_processed = static_cast(local_store_.Backfill()); ASSERT_EQ(0, documents_processed); } @@ -432,7 +432,7 @@ TEST_F(IndexBackfillerTest, UpdatesExistingDocToNewValue) { AddDoc("coll/doc", Version(10), "foo", 1); - int documents_processed = local_store_.Backfill(); + int documents_processed = static_cast(local_store_.Backfill()); ASSERT_EQ(1, documents_processed); VerifyQueryResults(query, {}); @@ -448,7 +448,7 @@ TEST_F(IndexBackfillerTest, UpdatesDocsThatNoLongerMatch) { AddFieldIndex("coll", "foo"); AddDoc("coll/doc", Version(10), "foo", 1); - int documents_processed = local_store_.Backfill(); + int documents_processed = static_cast(local_store_.Backfill()); ASSERT_EQ(1, documents_processed); VerifyQueryResults(query, {"coll/doc"}); @@ -456,7 +456,7 @@ TEST_F(IndexBackfillerTest, UpdatesDocsThatNoLongerMatch) { // index. AddDoc("coll/doc", Version(40), "foo", -1); - documents_processed = local_store_.Backfill(); + documents_processed = static_cast(local_store_.Backfill()); ASSERT_EQ(1, documents_processed); VerifyQueryResults(query, {}); } @@ -466,7 +466,7 @@ TEST_F(IndexBackfillerTest, DoesNotProcessSameDocumentTwice) { AddDoc("coll/doc", Version(5), "foo", 1); AddSetMutationsToOverlay(1, {"coll/doc"}); - int documents_processed = local_store_.Backfill(); + int documents_processed = static_cast(local_store_.Backfill()); ASSERT_EQ(1, documents_processed); const auto field_index = index_manager_->GetFieldIndexes("coll").at(0); @@ -478,13 +478,13 @@ TEST_F(IndexBackfillerTest, AppliesSetToRemoteDoc) { AddFieldIndex("coll", "foo"); AddDoc("coll/doc", Version(5), "boo", 1); - int documents_processed = local_store_.Backfill(); + int documents_processed = static_cast(local_store_.Backfill()); ASSERT_EQ(1, documents_processed); model::Mutation patch = PatchMutation("coll/doc", Map("foo", "bar")); AddMutationToOverlay("coll/doc", patch); - documents_processed = local_store_.Backfill(); + documents_processed = static_cast(local_store_.Backfill()); ASSERT_EQ(1, documents_processed); VerifyQueryResults("coll", {"coll/doc"}); @@ -498,7 +498,7 @@ TEST_F(IndexBackfillerTest, AppliesPatchToRemoteDoc) { AddFieldIndex("coll", "b"); AddDoc("coll/doc", Version(5), "a", 1); - int documents_processed = local_store_.Backfill(); + int documents_processed = static_cast(local_store_.Backfill()); ASSERT_EQ(1, documents_processed); VerifyQueryResults(query_a, {"coll/doc"}); @@ -506,7 +506,7 @@ TEST_F(IndexBackfillerTest, AppliesPatchToRemoteDoc) { model::Mutation patch = PatchMutation("coll/doc", Map("b", 1)); AddMutationToOverlay("coll/doc", patch); - documents_processed = local_store_.Backfill(); + documents_processed = static_cast(local_store_.Backfill()); ASSERT_EQ(1, documents_processed); VerifyQueryResults(query_a, {"coll/doc"}); @@ -517,12 +517,12 @@ TEST_F(IndexBackfillerTest, AppliesDeleteToRemoteDoc) { AddFieldIndex("coll", "foo"); AddDoc("coll/doc", Version(5), "foo", 1); - int documents_processed = local_store_.Backfill(); + int documents_processed = static_cast(local_store_.Backfill()); ASSERT_EQ(1, documents_processed); const model::DeleteMutation delete_mutation = DeleteMutation("coll/doc"); AddMutationToOverlay("coll/doc", delete_mutation); - documents_processed = local_store_.Backfill(); + documents_processed = static_cast(local_store_.Backfill()); ASSERT_EQ(1, documents_processed); persistence_->Run("BackfillAppliesDeleteToRemoteDoc", [&] { @@ -541,13 +541,13 @@ TEST_F(IndexBackfillerTest, ReindexesDocumentsWhenNewIndexIsAdded) { AddDoc("coll/doc1", Version(1), "a", 1); AddDoc("coll/doc2", Version(1), "b", 1); - int documents_processed = local_store_.Backfill(); + int documents_processed = static_cast(local_store_.Backfill()); ASSERT_EQ(2, documents_processed); VerifyQueryResults(query_a, {"coll/doc1"}); VerifyQueryResults(query_b, {}); AddFieldIndex("coll", "b"); - documents_processed = local_store_.Backfill(); + documents_processed = static_cast(local_store_.Backfill()); ASSERT_EQ(2, documents_processed); VerifyQueryResults(query_a, {"coll/doc1"}); From b68369f80e2c75e779e7453602b2a59692c79a1a Mon Sep 17 00:00:00 2001 From: Andrew Heard Date: Tue, 6 May 2025 18:56:04 -0400 Subject: [PATCH 012/113] [Firebase AI] Add support for Gemma models with Developer API (#14823) --- FirebaseAI/Sources/FirebaseAI.swift | 3 +- .../Sources/GenerateContentResponse.swift | 17 ++-- FirebaseAI/Sources/GenerativeModel.swift | 3 + FirebaseAI/Sources/ModelContent.swift | 6 ++ .../Tests/TestApp/Sources/Constants.swift | 1 + .../GenerateContentIntegrationTests.swift | 92 +++++++++++++------ .../Unit/GenerativeModelVertexAITests.swift | 18 ++-- 7 files changed, 96 insertions(+), 44 deletions(-) diff --git a/FirebaseAI/Sources/FirebaseAI.swift b/FirebaseAI/Sources/FirebaseAI.swift index b7e3ad2e893..48f7183d4e6 100644 --- a/FirebaseAI/Sources/FirebaseAI.swift +++ b/FirebaseAI/Sources/FirebaseAI.swift @@ -72,7 +72,8 @@ public final class FirebaseAI: Sendable { systemInstruction: ModelContent? = nil, requestOptions: RequestOptions = RequestOptions()) -> GenerativeModel { - if !modelName.starts(with: GenerativeModel.geminiModelNamePrefix) { + if !modelName.starts(with: GenerativeModel.geminiModelNamePrefix) + && !modelName.starts(with: GenerativeModel.gemmaModelNamePrefix) { AILog.warning(code: .unsupportedGeminiModel, """ Unsupported Gemini model "\(modelName)"; see \ https://firebase.google.com/docs/vertex-ai/models for a list supported Gemini model names. diff --git a/FirebaseAI/Sources/GenerateContentResponse.swift b/FirebaseAI/Sources/GenerateContentResponse.swift index e654389ce82..6d4ba6932ec 100644 --- a/FirebaseAI/Sources/GenerateContentResponse.swift +++ b/FirebaseAI/Sources/GenerateContentResponse.swift @@ -371,13 +371,7 @@ extension Candidate: Decodable { content = ModelContent(parts: []) } } catch { - // Check if `content` can be decoded as an empty dictionary to detect the `"content": {}` bug. - if let content = try? container.decode([String: String].self, forKey: .content), - content.isEmpty { - throw InvalidCandidateError.emptyContent(underlyingError: error) - } else { - throw InvalidCandidateError.malformedContent(underlyingError: error) - } + throw InvalidCandidateError.malformedContent(underlyingError: error) } if let safetyRatings = try container.decodeIfPresent( @@ -395,6 +389,15 @@ extension Candidate: Decodable { finishReason = try container.decodeIfPresent(FinishReason.self, forKey: .finishReason) + // The `content` may only be empty if a `finishReason` is included; if neither are included in + // the response then this is likely the `"content": {}` bug. + guard !content.parts.isEmpty || finishReason != nil else { + throw InvalidCandidateError.emptyContent(underlyingError: DecodingError.dataCorrupted(.init( + codingPath: [CodingKeys.content, CodingKeys.finishReason], + debugDescription: "Invalid Candidate: empty content and no finish reason" + ))) + } + citationMetadata = try container.decodeIfPresent( CitationMetadata.self, forKey: .citationMetadata diff --git a/FirebaseAI/Sources/GenerativeModel.swift b/FirebaseAI/Sources/GenerativeModel.swift index defe01c4665..8d3f5e043a7 100644 --- a/FirebaseAI/Sources/GenerativeModel.swift +++ b/FirebaseAI/Sources/GenerativeModel.swift @@ -23,6 +23,9 @@ public final class GenerativeModel: Sendable { /// Model name prefix to identify Gemini models. static let geminiModelNamePrefix = "gemini-" + /// Model name prefix to identify Gemma models. + static let gemmaModelNamePrefix = "gemma-" + /// The name of the model, for example "gemini-2.0-flash". let modelName: String diff --git a/FirebaseAI/Sources/ModelContent.swift b/FirebaseAI/Sources/ModelContent.swift index ba87736e648..7d82bd76445 100644 --- a/FirebaseAI/Sources/ModelContent.swift +++ b/FirebaseAI/Sources/ModelContent.swift @@ -112,6 +112,12 @@ extension ModelContent: Codable { case role case internalParts = "parts" } + + public init(from decoder: any Decoder) throws { + let container = try decoder.container(keyedBy: CodingKeys.self) + role = try container.decodeIfPresent(String.self, forKey: .role) + internalParts = try container.decodeIfPresent([InternalPart].self, forKey: .internalParts) ?? [] + } } @available(iOS 15.0, macOS 12.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) diff --git a/FirebaseAI/Tests/TestApp/Sources/Constants.swift b/FirebaseAI/Tests/TestApp/Sources/Constants.swift index 3a731813704..ff1e9bb0250 100644 --- a/FirebaseAI/Tests/TestApp/Sources/Constants.swift +++ b/FirebaseAI/Tests/TestApp/Sources/Constants.swift @@ -24,4 +24,5 @@ public enum ModelNames { public static let gemini2Flash = "gemini-2.0-flash-001" public static let gemini2FlashLite = "gemini-2.0-flash-lite-001" public static let gemini2FlashExperimental = "gemini-2.0-flash-exp" + public static let gemma3_27B = "gemma-3-27b-it" } diff --git a/FirebaseAI/Tests/TestApp/Tests/Integration/GenerateContentIntegrationTests.swift b/FirebaseAI/Tests/TestApp/Tests/Integration/GenerateContentIntegrationTests.swift index 0a9c9898291..ecb443b503e 100644 --- a/FirebaseAI/Tests/TestApp/Tests/Integration/GenerateContentIntegrationTests.swift +++ b/FirebaseAI/Tests/TestApp/Tests/Integration/GenerateContentIntegrationTests.swift @@ -47,12 +47,24 @@ struct GenerateContentIntegrationTests { storage = Storage.storage() } - @Test(arguments: InstanceConfig.allConfigs) - func generateContent(_ config: InstanceConfig) async throws { + @Test(arguments: [ + (InstanceConfig.vertexAI_v1, ModelNames.gemini2FlashLite), + (InstanceConfig.vertexAI_v1_staging, ModelNames.gemini2FlashLite), + (InstanceConfig.vertexAI_v1beta, ModelNames.gemini2FlashLite), + (InstanceConfig.vertexAI_v1beta_staging, ModelNames.gemini2FlashLite), + (InstanceConfig.googleAI_v1beta, ModelNames.gemini2FlashLite), + (InstanceConfig.googleAI_v1beta, ModelNames.gemma3_27B), + (InstanceConfig.googleAI_v1beta_staging, ModelNames.gemini2FlashLite), + (InstanceConfig.googleAI_v1beta_staging, ModelNames.gemma3_27B), + (InstanceConfig.googleAI_v1_freeTier_bypassProxy, ModelNames.gemini2FlashLite), + (InstanceConfig.googleAI_v1beta_freeTier_bypassProxy, ModelNames.gemini2FlashLite), + (InstanceConfig.googleAI_v1beta_freeTier_bypassProxy, ModelNames.gemma3_27B), + ]) + func generateContent(_ config: InstanceConfig, modelName: String) async throws { let model = FirebaseAI.componentInstance(config).generativeModel( - modelName: ModelNames.gemini2FlashLite, + modelName: modelName, generationConfig: generationConfig, - safetySettings: safetySettings + safetySettings: safetySettings, ) let prompt = "Where is Google headquarters located? Answer with the city name only." @@ -62,17 +74,22 @@ struct GenerateContentIntegrationTests { #expect(text == "Mountain View") let usageMetadata = try #require(response.usageMetadata) - #expect(usageMetadata.promptTokenCount == 13) + #expect(usageMetadata.promptTokenCount.isEqual(to: 13, accuracy: tokenCountAccuracy)) #expect(usageMetadata.candidatesTokenCount.isEqual(to: 3, accuracy: tokenCountAccuracy)) #expect(usageMetadata.totalTokenCount.isEqual(to: 16, accuracy: tokenCountAccuracy)) #expect(usageMetadata.promptTokensDetails.count == 1) let promptTokensDetails = try #require(usageMetadata.promptTokensDetails.first) #expect(promptTokensDetails.modality == .text) #expect(promptTokensDetails.tokenCount == usageMetadata.promptTokenCount) - #expect(usageMetadata.candidatesTokensDetails.count == 1) - let candidatesTokensDetails = try #require(usageMetadata.candidatesTokensDetails.first) - #expect(candidatesTokensDetails.modality == .text) - #expect(candidatesTokensDetails.tokenCount == usageMetadata.candidatesTokenCount) + // The field `candidatesTokensDetails` is not included when using Gemma models. + if modelName == ModelNames.gemma3_27B { + #expect(usageMetadata.candidatesTokensDetails.isEmpty) + } else { + #expect(usageMetadata.candidatesTokensDetails.count == 1) + let candidatesTokensDetails = try #require(usageMetadata.candidatesTokensDetails.first) + #expect(candidatesTokensDetails.modality == .text) + #expect(candidatesTokensDetails.tokenCount == usageMetadata.candidatesTokenCount) + } } @Test( @@ -168,24 +185,35 @@ struct GenerateContentIntegrationTests { // MARK: Streaming Tests - @Test(arguments: InstanceConfig.allConfigs) - func generateContentStream(_ config: InstanceConfig) async throws { - let expectedText = """ - 1. Mercury - 2. Venus - 3. Earth - 4. Mars - 5. Jupiter - 6. Saturn - 7. Uranus - 8. Neptune - """ + @Test(arguments: [ + (InstanceConfig.vertexAI_v1, ModelNames.gemini2FlashLite), + (InstanceConfig.vertexAI_v1_staging, ModelNames.gemini2FlashLite), + (InstanceConfig.vertexAI_v1beta, ModelNames.gemini2FlashLite), + (InstanceConfig.vertexAI_v1beta_staging, ModelNames.gemini2FlashLite), + (InstanceConfig.googleAI_v1beta, ModelNames.gemini2FlashLite), + (InstanceConfig.googleAI_v1beta, ModelNames.gemma3_27B), + (InstanceConfig.googleAI_v1beta_staging, ModelNames.gemini2FlashLite), + (InstanceConfig.googleAI_v1beta_staging, ModelNames.gemma3_27B), + (InstanceConfig.googleAI_v1_freeTier_bypassProxy, ModelNames.gemini2FlashLite), + (InstanceConfig.googleAI_v1beta_freeTier_bypassProxy, ModelNames.gemini2FlashLite), + (InstanceConfig.googleAI_v1beta_freeTier_bypassProxy, ModelNames.gemma3_27B), + ]) + func generateContentStream(_ config: InstanceConfig, modelName: String) async throws { + let expectedResponse = [ + "Mercury", "Venus", "Earth", "Mars", "Jupiter", "Saturn", "Uranus", "Neptune", + ] let prompt = """ - What are the names of the planets in the solar system, ordered from closest to furthest from - the sun? Answer with a Markdown numbered list of the names and no other text. + Generate a JSON array of strings. The array must contain the names of the planets in Earth's \ + solar system, ordered from closest to furthest from the Sun. + + Constraints: + - Output MUST be only the JSON array. + - Do NOT include any introductory or explanatory text. + - Do NOT wrap the JSON in Markdown code blocks (e.g., ```json ... ``` or ``` ... ```). + - The response must start with '[' and end with ']'. """ let model = FirebaseAI.componentInstance(config).generativeModel( - modelName: ModelNames.gemini2FlashLite, + modelName: modelName, generationConfig: generationConfig, safetySettings: safetySettings ) @@ -194,7 +222,13 @@ struct GenerateContentIntegrationTests { let stream = try chat.sendMessageStream(prompt) var textValues = [String]() for try await value in stream { - try textValues.append(#require(value.text)) + if let text = value.text { + textValues.append(text) + } else if let finishReason = value.candidates.first?.finishReason { + #expect(finishReason == .stop) + } else { + Issue.record("Expected a candidate with a `TextPart` or a `finishReason`; got \(value).") + } } let userHistory = try #require(chat.history.first) @@ -206,11 +240,9 @@ struct GenerateContentIntegrationTests { #expect(modelHistory.role == "model") #expect(modelHistory.parts.count == 1) let modelTextPart = try #require(modelHistory.parts.first as? TextPart) - let modelText = modelTextPart.text.trimmingCharacters(in: .whitespacesAndNewlines) - #expect(modelText == expectedText) - #expect(textValues.count > 1) - let text = textValues.joined().trimmingCharacters(in: .whitespacesAndNewlines) - #expect(text == expectedText) + let modelJSONData = try #require(modelTextPart.text.data(using: .utf8)) + let response = try JSONDecoder().decode([String].self, from: modelJSONData) + #expect(response == expectedResponse) } // MARK: - App Check Tests diff --git a/FirebaseAI/Tests/Unit/GenerativeModelVertexAITests.swift b/FirebaseAI/Tests/Unit/GenerativeModelVertexAITests.swift index 930f4efd987..f1092a4c4f6 100644 --- a/FirebaseAI/Tests/Unit/GenerativeModelVertexAITests.swift +++ b/FirebaseAI/Tests/Unit/GenerativeModelVertexAITests.swift @@ -918,6 +918,9 @@ final class GenerativeModelVertexAITests: XCTestCase { func testGenerateContent_failure_malformedContent() async throws { MockURLProtocol .requestHandler = try GenerativeModelTestUtil.httpRequestHandler( + // Note: Although this file does not contain `parts` in `content`, it is not actually + // malformed. The `invalid-field` in the payload could be added, as a non-breaking change to + // the proto API. Therefore, this test checks for the `emptyContent` error instead. forResource: "unary-failure-malformed-content", withExtension: "json", subdirectory: vertexSubdirectory @@ -939,13 +942,13 @@ final class GenerativeModelVertexAITests: XCTestCase { return } let invalidCandidateError = try XCTUnwrap(underlyingError as? InvalidCandidateError) - guard case let .malformedContent(malformedContentUnderlyingError) = invalidCandidateError else { - XCTFail("Not a malformed content error: \(invalidCandidateError)") + guard case let .emptyContent(emptyContentUnderlyingError) = invalidCandidateError else { + XCTFail("Not an empty content error: \(invalidCandidateError)") return } _ = try XCTUnwrap( - malformedContentUnderlyingError as? DecodingError, - "Not a decoding error: \(malformedContentUnderlyingError)" + emptyContentUnderlyingError as? DecodingError, + "Not a decoding error: \(emptyContentUnderlyingError)" ) } @@ -1446,6 +1449,9 @@ final class GenerativeModelVertexAITests: XCTestCase { func testGenerateContentStream_malformedContent() async throws { MockURLProtocol .requestHandler = try GenerativeModelTestUtil.httpRequestHandler( + // Note: Although this file does not contain `parts` in `content`, it is not actually + // malformed. The `invalid-field` in the payload could be added, as a non-breaking change to + // the proto API. Therefore, this test checks for the `emptyContent` error instead. forResource: "streaming-failure-malformed-content", withExtension: "txt", subdirectory: vertexSubdirectory @@ -1457,8 +1463,8 @@ final class GenerativeModelVertexAITests: XCTestCase { XCTFail("Unexpected content in stream: \(content)") } } catch let GenerateContentError.internalError(underlyingError as InvalidCandidateError) { - guard case let .malformedContent(contentError) = underlyingError else { - XCTFail("Not a malformed content error: \(underlyingError)") + guard case let .emptyContent(contentError) = underlyingError else { + XCTFail("Not an empty content error: \(underlyingError)") return } From da813baabbedfc65c93c6c61052ceb32773f2834 Mon Sep 17 00:00:00 2001 From: pcfba <111909874+pcfba@users.noreply.github.com> Date: Tue, 6 May 2025 16:52:13 -0700 Subject: [PATCH 013/113] Analytics 11.13.0 (#14824) --- FirebaseAnalytics.podspec | 2 +- GoogleAppMeasurement.podspec | 2 +- GoogleAppMeasurementOnDeviceConversion.podspec | 3 +-- Package.swift | 6 +++--- 4 files changed, 6 insertions(+), 7 deletions(-) diff --git a/FirebaseAnalytics.podspec b/FirebaseAnalytics.podspec index 646bd9b00a7..dcd6a9ee85b 100644 --- a/FirebaseAnalytics.podspec +++ b/FirebaseAnalytics.podspec @@ -13,7 +13,7 @@ Pod::Spec.new do |s| s.authors = 'Google, Inc.' s.source = { - :http => 'https://dl.google.com/firebase/ios/analytics/4552003335f1c2d0/FirebaseAnalytics-11.12.0.tar.gz' + :http => 'https://dl.google.com/firebase/ios/analytics/925f34cf030a1cdf/FirebaseAnalytics-11.13.0.tar.gz' } s.cocoapods_version = '>= 1.12.0' diff --git a/GoogleAppMeasurement.podspec b/GoogleAppMeasurement.podspec index 41deacbd79b..fd6bc282d10 100644 --- a/GoogleAppMeasurement.podspec +++ b/GoogleAppMeasurement.podspec @@ -16,7 +16,7 @@ Pod::Spec.new do |s| s.authors = 'Google, Inc.' s.source = { - :http => 'https://dl.google.com/firebase/ios/analytics/8fcabc8a7a8f1142/GoogleAppMeasurement-11.12.0.tar.gz' + :http => 'https://dl.google.com/firebase/ios/analytics/2af6a14a3c1e0357/GoogleAppMeasurement-11.13.0.tar.gz' } s.cocoapods_version = '>= 1.12.0' diff --git a/GoogleAppMeasurementOnDeviceConversion.podspec b/GoogleAppMeasurementOnDeviceConversion.podspec index 3f1d3cfedac..79681916fd1 100644 --- a/GoogleAppMeasurementOnDeviceConversion.podspec +++ b/GoogleAppMeasurementOnDeviceConversion.podspec @@ -17,7 +17,7 @@ Pod::Spec.new do |s| s.authors = 'Google, Inc.' s.source = { - :http => 'https://dl.google.com/firebase/ios/analytics/c2395501c3df522f/GoogleAppMeasurementOnDeviceConversion-11.12.0.tar.gz' + :http => 'https://dl.google.com/firebase/ios/analytics/d8a25f0d55c82700/GoogleAppMeasurementOnDeviceConversion-11.13.0.tar.gz' } s.cocoapods_version = '>= 1.12.0' @@ -28,4 +28,3 @@ Pod::Spec.new do |s| s.vendored_frameworks = 'Frameworks/GoogleAppMeasurementOnDeviceConversion.xcframework' end - diff --git a/Package.swift b/Package.swift index c121735282e..35c5c4bbe55 100644 --- a/Package.swift +++ b/Package.swift @@ -360,8 +360,8 @@ let package = Package( ), .binaryTarget( name: "FirebaseAnalytics", - url: "https://dl.google.com/firebase/ios/swiftpm/11.12.0/FirebaseAnalytics.zip", - checksum: "c08377e08631271788e6302a060f83ca1f17cdda345c8bce441ea2ba2a6999ae" + url: "https://dl.google.com/firebase/ios/swiftpm/11.13.0/FirebaseAnalytics.zip", + checksum: "3c23a870df5fe9d7c36f2cfb9fb26e1cbccaa5fa0b12a28bc42d36cbc92bf909" ), .testTarget( name: "AnalyticsSwiftUnit", @@ -1370,7 +1370,7 @@ func googleAppMeasurementDependency() -> Package.Dependency { return .package(url: appMeasurementURL, branch: "main") } - return .package(url: appMeasurementURL, exact: "11.12.0") + return .package(url: appMeasurementURL, exact: "11.13.0") } func abseilDependency() -> Package.Dependency { From 51779cf187ce43110453bb088f66564171c26d71 Mon Sep 17 00:00:00 2001 From: Nick Cooke <36927374+ncooke3@users.noreply.github.com> Date: Wed, 7 May 2025 18:19:39 -0400 Subject: [PATCH 014/113] [Release] Update Package.swift for M164 release (#14828) --- Package.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Package.swift b/Package.swift index 35c5c4bbe55..451abb8dcb8 100644 --- a/Package.swift +++ b/Package.swift @@ -1539,8 +1539,8 @@ func firestoreTargets() -> [Target] { } else { return .binaryTarget( name: "FirebaseFirestoreInternal", - url: "https://dl.google.com/firebase/ios/bin/firestore/11.12.0/rc0/FirebaseFirestoreInternal.zip", - checksum: "4c2b4f8bbe863aa295a91b90882ebd523248e82da46497e15797f03e3b6b0a0a" + url: "https://dl.google.com/firebase/ios/bin/firestore/11.13.0/rc0/FirebaseFirestoreInternal.zip", + checksum: "badb559c67f683d546873051642db7eaab3598e50f8095dc15d965d63a695145" ) } }() From a1e330dfa773fc031acf989986a6587f66528a63 Mon Sep 17 00:00:00 2001 From: Nick Cooke <36927374+ncooke3@users.noreply.github.com> Date: Wed, 7 May 2025 19:03:03 -0400 Subject: [PATCH 015/113] [Infra] Add `FIRAllocatedUnfairLock` type (#14825) Co-authored-by: Morgan Chen --- .../HeartbeatLogging/HeartbeatStorage.swift | 4 +- .../Utilities/FIRAllocatedUnfairLock.swift | 66 +++++++++++++++++++ .../Tests/Unit/HeartbeatStorageTests.swift | 14 ++-- 3 files changed, 76 insertions(+), 8 deletions(-) create mode 100644 FirebaseCore/Internal/Sources/Utilities/FIRAllocatedUnfairLock.swift diff --git a/FirebaseCore/Internal/Sources/HeartbeatLogging/HeartbeatStorage.swift b/FirebaseCore/Internal/Sources/HeartbeatLogging/HeartbeatStorage.swift index f28c2038582..224426e086a 100644 --- a/FirebaseCore/Internal/Sources/HeartbeatLogging/HeartbeatStorage.swift +++ b/FirebaseCore/Internal/Sources/HeartbeatLogging/HeartbeatStorage.swift @@ -52,9 +52,9 @@ final class HeartbeatStorage: Sendable, HeartbeatStorageProtocol { // MARK: - Instance Management /// Statically allocated cache of `HeartbeatStorage` instances keyed by string IDs. - private nonisolated(unsafe) static var cachedInstances: AtomicBox< + private static let cachedInstances: FIRAllocatedUnfairLock< [String: WeakContainer] - > = AtomicBox([:]) + > = FIRAllocatedUnfairLock(initialState: [:]) /// Gets an existing `HeartbeatStorage` instance with the given `id` if one exists. Otherwise, /// makes a new instance with the given `id`. diff --git a/FirebaseCore/Internal/Sources/Utilities/FIRAllocatedUnfairLock.swift b/FirebaseCore/Internal/Sources/Utilities/FIRAllocatedUnfairLock.swift new file mode 100644 index 00000000000..ae52faefce6 --- /dev/null +++ b/FirebaseCore/Internal/Sources/Utilities/FIRAllocatedUnfairLock.swift @@ -0,0 +1,66 @@ +// Copyright 2025 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 +import os.lock + +/// A reference wrapper around `os_unfair_lock`. Replace this class with +/// `OSAllocatedUnfairLock` once we support only iOS 16+. For an explanation +/// on why this is necessary, see the docs: +/// https://developer.apple.com/documentation/os/osallocatedunfairlock +public final class FIRAllocatedUnfairLock: @unchecked Sendable { + private var lockPointer: UnsafeMutablePointer + private var state: State + + public init(initialState: sending State) { + lockPointer = UnsafeMutablePointer + .allocate(capacity: 1) + lockPointer.initialize(to: os_unfair_lock()) + state = initialState + } + + public convenience init() where State == Void { + self.init(initialState: ()) + } + + public func lock() { + os_unfair_lock_lock(lockPointer) + } + + public func unlock() { + os_unfair_lock_unlock(lockPointer) + } + + @discardableResult + public func withLock(_ body: (inout State) throws -> R) rethrows -> R { + let value: R + lock() + defer { unlock() } + value = try body(&state) + return value + } + + @discardableResult + public func withLock(_ body: () throws -> R) rethrows -> R { + let value: R + lock() + defer { unlock() } + value = try body() + return value + } + + deinit { + lockPointer.deallocate() + } +} diff --git a/FirebaseCore/Internal/Tests/Unit/HeartbeatStorageTests.swift b/FirebaseCore/Internal/Tests/Unit/HeartbeatStorageTests.swift index 8d5a03f942c..c48cea653f7 100644 --- a/FirebaseCore/Internal/Tests/Unit/HeartbeatStorageTests.swift +++ b/FirebaseCore/Internal/Tests/Unit/HeartbeatStorageTests.swift @@ -405,13 +405,13 @@ class HeartbeatStorageTests: XCTestCase { // type '[WeakContainer]' to a `@Sendable` closure // (`DispatchQueue.global().async { ... }`). final class WeakRefs: @unchecked Sendable { - private(set) var weakRefs: [WeakContainer] = [] // Lock is used to synchronize `weakRefs` during concurrent access. - private let weakRefsLock = NSLock() + private(set) var weakRefs = + FIRAllocatedUnfairLock<[WeakContainer]>(initialState: []) func append(_ weakRef: WeakContainer) { - weakRefsLock.withLock { - weakRefs.append(weakRef) + weakRefs.withLock { + $0.append(weakRef) } } } @@ -436,8 +436,10 @@ class HeartbeatStorageTests: XCTestCase { // Then // The `weakRefs` array's references should all be nil; otherwise, something is being // unexpectedly strongly retained. - for weakRef in weakRefs.weakRefs { - XCTAssertNil(weakRef.object, "Potential memory leak detected.") + weakRefs.weakRefs.withLock { refs in + for weakRef in refs { + XCTAssertNil(weakRef.object, "Potential memory leak detected.") + } } } } From d624f8a2db9b1fc626de06c2cafca18a627bc501 Mon Sep 17 00:00:00 2001 From: Andrew Heard Date: Thu, 8 May 2025 18:38:18 -0400 Subject: [PATCH 016/113] [Firebase AI] Update error domain constant for renamed SDK (#14829) --- FirebaseAI/Sources/Constants.swift | 4 ++-- FirebaseAI/Tests/TestApp/Sources/Constants.swift | 2 +- .../GenerateContentIntegrationTests.swift | 14 +++++++------- scripts/quickstart_spm_xcodeproj.sh | 5 +++++ 4 files changed, 15 insertions(+), 10 deletions(-) diff --git a/FirebaseAI/Sources/Constants.swift b/FirebaseAI/Sources/Constants.swift index 8e312723993..1af4c44c531 100644 --- a/FirebaseAI/Sources/Constants.swift +++ b/FirebaseAI/Sources/Constants.swift @@ -19,6 +19,6 @@ enum Constants { /// The base reverse-DNS name for `NSError` or `CustomNSError` error domains. /// /// - Important: A suffix must be appended to produce an error domain (e.g., - /// "com.google.firebase.vertexai.ExampleError"). - static let baseErrorDomain = "com.google.firebase.vertexai" + /// "com.google.firebase.firebaseai.ExampleError"). + static let baseErrorDomain = "com.google.firebase.firebaseai" } diff --git a/FirebaseAI/Tests/TestApp/Sources/Constants.swift b/FirebaseAI/Tests/TestApp/Sources/Constants.swift index ff1e9bb0250..1010b27cee3 100644 --- a/FirebaseAI/Tests/TestApp/Sources/Constants.swift +++ b/FirebaseAI/Tests/TestApp/Sources/Constants.swift @@ -24,5 +24,5 @@ public enum ModelNames { public static let gemini2Flash = "gemini-2.0-flash-001" public static let gemini2FlashLite = "gemini-2.0-flash-lite-001" public static let gemini2FlashExperimental = "gemini-2.0-flash-exp" - public static let gemma3_27B = "gemma-3-27b-it" + public static let gemma3_4B = "gemma-3-4b-it" } diff --git a/FirebaseAI/Tests/TestApp/Tests/Integration/GenerateContentIntegrationTests.swift b/FirebaseAI/Tests/TestApp/Tests/Integration/GenerateContentIntegrationTests.swift index ecb443b503e..b90f937b480 100644 --- a/FirebaseAI/Tests/TestApp/Tests/Integration/GenerateContentIntegrationTests.swift +++ b/FirebaseAI/Tests/TestApp/Tests/Integration/GenerateContentIntegrationTests.swift @@ -53,12 +53,12 @@ struct GenerateContentIntegrationTests { (InstanceConfig.vertexAI_v1beta, ModelNames.gemini2FlashLite), (InstanceConfig.vertexAI_v1beta_staging, ModelNames.gemini2FlashLite), (InstanceConfig.googleAI_v1beta, ModelNames.gemini2FlashLite), - (InstanceConfig.googleAI_v1beta, ModelNames.gemma3_27B), + (InstanceConfig.googleAI_v1beta, ModelNames.gemma3_4B), (InstanceConfig.googleAI_v1beta_staging, ModelNames.gemini2FlashLite), - (InstanceConfig.googleAI_v1beta_staging, ModelNames.gemma3_27B), + (InstanceConfig.googleAI_v1beta_staging, ModelNames.gemma3_4B), (InstanceConfig.googleAI_v1_freeTier_bypassProxy, ModelNames.gemini2FlashLite), (InstanceConfig.googleAI_v1beta_freeTier_bypassProxy, ModelNames.gemini2FlashLite), - (InstanceConfig.googleAI_v1beta_freeTier_bypassProxy, ModelNames.gemma3_27B), + (InstanceConfig.googleAI_v1beta_freeTier_bypassProxy, ModelNames.gemma3_4B), ]) func generateContent(_ config: InstanceConfig, modelName: String) async throws { let model = FirebaseAI.componentInstance(config).generativeModel( @@ -82,7 +82,7 @@ struct GenerateContentIntegrationTests { #expect(promptTokensDetails.modality == .text) #expect(promptTokensDetails.tokenCount == usageMetadata.promptTokenCount) // The field `candidatesTokensDetails` is not included when using Gemma models. - if modelName == ModelNames.gemma3_27B { + if modelName == ModelNames.gemma3_4B { #expect(usageMetadata.candidatesTokensDetails.isEmpty) } else { #expect(usageMetadata.candidatesTokensDetails.count == 1) @@ -191,12 +191,12 @@ struct GenerateContentIntegrationTests { (InstanceConfig.vertexAI_v1beta, ModelNames.gemini2FlashLite), (InstanceConfig.vertexAI_v1beta_staging, ModelNames.gemini2FlashLite), (InstanceConfig.googleAI_v1beta, ModelNames.gemini2FlashLite), - (InstanceConfig.googleAI_v1beta, ModelNames.gemma3_27B), + (InstanceConfig.googleAI_v1beta, ModelNames.gemma3_4B), (InstanceConfig.googleAI_v1beta_staging, ModelNames.gemini2FlashLite), - (InstanceConfig.googleAI_v1beta_staging, ModelNames.gemma3_27B), + (InstanceConfig.googleAI_v1beta_staging, ModelNames.gemma3_4B), (InstanceConfig.googleAI_v1_freeTier_bypassProxy, ModelNames.gemini2FlashLite), (InstanceConfig.googleAI_v1beta_freeTier_bypassProxy, ModelNames.gemini2FlashLite), - (InstanceConfig.googleAI_v1beta_freeTier_bypassProxy, ModelNames.gemma3_27B), + (InstanceConfig.googleAI_v1beta_freeTier_bypassProxy, ModelNames.gemma3_4B), ]) func generateContentStream(_ config: InstanceConfig, modelName: String) async throws { let expectedResponse = [ diff --git a/scripts/quickstart_spm_xcodeproj.sh b/scripts/quickstart_spm_xcodeproj.sh index 504f18e80aa..f0cbd0073be 100755 --- a/scripts/quickstart_spm_xcodeproj.sh +++ b/scripts/quickstart_spm_xcodeproj.sh @@ -25,6 +25,11 @@ XCODEPROJ=${SAMPLE}/${SAMPLE}Example.xcodeproj/project.pbxproj if grep -q "branch = main;" "$XCODEPROJ"; then sed -i "" "s#branch = main;#branch = $BRANCH_NAME;#" "$XCODEPROJ" + + # Point SPM CI to the tip of `main` of + # https://github.com/google/GoogleAppMeasurement so that the release process + # can defer publishing the `GoogleAppMeasurement` tag until after testing. + export FIREBASECI_USE_LATEST_GOOGLEAPPMEASUREMENT=1 else echo "Failed to update quickstart's Xcode project to the current branch" exit 1 From bf822b111faa1622482d113bc3b836be3a7a7e1a Mon Sep 17 00:00:00 2001 From: Nick Cooke <36927374+ncooke3@users.noreply.github.com> Date: Thu, 8 May 2025 19:01:57 -0400 Subject: [PATCH 017/113] [Auth] Add Swift 6 conformance to `FirebaseAuth/Sources/Swift/ActionCode/` directory (#14833) Co-authored-by: Morgan Chen --- .../Swift/ActionCode/ActionCodeInfo.swift | 5 +- .../ActionCode/ActionCodeOperation.swift | 2 +- .../Swift/ActionCode/ActionCodeSettings.swift | 106 +++++++++++++++--- .../Swift/ActionCode/ActionCodeURL.swift | 5 +- .../Utilities/FIRAllocatedUnfairLock.swift | 6 + 5 files changed, 107 insertions(+), 17 deletions(-) diff --git a/FirebaseAuth/Sources/Swift/ActionCode/ActionCodeInfo.swift b/FirebaseAuth/Sources/Swift/ActionCode/ActionCodeInfo.swift index 3cfa35909f6..abc783276ae 100644 --- a/FirebaseAuth/Sources/Swift/ActionCode/ActionCodeInfo.swift +++ b/FirebaseAuth/Sources/Swift/ActionCode/ActionCodeInfo.swift @@ -14,8 +14,11 @@ import Foundation +// TODO(Swift 6 Breaking): This type is immutable. Consider removing `open` at +// breaking change so checked Sendable can be used. + /// Manages information regarding action codes. -@objc(FIRActionCodeInfo) open class ActionCodeInfo: NSObject { +@objc(FIRActionCodeInfo) open class ActionCodeInfo: NSObject, @unchecked Sendable { /// The operation being performed. @objc public let operation: ActionCodeOperation diff --git a/FirebaseAuth/Sources/Swift/ActionCode/ActionCodeOperation.swift b/FirebaseAuth/Sources/Swift/ActionCode/ActionCodeOperation.swift index e345b6e91e8..f916e283267 100644 --- a/FirebaseAuth/Sources/Swift/ActionCode/ActionCodeOperation.swift +++ b/FirebaseAuth/Sources/Swift/ActionCode/ActionCodeOperation.swift @@ -15,7 +15,7 @@ import Foundation /// Operations which can be performed with action codes. -@objc(FIRActionCodeOperation) public enum ActionCodeOperation: Int, @unchecked Sendable { +@objc(FIRActionCodeOperation) public enum ActionCodeOperation: Int, Sendable { /// Action code for unknown operation. case unknown = 0 diff --git a/FirebaseAuth/Sources/Swift/ActionCode/ActionCodeSettings.swift b/FirebaseAuth/Sources/Swift/ActionCode/ActionCodeSettings.swift index 409b836545a..2f98f08b332 100644 --- a/FirebaseAuth/Sources/Swift/ActionCode/ActionCodeSettings.swift +++ b/FirebaseAuth/Sources/Swift/ActionCode/ActionCodeSettings.swift @@ -12,32 +12,55 @@ // See the License for the specific language governing permissions and // limitations under the License. +import FirebaseCoreInternal import Foundation +// TODO(Swift 6 Breaking): Consider breaking up into a checked Sendable Swift +// type and unchecked Sendable ObjC wrapper class. + /// Used to set and retrieve settings related to handling action codes. -@objc(FIRActionCodeSettings) open class ActionCodeSettings: NSObject { +@objc(FIRActionCodeSettings) open class ActionCodeSettings: NSObject, + @unchecked Sendable { /// This URL represents the state/Continue URL in the form of a universal link. /// /// This URL can should be constructed as a universal link that would either directly open /// the app where the action code would be handled or continue to the app after the action code /// is handled by Firebase. - @objc(URL) open var url: URL? + @objc(URL) open var url: URL? { + get { impl.url.value() } + set { impl.url.withLock { $0 = newValue } } + } /// Indicates whether the action code link will open the app directly or after being /// redirected from a Firebase owned web widget. - @objc open var handleCodeInApp: Bool = false + @objc open var handleCodeInApp: Bool { + get { impl.handleCodeInApp.value() } + set { impl.handleCodeInApp.withLock { $0 = newValue } } + } /// The iOS bundle ID, if available. The default value is the current app's bundle ID. - @objc open var iOSBundleID: String? + @objc open var iOSBundleID: String? { + get { impl.iOSBundleID.value() } + set { impl.iOSBundleID.withLock { $0 = newValue } } + } /// The Android package name, if available. - @objc open var androidPackageName: String? + @objc open var androidPackageName: String? { + get { impl.androidPackageName.value() } + set { impl.androidPackageName.withLock { $0 = newValue } } + } /// The minimum Android version supported, if available. - @objc open var androidMinimumVersion: String? + @objc open var androidMinimumVersion: String? { + get { impl.androidMinimumVersion.value() } + set { impl.androidMinimumVersion.withLock { $0 = newValue } } + } /// Indicates whether the Android app should be installed on a device where it is not available. - @objc open var androidInstallIfNotAvailable: Bool = false + @objc open var androidInstallIfNotAvailable: Bool { + get { impl.androidInstallIfNotAvailable.value() } + set { impl.androidInstallIfNotAvailable.withLock { $0 = newValue } } + } /// The Firebase Dynamic Link domain used for out of band code flow. #if !FIREBASE_CI @@ -47,14 +70,22 @@ import Foundation message: "Firebase Dynamic Links is deprecated. Migrate to use Firebase Hosting link and use `linkDomain` to set a custom domain instead." ) #endif // !FIREBASE_CI - @objc open var dynamicLinkDomain: String? + @objc open var dynamicLinkDomain: String? { + get { impl.dynamicLinkDomain.value() } + set { impl.dynamicLinkDomain.withLock { $0 = newValue } } + } /// The out of band custom domain for handling code in app. - @objc public var linkDomain: String? + @objc public var linkDomain: String? { + get { impl.linkDomain.value() } + set { impl.linkDomain.withLock { $0 = newValue } } + } + + private let impl: SendableActionCodeSettings /// Sets the iOS bundle ID. @objc override public init() { - iOSBundleID = Bundle.main.bundleIdentifier + impl = .init() } /// Sets the Android package name, the flag to indicate whether or not to install the app, @@ -70,13 +101,60 @@ import Foundation @objc open func setAndroidPackageName(_ androidPackageName: String, installIfNotAvailable: Bool, minimumVersion: String?) { - self.androidPackageName = androidPackageName - androidInstallIfNotAvailable = installIfNotAvailable - androidMinimumVersion = minimumVersion + impl + .setAndroidPackageName( + androidPackageName, + installIfNotAvailable: installIfNotAvailable, + minimumVersion: minimumVersion + ) } /// Sets the iOS bundle ID. open func setIOSBundleID(_ bundleID: String) { - iOSBundleID = bundleID + impl.setIOSBundleID(bundleID) + } +} + +private extension ActionCodeSettings { + /// Checked Sendable implementation of `ActionCodeSettings`. + final class SendableActionCodeSettings: Sendable { + let url = FIRAllocatedUnfairLock(initialState: nil) + + let handleCodeInApp = FIRAllocatedUnfairLock(initialState: false) + + let iOSBundleID: FIRAllocatedUnfairLock + + let androidPackageName = FIRAllocatedUnfairLock(initialState: nil) + + let androidMinimumVersion = FIRAllocatedUnfairLock(initialState: nil) + + let androidInstallIfNotAvailable = FIRAllocatedUnfairLock(initialState: false) + + #if !FIREBASE_CI + @available( + *, + deprecated, + message: "Firebase Dynamic Links is deprecated. Migrate to use Firebase Hosting link and use `linkDomain` to set a custom domain instead." + ) + #endif // !FIREBASE_CI + let dynamicLinkDomain = FIRAllocatedUnfairLock(initialState: nil) + + let linkDomain = FIRAllocatedUnfairLock(initialState: nil) + + init() { + iOSBundleID = FIRAllocatedUnfairLock(initialState: Bundle.main.bundleIdentifier) + } + + func setAndroidPackageName(_ androidPackageName: String, + installIfNotAvailable: Bool, + minimumVersion: String?) { + self.androidPackageName.withLock { $0 = androidPackageName } + androidInstallIfNotAvailable.withLock { $0 = installIfNotAvailable } + androidMinimumVersion.withLock { $0 = minimumVersion } + } + + func setIOSBundleID(_ bundleID: String) { + iOSBundleID.withLock { $0 = bundleID } + } } } diff --git a/FirebaseAuth/Sources/Swift/ActionCode/ActionCodeURL.swift b/FirebaseAuth/Sources/Swift/ActionCode/ActionCodeURL.swift index 16c28437f4f..dbed003f05a 100644 --- a/FirebaseAuth/Sources/Swift/ActionCode/ActionCodeURL.swift +++ b/FirebaseAuth/Sources/Swift/ActionCode/ActionCodeURL.swift @@ -14,8 +14,11 @@ import Foundation +// TODO(Swift 6 Breaking): This type is immutable. Consider removing `open` at +// breaking change so checked Sendable can be used. + /// This class will allow developers to easily extract information about out of band links. -@objc(FIRActionCodeURL) open class ActionCodeURL: NSObject { +@objc(FIRActionCodeURL) open class ActionCodeURL: NSObject, @unchecked Sendable { /// Returns the API key from the link. nil, if not provided. @objc(APIKey) public let apiKey: String? diff --git a/FirebaseCore/Internal/Sources/Utilities/FIRAllocatedUnfairLock.swift b/FirebaseCore/Internal/Sources/Utilities/FIRAllocatedUnfairLock.swift index ae52faefce6..c94f3153db9 100644 --- a/FirebaseCore/Internal/Sources/Utilities/FIRAllocatedUnfairLock.swift +++ b/FirebaseCore/Internal/Sources/Utilities/FIRAllocatedUnfairLock.swift @@ -42,6 +42,12 @@ public final class FIRAllocatedUnfairLock: @unchecked Sendable { os_unfair_lock_unlock(lockPointer) } + public func value() -> State { + lock() + defer { unlock() } + return state + } + @discardableResult public func withLock(_ body: (inout State) throws -> R) rethrows -> R { let value: R From baa6fb8dfab3c1ef8b9292067e86d7e8db811e90 Mon Sep 17 00:00:00 2001 From: Nick Cooke <36927374+ncooke3@users.noreply.github.com> Date: Fri, 9 May 2025 11:59:06 -0400 Subject: [PATCH 018/113] [Functions] More Swift 6 improvements (#14788) --- .../Sources/Callable+Codable.swift | 26 ++- FirebaseFunctions/Sources/Functions.swift | 32 ++-- .../Sources/FunctionsError.swift | 6 +- FirebaseFunctions/Sources/HTTPSCallable.swift | 150 ++++++++++++------ .../CombineUnit/HTTPSCallableTests.swift | 4 +- 5 files changed, 141 insertions(+), 77 deletions(-) diff --git a/FirebaseFunctions/Sources/Callable+Codable.swift b/FirebaseFunctions/Sources/Callable+Codable.swift index e18ac702fa7..ba768e4b4ff 100644 --- a/FirebaseFunctions/Sources/Callable+Codable.swift +++ b/FirebaseFunctions/Sources/Callable+Codable.swift @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -import FirebaseSharedSwift +@preconcurrency import FirebaseSharedSwift import Foundation /// A `Callable` is a reference to a particular Callable HTTPS trigger in Cloud Functions. @@ -20,7 +20,7 @@ import Foundation /// - Note: If the Callable HTTPS trigger accepts no parameters, ``Never`` can be used for /// iOS 17.0+. Otherwise, a simple encodable placeholder type (e.g., /// `struct EmptyRequest: Encodable {}`) can be used. -public struct Callable { +public struct Callable: Sendable { /// The timeout to use when calling the function. Defaults to 70 seconds. public var timeoutInterval: TimeInterval { get { @@ -61,11 +61,10 @@ public struct Callable { /// - Parameter data: Parameters to pass to the trigger. /// - Parameter completion: The block to call when the HTTPS request has completed. public func call(_ data: Request, - completion: @escaping (Result) + completion: @escaping @MainActor (Result) -> Void) { do { let encoded = try encoder.encode(data) - callable.call(encoded) { result, error in do { if let result { @@ -81,7 +80,9 @@ public struct Callable { } } } catch { - completion(.failure(error)) + DispatchQueue.main.async { + completion(.failure(error)) + } } } @@ -108,7 +109,7 @@ public struct Callable { /// - data: Parameters to pass to the trigger. /// - completion: The block to call when the HTTPS request has completed. public func callAsFunction(_ data: Request, - completion: @escaping (Result) + completion: @escaping @MainActor (Result) -> Void) { call(data, completion: completion) } @@ -265,9 +266,9 @@ public extension Callable where Request: Sendable, Response: Sendable { /// - Returns: A stream wrapping responses yielded by the streaming callable function or /// a ``FunctionsError`` if an error occurred. func stream(_ data: Request? = nil) throws -> AsyncThrowingStream { - let encoded: Any + let encoded: SendableWrapper do { - encoded = try encoder.encode(data) + encoded = try SendableWrapper(value: encoder.encode(data)) } catch { throw FunctionsError(.invalidArgument, userInfo: [NSUnderlyingErrorKey: error]) } @@ -336,3 +337,12 @@ enum JSONStreamResponse { case message([String: Any]) case result([String: Any]) } + +// TODO(Swift 6): Remove need for below type by changing `FirebaseDataEncoder` to not returning +// `Any`. +/// This wrapper is only intended to be used for passing encoded data in the +/// `stream` function's hierarchy. When using, carefully audit that `value` is +/// only ever accessed in one isolation domain. +struct SendableWrapper: @unchecked Sendable { + let value: Any +} diff --git a/FirebaseFunctions/Sources/Functions.swift b/FirebaseFunctions/Sources/Functions.swift index 091d63fe6f6..8f04368d8d2 100644 --- a/FirebaseFunctions/Sources/Functions.swift +++ b/FirebaseFunctions/Sources/Functions.swift @@ -19,18 +19,18 @@ import FirebaseMessagingInterop import FirebaseSharedSwift import Foundation #if COCOAPODS - import GTMSessionFetcher + @preconcurrency import GTMSessionFetcher #else - import GTMSessionFetcherCore + @preconcurrency import GTMSessionFetcherCore #endif internal import FirebaseCoreExtension -final class AtomicBox { - private var _value: T +final class AtomicBox: Sendable { + private nonisolated(unsafe) var _value: T private let lock = NSLock() - public init(_ value: T) { + public init(_ value: T) where T: Sendable { _value = value } @@ -68,7 +68,7 @@ enum FunctionsConstants { } /// `Functions` is the client for Cloud Functions for a Firebase project. -@objc(FIRFunctions) open class Functions: NSObject { +@objc(FIRFunctions) open class Functions: NSObject, @unchecked Sendable { // MARK: - Private Variables /// The network client to use for http requests. @@ -82,7 +82,7 @@ enum FunctionsConstants { /// A map of active instances, grouped by app. Keys are FirebaseApp names and values are arrays /// containing all instances of Functions associated with the given app. - private nonisolated(unsafe) static var instances: AtomicBox<[String: [Functions]]> = + private static let instances: AtomicBox<[String: [Functions]]> = AtomicBox([:]) /// The custom domain to use for all functions references (optional). @@ -91,10 +91,14 @@ enum FunctionsConstants { /// The region to use for all function references. let region: String + private let _emulatorOrigin: AtomicBox + // MARK: - Public APIs /// The current emulator origin, or `nil` if it is not set. - open private(set) var emulatorOrigin: String? + open var emulatorOrigin: String? { + _emulatorOrigin.value() + } /// Creates a Cloud Functions client using the default or returns a pre-existing instance if it /// already exists. @@ -318,7 +322,9 @@ enum FunctionsConstants { @objc open func useEmulator(withHost host: String, port: Int) { let prefix = host.hasPrefix("http") ? "" : "http://" let origin = String(format: "\(prefix)\(host):%li", port) - emulatorOrigin = origin + _emulatorOrigin.withLock { emulatorOrigin in + emulatorOrigin = origin + } } // MARK: - Private Funcs (or Internal for tests) @@ -365,7 +371,7 @@ enum FunctionsConstants { self.projectID = projectID self.region = region self.customDomain = customDomain - emulatorOrigin = nil + _emulatorOrigin = AtomicBox(nil) contextProvider = FunctionsContextProvider(auth: auth, messaging: messaging, appCheck: appCheck) @@ -414,7 +420,7 @@ enum FunctionsConstants { func callFunction(at url: URL, withObject data: Any?, options: HTTPSCallableOptions?, - timeout: TimeInterval) async throws -> HTTPSCallableResult { + timeout: TimeInterval) async throws -> sending HTTPSCallableResult { let context = try await contextProvider.context(options: options) let fetcher = try makeFetcher( url: url, @@ -501,7 +507,7 @@ enum FunctionsConstants { @available(macOS 12.0, iOS 15.0, watchOS 8.0, tvOS 15.0, *) func stream(at url: URL, - data: Any?, + data: SendableWrapper?, options: HTTPSCallableOptions?, timeout: TimeInterval) -> AsyncThrowingStream { @@ -512,7 +518,7 @@ enum FunctionsConstants { let context = try await contextProvider.context(options: options) urlRequest = try makeRequestForStreamableContent( url: url, - data: data, + data: data?.value, options: options, timeout: timeout, context: context diff --git a/FirebaseFunctions/Sources/FunctionsError.swift b/FirebaseFunctions/Sources/FunctionsError.swift index f495f51e68e..7d1b5d0902b 100644 --- a/FirebaseFunctions/Sources/FunctionsError.swift +++ b/FirebaseFunctions/Sources/FunctionsError.swift @@ -217,9 +217,9 @@ struct FunctionsError: CustomNSError { } if code == .OK { - // Technically, there's an edge case where a developer could explicitly return an error code - // of - // OK, and we will treat it as success, but that seems reasonable. + // Technically, there's an edge case where a developer could explicitly + // return an error code of OK, and we will treat it as success, but that + // seems reasonable. return nil } diff --git a/FirebaseFunctions/Sources/HTTPSCallable.swift b/FirebaseFunctions/Sources/HTTPSCallable.swift index 4c0555e43ce..00b6ee37463 100644 --- a/FirebaseFunctions/Sources/HTTPSCallable.swift +++ b/FirebaseFunctions/Sources/HTTPSCallable.swift @@ -29,29 +29,25 @@ open class HTTPSCallableResult: NSObject { } } -/** - * A `HTTPSCallable` is a reference to a particular Callable HTTPS trigger in Cloud Functions. - */ +/// A `HTTPSCallable` is a reference to a particular Callable HTTPS trigger in Cloud Functions. @objc(FIRHTTPSCallable) -open class HTTPSCallable: NSObject { +open class HTTPSCallable: NSObject, @unchecked Sendable { // MARK: - Private Properties - // The functions client to use for making calls. - private let functions: Functions - - private let url: URL - - private let options: HTTPSCallableOptions? + /// Until this class can be marked *checked* `Sendable`, it's implementation + /// is delegated to an auxialiary class that is checked Sendable. + private let sendableCallable: SendableHTTPSCallable // MARK: - Public Properties /// The timeout to use when calling the function. Defaults to 70 seconds. - @objc open var timeoutInterval: TimeInterval = 70 + @objc open var timeoutInterval: TimeInterval { + get { sendableCallable.timeoutInterval } + set { sendableCallable.timeoutInterval = newValue } + } init(functions: Functions, url: URL, options: HTTPSCallableOptions? = nil) { - self.functions = functions - self.url = url - self.options = options + sendableCallable = SendableHTTPSCallable(functions: functions, url: url, options: options) } /// Executes this Callable HTTPS trigger asynchronously. @@ -79,36 +75,7 @@ open class HTTPSCallable: NSObject { completion: @escaping @MainActor (HTTPSCallableResult?, Error?) -> Void) { - if #available(iOS 13, macCatalyst 13, macOS 10.15, tvOS 13, watchOS 7, *) { - Task { - do { - let result = try await call(data) - await completion(result, nil) - } catch { - await completion(nil, error) - } - } - } else { - // This isn’t expected to ever be called because Functions - // doesn’t officially support the older platforms. - functions.callFunction( - at: url, - withObject: data, - options: options, - timeout: timeoutInterval - ) { result in - switch result { - case let .success(callableResult): - DispatchQueue.main.async { - completion(callableResult, nil) - } - case let .failure(error): - DispatchQueue.main.async { - completion(nil, error) - } - } - } - } + sendableCallable.call(data, completion: completion) } /// Executes this Callable HTTPS trigger asynchronously. This API should only be used from @@ -124,8 +91,8 @@ open class HTTPSCallable: NSObject { /// resumes with a new FCM Token the next time you call this method. /// /// - Parameter completion: The block to call when the HTTPS request has completed. - @objc(callWithCompletion:) public func __call(completion: @escaping (HTTPSCallableResult?, - Error?) -> Void) { + @objc(callWithCompletion:) public func __call(completion: @escaping @MainActor (HTTPSCallableResult?, + Error?) -> Void) { call(nil, completion: completion) } @@ -144,13 +111,94 @@ open class HTTPSCallable: NSObject { /// - Throws: An error if the Cloud Functions invocation failed. /// - Returns: The result of the call. @available(iOS 13, tvOS 13, macOS 10.15, macCatalyst 13, watchOS 7, *) - open func call(_ data: Any? = nil) async throws -> HTTPSCallableResult { - try await functions - .callFunction(at: url, withObject: data, options: options, timeout: timeoutInterval) + open func call(_ data: Any? = nil) async throws -> sending HTTPSCallableResult { + try await sendableCallable.call(data) } @available(macOS 12.0, iOS 15.0, watchOS 8.0, tvOS 15.0, *) - func stream(_ data: Any? = nil) -> AsyncThrowingStream { - functions.stream(at: url, data: data, options: options, timeout: timeoutInterval) + func stream(_ data: SendableWrapper? = nil) -> AsyncThrowingStream { + sendableCallable.stream(data) + } +} + +private extension HTTPSCallable { + final class SendableHTTPSCallable: Sendable { + // MARK: - Private Properties + + // The functions client to use for making calls. + private let functions: Functions + + private let url: URL + + private let options: HTTPSCallableOptions? + + // MARK: - Public Properties + + let _timeoutInterval: AtomicBox = .init(70) + + /// The timeout to use when calling the function. Defaults to 70 seconds. + var timeoutInterval: TimeInterval { + get { _timeoutInterval.value() } + set { + _timeoutInterval.withLock { timeoutInterval in + timeoutInterval = newValue + } + } + } + + init(functions: Functions, url: URL, options: HTTPSCallableOptions? = nil) { + self.functions = functions + self.url = url + self.options = options + } + + func call(_ data: sending Any? = nil, + completion: @escaping @MainActor (HTTPSCallableResult?, Error?) -> Void) { + if #available(iOS 13, macCatalyst 13, macOS 10.15, tvOS 13, watchOS 7, *) { + Task { + do { + let result = try await call(data) + await completion(result, nil) + } catch { + await completion(nil, error) + } + } + } else { + // This isn’t expected to ever be called because Functions + // doesn’t officially support the older platforms. + functions.callFunction( + at: url, + withObject: data, + options: options, + timeout: timeoutInterval + ) { result in + switch result { + case let .success(callableResult): + DispatchQueue.main.async { + completion(callableResult, nil) + } + case let .failure(error): + DispatchQueue.main.async { + completion(nil, error) + } + } + } + } + } + + func __call(completion: @escaping @MainActor (HTTPSCallableResult?, Error?) -> Void) { + call(nil, completion: completion) + } + + @available(iOS 13, tvOS 13, macOS 10.15, macCatalyst 13, watchOS 7, *) + func call(_ data: Any? = nil) async throws -> sending HTTPSCallableResult { + try await functions + .callFunction(at: url, withObject: data, options: options, timeout: timeoutInterval) + } + + @available(macOS 12.0, iOS 15.0, watchOS 8.0, tvOS 15.0, *) + func stream(_ data: SendableWrapper? = nil) -> AsyncThrowingStream { + functions.stream(at: url, data: data, options: options, timeout: timeoutInterval) + } } } diff --git a/FirebaseFunctions/Tests/CombineUnit/HTTPSCallableTests.swift b/FirebaseFunctions/Tests/CombineUnit/HTTPSCallableTests.swift index 1db73d3930a..5db8b80fd77 100644 --- a/FirebaseFunctions/Tests/CombineUnit/HTTPSCallableTests.swift +++ b/FirebaseFunctions/Tests/CombineUnit/HTTPSCallableTests.swift @@ -28,14 +28,14 @@ import XCTest private let timeoutInterval: TimeInterval = 70.0 private let expectationTimeout: TimeInterval = 2 -class MockFunctions: Functions { +class MockFunctions: Functions, @unchecked Sendable { let mockCallFunction: () throws -> HTTPSCallableResult var verifyParameters: ((_ url: URL, _ data: Any?, _ timeout: TimeInterval) throws -> Void)? override func callFunction(at url: URL, withObject data: Any?, options: HTTPSCallableOptions?, - timeout: TimeInterval) async throws -> HTTPSCallableResult { + timeout: TimeInterval) async throws -> sending HTTPSCallableResult { try verifyParameters?(url, data, timeout) return try mockCallFunction() } From bd6fae7056e89ce3d158ecc6b3d30a7c94bb8179 Mon Sep 17 00:00:00 2001 From: Morgan Chen Date: Fri, 9 May 2025 14:59:33 -0700 Subject: [PATCH 019/113] add FirebaseAI to release notes (#14840) --- scripts/make_release_notes.py | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/make_release_notes.py b/scripts/make_release_notes.py index 4ce00dc87a6..bcda05d53c7 100755 --- a/scripts/make_release_notes.py +++ b/scripts/make_release_notes.py @@ -27,6 +27,7 @@ PRODUCTS = { 'FirebaseABTesting/CHANGELOG.md': '{{ab_testing}}', + 'FirebaseAI/CHANGELOG.md': 'Firebase AI Logic', # update with var 'FirebaseAppCheck/CHANGELOG.md': 'App Check', 'FirebaseAppDistribution/CHANGELOG.md': 'App Distribution', 'FirebaseAuth/CHANGELOG.md': '{{auth}}', From 9b1b647ac1f1a1fec72fcac8d6fbc809d7c9b4c3 Mon Sep 17 00:00:00 2001 From: Nick Cooke <36927374+ncooke3@users.noreply.github.com> Date: Tue, 13 May 2025 11:07:39 -0400 Subject: [PATCH 020/113] [Functions] Complete Swift 6 support (#14838) --- .github/workflows/functions.yml | 3 + .../Sources/Callable+Codable.swift | 3 +- .../Sources/FunctionsError.swift | 4 +- FirebaseFunctions/Sources/HTTPSCallable.swift | 30 +++++++++ .../Internal/FunctionsSerializer.swift | 14 ++++ .../Tests/Integration/IntegrationTests.swift | 64 ++++++++++--------- .../FirebaseDataEncoder.swift | 2 +- 7 files changed, 87 insertions(+), 33 deletions(-) diff --git a/.github/workflows/functions.yml b/.github/workflows/functions.yml index a44b1a603bb..ffb82914e53 100644 --- a/.github/workflows/functions.yml +++ b/.github/workflows/functions.yml @@ -31,6 +31,7 @@ jobs: strategy: matrix: target: [ios, tvos, macos, watchos] + swift_version: [5.9, 6.0] build-env: - os: macos-15 xcode: Xcode_16.3 @@ -44,6 +45,8 @@ jobs: run: scripts/setup_bundler.sh - name: Integration Test Server run: FirebaseFunctions/Backend/start.sh synchronous + - name: Set Swift swift_version + run: sed -i "" "s/s.swift_version[[:space:]]*=[[:space:]]*'5.9'/s.swift_version = '${{ matrix.swift_version }}'/" FirebaseFunctions.podspec - name: Build and test run: | scripts/third_party/travis/retry.sh scripts/pod_lib_lint.rb FirebaseFunctions.podspec \ diff --git a/FirebaseFunctions/Sources/Callable+Codable.swift b/FirebaseFunctions/Sources/Callable+Codable.swift index ba768e4b4ff..4938dad1ab3 100644 --- a/FirebaseFunctions/Sources/Callable+Codable.swift +++ b/FirebaseFunctions/Sources/Callable+Codable.swift @@ -175,7 +175,8 @@ private protocol StreamResponseProtocol {} /// This can be used as the generic `Response` parameter to ``Callable`` to receive both the /// yielded messages and final return value of the streaming callable function. @available(macOS 12.0, iOS 15.0, watchOS 8.0, tvOS 15.0, *) -public enum StreamResponse: Decodable, +public enum StreamResponse: Decodable, + Sendable, StreamResponseProtocol { /// The message yielded by the callable function. case message(Message) diff --git a/FirebaseFunctions/Sources/FunctionsError.swift b/FirebaseFunctions/Sources/FunctionsError.swift index 7d1b5d0902b..9da9d4a6da7 100644 --- a/FirebaseFunctions/Sources/FunctionsError.swift +++ b/FirebaseFunctions/Sources/FunctionsError.swift @@ -151,8 +151,10 @@ private extension FunctionsErrorCode { } } +// TODO(ncooke3): Revisit this unchecked Sendable conformance. + /// The object used to report errors that occur during a function’s execution. -struct FunctionsError: CustomNSError { +struct FunctionsError: CustomNSError, @unchecked Sendable { static let errorDomain = FunctionsErrorDomain let code: FunctionsErrorCode diff --git a/FirebaseFunctions/Sources/HTTPSCallable.swift b/FirebaseFunctions/Sources/HTTPSCallable.swift index 00b6ee37463..ab1c02378e8 100644 --- a/FirebaseFunctions/Sources/HTTPSCallable.swift +++ b/FirebaseFunctions/Sources/HTTPSCallable.swift @@ -71,10 +71,39 @@ open class HTTPSCallable: NSObject, @unchecked Sendable { /// - Parameters: /// - data: Parameters to pass to the trigger. /// - completion: The block to call when the HTTPS request has completed. + @available(swift 1000.0) // Objective-C only API @objc(callWithObject:completion:) open func call(_ data: Any? = nil, completion: @escaping @MainActor (HTTPSCallableResult?, Error?) -> Void) { + sendableCallable.call(SendableWrapper(value: data as Any), completion: completion) + } + + /// Executes this Callable HTTPS trigger asynchronously. + /// + /// The data passed into the trigger can be any of the following types: + /// - `nil` or `NSNull` + /// - `String` + /// - `NSNumber`, or any Swift numeric type bridgeable to `NSNumber` + /// - `[Any]`, where the contained objects are also one of these types. + /// - `[String: Any]` where the values are also one of these types. + /// + /// The request to the Cloud Functions backend made by this method automatically includes a + /// Firebase Installations ID token to identify the app instance. If a user is logged in with + /// Firebase Auth, an auth ID token for the user is also automatically included. + /// + /// Firebase Cloud Messaging sends data to the Firebase backend periodically to collect + /// information + /// regarding the app instance. To stop this, see `Messaging.deleteData()`. It + /// resumes with a new FCM Token the next time you call this method. + /// + /// - Parameters: + /// - data: Parameters to pass to the trigger. + /// - completion: The block to call when the HTTPS request has completed. + @nonobjc open func call(_ data: sending Any? = nil, + completion: @escaping @MainActor (HTTPSCallableResult?, + Error?) + -> Void) { sendableCallable.call(data, completion: completion) } @@ -154,6 +183,7 @@ private extension HTTPSCallable { func call(_ data: sending Any? = nil, completion: @escaping @MainActor (HTTPSCallableResult?, Error?) -> Void) { + let data = (data as? SendableWrapper)?.value ?? data if #available(iOS 13, macCatalyst 13, macOS 10.15, tvOS 13, watchOS 7, *) { Task { do { diff --git a/FirebaseFunctions/Sources/Internal/FunctionsSerializer.swift b/FirebaseFunctions/Sources/Internal/FunctionsSerializer.swift index 6eda0720cb9..00415cfa341 100644 --- a/FirebaseFunctions/Sources/Internal/FunctionsSerializer.swift +++ b/FirebaseFunctions/Sources/Internal/FunctionsSerializer.swift @@ -31,6 +31,13 @@ extension FunctionsSerializer { final class FunctionsSerializer: Sendable { // MARK: - Internal APIs + // This function only supports the following types and will otherwise throw + // an error. + // - NSNull (note: `nil` collection values from a Swift caller will be treated as NSNull) + // - NSNumber + // - NSString + // - NSDicionary + // - NSArray func encode(_ object: Any) throws -> Any { if object is NSNull { return object @@ -53,6 +60,13 @@ final class FunctionsSerializer: Sendable { } } + // This function only supports the following types and will otherwise throw + // an error. + // - NSNull (note: `nil` collection values from a Swift caller will be treated as NSNull) + // - NSNumber + // - NSString + // - NSDicionary + // - NSArray func decode(_ object: Any) throws -> Any { // Return these types as is. PORTING NOTE: Moved from the bottom of the func for readability. if let dict = object as? NSDictionary { diff --git a/FirebaseFunctions/Tests/Integration/IntegrationTests.swift b/FirebaseFunctions/Tests/Integration/IntegrationTests.swift index 0fa9c21e862..3032c700bc1 100644 --- a/FirebaseFunctions/Tests/Integration/IntegrationTests.swift +++ b/FirebaseFunctions/Tests/Integration/IntegrationTests.swift @@ -83,7 +83,7 @@ class IntegrationTests: XCTestCase { return URL(string: "http://localhost:5005/functions-integration-test/us-central1/\(funcName)")! } - func testData() { + @MainActor func testData() { let data = DataTestRequest( bool: true, int: 2, @@ -148,7 +148,7 @@ class IntegrationTests: XCTestCase { } } - func testScalar() { + @MainActor func testScalar() { let byName = functions.httpsCallable( "scalarTest", requestAs: Int16.self, @@ -203,7 +203,7 @@ class IntegrationTests: XCTestCase { } } - func testToken() { + @MainActor func testToken() { // Recreate functions with a token. let functions = Functions( projectID: "functions-integration-test", @@ -271,7 +271,7 @@ class IntegrationTests: XCTestCase { } } - func testFCMToken() { + @MainActor func testFCMToken() { let byName = functions.httpsCallable( "FCMTokenTest", requestAs: [String: Int].self, @@ -316,7 +316,7 @@ class IntegrationTests: XCTestCase { } } - func testNull() { + @MainActor func testNull() { let byName = functions.httpsCallable( "nullTest", requestAs: Int?.self, @@ -361,7 +361,7 @@ class IntegrationTests: XCTestCase { } } - func testMissingResult() { + @MainActor func testMissingResult() { let byName = functions.httpsCallable( "missingResultTest", requestAs: Int?.self, @@ -415,7 +415,7 @@ class IntegrationTests: XCTestCase { } } - func testUnhandledError() { + @MainActor func testUnhandledError() { let byName = functions.httpsCallable( "unhandledErrorTest", requestAs: [Int].self, @@ -469,7 +469,7 @@ class IntegrationTests: XCTestCase { } } - func testUnknownError() { + @MainActor func testUnknownError() { let byName = functions.httpsCallable( "unknownErrorTest", requestAs: [Int].self, @@ -522,7 +522,7 @@ class IntegrationTests: XCTestCase { } } - func testExplicitError() { + @MainActor func testExplicitError() { let byName = functions.httpsCallable( "explicitErrorTest", requestAs: [Int].self, @@ -579,7 +579,7 @@ class IntegrationTests: XCTestCase { } } - func testHttpError() { + @MainActor func testHttpError() { let byName = functions.httpsCallable( "httpErrorTest", requestAs: [Int].self, @@ -631,7 +631,7 @@ class IntegrationTests: XCTestCase { } } - func testThrowError() { + @MainActor func testThrowError() { let byName = functions.httpsCallable( "throwTest", requestAs: [Int].self, @@ -685,7 +685,7 @@ class IntegrationTests: XCTestCase { } } - func testTimeout() { + @MainActor func testTimeout() { let byName = functions.httpsCallable( "timeoutTest", requestAs: [Int].self, @@ -743,7 +743,7 @@ class IntegrationTests: XCTestCase { } } - func testCallAsFunction() { + @MainActor func testCallAsFunction() { let data = DataTestRequest( bool: true, int: 2, @@ -808,7 +808,7 @@ class IntegrationTests: XCTestCase { } } - func testInferredTypes() { + @MainActor func testInferredTypes() { let data = DataTestRequest( bool: true, int: 2, @@ -868,7 +868,7 @@ class IntegrationTests: XCTestCase { } } - func testFunctionsReturnsOnMainThread() { + @MainActor func testFunctionsReturnsOnMainThread() { let expectation = expectation(description: #function) functions.httpsCallable( "scalarTest", @@ -884,7 +884,7 @@ class IntegrationTests: XCTestCase { waitForExpectations(timeout: 5) } - func testFunctionsThrowsOnMainThread() { + @MainActor func testFunctionsThrowsOnMainThread() { let expectation = expectation(description: #function) functions.httpsCallable( "httpErrorTest", @@ -908,7 +908,7 @@ class IntegrationTests: XCTestCase { /// /// This can be used as the generic `Request` parameter to ``Callable`` to /// indicate the callable function does not accept parameters. -private struct EmptyRequest: Encodable {} +private struct EmptyRequest: Encodable, Sendable {} @available(macOS 12.0, iOS 15.0, watchOS 8.0, tvOS 15.0, *) extension IntegrationTests { @@ -1100,18 +1100,21 @@ extension IntegrationTests { ) } - func testStream_Canceled() async throws { - let task = Task.detached { [self] in - let callable: Callable = functions.httpsCallable("genStream") - let stream = try callable.stream() - // Since we cancel the call we are expecting an empty array. - return try await stream.reduce([]) { $0 + [$1] } as [String] + // Concurrency rules prevent easily testing this feature. + #if swift(<6) + func testStream_Canceled() async throws { + let task = Task.detached { [self] in + let callable: Callable = functions.httpsCallable("genStream") + let stream = try callable.stream() + // Since we cancel the call we are expecting an empty array. + return try await stream.reduce([]) { $0 + [$1] } as [String] + } + // We cancel the task and we expect a null response even if the stream was initiated. + task.cancel() + let respone = try await task.value + XCTAssertEqual(respone, []) } - // We cancel the task and we expect a null response even if the stream was initiated. - task.cancel() - let respone = try await task.value - XCTAssertEqual(respone, []) - } + #endif func testStream_NonexistentFunction() async throws { let callable: Callable = functions.httpsCallable( @@ -1163,7 +1166,8 @@ extension IntegrationTests { func testStream_ResultIsOnlyExposedInStreamResponse() async throws { // The implementation is copied from `StreamResponse`. The only difference is the do-catch is // removed from the decoding initializer. - enum MyStreamResponse: Decodable { + enum MyStreamResponse: Decodable, + Sendable { /// The message yielded by the callable function. case message(Message) /// The final result returned by the callable function. @@ -1248,7 +1252,7 @@ extension IntegrationTests { } func testStream_ResultOnly_StreamResponse() async throws { - struct EmptyResponse: Decodable {} + struct EmptyResponse: Decodable, Sendable {} let callable: Callable> = functions .httpsCallable( "genStreamResultOnly" diff --git a/FirebaseSharedSwift/Sources/third_party/FirebaseDataEncoder/FirebaseDataEncoder.swift b/FirebaseSharedSwift/Sources/third_party/FirebaseDataEncoder/FirebaseDataEncoder.swift index cc3dc36bd30..b881486388e 100644 --- a/FirebaseSharedSwift/Sources/third_party/FirebaseDataEncoder/FirebaseDataEncoder.swift +++ b/FirebaseSharedSwift/Sources/third_party/FirebaseDataEncoder/FirebaseDataEncoder.swift @@ -286,7 +286,7 @@ public class FirebaseDataEncoder { /// - returns: A new `Data` value containing the encoded JSON data. /// - throws: `EncodingError.invalidValue` if a non-conforming floating-point value is encountered during encoding, and the encoding strategy is `.throw`. /// - throws: An error if any value throws an error during encoding. - open func encode(_ value: T) throws -> Any { + open func encode(_ value: T) throws -> sending Any { let encoder = __JSONEncoder(options: self.options) guard let topLevel = try encoder.box_(value) else { From 45d1d2cef52bda094f37d1e917547ae7fd4d5918 Mon Sep 17 00:00:00 2001 From: Andrew Heard Date: Wed, 14 May 2025 11:59:49 -0400 Subject: [PATCH 021/113] [Firebase AI] Update Gemma candidate token count integration tests (#14855) --- .../GenerateContentIntegrationTests.swift | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/FirebaseAI/Tests/TestApp/Tests/Integration/GenerateContentIntegrationTests.swift b/FirebaseAI/Tests/TestApp/Tests/Integration/GenerateContentIntegrationTests.swift index b90f937b480..608c28b4833 100644 --- a/FirebaseAI/Tests/TestApp/Tests/Integration/GenerateContentIntegrationTests.swift +++ b/FirebaseAI/Tests/TestApp/Tests/Integration/GenerateContentIntegrationTests.swift @@ -75,21 +75,25 @@ struct GenerateContentIntegrationTests { let usageMetadata = try #require(response.usageMetadata) #expect(usageMetadata.promptTokenCount.isEqual(to: 13, accuracy: tokenCountAccuracy)) - #expect(usageMetadata.candidatesTokenCount.isEqual(to: 3, accuracy: tokenCountAccuracy)) - #expect(usageMetadata.totalTokenCount.isEqual(to: 16, accuracy: tokenCountAccuracy)) #expect(usageMetadata.promptTokensDetails.count == 1) let promptTokensDetails = try #require(usageMetadata.promptTokensDetails.first) #expect(promptTokensDetails.modality == .text) #expect(promptTokensDetails.tokenCount == usageMetadata.promptTokenCount) - // The field `candidatesTokensDetails` is not included when using Gemma models. - if modelName == ModelNames.gemma3_4B { + // The fields `candidatesTokenCount` and `candidatesTokensDetails` are not included when using + // Gemma models. + if modelName.hasPrefix("gemma") { + #expect(usageMetadata.candidatesTokenCount == 0) #expect(usageMetadata.candidatesTokensDetails.isEmpty) } else { + #expect(usageMetadata.candidatesTokenCount.isEqual(to: 3, accuracy: tokenCountAccuracy)) #expect(usageMetadata.candidatesTokensDetails.count == 1) let candidatesTokensDetails = try #require(usageMetadata.candidatesTokensDetails.first) #expect(candidatesTokensDetails.modality == .text) #expect(candidatesTokensDetails.tokenCount == usageMetadata.candidatesTokenCount) } + #expect(usageMetadata.totalTokenCount > 0) + #expect(usageMetadata.totalTokenCount == + (usageMetadata.promptTokenCount + usageMetadata.candidatesTokenCount)) } @Test( From 0b78a276e8e3b18f0ca632fa8176254830cd7613 Mon Sep 17 00:00:00 2001 From: Nick Cooke <36927374+ncooke3@users.noreply.github.com> Date: Wed, 14 May 2025 17:53:28 -0400 Subject: [PATCH 022/113] [Auth] Add Swift 6 conformance to `FirebaseAuth/Sources/Swift/SystemService/` directory (#14839) Co-authored-by: Morgan Chen --- .../Swift/SystemService/AuthAPNSToken.swift | 8 ++-- .../SystemService/AuthAPNSTokenManager.swift | 13 +++--- .../SystemService/AuthAPNSTokenType.swift | 2 +- .../SystemService/AuthAppCredential.swift | 6 +-- .../SystemService/SecureTokenService.swift | 40 +++++++++++------ .../Unit/AuthAPNSTokenManagerTests.swift | 45 +++++++++++-------- FirebaseAuth/Tests/Unit/AuthTests.swift | 4 +- .../Tests/Unit/PhoneAuthProviderTests.swift | 2 +- 8 files changed, 73 insertions(+), 47 deletions(-) diff --git a/FirebaseAuth/Sources/Swift/SystemService/AuthAPNSToken.swift b/FirebaseAuth/Sources/Swift/SystemService/AuthAPNSToken.swift index 3867f661e89..3f5ad9951ae 100644 --- a/FirebaseAuth/Sources/Swift/SystemService/AuthAPNSToken.swift +++ b/FirebaseAuth/Sources/Swift/SystemService/AuthAPNSToken.swift @@ -15,8 +15,10 @@ #if !os(macOS) import Foundation + // TODO(ncooke3): I believe this could be made a struct now. + /// A data structure for an APNs token. - class AuthAPNSToken { + final class AuthAPNSToken: Sendable { let data: Data let type: AuthAPNSTokenType @@ -30,13 +32,13 @@ } /// The uppercase hexadecimal string form of the APNs token data. - lazy var string: String = { + var string: String { let byteArray = [UInt8](data) var s = "" for byte in byteArray { s.append(String(format: "%02X", byte)) } return s - }() + } } #endif diff --git a/FirebaseAuth/Sources/Swift/SystemService/AuthAPNSTokenManager.swift b/FirebaseAuth/Sources/Swift/SystemService/AuthAPNSTokenManager.swift index 7ced32a77cd..f7da822342e 100644 --- a/FirebaseAuth/Sources/Swift/SystemService/AuthAPNSTokenManager.swift +++ b/FirebaseAuth/Sources/Swift/SystemService/AuthAPNSTokenManager.swift @@ -24,24 +24,25 @@ // Protocol to help with unit tests. protocol AuthAPNSTokenApplication { - func registerForRemoteNotifications() + @MainActor func registerForRemoteNotifications() } extension UIApplication: AuthAPNSTokenApplication {} /// A class to manage APNs token in memory. @available(iOS 13, tvOS 13, macOS 10.15, macCatalyst 13, watchOS 7, *) - class AuthAPNSTokenManager { + class AuthAPNSTokenManager: @unchecked Sendable /* TODO: sendable */ { /// The timeout for registering for remote notification. /// /// Only tests should access this property. - var timeout: TimeInterval = 5 + let timeout: TimeInterval /// Initializes the instance. /// - Parameter application: The `UIApplication` to request the token from. /// - Returns: The initialized instance. - init(withApplication application: AuthAPNSTokenApplication) { + init(withApplication application: sending AuthAPNSTokenApplication, timeout: TimeInterval = 5) { self.application = application + self.timeout = timeout } /// Attempts to get the APNs token. @@ -49,13 +50,15 @@ /// token becomes available, or when timeout occurs, whichever happens earlier. /// /// This function is internal to make visible for tests. - func getTokenInternal(callback: @escaping (Result) -> Void) { + func getTokenInternal(callback: @escaping @Sendable (Result) -> Void) { if let token = tokenStore { callback(.success(token)) return } if pendingCallbacks.count > 0 { pendingCallbacks.append(callback) + // TODO(ncooke3): This is likely a bug in that the async wrapper method + // cannot make forward progress. return } pendingCallbacks = [callback] diff --git a/FirebaseAuth/Sources/Swift/SystemService/AuthAPNSTokenType.swift b/FirebaseAuth/Sources/Swift/SystemService/AuthAPNSTokenType.swift index a11ab157bd4..057676003b0 100644 --- a/FirebaseAuth/Sources/Swift/SystemService/AuthAPNSTokenType.swift +++ b/FirebaseAuth/Sources/Swift/SystemService/AuthAPNSTokenType.swift @@ -19,7 +19,7 @@ /// /// This enum is available on iOS, macOS Catalyst, tvOS, and watchOS only. - @objc(FIRAuthAPNSTokenType) public enum AuthAPNSTokenType: Int { + @objc(FIRAuthAPNSTokenType) public enum AuthAPNSTokenType: Int, Sendable { /// Unknown token type. /// /// The actual token type will be detected from the provisioning profile in the app's bundle. diff --git a/FirebaseAuth/Sources/Swift/SystemService/AuthAppCredential.swift b/FirebaseAuth/Sources/Swift/SystemService/AuthAppCredential.swift index beb0d15a7b1..e5624eb4106 100644 --- a/FirebaseAuth/Sources/Swift/SystemService/AuthAppCredential.swift +++ b/FirebaseAuth/Sources/Swift/SystemService/AuthAppCredential.swift @@ -16,12 +16,12 @@ import Foundation /// A class represents a credential that proves the identity of the app. @objc(FIRAuthAppCredential) // objc Needed for decoding old versions -class AuthAppCredential: NSObject, NSSecureCoding { +final class AuthAppCredential: NSObject, NSSecureCoding, Sendable { /// The server acknowledgement of receiving client's claim of identity. - var receipt: String + let receipt: String /// The secret that the client received from server via a trusted channel, if ever. - var secret: String? + let secret: String? /// Initializes the instance. /// - Parameter receipt: The server acknowledgement of receiving client's claim of identity. diff --git a/FirebaseAuth/Sources/Swift/SystemService/SecureTokenService.swift b/FirebaseAuth/Sources/Swift/SystemService/SecureTokenService.swift index a0cfa6faed0..0faa99e25f7 100644 --- a/FirebaseAuth/Sources/Swift/SystemService/SecureTokenService.swift +++ b/FirebaseAuth/Sources/Swift/SystemService/SecureTokenService.swift @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -import Foundation +import FirebaseCoreInternal private let kFiveMinutes = 5 * 60.0 @@ -114,12 +114,17 @@ actor SecureTokenServiceInternal { /// A class represents a credential that proves the identity of the app. @available(iOS 13, tvOS 13, macOS 10.15, macCatalyst 13, watchOS 7, *) @objc(FIRSecureTokenService) // objc Needed for decoding old versions -class SecureTokenService: NSObject, NSSecureCoding { +final class SecureTokenService: NSObject, NSSecureCoding, Sendable { /// Internal actor to enforce serialization private let internalService: SecureTokenServiceInternal /// The configuration for making requests to server. - var requestConfiguration: AuthRequestConfiguration? + var requestConfiguration: AuthRequestConfiguration? { + get { _requestConfiguration.withLock { $0 } } + set { _requestConfiguration.withLock { $0 = newValue } } + } + + let _requestConfiguration: FIRAllocatedUnfairLock /// The cached access token. /// @@ -130,20 +135,29 @@ class SecureTokenService: NSObject, NSSecureCoding { /// - Note: The atomic wrapper can be removed when the SDK is fully /// synchronized with structured concurrency. var accessToken: String { - get { accessTokenLock.withLock { _accessToken } } - set { accessTokenLock.withLock { _accessToken = newValue } } + get { _accessToken.withLock { $0 } } + set { _accessToken.withLock { $0 = newValue } } } - private var _accessToken: String - private let accessTokenLock = NSLock() + private let _accessToken: FIRAllocatedUnfairLock /// The refresh token for the user, or `nil` if the user has yet completed sign-in flow. /// /// This property needs to be set manually after the instance is decoded from archive. - var refreshToken: String? + var refreshToken: String? { + get { _refreshToken.withLock { $0 } } + set { _refreshToken.withLock { $0 = newValue } } + } + + private let _refreshToken: FIRAllocatedUnfairLock /// The expiration date of the cached access token. - var accessTokenExpirationDate: Date? + var accessTokenExpirationDate: Date? { + get { _accessTokenExpirationDate.withLock { $0 } } + set { _accessTokenExpirationDate.withLock { $0 = newValue } } + } + + private let _accessTokenExpirationDate: FIRAllocatedUnfairLock /// Creates a `SecureTokenService` with access and refresh tokens. /// - Parameter requestConfiguration: The configuration for making requests to server. @@ -155,10 +169,10 @@ class SecureTokenService: NSObject, NSSecureCoding { accessTokenExpirationDate: Date?, refreshToken: String) { internalService = SecureTokenServiceInternal() - self.requestConfiguration = requestConfiguration - _accessToken = accessToken - self.accessTokenExpirationDate = accessTokenExpirationDate - self.refreshToken = refreshToken + _requestConfiguration = FIRAllocatedUnfairLock(initialState: requestConfiguration) + _accessToken = FIRAllocatedUnfairLock(initialState: accessToken) + _accessTokenExpirationDate = FIRAllocatedUnfairLock(initialState: accessTokenExpirationDate) + _refreshToken = FIRAllocatedUnfairLock(initialState: refreshToken) } /// Fetch a fresh ephemeral access token for the ID associated with this instance. The token diff --git a/FirebaseAuth/Tests/Unit/AuthAPNSTokenManagerTests.swift b/FirebaseAuth/Tests/Unit/AuthAPNSTokenManagerTests.swift index 3406149ee90..0dec3c5e4ce 100644 --- a/FirebaseAuth/Tests/Unit/AuthAPNSTokenManagerTests.swift +++ b/FirebaseAuth/Tests/Unit/AuthAPNSTokenManagerTests.swift @@ -17,6 +17,7 @@ import XCTest @testable import FirebaseAuth + import FirebaseCoreInternal @available(iOS 13, tvOS 13, macOS 10.15, macCatalyst 13, watchOS 7, *) class AuthAPNSTokenManagerTests: XCTestCase { @@ -61,10 +62,10 @@ func testCallback() throws { let expectation = self.expectation(description: #function) XCTAssertFalse(fakeApplication!.registerCalled) - var firstCallbackCalled = false + let firstCallbackCalled = FIRAllocatedUnfairLock(initialState: false) let manager = try XCTUnwrap(manager) manager.getTokenInternal { result in - firstCallbackCalled = true + firstCallbackCalled.withLock { $0 = true } switch result { case let .success(token): XCTAssertEqual(token.data, self.data) @@ -73,12 +74,12 @@ XCTFail("Unexpected error: \(error)") } } - XCTAssertFalse(firstCallbackCalled) + XCTAssertFalse(firstCallbackCalled.value()) // Add second callback, which is yet to be called either. - var secondCallbackCalled = false + let secondCallbackCalled = FIRAllocatedUnfairLock(initialState: false) manager.getTokenInternal { result in - secondCallbackCalled = true + secondCallbackCalled.withLock { $0 = true } switch result { case let .success(token): XCTAssertEqual(token.data, self.data) @@ -87,25 +88,25 @@ XCTFail("Unexpected error: \(error)") } } - XCTAssertFalse(secondCallbackCalled) + XCTAssertFalse(secondCallbackCalled.value()) // Setting nil token shouldn't trigger either callbacks. manager.token = nil - XCTAssertFalse(firstCallbackCalled) - XCTAssertFalse(secondCallbackCalled) + XCTAssertFalse(firstCallbackCalled.value()) + XCTAssertFalse(secondCallbackCalled.value()) XCTAssertNil(manager.token) // Setting a real token should trigger both callbacks. manager.token = AuthAPNSToken(withData: data!, type: .sandbox) - XCTAssertTrue(firstCallbackCalled) - XCTAssertTrue(secondCallbackCalled) + XCTAssertTrue(firstCallbackCalled.value()) + XCTAssertTrue(secondCallbackCalled.value()) XCTAssertEqual(manager.token?.data, data) XCTAssertEqual(manager.token?.type, .sandbox) // Add third callback, which should be called back immediately. - var thirdCallbackCalled = false + let thirdCallbackCalled = FIRAllocatedUnfairLock(initialState: false) manager.getTokenInternal { result in - thirdCallbackCalled = true + thirdCallbackCalled.withLock { $0 = true } switch result { case let .success(token): XCTAssertEqual(token.data, self.data) @@ -114,7 +115,7 @@ XCTFail("Unexpected error: \(error)") } } - XCTAssertTrue(thirdCallbackCalled) + XCTAssertTrue(thirdCallbackCalled.value()) // In the main thread, Verify the that the fake `registerForRemoteNotifications` was called. DispatchQueue.main.async { @@ -129,9 +130,12 @@ */ func testTimeout() throws { // Set up timeout. + manager = AuthAPNSTokenManager( + withApplication: fakeApplication!, + timeout: kRegistrationTimeout + ) let manager = try XCTUnwrap(manager) XCTAssertGreaterThan(try XCTUnwrap(manager.timeout), 0) - manager.timeout = kRegistrationTimeout // Add callback to time out. let expectation = self.expectation(description: #function) @@ -166,12 +170,15 @@ */ func testCancel() throws { // Set up timeout. + manager = AuthAPNSTokenManager( + withApplication: fakeApplication!, + timeout: kRegistrationTimeout + ) let manager = try XCTUnwrap(manager) XCTAssertGreaterThan(try XCTUnwrap(manager.timeout), 0) - manager.timeout = kRegistrationTimeout // Add callback to cancel. - var callbackCalled = false + let callbackCalled = FIRAllocatedUnfairLock(initialState: false) manager.getTokenInternal { result in switch result { case let .success(token): @@ -179,10 +186,10 @@ case let .failure(error): XCTAssertEqual(error as NSError, self.error as NSError) } - XCTAssertFalse(callbackCalled) // verify callback is not called twice - callbackCalled = true + XCTAssertFalse(callbackCalled.value()) // verify callback is not called twice + callbackCalled.withLock { $0 = true } } - XCTAssertFalse(callbackCalled) + XCTAssertFalse(callbackCalled.value()) // Call cancel. manager.cancel(withError: error) diff --git a/FirebaseAuth/Tests/Unit/AuthTests.swift b/FirebaseAuth/Tests/Unit/AuthTests.swift index dc39e1448cb..e1057f247b2 100644 --- a/FirebaseAuth/Tests/Unit/AuthTests.swift +++ b/FirebaseAuth/Tests/Unit/AuthTests.swift @@ -2291,7 +2291,7 @@ class AuthTests: RPCBaseTests { #if os(iOS) func testAppDidRegisterForRemoteNotifications_APNSTokenUpdated() { - class FakeAuthTokenManager: AuthAPNSTokenManager { + class FakeAuthTokenManager: AuthAPNSTokenManager, @unchecked Sendable { override var token: AuthAPNSToken? { get { return tokenStore @@ -2310,7 +2310,7 @@ class AuthTests: RPCBaseTests { } func testAppDidFailToRegisterForRemoteNotifications_TokenManagerCancels() { - class FakeAuthTokenManager: AuthAPNSTokenManager { + class FakeAuthTokenManager: AuthAPNSTokenManager, @unchecked Sendable { var cancelled = false override func cancel(withError error: Error) { cancelled = true diff --git a/FirebaseAuth/Tests/Unit/PhoneAuthProviderTests.swift b/FirebaseAuth/Tests/Unit/PhoneAuthProviderTests.swift index 94880a3d856..e5a3e3bf766 100644 --- a/FirebaseAuth/Tests/Unit/PhoneAuthProviderTests.swift +++ b/FirebaseAuth/Tests/Unit/PhoneAuthProviderTests.swift @@ -923,7 +923,7 @@ } } - class FakeTokenManager: AuthAPNSTokenManager { + class FakeTokenManager: AuthAPNSTokenManager, @unchecked Sendable { override func getTokenInternal(callback: @escaping (Result) -> Void) { let error = NSError(domain: "dummy domain", code: AuthErrorCode.missingAppToken.rawValue) callback(.failure(error)) From 9daa421d0756016b9156664f0c7aa8c849fb22cc Mon Sep 17 00:00:00 2001 From: Andrew Heard Date: Thu, 15 May 2025 10:39:32 -0400 Subject: [PATCH 023/113] [Firebase AI] Upload `xcodebuild` logs in integration tests (#14844) --- .github/workflows/firebaseai.yml | 7 +++++++ scripts/build.sh | 24 +++++++++++++++++------- 2 files changed, 24 insertions(+), 7 deletions(-) diff --git a/.github/workflows/firebaseai.yml b/.github/workflows/firebaseai.yml index 2b719a9fc41..1924ecbf2a0 100644 --- a/.github/workflows/firebaseai.yml +++ b/.github/workflows/firebaseai.yml @@ -131,6 +131,13 @@ jobs: run: sudo xcode-select -s /Applications/${{ matrix.xcode }}.app/Contents/Developer - name: Run IntegrationTests run: scripts/build.sh FirebaseAIIntegration ${{ matrix.target }} + - name: Upload xcodebuild logs + if: failure() + uses: actions/upload-artifact@v4 + with: + name: xcodebuild-${{ matrix.target }}-${{ matrix.os }}-${{ matrix.xcode }}.log + path: xcodebuild-*.log + retention-days: 2 pod-lib-lint: # Don't run on private repo unless it is a PR. diff --git a/scripts/build.sh b/scripts/build.sh index 72fa057f65e..b11fba7d804 100755 --- a/scripts/build.sh +++ b/scripts/build.sh @@ -109,12 +109,15 @@ source scripts/check_secrets.sh # If xcodebuild fails with known error codes, retries once. function RunXcodebuild() { echo xcodebuild "$@" + local xcodebuild_args=("$@") + local buildaction="${xcodebuild_args[$# - 1]}" # buildaction is the last arg + local log_filename="xcodebuild-${buildaction}.log" - xcbeautify_cmd=(xcbeautify --renderer github-actions --disable-logging) + local xcbeautify_cmd=(xcbeautify --renderer github-actions --disable-logging) - result=0 - xcodebuild "$@" | tee xcodebuild.log | "${xcbeautify_cmd[@]}" \ - && CheckUnexpectedFailures xcodebuild.log \ + local result=0 + NSUnbufferedIO=YES xcodebuild "$@" 2>&1 | tee "$log_filename" | \ + "${xcbeautify_cmd[@]}" && CheckUnexpectedFailures "$log_filename" \ || result=$? if [[ $result == 65 ]]; then @@ -124,8 +127,8 @@ function RunXcodebuild() { sleep 5 result=0 - xcodebuild "$@" | tee xcodebuild.log | "${xcbeautify_cmd[@]}" \ - && CheckUnexpectedFailures xcodebuild.log \ + NSUnbufferedIO=YES xcodebuild "$@" 2>&1 | tee "$log_filename" | \ + "${xcbeautify_cmd[@]}" && CheckUnexpectedFailures "$log_filename" \ || result=$? fi @@ -505,12 +508,19 @@ case "$product-$platform-$method" in ;; FirebaseAIIntegration-*-*) + # Build + RunXcodebuild \ + -project 'FirebaseAI/Tests/TestApp/VertexAITestApp.xcodeproj' \ + -scheme "VertexAITestApp-SPM" \ + "${xcb_flags[@]}" \ + build + + # Run tests RunXcodebuild \ -project 'FirebaseAI/Tests/TestApp/VertexAITestApp.xcodeproj' \ -scheme "VertexAITestApp-SPM" \ "${xcb_flags[@]}" \ -parallel-testing-enabled NO \ - build \ test ;; From 6e562a0c1f5771a60fbb57faedcbd8148992d4db Mon Sep 17 00:00:00 2001 From: Andrew Heard Date: Thu, 15 May 2025 15:12:29 -0400 Subject: [PATCH 024/113] [Firebase AI] Update CHANGELOG entry wording (#14857) --- .github/workflows/firebaseai.yml | 2 ++ FirebaseAI/CHANGELOG.md | 19 ++++++++++--------- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/.github/workflows/firebaseai.yml b/.github/workflows/firebaseai.yml index 1924ecbf2a0..0dd842615cc 100644 --- a/.github/workflows/firebaseai.yml +++ b/.github/workflows/firebaseai.yml @@ -8,6 +8,8 @@ on: - 'scripts/quickstart_build_spm.sh' - 'scripts/quickstart_spm_xcodeproj.sh' - 'Gemfile*' + # Do not run for documentation-only PRs. + - '!**.md' schedule: # Run every day at 11pm (PST) - cron uses UTC times - cron: '0 7 * * *' diff --git a/FirebaseAI/CHANGELOG.md b/FirebaseAI/CHANGELOG.md index e2abf5120ed..d7b7ac5536e 100644 --- a/FirebaseAI/CHANGELOG.md +++ b/FirebaseAI/CHANGELOG.md @@ -1,19 +1,20 @@ # 11.13.0 -- [feature] Initial release of the Firebase AI SDK (`FirebaseAI`). This SDK - *replaces* the previous Vertex AI in Firebase SDK (`FirebaseVertexAI`) to +- [feature] Initial release of the Firebase AI Logic SDK (`FirebaseAI`). This + SDK *replaces* the previous Vertex AI in Firebase SDK (`FirebaseVertexAI`) to accommodate the evolving set of supported features and services. - - The new Firebase AI SDK provides **public preview** support for the Gemini + - The new Firebase AI Logic SDK provides **preview** support for the Gemini Developer API, including its free tier offering. - - Using the Firebase AI SDK with the Vertex AI Gemini API is still generally - available (GA). -

+ - Using the Firebase AI Logic SDK with the Vertex AI Gemini API is still + generally available (GA). + To start using the new SDK, import the `FirebaseAI` module and use the - top-level `FirebaseAI` class. + top-level `FirebaseAI` class. See details in the [migration guide + ](https://firebase.google.com/docs/vertex-ai/migrate-to-latest-sdk). - [fixed] Fixed `ModalityTokenCount` decoding when the `tokenCount` field is omitted; this occurs when the count is 0. (#14745) - [fixed] Fixed `Candidate` decoding when `SafetyRating` values are missing a - category or probability; this may occur when using `gemini-2.0-flash-exp` for - image generation. (#14817) + category or probability; this may occur when using Gemini for image + generation. (#14817) # 11.12.0 - [added] **Public Preview**: Added support for specifying response modalities From 79f584a091b32f33e2b73eb82443d44c292fdcf6 Mon Sep 17 00:00:00 2001 From: leojaygoogle <98397998+leojaygoogle@users.noreply.github.com> Date: Thu, 15 May 2025 12:16:04 -0700 Subject: [PATCH 025/113] Bind rmqID instead of using stringWithFormat. (#14856) --- FirebaseMessaging/CHANGELOG.md | 3 +++ .../Sources/FIRMessagingRmqManager.m | 13 ++++++++++--- .../Tests/UnitTests/FIRMessagingRmqManagerTest.m | 15 +++++++++++++++ 3 files changed, 28 insertions(+), 3 deletions(-) diff --git a/FirebaseMessaging/CHANGELOG.md b/FirebaseMessaging/CHANGELOG.md index 68694c63d15..93e20e17717 100644 --- a/FirebaseMessaging/CHANGELOG.md +++ b/FirebaseMessaging/CHANGELOG.md @@ -1,3 +1,6 @@ +# Unreleased +- [fixed] Fix a potential SQL injection issue. (#14846). + # 11.9.0 - [fixed] Migrate FCM codebase to new NSKeyedUnarchiver APIs. (#14424). diff --git a/FirebaseMessaging/Sources/FIRMessagingRmqManager.m b/FirebaseMessaging/Sources/FIRMessagingRmqManager.m index a5499c7b7ce..6a28d1d926d 100644 --- a/FirebaseMessaging/Sources/FIRMessagingRmqManager.m +++ b/FirebaseMessaging/Sources/FIRMessagingRmqManager.m @@ -277,14 +277,14 @@ - (int64_t)queryLastRmqId { - (FIRMessagingPersistentSyncMessage *)querySyncMessageWithRmqID:(NSString *)rmqID { __block FIRMessagingPersistentSyncMessage *persistentMessage; dispatch_sync(_databaseOperationQueue, ^{ - NSString *queryFormat = @"SELECT %@ FROM %@ WHERE %@ = '%@'"; + NSString *queryFormat = @"SELECT %@ FROM %@ WHERE %@ = ?"; NSString *query = [NSString stringWithFormat:queryFormat, kSyncMessagesColumns, // SELECT (rmq_id, expiration_ts, // apns_recv, mcs_recv) kTableSyncMessages, // FROM sync_rmq - kRmqIdColumn, // WHERE rmq_id - rmqID]; + kRmqIdColumn // WHERE rmq_id + ]; sqlite3_stmt *stmt; if (sqlite3_prepare_v2(self->_database, [query UTF8String], -1, &stmt, NULL) != SQLITE_OK) { @@ -293,6 +293,13 @@ - (FIRMessagingPersistentSyncMessage *)querySyncMessageWithRmqID:(NSString *)rmq return; } + if (sqlite3_bind_text(stmt, 1, [rmqID UTF8String], (int)[rmqID length], SQLITE_STATIC) != + SQLITE_OK) { + [self logError]; + sqlite3_finalize(stmt); + return; + } + const int rmqIDColumn = 0; const int expirationTimestampColumn = 1; const int apnsReceivedColumn = 2; diff --git a/FirebaseMessaging/Tests/UnitTests/FIRMessagingRmqManagerTest.m b/FirebaseMessaging/Tests/UnitTests/FIRMessagingRmqManagerTest.m index 44b207444fd..ef08e31e4f5 100644 --- a/FirebaseMessaging/Tests/UnitTests/FIRMessagingRmqManagerTest.m +++ b/FirebaseMessaging/Tests/UnitTests/FIRMessagingRmqManagerTest.m @@ -81,6 +81,21 @@ - (void)testSavingSyncMessage { XCTAssertFalse(persistentMessage.mcsReceived); } +- (void)testQuerySyncMessageWithRmqID { + // This is to make sure there is no sql injection vulnerability. + // Otherwise, this would generate an SQL like this: + // SELECT ... FROM ... WHERE rmq_id = '' --'; + // Which is a valid SQL and matches empty rmq_id. + NSString *rmqID = @"' --"; + int64_t expirationTime = FIRMessagingCurrentTimestampInSeconds() + 1; + [self.rmqManager saveSyncMessageWithRmqID:rmqID expirationTime:expirationTime]; + + FIRMessagingPersistentSyncMessage *persistentMessage = + [self.rmqManager querySyncMessageWithRmqID:rmqID]; + XCTAssertEqual(persistentMessage.expirationTime, expirationTime); + XCTAssertEqualObjects(persistentMessage.rmqID, rmqID); +} + /** * Test updating a sync message initially received via MCS, now being received via APNS. */ From 20e73820c58b84ad6c91bef6ec2a5b9064014160 Mon Sep 17 00:00:00 2001 From: Nick Cooke <36927374+ncooke3@users.noreply.github.com> Date: Thu, 15 May 2025 19:16:21 -0400 Subject: [PATCH 026/113] [Swift 6] Add Swift 6 testing for Sessions (#14599) Co-authored-by: Morgan Chen --- .github/workflows/sessions.yml | 9 ++ .../FirebaseInstallations/FIRInstallations.h | 3 +- .../Sources/ApplicationInfo.swift | 9 +- .../Development/DevEventConsoleLogger.swift | 2 +- FirebaseSessions/Sources/EventGDTLogger.swift | 4 +- .../Sources/FirebaseSessions.swift | 34 +++++- .../Sources/FirebaseSessionsError.swift | 2 +- ...ransport+GoogleDataTransportProtocol.swift | 25 +++- .../Installations+InstallationsProtocol.swift | 2 +- FirebaseSessions/Sources/NetworkInfo.swift | 4 +- .../Sources/Public/SessionsSubscriber.swift | 4 +- .../Sources/SessionCoordinator.swift | 5 +- .../Sources/SessionInitiator.swift | 6 +- .../Sources/Settings/RemoteSettings.swift | 91 ++++++-------- .../Settings/SettingsCacheClient.swift | 48 +++++++- .../Settings/SettingsDownloadClient.swift | 10 +- .../FirebaseSessionsTests+BaseBehaviors.swift | 10 +- ...FirebaseSessionsTests+DataCollection.swift | 8 +- .../FirebaseSessionsTests+Subscribers.swift | 10 +- .../Tests/Unit/InitiatorTests.swift | 10 +- .../Library/FirebaseSessionsTestsBase.swift | 23 ++-- .../Unit/Library/LifecycleNotifications.swift | 112 +++++------------- .../Unit/Mocks/MockApplicationInfo.swift | 2 +- .../Tests/Unit/Mocks/MockGDTLogger.swift | 3 +- .../Mocks/MockInstallationsProtocol.swift | 2 +- .../Tests/Unit/Mocks/MockNetworkInfo.swift | 2 +- .../Unit/Mocks/MockSessionCoordinator.swift | 2 +- .../Unit/Mocks/MockSettingsDownloader.swift | 2 +- .../Tests/Unit/Mocks/MockSubscriber.swift | 26 ++-- .../Tests/Unit/SessionGeneratorTests.swift | 1 + 30 files changed, 252 insertions(+), 219 deletions(-) diff --git a/.github/workflows/sessions.yml b/.github/workflows/sessions.yml index f5372a2091b..055f604457b 100644 --- a/.github/workflows/sessions.yml +++ b/.github/workflows/sessions.yml @@ -39,10 +39,17 @@ jobs: - os: macos-14 xcode: Xcode_16.2 tests: + swift_version: 5.9 # Flaky tests on CI - os: macos-15 xcode: Xcode_16.3 tests: --skip-tests + swift_version: 5.9 + # Flaky tests on CI + - os: macos-15 + xcode: Xcode_16.2 + tests: --skip-tests + swift_version: 6.0 runs-on: ${{ matrix.build-env.os }} steps: - uses: actions/checkout@v4 @@ -51,6 +58,8 @@ jobs: run: scripts/setup_bundler.sh - name: Xcode run: sudo xcode-select -s /Applications/${{ matrix.build-env.xcode }}.app/Contents/Developer + - name: Set Swift swift_version + run: sed -i "" "s/s.swift_version[[:space:]]*=[[:space:]]*'5.9'/s.swift_version = '${{ matrix.build-env.swift_version }}'/" FirebaseSessions.podspec - uses: nick-fields/retry@ce71cc2ab81d554ebbe88c79ab5975992d79ba08 # v3 with: timeout_minutes: 120 diff --git a/FirebaseInstallations/Source/Library/Public/FirebaseInstallations/FIRInstallations.h b/FirebaseInstallations/Source/Library/Public/FirebaseInstallations/FIRInstallations.h index 1811d2bbdf1..7670d40b301 100644 --- a/FirebaseInstallations/Source/Library/Public/FirebaseInstallations/FIRInstallations.h +++ b/FirebaseInstallations/Source/Library/Public/FirebaseInstallations/FIRInstallations.h @@ -57,8 +57,7 @@ typedef void (^FIRInstallationsTokenHandler)( * as the ability to delete it. A Firebase Installation is unique by `FirebaseApp.name` and * `FirebaseApp.options.googleAppID` . */ -NS_SWIFT_NAME(Installations) -@interface FIRInstallations : NSObject +NS_SWIFT_NAME(Installations) NS_SWIFT_SENDABLE @interface FIRInstallations : NSObject - (instancetype)init NS_UNAVAILABLE; diff --git a/FirebaseSessions/Sources/ApplicationInfo.swift b/FirebaseSessions/Sources/ApplicationInfo.swift index b298bd5550a..85c42a9ef9d 100644 --- a/FirebaseSessions/Sources/ApplicationInfo.swift +++ b/FirebaseSessions/Sources/ApplicationInfo.swift @@ -34,7 +34,7 @@ enum DevEnvironment: String { case autopush // Autopush environment } -protocol ApplicationInfoProtocol { +protocol ApplicationInfoProtocol: Sendable { /// Google App ID / GMP App ID var appID: String { get } @@ -62,12 +62,15 @@ protocol ApplicationInfoProtocol { var osDisplayVersion: String { get } } -class ApplicationInfo: ApplicationInfoProtocol { +final class ApplicationInfo: ApplicationInfoProtocol { let appID: String private let networkInformation: NetworkInfoProtocol private let envParams: [String: String] - private let infoDict: [String: Any]? + + // Used to hold bundle info, so the `Any` params should also + // be Sendable. + private nonisolated(unsafe) let infoDict: [String: Any]? init(appID: String, networkInfo: NetworkInfoProtocol = NetworkInfo(), envParams: [String: String] = ProcessInfo.processInfo.environment, diff --git a/FirebaseSessions/Sources/Development/DevEventConsoleLogger.swift b/FirebaseSessions/Sources/Development/DevEventConsoleLogger.swift index 488fca7efc6..8eeb17739dd 100644 --- a/FirebaseSessions/Sources/Development/DevEventConsoleLogger.swift +++ b/FirebaseSessions/Sources/Development/DevEventConsoleLogger.swift @@ -19,7 +19,7 @@ import Foundation import FirebaseSessionsObjC #endif // SWIFT_PACKAGE -class DevEventConsoleLogger: EventGDTLoggerProtocol { +final class DevEventConsoleLogger: EventGDTLoggerProtocol { private let commandLineArgument = "-FIRSessionsDebugEvents" func logEvent(event: SessionStartEvent, completion: @escaping (Result) -> Void) { diff --git a/FirebaseSessions/Sources/EventGDTLogger.swift b/FirebaseSessions/Sources/EventGDTLogger.swift index 20070706ae5..bb96c7753bc 100644 --- a/FirebaseSessions/Sources/EventGDTLogger.swift +++ b/FirebaseSessions/Sources/EventGDTLogger.swift @@ -17,7 +17,7 @@ import Foundation internal import GoogleDataTransport -protocol EventGDTLoggerProtocol { +protocol EventGDTLoggerProtocol: Sendable { func logEvent(event: SessionStartEvent, completion: @escaping (Result) -> Void) } @@ -26,7 +26,7 @@ protocol EventGDTLoggerProtocol { /// 1) Creating GDT Events and logging them to the GoogleDataTransport SDK /// 2) Handling debugging situations (eg. running in Simulator or printing the event to console) /// -class EventGDTLogger: EventGDTLoggerProtocol { +final class EventGDTLogger: EventGDTLoggerProtocol { let googleDataTransport: GoogleDataTransportProtocol let devEventConsoleLogger: EventGDTLoggerProtocol diff --git a/FirebaseSessions/Sources/FirebaseSessions.swift b/FirebaseSessions/Sources/FirebaseSessions.swift index be057cfc50f..0894bf2a028 100644 --- a/FirebaseSessions/Sources/FirebaseSessions.swift +++ b/FirebaseSessions/Sources/FirebaseSessions.swift @@ -62,13 +62,13 @@ private enum GoogleDataTransportConfig { // Initializes the SDK and top-level classes required convenience init(appID: String, installations: InstallationsProtocol) { - let googleDataTransport = GDTCORTransport( + let googleDataTransport = GoogleDataTransporter( mappingID: GoogleDataTransportConfig.sessionsLogSource, transformers: nil, target: GoogleDataTransportConfig.sessionsTarget ) - let fireLogger = EventGDTLogger(googleDataTransport: googleDataTransport!) + let fireLogger = EventGDTLogger(googleDataTransport: googleDataTransport) let appInfo = ApplicationInfo(appID: appID) let settings = SessionsSettings( @@ -135,10 +135,10 @@ private enum GoogleDataTransportConfig { } // Initializes the SDK and begins the process of listening for lifecycle events and logging - // events + // events. `logEventCallback` is invoked on a global background queue. init(appID: String, sessionGenerator: SessionGenerator, coordinator: SessionCoordinatorProtocol, initiator: SessionInitiator, appInfo: ApplicationInfoProtocol, settings: SettingsProtocol, - loggedEventCallback: @escaping (Result) -> Void) { + loggedEventCallback: @escaping @Sendable (Result) -> Void) { self.appID = appID self.sessionGenerator = sessionGenerator @@ -247,18 +247,40 @@ private enum GoogleDataTransportConfig { return SessionDetails(sessionId: sessionGenerator.currentSession?.sessionId) } + // This type is not actually sendable, but works around an issue below. + // It's safe only if executed on the main actor. + private struct MainActorNotificationCallback: @unchecked Sendable { + private let callback: (Notification) -> Void + + init(_ callback: @escaping (Notification) -> Void) { + self.callback = callback + } + + func invoke(notification: Notification) { + dispatchPrecondition(condition: .onQueue(.main)) + callback(notification) + } + } + func register(subscriber: SessionsSubscriber) { Logger .logDebug( "Registering Sessions SDK subscriber with name: \(subscriber.sessionsSubscriberName), data collection enabled: \(subscriber.isDataCollectionEnabled)" ) + // TODO(Firebase 12): After bumping to iOS 13, this hack should be replaced + // with `Task { @MainActor in }`. + let callback = MainActorNotificationCallback { notification in + subscriber.onSessionChanged(self.currentSessionDetails) + } + + // Guaranteed to execute its callback on the main queue because of the queue parameter. notificationCenter.addObserver( forName: Sessions.SessionIDChangedNotificationName, object: nil, - queue: nil + queue: OperationQueue.main ) { notification in - subscriber.onSessionChanged(self.currentSessionDetails) + callback.invoke(notification: notification) } // Immediately call the callback because the Sessions SDK starts // before subscribers, so subscribers will miss the first Notification diff --git a/FirebaseSessions/Sources/FirebaseSessionsError.swift b/FirebaseSessions/Sources/FirebaseSessionsError.swift index 12ed1fb139b..6bfae66b56d 100644 --- a/FirebaseSessions/Sources/FirebaseSessionsError.swift +++ b/FirebaseSessions/Sources/FirebaseSessionsError.swift @@ -15,7 +15,7 @@ import Foundation /// Contains the list of errors that are localized for Firebase Sessions Library -enum FirebaseSessionsError: Error { +enum FirebaseSessionsError: Error, Sendable { /// Event sampling related error case SessionSamplingError /// Firebase Installation ID related error diff --git a/FirebaseSessions/Sources/GoogleDataTransport+GoogleDataTransportProtocol.swift b/FirebaseSessions/Sources/GoogleDataTransport+GoogleDataTransportProtocol.swift index b194b736ba4..9c244fe6fe4 100644 --- a/FirebaseSessions/Sources/GoogleDataTransport+GoogleDataTransportProtocol.swift +++ b/FirebaseSessions/Sources/GoogleDataTransport+GoogleDataTransportProtocol.swift @@ -15,20 +15,31 @@ import Foundation -internal import GoogleDataTransport +@preconcurrency internal import GoogleDataTransport enum GoogleDataTransportProtocolErrors: Error { case writeFailure } -protocol GoogleDataTransportProtocol { +protocol GoogleDataTransportProtocol: Sendable { func logGDTEvent(event: GDTCOREvent, completion: @escaping (Result) -> Void) func eventForTransport() -> GDTCOREvent } -extension GDTCORTransport: GoogleDataTransportProtocol { - func logGDTEvent(event: GDTCOREvent, completion: @escaping (Result) -> Void) { - sendDataEvent(event) { wasWritten, error in +/// Workaround in combo with preconcurrency import of GDT. When GDT's +/// `GDTCORTransport`type conforms to Sendable within the GDT module, +/// this can be removed. +final class GoogleDataTransporter: GoogleDataTransportProtocol { + private let transporter: GDTCORTransport + + init(mappingID: String, + transformers: [any GDTCOREventTransformer]?, + target: GDTCORTarget) { + transporter = GDTCORTransport(mappingID: mappingID, transformers: transformers, target: target)! + } + + func logGDTEvent(event: GDTCOREvent, completion: @escaping (Result) -> Void) { + transporter.sendDataEvent(event) { wasWritten, error in if let error { completion(.failure(error)) } else if !wasWritten { @@ -38,4 +49,8 @@ extension GDTCORTransport: GoogleDataTransportProtocol { } } } + + func eventForTransport() -> GDTCOREvent { + transporter.eventForTransport() + } } diff --git a/FirebaseSessions/Sources/Installations+InstallationsProtocol.swift b/FirebaseSessions/Sources/Installations+InstallationsProtocol.swift index 04f30b3ad75..98f54771411 100644 --- a/FirebaseSessions/Sources/Installations+InstallationsProtocol.swift +++ b/FirebaseSessions/Sources/Installations+InstallationsProtocol.swift @@ -17,7 +17,7 @@ import Foundation internal import FirebaseInstallations -protocol InstallationsProtocol { +protocol InstallationsProtocol: Sendable { var installationsWaitTimeInSecond: Int { get } /// Override Installation function for testing diff --git a/FirebaseSessions/Sources/NetworkInfo.swift b/FirebaseSessions/Sources/NetworkInfo.swift index a197f3d75ff..8d7e4110571 100644 --- a/FirebaseSessions/Sources/NetworkInfo.swift +++ b/FirebaseSessions/Sources/NetworkInfo.swift @@ -25,13 +25,13 @@ import Foundation internal import GoogleUtilities #endif // SWIFT_PACKAGE -protocol NetworkInfoProtocol { +protocol NetworkInfoProtocol: Sendable { var networkType: GULNetworkType { get } var mobileSubtype: String { get } } -class NetworkInfo: NetworkInfoProtocol { +final class NetworkInfo: NetworkInfoProtocol { var networkType: GULNetworkType { return GULNetworkInfo.getNetworkType() } diff --git a/FirebaseSessions/Sources/Public/SessionsSubscriber.swift b/FirebaseSessions/Sources/Public/SessionsSubscriber.swift index 54b1b3fcba4..bc15106e3c5 100644 --- a/FirebaseSessions/Sources/Public/SessionsSubscriber.swift +++ b/FirebaseSessions/Sources/Public/SessionsSubscriber.swift @@ -18,7 +18,7 @@ import Foundation /// Sessions Subscriber is an interface that dependent SDKs /// must implement. @objc(FIRSessionsSubscriber) -public protocol SessionsSubscriber { +public protocol SessionsSubscriber: Sendable { func onSessionChanged(_ session: SessionDetails) var isDataCollectionEnabled: Bool { get } var sessionsSubscriberName: SessionsSubscriberName { get } @@ -38,7 +38,7 @@ public class SessionDetails: NSObject { /// Session Subscriber Names are used for identifying subscribers @objc(FIRSessionsSubscriberName) -public enum SessionsSubscriberName: Int, CustomStringConvertible { +public enum SessionsSubscriberName: Int, CustomStringConvertible, Sendable { case Unknown case Crashlytics case Performance diff --git a/FirebaseSessions/Sources/SessionCoordinator.swift b/FirebaseSessions/Sources/SessionCoordinator.swift index 3d4cec1b072..ab2d8898f67 100644 --- a/FirebaseSessions/Sources/SessionCoordinator.swift +++ b/FirebaseSessions/Sources/SessionCoordinator.swift @@ -14,7 +14,7 @@ import Foundation -protocol SessionCoordinatorProtocol { +protocol SessionCoordinatorProtocol: Sendable { func attemptLoggingSessionStart(event: SessionStartEvent, callback: @escaping (Result) -> Void) } @@ -23,8 +23,9 @@ protocol SessionCoordinatorProtocol { /// SessionCoordinator is responsible for coordinating the systems in this SDK /// involved with sending a Session Start event. /// -class SessionCoordinator: SessionCoordinatorProtocol { +final class SessionCoordinator: SessionCoordinatorProtocol { let installations: InstallationsProtocol + let fireLogger: EventGDTLoggerProtocol init(installations: InstallationsProtocol, diff --git a/FirebaseSessions/Sources/SessionInitiator.swift b/FirebaseSessions/Sources/SessionInitiator.swift index 77cd8eeda50..4a58fa9cea8 100644 --- a/FirebaseSessions/Sources/SessionInitiator.swift +++ b/FirebaseSessions/Sources/SessionInitiator.swift @@ -41,9 +41,9 @@ import Foundation /// class SessionInitiator { let currentTime: () -> Date - var settings: SettingsProtocol - var backgroundTime = Date.distantFuture - var initiateSessionStart: () -> Void = {} + let settings: SettingsProtocol + private var backgroundTime = Date.distantFuture + private var initiateSessionStart: () -> Void = {} init(settings: SettingsProtocol, currentTimeProvider: @escaping () -> Date = Date.init) { currentTime = currentTimeProvider diff --git a/FirebaseSessions/Sources/Settings/RemoteSettings.swift b/FirebaseSessions/Sources/Settings/RemoteSettings.swift index 15dffb18e43..9f57b348b88 100644 --- a/FirebaseSessions/Sources/Settings/RemoteSettings.swift +++ b/FirebaseSessions/Sources/Settings/RemoteSettings.swift @@ -14,6 +14,7 @@ // limitations under the License. import Foundation +internal import FirebaseCoreInternal /// Extends ApplicationInfoProtocol to string-format a combined appDisplayVersion and /// appBuildVersion @@ -21,56 +22,57 @@ extension ApplicationInfoProtocol { var synthesizedVersion: String { return "\(appDisplayVersion) (\(appBuildVersion))" } } -class RemoteSettings: SettingsProvider { - private static let cacheDurationSecondsDefault: TimeInterval = 60 * 60 +final class RemoteSettings: SettingsProvider, Sendable { private static let flagSessionsEnabled = "sessions_enabled" private static let flagSamplingRate = "sampling_rate" private static let flagSessionTimeout = "session_timeout_seconds" - private static let flagCacheDuration = "cache_duration" private static let flagSessionsCache = "app_quality" private let appInfo: ApplicationInfoProtocol private let downloader: SettingsDownloadClient - private var cache: SettingsCacheClient - - private var cacheDurationSeconds: TimeInterval { - guard let duration = cache.cacheContent[RemoteSettings.flagCacheDuration] as? Double else { - return RemoteSettings.cacheDurationSecondsDefault - } - return duration - } + private let cache: FIRAllocatedUnfairLock private var sessionsCache: [String: Any] { - return cache.cacheContent[RemoteSettings.flagSessionsCache] as? [String: Any] ?? [:] + cache.withLock { cache in + cache.cacheContent[RemoteSettings.flagSessionsCache] as? [String: Any] ?? [:] + } } init(appInfo: ApplicationInfoProtocol, downloader: SettingsDownloadClient, cache: SettingsCacheClient = SettingsCache()) { self.appInfo = appInfo - self.cache = cache + self.cache = FIRAllocatedUnfairLock(initialState: cache) self.downloader = downloader } private func fetchAndCacheSettings(currentTime: Date) { - // Only fetch if cache is expired, otherwise do nothing - guard isCacheExpired(time: currentTime) else { - Logger.logDebug("[Settings] Cache is not expired, no fetch will be made.") - return + let shouldFetch = cache.withLock { cache in + // Only fetch if cache is expired, otherwise do nothing + guard cache.isExpired(for: appInfo, time: currentTime) else { + Logger.logDebug("[Settings] Cache is not expired, no fetch will be made.") + return false + } + return true } - downloader.fetch { result in - switch result { - case let .success(dictionary): - // Saves all newly fetched Settings to cache - self.cache.cacheContent = dictionary - // Saves a "cache-key" which carries TTL metadata about current cache - self.cache.cacheKey = CacheKey( - createdAt: currentTime, - googleAppID: self.appInfo.appID, - appVersion: self.appInfo.synthesizedVersion - ) - case let .failure(error): - Logger.logError("[Settings] Fetching newest settings failed with error: \(error)") + if shouldFetch { + downloader.fetch { result in + + switch result { + case let .success(dictionary): + self.cache.withLock { cache in + // Saves all newly fetched Settings to cache + cache.cacheContent = dictionary + // Saves a "cache-key" which carries TTL metadata about current cache + cache.cacheKey = CacheKey( + createdAt: currentTime, + googleAppID: self.appInfo.appID, + appVersion: self.appInfo.synthesizedVersion + ) + } + case let .failure(error): + Logger.logError("[Settings] Fetching newest settings failed with error: \(error)") + } } } } @@ -102,33 +104,8 @@ extension RemoteSettingsConfigurations { } func isSettingsStale() -> Bool { - return isCacheExpired(time: Date()) - } - - private func isCacheExpired(time: Date) -> Bool { - guard !cache.cacheContent.isEmpty else { - cache.removeCache() - return true - } - guard let cacheKey = cache.cacheKey else { - Logger.logError("[Settings] Could not load settings cache key") - cache.removeCache() - return true - } - guard cacheKey.googleAppID == appInfo.appID else { - Logger - .logDebug("[Settings] Cache expired because Google App ID changed") - cache.removeCache() - return true - } - if time.timeIntervalSince(cacheKey.createdAt) > cacheDurationSeconds { - Logger.logDebug("[Settings] Cache TTL expired") - return true - } - if appInfo.synthesizedVersion != cacheKey.appVersion { - Logger.logDebug("[Settings] Cache expired because app version changed") - return true + cache.withLock { cache in + cache.isExpired(for: appInfo, time: Date()) } - return false } } diff --git a/FirebaseSessions/Sources/Settings/SettingsCacheClient.swift b/FirebaseSessions/Sources/Settings/SettingsCacheClient.swift index 52d222e46f7..18f9bcefbff 100644 --- a/FirebaseSessions/Sources/Settings/SettingsCacheClient.swift +++ b/FirebaseSessions/Sources/Settings/SettingsCacheClient.swift @@ -15,10 +15,11 @@ import Foundation +// TODO: sendable (remove preconcurrency) #if SWIFT_PACKAGE - internal import GoogleUtilities_UserDefaults + @preconcurrency internal import GoogleUtilities_UserDefaults #else - internal import GoogleUtilities + @preconcurrency internal import GoogleUtilities #endif // SWIFT_PACKAGE /// CacheKey is like a "key" to a "safe". It provides necessary metadata about the current cache to @@ -30,7 +31,7 @@ struct CacheKey: Codable { } /// SettingsCacheClient is responsible for accessing the cache that Settings are stored in. -protocol SettingsCacheClient { +protocol SettingsCacheClient: Sendable { /// Returns in-memory cache content in O(1) time. Returns empty dictionary if it does not exist in /// cache. var cacheContent: [String: Any] { get set } @@ -39,13 +40,17 @@ protocol SettingsCacheClient { var cacheKey: CacheKey? { get set } /// Removes all cache content and cache-key func removeCache() + /// Returns whether the cache is expired for the given app info structure and time. + func isExpired(for appInfo: ApplicationInfoProtocol, time: Date) -> Bool } /// SettingsCache uses UserDefaults to store Settings on-disk, but also directly query UserDefaults /// when accessing Settings values during run-time. This is because UserDefaults encapsulates both /// in-memory and persisted-on-disk storage, allowing fast synchronous access in-app while hiding /// away the complexity of managing persistence asynchronously. -class SettingsCache: SettingsCacheClient { +final class SettingsCache: SettingsCacheClient { + private static let cacheDurationSecondsDefault: TimeInterval = 60 * 60 + private static let flagCacheDuration = "cache_duration" private static let settingsVersion: Int = 1 private enum UserDefaultsKeys { static let forContent = "firebase-sessions-settings" @@ -92,4 +97,39 @@ class SettingsCache: SettingsCacheClient { cache.setObject(nil, forKey: UserDefaultsKeys.forContent) cache.setObject(nil, forKey: UserDefaultsKeys.forCacheKey) } + + func isExpired(for appInfo: ApplicationInfoProtocol, time: Date) -> Bool { + guard !cacheContent.isEmpty else { + removeCache() + return true + } + guard let cacheKey = cacheKey else { + Logger.logError("[Settings] Could not load settings cache key") + removeCache() + return true + } + guard cacheKey.googleAppID == appInfo.appID else { + Logger + .logDebug("[Settings] Cache expired because Google App ID changed") + removeCache() + return true + } + if time.timeIntervalSince(cacheKey.createdAt) > cacheDuration() { + Logger.logDebug("[Settings] Cache TTL expired") + return true + } + if appInfo.synthesizedVersion != cacheKey.appVersion { + Logger.logDebug("[Settings] Cache expired because app version changed") + return true + } + return false + } + + private func cacheDuration() -> TimeInterval { + guard let duration = cacheContent[Self.flagCacheDuration] as? Double else { + return Self.cacheDurationSecondsDefault + } + print("Duration: \(duration)") + return duration + } } diff --git a/FirebaseSessions/Sources/Settings/SettingsDownloadClient.swift b/FirebaseSessions/Sources/Settings/SettingsDownloadClient.swift index dbfd7b2a666..a1e1deaad82 100644 --- a/FirebaseSessions/Sources/Settings/SettingsDownloadClient.swift +++ b/FirebaseSessions/Sources/Settings/SettingsDownloadClient.swift @@ -21,8 +21,9 @@ import Foundation internal import GoogleUtilities #endif // SWIFT_PACKAGE -protocol SettingsDownloadClient { - func fetch(completion: @escaping (Result<[String: Any], SettingsDownloaderError>) -> Void) +protocol SettingsDownloadClient: Sendable { + func fetch(completion: @Sendable @escaping (Result<[String: Any], SettingsDownloaderError>) + -> Void) } enum SettingsDownloaderError: Error { @@ -36,7 +37,7 @@ enum SettingsDownloaderError: Error { case InstallationIDError(String) } -class SettingsDownloader: SettingsDownloadClient { +final class SettingsDownloader: SettingsDownloadClient { private let appInfo: ApplicationInfoProtocol private let installations: InstallationsProtocol @@ -45,7 +46,8 @@ class SettingsDownloader: SettingsDownloadClient { self.installations = installations } - func fetch(completion: @escaping (Result<[String: Any], SettingsDownloaderError>) -> Void) { + func fetch(completion: @Sendable @escaping (Result<[String: Any], SettingsDownloaderError>) + -> Void) { guard let validURL = url else { completion(.failure(.URLError("Invalid URL"))) return diff --git a/FirebaseSessions/Tests/Unit/FirebaseSessionsTests+BaseBehaviors.swift b/FirebaseSessions/Tests/Unit/FirebaseSessionsTests+BaseBehaviors.swift index 2c453a4518a..462be23ead3 100644 --- a/FirebaseSessions/Tests/Unit/FirebaseSessionsTests+BaseBehaviors.swift +++ b/FirebaseSessions/Tests/Unit/FirebaseSessionsTests+BaseBehaviors.swift @@ -24,7 +24,7 @@ import XCTest final class FirebaseSessionsTestsBase_BaseBehaviors: FirebaseSessionsTestsBase { // MARK: - Test Settings & Sampling - func test_settingsDisabled_doesNotLogSessionEventButDoesFetchSettings() { + @MainActor func test_settingsDisabled_doesNotLogSessionEventButDoesFetchSettings() { runSessionsSDK( subscriberSDKs: [ mockPerformanceSubscriber, @@ -49,7 +49,7 @@ final class FirebaseSessionsTestsBase_BaseBehaviors: FirebaseSessionsTestsBase { ) } - func test_sessionSampled_doesNotLogSessionEventButDoesFetchSettings() { + @MainActor func test_sessionSampled_doesNotLogSessionEventButDoesFetchSettings() { runSessionsSDK( subscriberSDKs: [ mockPerformanceSubscriber, @@ -87,7 +87,7 @@ final class FirebaseSessionsTestsBase_BaseBehaviors: FirebaseSessionsTestsBase { // We wanted to make sure that since we've introduced promises, // once the promise has been fulfilled, that .then'ing on the promise // in future initiations still results in a log - func test_multipleInitiations_logsSessionEventEachInitiation() { + @MainActor func test_multipleInitiations_logsSessionEventEachInitiation() { var loggedCount = 0 var lastLoggedSessionID = "" let loggedTwiceExpectation = expectation(description: "Sessions SDK logged events twice") @@ -128,9 +128,9 @@ final class FirebaseSessionsTestsBase_BaseBehaviors: FirebaseSessionsTestsBase { // then bring the app to the foreground to generate another session. // // This postLogEvent callback will be called again after this - self.postBackgroundedNotification() + postBackgroundedNotification() self.pausedClock.addTimeInterval(30 * 60 + 1) - self.postForegroundedNotification() + postForegroundedNotification() } else { loggedTwiceExpectation.fulfill() diff --git a/FirebaseSessions/Tests/Unit/FirebaseSessionsTests+DataCollection.swift b/FirebaseSessions/Tests/Unit/FirebaseSessionsTests+DataCollection.swift index 3b4ef30c05c..5a2c5d1da97 100644 --- a/FirebaseSessions/Tests/Unit/FirebaseSessionsTests+DataCollection.swift +++ b/FirebaseSessions/Tests/Unit/FirebaseSessionsTests+DataCollection.swift @@ -81,7 +81,7 @@ final class FirebaseSessionsTestsBase_DataCollection: FirebaseSessionsTestsBase // MARK: - Test Data Collection - func test_subscriberWithDataCollectionEnabled_logsSessionEvent() { + @MainActor func test_subscriberWithDataCollectionEnabled_logsSessionEvent() { runSessionsSDK( subscriberSDKs: [ mockCrashlyticsSubscriber, @@ -105,7 +105,7 @@ final class FirebaseSessionsTestsBase_DataCollection: FirebaseSessionsTestsBase ) } - func test_subscribersSomeDataCollectionDisabled_logsSessionEvent() { + @MainActor func test_subscribersSomeDataCollectionDisabled_logsSessionEvent() { runSessionsSDK( subscriberSDKs: [ mockCrashlyticsSubscriber, @@ -132,7 +132,7 @@ final class FirebaseSessionsTestsBase_DataCollection: FirebaseSessionsTestsBase ) } - func test_subscribersAllDataCollectionDisabled_doesNotLogSessionEvent() { + @MainActor func test_subscribersAllDataCollectionDisabled_doesNotLogSessionEvent() { runSessionsSDK( subscriberSDKs: [ mockCrashlyticsSubscriber, @@ -159,7 +159,7 @@ final class FirebaseSessionsTestsBase_DataCollection: FirebaseSessionsTestsBase ) } - func test_defaultSamplingRate_isSetInProto() { + @MainActor func test_defaultSamplingRate_isSetInProto() { runSessionsSDK( subscriberSDKs: [ mockCrashlyticsSubscriber, diff --git a/FirebaseSessions/Tests/Unit/FirebaseSessionsTests+Subscribers.swift b/FirebaseSessions/Tests/Unit/FirebaseSessionsTests+Subscribers.swift index a4166207dd2..139a8826e0e 100644 --- a/FirebaseSessions/Tests/Unit/FirebaseSessionsTests+Subscribers.swift +++ b/FirebaseSessions/Tests/Unit/FirebaseSessionsTests+Subscribers.swift @@ -25,7 +25,7 @@ final class FirebaseSessionsTestsBase_Subscribers: FirebaseSessionsTestsBase { // Check that the Session ID that was passed to the Subscriber SDK // matches the Session ID that the Sessions SDK logged, and ensure // both are not empty. - func assertValidChangedSessionID() { + @MainActor func assertValidChangedSessionID() { let expectedSessionID = sessions.currentSessionDetails.sessionId XCTAssert(expectedSessionID!.count > 0) for mock in [mockCrashlyticsSubscriber, mockPerformanceSubscriber] { @@ -37,7 +37,7 @@ final class FirebaseSessionsTestsBase_Subscribers: FirebaseSessionsTestsBase { // MARK: - Test Subscriber Callbacks - func test_registerSubscriber_callsOnSessionChanged() { + @MainActor func test_registerSubscriber_callsOnSessionChanged() { runSessionsSDK( subscriberSDKs: [ mockCrashlyticsSubscriber, @@ -61,7 +61,7 @@ final class FirebaseSessionsTestsBase_Subscribers: FirebaseSessionsTestsBase { // Make sure that even if the Sessions SDK is disabled, and data collection // is disabled, the Sessions SDK still generates Session IDs and provides // them to Subscribers - func test_subscribersDataCollectionDisabled_callsOnSessionChanged() { + @MainActor func test_subscribersDataCollectionDisabled_callsOnSessionChanged() { runSessionsSDK( subscriberSDKs: [ mockCrashlyticsSubscriber, @@ -86,7 +86,7 @@ final class FirebaseSessionsTestsBase_Subscribers: FirebaseSessionsTestsBase { ) } - func test_noDependencies_doesNotLogSessionEvent() { + @MainActor func test_noDependencies_doesNotLogSessionEvent() { runSessionsSDK( subscriberSDKs: [], preSessionsInit: { _ in @@ -102,7 +102,7 @@ final class FirebaseSessionsTestsBase_Subscribers: FirebaseSessionsTestsBase { ) } - func test_noSubscribersWithRegistrations_doesNotCrash() { + @MainActor func test_noSubscribersWithRegistrations_doesNotCrash() { runSessionsSDK( subscriberSDKs: [], preSessionsInit: { _ in diff --git a/FirebaseSessions/Tests/Unit/InitiatorTests.swift b/FirebaseSessions/Tests/Unit/InitiatorTests.swift index c3b17fb3dde..0f6ca6b2f5e 100644 --- a/FirebaseSessions/Tests/Unit/InitiatorTests.swift +++ b/FirebaseSessions/Tests/Unit/InitiatorTests.swift @@ -58,7 +58,7 @@ class InitiatorTests: XCTestCase { XCTAssert(initiateCalled) } - func test_appForegrounded_initiatesNewSession() throws { + func test_appForegrounded_initiatesNewSession() async throws { // Given var pausedClock = date let initiator = SessionInitiator( @@ -73,18 +73,18 @@ class InitiatorTests: XCTestCase { // When // Background, advance time by 30 minutes + 1 second, then foreground - postBackgroundedNotification() + await postBackgroundedNotification() pausedClock.addTimeInterval(30 * 60 + 1) - postForegroundedNotification() + await postForegroundedNotification() // Then // Session count increases because time spent in background > 30 minutes XCTAssert(sessionCount == 2) // When // Background, advance time by exactly 30 minutes, then foreground - postBackgroundedNotification() + await postBackgroundedNotification() pausedClock.addTimeInterval(30 * 60) - postForegroundedNotification() + await postForegroundedNotification() // Then // Session count doesn't increase because time spent in background <= 30 minutes XCTAssert(sessionCount == 2) diff --git a/FirebaseSessions/Tests/Unit/Library/FirebaseSessionsTestsBase.swift b/FirebaseSessions/Tests/Unit/Library/FirebaseSessionsTestsBase.swift index fed12144691..86d1c24131c 100644 --- a/FirebaseSessions/Tests/Unit/Library/FirebaseSessionsTestsBase.swift +++ b/FirebaseSessions/Tests/Unit/Library/FirebaseSessionsTestsBase.swift @@ -71,11 +71,13 @@ class FirebaseSessionsTestsBase: XCTestCase { /// is a good place for Subscribers to call register on the Sessions SDK /// - `postLogEvent` is called whenever an event is logged via the Sessions SDK. This is where /// most assertions will happen. - func runSessionsSDK(subscriberSDKs: [SessionsSubscriber], - preSessionsInit: (MockSettingsProtocol) -> Void, - postSessionsInit: () -> Void, - postLogEvent: @escaping (Result, - [SessionsSubscriber]) -> Void) { + @MainActor func runSessionsSDK(subscriberSDKs: [SessionsSubscriber], + preSessionsInit: (MockSettingsProtocol) -> Void, + postSessionsInit: () -> Void, + postLogEvent: @escaping @MainActor (Result, + [SessionsSubscriber]) + -> Void) { // This class is static, so we need to clear global state SessionsDependencies.removeAll() @@ -109,12 +111,13 @@ class FirebaseSessionsTestsBase: XCTestCase { initiator: initiator, appInfo: mockAppInfo, settings: mockSettings) { result in + DispatchQueue.main.async { + // Provide the result for tests to test against + postLogEvent(result, subscriberSDKs) - // Provide the result for tests to test against - postLogEvent(result, subscriberSDKs) - - // Fulfil the expectation so the test can continue - loggedEventExpectation.fulfill() + // Fulfil the expectation so the test can continue + loggedEventExpectation.fulfill() + } } // Execute test cases after Sessions is initialized. This is a good diff --git a/FirebaseSessions/Tests/Unit/Library/LifecycleNotifications.swift b/FirebaseSessions/Tests/Unit/Library/LifecycleNotifications.swift index 80c6f7c38f9..b406c32ece5 100644 --- a/FirebaseSessions/Tests/Unit/Library/LifecycleNotifications.swift +++ b/FirebaseSessions/Tests/Unit/Library/LifecycleNotifications.swift @@ -17,7 +17,7 @@ import XCTest import Dispatch -#if os(iOS) || os(tvOS) +#if os(iOS) || os(tvOS) || os(visionOS) import UIKit #elseif os(macOS) import AppKit @@ -26,88 +26,36 @@ import Dispatch import WatchKit #endif // os(iOS) || os(tvOS) -// swift(>=5.9) implies Xcode 15+ -// Need to have this Swift version check to use os(visionOS) macro, VisionOS support. -// TODO: Remove this check and add `os(visionOS)` to the `os(iOS) || os(tvOS)` conditional above -// when Xcode 15 is the minimum supported by Firebase. -#if swift(>=5.9) - #if os(visionOS) - import UIKit - #endif // os(visionOS) -#endif // swift(>=5.9) - -extension XCTestCase { - func postBackgroundedNotification() { - // On Catalyst, the notifications can only be called on a the main thread - if Thread.isMainThread { - postBackgroundedNotificationInternal() - } else { - DispatchQueue.main.sync { - self.postBackgroundedNotificationInternal() - } +@MainActor func postBackgroundedNotification() { + // On Catalyst, the notifications can only be called on the main thread + let notificationCenter = NotificationCenter.default + #if os(iOS) || os(tvOS) || os(visionOS) + notificationCenter.post(name: UIApplication.didEnterBackgroundNotification, object: nil) + #elseif os(macOS) + notificationCenter.post(name: NSApplication.didResignActiveNotification, object: nil) + #elseif os(watchOS) + if #available(watchOSApplicationExtension 7.0, *) { + notificationCenter.post( + name: WKExtension.applicationDidEnterBackgroundNotification, + object: nil + ) } - } - - private func postBackgroundedNotificationInternal() { - let notificationCenter = NotificationCenter.default - #if os(iOS) || os(tvOS) - notificationCenter.post(name: UIApplication.didEnterBackgroundNotification, object: nil) - #elseif os(macOS) - notificationCenter.post(name: NSApplication.didResignActiveNotification, object: nil) - #elseif os(watchOS) - if #available(watchOSApplicationExtension 7.0, *) { - notificationCenter.post( - name: WKExtension.applicationDidEnterBackgroundNotification, - object: nil - ) - } - #endif // os(iOS) || os(tvOS) - - // swift(>=5.9) implies Xcode 15+ - // Need to have this Swift version check to use os(visionOS) macro, VisionOS support. - // TODO: Remove this check and add `os(visionOS)` to the `os(iOS) || os(tvOS)` conditional above - // when Xcode 15 is the minimum supported by Firebase. - #if swift(>=5.9) - #if os(visionOS) - notificationCenter.post(name: UIApplication.didEnterBackgroundNotification, object: nil) - #endif // os(visionOS) - #endif // swift(>=5.9) - } + #endif // os(iOS) || os(tvOS) +} - func postForegroundedNotification() { - // On Catalyst, the notifications can only be called on a the main thread - if Thread.isMainThread { - postForegroundedNotificationInternal() - } else { - DispatchQueue.main.sync { - self.postForegroundedNotificationInternal() - } +@MainActor func postForegroundedNotification() { + // On Catalyst, the notifications can only be called on a the main thread + let notificationCenter = NotificationCenter.default + #if os(iOS) || os(tvOS) || os(visionOS) + notificationCenter.post(name: UIApplication.didBecomeActiveNotification, object: nil) + #elseif os(macOS) + notificationCenter.post(name: NSApplication.didBecomeActiveNotification, object: nil) + #elseif os(watchOS) + if #available(watchOSApplicationExtension 7.0, *) { + notificationCenter.post( + name: WKExtension.applicationDidBecomeActiveNotification, + object: nil + ) } - } - - private func postForegroundedNotificationInternal() { - let notificationCenter = NotificationCenter.default - #if os(iOS) || os(tvOS) - notificationCenter.post(name: UIApplication.didBecomeActiveNotification, object: nil) - #elseif os(macOS) - notificationCenter.post(name: NSApplication.didBecomeActiveNotification, object: nil) - #elseif os(watchOS) - if #available(watchOSApplicationExtension 7.0, *) { - notificationCenter.post( - name: WKExtension.applicationDidBecomeActiveNotification, - object: nil - ) - } - #endif // os(iOS) || os(tvOS) - - // swift(>=5.9) implies Xcode 15+ - // Need to have this Swift version check to use os(visionOS) macro, VisionOS support. - // TODO: Remove this check and add `os(visionOS)` to the `os(iOS) || os(tvOS)` conditional above - // when Xcode 15 is the minimum supported by Firebase. - #if swift(>=5.9) - #if os(visionOS) - notificationCenter.post(name: UIApplication.didBecomeActiveNotification, object: nil) - #endif // os(visionOS) - #endif // swift(>=5.9) - } + #endif // os(iOS) || os(tvOS) } diff --git a/FirebaseSessions/Tests/Unit/Mocks/MockApplicationInfo.swift b/FirebaseSessions/Tests/Unit/Mocks/MockApplicationInfo.swift index fea2bfc5cfd..8c5e3e5d07c 100644 --- a/FirebaseSessions/Tests/Unit/Mocks/MockApplicationInfo.swift +++ b/FirebaseSessions/Tests/Unit/Mocks/MockApplicationInfo.swift @@ -23,7 +23,7 @@ import Foundation @testable import FirebaseSessions -class MockApplicationInfo: ApplicationInfoProtocol { +class MockApplicationInfo: ApplicationInfoProtocol, @unchecked Sendable { var appID: String = "" var bundleID: String = "" diff --git a/FirebaseSessions/Tests/Unit/Mocks/MockGDTLogger.swift b/FirebaseSessions/Tests/Unit/Mocks/MockGDTLogger.swift index a44a2dd0147..732470e5c8d 100644 --- a/FirebaseSessions/Tests/Unit/Mocks/MockGDTLogger.swift +++ b/FirebaseSessions/Tests/Unit/Mocks/MockGDTLogger.swift @@ -17,7 +17,8 @@ import Foundation @testable import FirebaseSessions -class MockGDTLogger: EventGDTLoggerProtocol { +// TODO(Swift 6): Add checked Sendable support. +final class MockGDTLogger: EventGDTLoggerProtocol, @unchecked Sendable { var loggedEvent: SessionStartEvent? var result: Result = .success(()) diff --git a/FirebaseSessions/Tests/Unit/Mocks/MockInstallationsProtocol.swift b/FirebaseSessions/Tests/Unit/Mocks/MockInstallationsProtocol.swift index e61f492e8df..112605e7aeb 100644 --- a/FirebaseSessions/Tests/Unit/Mocks/MockInstallationsProtocol.swift +++ b/FirebaseSessions/Tests/Unit/Mocks/MockInstallationsProtocol.swift @@ -17,7 +17,7 @@ internal import FirebaseInstallations @testable import FirebaseSessions -class MockInstallationsProtocol: InstallationsProtocol { +class MockInstallationsProtocol: InstallationsProtocol, @unchecked Sendable { static let testInstallationId = "testInstallationId" static let testAuthToken = "testAuthToken" var result: Result<(String, String), Error> = .success((testInstallationId, testAuthToken)) diff --git a/FirebaseSessions/Tests/Unit/Mocks/MockNetworkInfo.swift b/FirebaseSessions/Tests/Unit/Mocks/MockNetworkInfo.swift index 103434179dc..9413c3951b0 100644 --- a/FirebaseSessions/Tests/Unit/Mocks/MockNetworkInfo.swift +++ b/FirebaseSessions/Tests/Unit/Mocks/MockNetworkInfo.swift @@ -23,7 +23,7 @@ import Foundation @testable import FirebaseSessions -class MockNetworkInfo: NetworkInfoProtocol { +class MockNetworkInfo: NetworkInfoProtocol, @unchecked Sendable { var mobileCountryCode: String? var mobileNetworkCode: String? var networkType: GULNetworkType = .WIFI diff --git a/FirebaseSessions/Tests/Unit/Mocks/MockSessionCoordinator.swift b/FirebaseSessions/Tests/Unit/Mocks/MockSessionCoordinator.swift index 19672f70b6a..3bfad146882 100644 --- a/FirebaseSessions/Tests/Unit/Mocks/MockSessionCoordinator.swift +++ b/FirebaseSessions/Tests/Unit/Mocks/MockSessionCoordinator.swift @@ -16,7 +16,7 @@ @testable import FirebaseSessions import XCTest -class MockSessionCoordinator: SessionCoordinatorProtocol { +class MockSessionCoordinator: SessionCoordinatorProtocol, @unchecked Sendable { var loggedEvent: FirebaseSessions.SessionStartEvent? func attemptLoggingSessionStart(event: FirebaseSessions.SessionStartEvent, diff --git a/FirebaseSessions/Tests/Unit/Mocks/MockSettingsDownloader.swift b/FirebaseSessions/Tests/Unit/Mocks/MockSettingsDownloader.swift index 3785f52e54e..df8c10fa3d8 100644 --- a/FirebaseSessions/Tests/Unit/Mocks/MockSettingsDownloader.swift +++ b/FirebaseSessions/Tests/Unit/Mocks/MockSettingsDownloader.swift @@ -17,7 +17,7 @@ import Foundation @testable import FirebaseSessions -class MockSettingsDownloader: SettingsDownloadClient { +class MockSettingsDownloader: SettingsDownloadClient, @unchecked Sendable { public var shouldSucceed: Bool = true public var successResponse: [String: Any] diff --git a/FirebaseSessions/Tests/Unit/Mocks/MockSubscriber.swift b/FirebaseSessions/Tests/Unit/Mocks/MockSubscriber.swift index 7840809f586..2f3845e70bc 100644 --- a/FirebaseSessions/Tests/Unit/Mocks/MockSubscriber.swift +++ b/FirebaseSessions/Tests/Unit/Mocks/MockSubscriber.swift @@ -13,21 +13,33 @@ // See the License for the specific language governing permissions and // limitations under the License. +import FirebaseCoreInternal @testable import FirebaseSessions import Foundation -final class MockSubscriber: SessionsSubscriber { - var sessionThatChanged: FirebaseSessions.SessionDetails? +final class MockSubscriber: SessionsSubscriber, Sendable { + let sessionsSubscriberName: FirebaseSessions.SessionsSubscriberName + + var sessionThatChanged: FirebaseSessions.SessionDetails? { + get { _sessionThatChanged.value() } + set { _sessionThatChanged.withLock { $0 = newValue } } + } + + var isDataCollectionEnabled: Bool { + get { _isDataCollectionEnabled.value() } + set { _isDataCollectionEnabled.withLock { $0 = newValue } } + } + + private let _sessionThatChanged = FIRAllocatedUnfairLock( + initialState: nil + ) + private let _isDataCollectionEnabled = FIRAllocatedUnfairLock(initialState: true) init(name: SessionsSubscriberName) { sessionsSubscriberName = name } func onSessionChanged(_ session: FirebaseSessions.SessionDetails) { - sessionThatChanged = session + _sessionThatChanged.withLock { $0 = session } } - - var isDataCollectionEnabled: Bool = true - - var sessionsSubscriberName: FirebaseSessions.SessionsSubscriberName } diff --git a/FirebaseSessions/Tests/Unit/SessionGeneratorTests.swift b/FirebaseSessions/Tests/Unit/SessionGeneratorTests.swift index e71215c8aa2..9d64940bca2 100644 --- a/FirebaseSessions/Tests/Unit/SessionGeneratorTests.swift +++ b/FirebaseSessions/Tests/Unit/SessionGeneratorTests.swift @@ -53,6 +53,7 @@ class SessionGeneratorTests: XCTestCase { localOverrides: localOverrideSettings, remoteSettings: remoteSettings ) + generator = SessionGenerator(collectEvents: Sessions .shouldCollectEvents(settings: sessionSettings)) } From d259d888537314f54c437349f3d84d0fb0ef3de2 Mon Sep 17 00:00:00 2001 From: Nick Cooke <36927374+ncooke3@users.noreply.github.com> Date: Mon, 19 May 2025 12:51:13 -0400 Subject: [PATCH 027/113] [Auth] Conform 'AuthKeychainServices' to 'Sendable' (#14862) --- FirebaseAuth/CHANGELOG.md | 4 +++ FirebaseAuth/Sources/Swift/Auth/Auth.swift | 2 +- .../Sources/Swift/Auth/AuthComponent.swift | 5 +++- .../Swift/Storage/AuthKeychainServices.swift | 24 +++++++-------- .../Swift/Storage/AuthKeychainStorage.swift | 2 +- .../Storage/AuthKeychainStorageReal.swift | 7 +++-- .../Swift/Storage/AuthUserDefaults.swift | 6 ---- .../Unit/AuthKeychainServicesTests.swift | 17 ++++++----- FirebaseAuth/Tests/Unit/AuthTests.swift | 2 +- .../Unit/Fakes/FakeAuthKeychainStorage.swift | 29 ++++++++++--------- FirebaseAuth/Tests/Unit/UserTests.swift | 2 +- 11 files changed, 51 insertions(+), 49 deletions(-) diff --git a/FirebaseAuth/CHANGELOG.md b/FirebaseAuth/CHANGELOG.md index 04ff2a7322f..0d7a15811b6 100644 --- a/FirebaseAuth/CHANGELOG.md +++ b/FirebaseAuth/CHANGELOG.md @@ -1,3 +1,7 @@ +# Unreleased +- [fixed] Synchronize internal `AuthKeychainServices` class to prevent + crashes from concurrent access. (#14835) + # 11.12.0 - [fixed] Fix a `fatalError` unenrolling from MFA. An invalid user token now throws an `invalidUserToken` error instead of crashing. (#14663) diff --git a/FirebaseAuth/Sources/Swift/Auth/Auth.swift b/FirebaseAuth/Sources/Swift/Auth/Auth.swift index 5d8050cc891..1f89d5ddfe4 100644 --- a/FirebaseAuth/Sources/Swift/Auth/Auth.swift +++ b/FirebaseAuth/Sources/Swift/Auth/Auth.swift @@ -1625,7 +1625,7 @@ extension Auth: AuthInterop { // MARK: Internal methods init(app: FirebaseApp, - keychainStorageProvider: AuthKeychainStorage = AuthKeychainStorageReal(), + keychainStorageProvider: AuthKeychainStorage = AuthKeychainStorageReal.shared, backend: AuthBackend = .init(rpcIssuer: AuthBackendRPCIssuer()), authDispatcher: AuthDispatcher = .init()) { self.app = app diff --git a/FirebaseAuth/Sources/Swift/Auth/AuthComponent.swift b/FirebaseAuth/Sources/Swift/Auth/AuthComponent.swift index 649d274c294..af50c79fd3d 100644 --- a/FirebaseAuth/Sources/Swift/Auth/AuthComponent.swift +++ b/FirebaseAuth/Sources/Swift/Auth/AuthComponent.swift @@ -78,7 +78,10 @@ class AuthComponent: NSObject, Library, ComponentLifecycleMaintainer { // This doesn't stop any request already issued, see b/27704535 if let keychainServiceName = Auth.deleteKeychainServiceNameForAppName(app.name) { - let keychain = AuthKeychainServices(service: keychainServiceName) + let keychain = AuthKeychainServices( + service: keychainServiceName, + storage: AuthKeychainStorageReal.shared + ) let userKey = "\(app.name)_firebase_user" try? keychain.removeData(forKey: userKey) } diff --git a/FirebaseAuth/Sources/Swift/Storage/AuthKeychainServices.swift b/FirebaseAuth/Sources/Swift/Storage/AuthKeychainServices.swift index fcf24de126a..349da7b73f8 100644 --- a/FirebaseAuth/Sources/Swift/Storage/AuthKeychainServices.swift +++ b/FirebaseAuth/Sources/Swift/Storage/AuthKeychainServices.swift @@ -13,6 +13,7 @@ // limitations under the License. import FirebaseCoreExtension +import FirebaseCoreInternal import Foundation /// The prefix string for keychain item account attribute before the key. @@ -22,16 +23,15 @@ private let kAccountPrefix = "firebase_auth_1_" /// The utility class to manipulate data in iOS Keychain. @available(iOS 13, tvOS 13, macOS 10.15, macCatalyst 13, watchOS 7, *) -final class AuthKeychainServices { +final class AuthKeychainServices: Sendable { /// The name of the keychain service. - let service: String + private let service: String - let keychainStorage: AuthKeychainStorage + private let keychainStorage: AuthKeychainStorage // MARK: - Internal methods for shared keychain operations - required init(service: String = "Unset service", - storage: AuthKeychainStorage = AuthKeychainStorageReal()) { + required init(service: String = "Unset service", storage: AuthKeychainStorage) { self.service = service keychainStorage = storage } @@ -102,11 +102,7 @@ final class AuthKeychainServices { /// been deleted. /// /// This dictionary is to avoid unnecessary keychain operations against legacy items. - private var legacyEntryDeletedForKey: Set = [] - - static func storage(identifier: String) -> Self { - return Self(service: identifier) - } + private let legacyEntryDeletedForKey = FIRAllocatedUnfairLock>(initialState: []) func data(forKey key: String) throws -> Data? { if let data = try getItemLegacy(query: genericPasswordQuery(key: key)) { @@ -114,7 +110,7 @@ final class AuthKeychainServices { } // Check for legacy form. - if legacyEntryDeletedForKey.contains(key) { + if legacyEntryDeletedForKey.value().contains(key) { return nil } if let data = try getItemLegacy(query: legacyGenericPasswordQuery(key: key)) { @@ -124,7 +120,7 @@ final class AuthKeychainServices { return data } else { // Mark legacy data as non-existing so we don't have to query it again. - legacyEntryDeletedForKey.insert(key) + legacyEntryDeletedForKey.withLock { $0.insert(key) } return nil } } @@ -214,12 +210,12 @@ final class AuthKeychainServices { /// Deletes legacy item from the keychain if it is not already known to be deleted. /// - Parameter key: The key for the item. private func deleteLegacyItem(key: String) { - if legacyEntryDeletedForKey.contains(key) { + if legacyEntryDeletedForKey.value().contains(key) { return } let query = legacyGenericPasswordQuery(key: key) keychainStorage.delete(query: query) - legacyEntryDeletedForKey.insert(key) + legacyEntryDeletedForKey.withLock { $0.insert(key) } } /// Returns a keychain query of generic password to be used to manipulate key'ed value. diff --git a/FirebaseAuth/Sources/Swift/Storage/AuthKeychainStorage.swift b/FirebaseAuth/Sources/Swift/Storage/AuthKeychainStorage.swift index d53bb612402..a5e0689d6ed 100644 --- a/FirebaseAuth/Sources/Swift/Storage/AuthKeychainStorage.swift +++ b/FirebaseAuth/Sources/Swift/Storage/AuthKeychainStorage.swift @@ -17,7 +17,7 @@ import Foundation /// Protocol to manage keychain updates. Tests can do a fake implementation. @available(iOS 13, tvOS 13, macOS 10.15, macCatalyst 13, watchOS 7, *) -protocol AuthKeychainStorage { +protocol AuthKeychainStorage: Sendable { func get(query: [String: Any], result: inout AnyObject?) -> OSStatus func add(query: [String: Any]) -> OSStatus func update(query: [String: Any], attributes: [String: Any]) -> OSStatus diff --git a/FirebaseAuth/Sources/Swift/Storage/AuthKeychainStorageReal.swift b/FirebaseAuth/Sources/Swift/Storage/AuthKeychainStorageReal.swift index 777ff056c3b..c2f4d762fcb 100644 --- a/FirebaseAuth/Sources/Swift/Storage/AuthKeychainStorageReal.swift +++ b/FirebaseAuth/Sources/Swift/Storage/AuthKeychainStorageReal.swift @@ -15,9 +15,12 @@ import Foundation /// The utility class to update the real keychain - @available(iOS 13, tvOS 13, macOS 10.15, macCatalyst 13, watchOS 7, *) -class AuthKeychainStorageReal: AuthKeychainStorage { +final class AuthKeychainStorageReal: AuthKeychainStorage { + static let shared: AuthKeychainStorageReal = .init() + + private init() {} + func get(query: [String: Any], result: inout AnyObject?) -> OSStatus { return SecItemCopyMatching(query as CFDictionary, &result) } diff --git a/FirebaseAuth/Sources/Swift/Storage/AuthUserDefaults.swift b/FirebaseAuth/Sources/Swift/Storage/AuthUserDefaults.swift index a3e6719eb95..4a16e8150cc 100644 --- a/FirebaseAuth/Sources/Swift/Storage/AuthUserDefaults.swift +++ b/FirebaseAuth/Sources/Swift/Storage/AuthUserDefaults.swift @@ -19,17 +19,11 @@ private let kPersistentDomainNamePrefix = "com.google.Firebase.Auth." /// The utility class to manage data storage in NSUserDefaults. class AuthUserDefaults { /// The name of the persistent domain in user defaults. - private let persistentDomainName: String /// The backing NSUserDefaults storage for this instance. - private let storage: UserDefaults - static func storage(identifier: String) -> Self { - return Self(service: identifier) - } - required init(service: String) { persistentDomainName = kPersistentDomainNamePrefix + service storage = UserDefaults() diff --git a/FirebaseAuth/Tests/Unit/AuthKeychainServicesTests.swift b/FirebaseAuth/Tests/Unit/AuthKeychainServicesTests.swift index 82b643bf50d..4c1e1f2d43c 100644 --- a/FirebaseAuth/Tests/Unit/AuthKeychainServicesTests.swift +++ b/FirebaseAuth/Tests/Unit/AuthKeychainServicesTests.swift @@ -33,14 +33,15 @@ class AuthKeychainServicesTests: XCTestCase { } var keychain: AuthKeychainServices! + #if (os(macOS) && !FIREBASE_AUTH_TESTING_USE_MACOS_KEYCHAIN) || SWIFT_PACKAGE + let storage: AuthKeychainStorage = FakeAuthKeychainStorage() + #else + let storage: AuthKeychainStorage = AuthKeychainStorageReal.shared + #endif // (os(macOS) && !FIREBASE_AUTH_TESTING_USE_MACOS_KEYCHAIN) || SWIFT_PACKAGE override func setUp() { super.setUp() - #if (os(macOS) && !FIREBASE_AUTH_TESTING_USE_MACOS_KEYCHAIN) || SWIFT_PACKAGE - keychain = AuthKeychainServices(service: Self.service, storage: FakeAuthKeychainStorage()) - #else - keychain = AuthKeychainServices(service: Self.service) - #endif // (os(macOS) && !FIREBASE_AUTH_TESTING_USE_MACOS_KEYCHAIN) || SWIFT_PACKAGE + keychain = AuthKeychainServices(service: Self.service, storage: storage) } func testReadNonexisting() throws { @@ -142,7 +143,7 @@ class AuthKeychainServicesTests: XCTestCase { } var result: CFTypeRef? - let status = keychain.keychainStorage.get(query: query as [String: Any], result: &result) + let status = storage.get(query: query as [String: Any], result: &result) guard let result = result as? Data, status != errSecItemNotFound else { if let resultArray = result as? [[String: Any]], @@ -168,7 +169,7 @@ class AuthKeychainServicesTests: XCTestCase { if let service { query[kSecAttrService] = service } - XCTAssertEqual(keychain.keychainStorage.add(query: query as [String: Any]), errSecSuccess) + XCTAssertEqual(storage.add(query: query as [String: Any]), errSecSuccess) } private func setPassword(_ password: String?, @@ -192,6 +193,6 @@ class AuthKeychainServicesTests: XCTestCase { if let service { query[kSecAttrService] = service } - XCTAssertEqual(keychain.keychainStorage.delete(query: query as [String: Any]), errSecSuccess) + XCTAssertEqual(storage.delete(query: query as [String: Any]), errSecSuccess) } } diff --git a/FirebaseAuth/Tests/Unit/AuthTests.swift b/FirebaseAuth/Tests/Unit/AuthTests.swift index e1057f247b2..5ae1d522108 100644 --- a/FirebaseAuth/Tests/Unit/AuthTests.swift +++ b/FirebaseAuth/Tests/Unit/AuthTests.swift @@ -43,7 +43,7 @@ class AuthTests: RPCBaseTests { #if (os(macOS) && !FIREBASE_AUTH_TESTING_USE_MACOS_KEYCHAIN) || SWIFT_PACKAGE let keychainStorageProvider = FakeAuthKeychainStorage() #else - let keychainStorageProvider = AuthKeychainStorageReal() + let keychainStorageProvider = AuthKeychainStorageReal.shared #endif // (os(macOS) && !FIREBASE_AUTH_TESTING_USE_MACOS_KEYCHAIN) || SWIFT_PACKAGE // Stub the implementation to save the token refresh task for later execution. diff --git a/FirebaseAuth/Tests/Unit/Fakes/FakeAuthKeychainStorage.swift b/FirebaseAuth/Tests/Unit/Fakes/FakeAuthKeychainStorage.swift index 41a0d0e2b48..251c1b719db 100644 --- a/FirebaseAuth/Tests/Unit/Fakes/FakeAuthKeychainStorage.swift +++ b/FirebaseAuth/Tests/Unit/Fakes/FakeAuthKeychainStorage.swift @@ -13,29 +13,28 @@ // limitations under the License. @testable import FirebaseAuth +import FirebaseCoreInternal import Foundation import XCTest -/** @class AuthKeychainStorage - @brief The utility class to update the real keychain - */ +/// The utility class to update the real keychain @available(iOS 13, tvOS 13, macOS 10.15, macCatalyst 13, watchOS 7, *) -class FakeAuthKeychainStorage: AuthKeychainStorage { +final class FakeAuthKeychainStorage: AuthKeychainStorage { // Fake Keychain. It's a dictionary, keyed by service name, for each key-value store dictionary - private var fakeKeychain: [String: [String: Any]] = [:] + private let fakeKeychain = FIRAllocatedUnfairLock<[String: [String: Any]]>(initialState: [:]) - private var fakeLegacyKeychain: [String: Any] = [:] + private let fakeLegacyKeychain = FIRAllocatedUnfairLock<[String: Any]>(initialState: [:]) func get(query: [String: Any], result: inout AnyObject?) -> OSStatus { if let service = queryService(query) { - guard let value = fakeKeychain[service]?[queryKey(query)] else { + guard let value = fakeKeychain.value()[service]?[queryKey(query)] else { return errSecItemNotFound } let returnArrayofDictionary = [[kSecValueData as String: value]] result = returnArrayofDictionary as AnyObject return noErr } else { - guard let value = fakeLegacyKeychain[queryKey(query)] else { + guard let value = fakeLegacyKeychain.value()[queryKey(query)] else { return errSecItemNotFound } let returnArrayofDictionary = [[kSecValueData as String: value]] @@ -46,9 +45,9 @@ class FakeAuthKeychainStorage: AuthKeychainStorage { func add(query: [String: Any]) -> OSStatus { if let service = queryService(query) { - fakeKeychain[service]?[queryKey(query)] = query[kSecValueData as String] + fakeKeychain.withLock { $0[service]?[queryKey(query)] = query[kSecValueData as String] } } else { - fakeLegacyKeychain[queryKey(query)] = query[kSecValueData as String] + fakeLegacyKeychain.withLock { $0[queryKey(query)] = query[kSecValueData as String] } } return noErr } @@ -59,9 +58,9 @@ class FakeAuthKeychainStorage: AuthKeychainStorage { @discardableResult func delete(query: [String: Any]) -> OSStatus { if let service = queryService(query) { - fakeKeychain[service]?[queryKey(query)] = nil + fakeKeychain.withLock { $0[service]?[queryKey(query)] = nil } } else { - fakeLegacyKeychain[queryKey(query)] = nil + fakeLegacyKeychain.withLock { $0[queryKey(query)] = nil } } return noErr } @@ -79,8 +78,10 @@ class FakeAuthKeychainStorage: AuthKeychainStorage { guard let service = query[kSecAttrService as String] as? String else { return nil } - if fakeKeychain[service] == nil { - fakeKeychain[service] = [:] + fakeKeychain.withLock { fakeKeychain in + if fakeKeychain[service] == nil { + fakeKeychain[service] = [:] + } } return service } diff --git a/FirebaseAuth/Tests/Unit/UserTests.swift b/FirebaseAuth/Tests/Unit/UserTests.swift index 0462c2306e3..c610e04a0bc 100644 --- a/FirebaseAuth/Tests/Unit/UserTests.swift +++ b/FirebaseAuth/Tests/Unit/UserTests.swift @@ -45,7 +45,7 @@ class UserTests: RPCBaseTests { #if (os(macOS) && !FIREBASE_AUTH_TESTING_USE_MACOS_KEYCHAIN) || SWIFT_PACKAGE let keychainStorageProvider = FakeAuthKeychainStorage() #else - let keychainStorageProvider = AuthKeychainStorageReal() + let keychainStorageProvider = AuthKeychainStorageReal.shared #endif // (os(macOS) && !FIREBASE_AUTH_TESTING_USE_MACOS_KEYCHAIN) || SWIFT_PACKAGE auth = Auth( app: FirebaseApp.app(name: "test-UserTests")!, From 116c6d6d333fe4840a6867830beeef529909da67 Mon Sep 17 00:00:00 2001 From: Nick Cooke <36927374+ncooke3@users.noreply.github.com> Date: Mon, 19 May 2025 14:07:48 -0400 Subject: [PATCH 028/113] [Sessions] Remove Swift 5.9 guard statements (#14866) --- .../Sources/SessionInitiator.swift | 36 ++----------------- 1 file changed, 2 insertions(+), 34 deletions(-) diff --git a/FirebaseSessions/Sources/SessionInitiator.swift b/FirebaseSessions/Sources/SessionInitiator.swift index 4a58fa9cea8..745f8e969c5 100644 --- a/FirebaseSessions/Sources/SessionInitiator.swift +++ b/FirebaseSessions/Sources/SessionInitiator.swift @@ -13,7 +13,7 @@ // limitations under the License. import Foundation -#if os(iOS) || os(tvOS) +#if os(iOS) || os(tvOS) || os(visionOS) import UIKit #elseif os(macOS) import AppKit @@ -22,17 +22,6 @@ import Foundation import WatchKit #endif // os(iOS) || os(tvOS) -// swift(>=5.9) implies Xcode 15+ -// Need to have this Swift version check to use os(visionOS) macro, VisionOS support. -// TODO: Remove this check and add `os(visionOS)` to the `os(iOS) || os(tvOS)` conditional above -// when Xcode 15 is the minimum supported by Firebase. -#if swift(>=5.9) - #if os(visionOS) - import UIKit - #endif // os(visionOS) -#endif // swift(>=5.9) - -/// /// The SessionInitiator is responsible for: /// 1) Running the initiate callback whenever a Session Start Event should /// begin sending. This can happen at a cold start of the app, and when it @@ -55,7 +44,7 @@ class SessionInitiator { self.initiateSessionStart() let notificationCenter = NotificationCenter.default - #if os(iOS) || os(tvOS) + #if os(iOS) || os(tvOS) || os(visionOS) notificationCenter.addObserver( self, selector: #selector(appBackgrounded), @@ -98,27 +87,6 @@ class SessionInitiator { ) } #endif // os(iOS) || os(tvOS) - - // swift(>=5.9) implies Xcode 15+ - // Need to have this Swift version check to use os(visionOS) macro, VisionOS support. - // TODO: Remove this check and add `os(visionOS)` to the `os(iOS) || os(tvOS)` conditional above - // when Xcode 15 is the minimum supported by Firebase. - #if swift(>=5.9) - #if os(visionOS) - notificationCenter.addObserver( - self, - selector: #selector(appBackgrounded), - name: UIApplication.didEnterBackgroundNotification, - object: nil - ) - notificationCenter.addObserver( - self, - selector: #selector(appForegrounded), - name: UIApplication.didBecomeActiveNotification, - object: nil - ) - #endif // os(visionOS) - #endif // swift(>=5.9) } @objc private func appBackgrounded() { From baa78c4179efc004752078e662540cbae7f0ade9 Mon Sep 17 00:00:00 2001 From: Nick Cooke <36927374+ncooke3@users.noreply.github.com> Date: Tue, 20 May 2025 10:07:47 -0400 Subject: [PATCH 029/113] [Auth] More Swift 6 progress (#14867) Co-authored-by: Morgan Chen --- .../AuthProvider/PhoneAuthProvider.swift | 20 +++++------ .../Swift/MultiFactor/MultiFactorInfo.swift | 4 ++- .../MultiFactor/MultiFactorSession.swift | 35 +++++++++++++------ .../Phone/PhoneMultiFactorInfo.swift | 5 ++- .../TOTP/TOTPMultiFactorInfo.swift | 5 ++- 5 files changed, 43 insertions(+), 26 deletions(-) diff --git a/FirebaseAuth/Sources/Swift/AuthProvider/PhoneAuthProvider.swift b/FirebaseAuth/Sources/Swift/AuthProvider/PhoneAuthProvider.swift index 61e5693f374..c0395182268 100644 --- a/FirebaseAuth/Sources/Swift/AuthProvider/PhoneAuthProvider.swift +++ b/FirebaseAuth/Sources/Swift/AuthProvider/PhoneAuthProvider.swift @@ -15,11 +15,13 @@ import FirebaseCore import Foundation +// TODO(Swift 6 Breaking): Make checked Sendable. + /// A concrete implementation of `AuthProvider` for phone auth providers. /// /// This class is available on iOS only. @available(iOS 13, tvOS 13, macOS 10.15, macCatalyst 13, watchOS 7, *) -@objc(FIRPhoneAuthProvider) open class PhoneAuthProvider: NSObject { +@objc(FIRPhoneAuthProvider) open class PhoneAuthProvider: NSObject, @unchecked Sendable { /// A string constant identifying the phone identity provider. @objc public static let id = "phone" private static let recaptchaVersion = "RECAPTCHA_ENTERPRISE" @@ -56,7 +58,7 @@ import Foundation @objc(verifyPhoneNumber:UIDelegate:completion:) open func verifyPhoneNumber(_ phoneNumber: String, uiDelegate: AuthUIDelegate? = nil, - completion: ((_: String?, _: Error?) -> Void)?) { + completion: (@MainActor (String?, Error?) -> Void)?) { verifyPhoneNumber(phoneNumber, uiDelegate: uiDelegate, multiFactorSession: nil, @@ -75,7 +77,7 @@ import Foundation open func verifyPhoneNumber(_ phoneNumber: String, uiDelegate: AuthUIDelegate? = nil, multiFactorSession: MultiFactorSession? = nil, - completion: ((_: String?, _: Error?) -> Void)?) { + completion: (@MainActor (String?, Error?) -> Void)?) { Task { do { let verificationID = try await verifyPhoneNumber( @@ -83,13 +85,9 @@ import Foundation uiDelegate: uiDelegate, multiFactorSession: multiFactorSession ) - await MainActor.run { - completion?(verificationID, nil) - } + await completion?(verificationID, nil) } catch { - await MainActor.run { - completion?(nil, error) - } + await completion?(nil, error) } } } @@ -135,7 +133,7 @@ import Foundation open func verifyPhoneNumber(with multiFactorInfo: PhoneMultiFactorInfo, uiDelegate: AuthUIDelegate? = nil, multiFactorSession: MultiFactorSession?, - completion: ((_: String?, _: Error?) -> Void)?) { + completion: ((String?, Error?) -> Void)?) { Task { do { let verificationID = try await verifyPhoneNumber( @@ -641,7 +639,6 @@ import Foundation private let auth: Auth private let callbackScheme: String private let usingClientIDScheme: Bool - private var recaptchaVerifier: AuthRecaptchaVerifier? init(auth: Auth) { self.auth = auth @@ -662,7 +659,6 @@ import Foundation return } callbackScheme = "" - recaptchaVerifier = AuthRecaptchaVerifier.shared(auth: auth) } private let kAuthTypeVerifyApp = "verifyApp" diff --git a/FirebaseAuth/Sources/Swift/MultiFactor/MultiFactorInfo.swift b/FirebaseAuth/Sources/Swift/MultiFactor/MultiFactorInfo.swift index 0115afc7533..839e405fc05 100644 --- a/FirebaseAuth/Sources/Swift/MultiFactor/MultiFactorInfo.swift +++ b/FirebaseAuth/Sources/Swift/MultiFactor/MultiFactorInfo.swift @@ -14,13 +14,15 @@ import Foundation +// TODO(Swift 6 Breaking): Make checked Sendable. + #if os(iOS) extension MultiFactorInfo: NSSecureCoding {} /// Safe public structure used to represent a second factor entity from a client perspective. /// /// This class is available on iOS only. - @objc(FIRMultiFactorInfo) open class MultiFactorInfo: NSObject { + @objc(FIRMultiFactorInfo) open class MultiFactorInfo: NSObject, @unchecked Sendable { /// The multi-factor enrollment ID. @objc(UID) public let uid: String diff --git a/FirebaseAuth/Sources/Swift/MultiFactor/MultiFactorSession.swift b/FirebaseAuth/Sources/Swift/MultiFactor/MultiFactorSession.swift index c4bda3eba36..33f7ef927ce 100644 --- a/FirebaseAuth/Sources/Swift/MultiFactor/MultiFactorSession.swift +++ b/FirebaseAuth/Sources/Swift/MultiFactor/MultiFactorSession.swift @@ -27,33 +27,46 @@ import Foundation @available(iOS 13, tvOS 13, macOS 10.15, macCatalyst 13, watchOS 7, *) @objc(FIRMultiFactorSession) open class MultiFactorSession: NSObject { /// The ID token for an enroll flow. This has to be retrieved after recent authentication. - var idToken: String? + let idToken: String? /// The pending credential after an enrolled second factor user signs in successfully with the /// first factor. - var mfaPendingCredential: String? + let mfaPendingCredential: String? + + /// Current user object. + let currentUser: User? /// Multi factor info for the current user. var multiFactorInfo: MultiFactorInfo? - /// Current user object. - var currentUser: User? - class func session(for user: User?) -> MultiFactorSession { let currentUser = user ?? Auth.auth().currentUser guard let currentUser else { fatalError("Internal Auth Error: missing user for multifactor auth") } - return .init(idToken: currentUser.tokenService.accessToken, currentUser: currentUser) + return .init( + idToken: currentUser.tokenService.accessToken, + mfaPendingCredential: nil, + multiFactorInfo: nil, + currentUser: currentUser + ) } - init(idToken: String?, currentUser: User) { - self.idToken = idToken - self.currentUser = currentUser + convenience init(mfaCredential: String?) { + self.init( + idToken: nil, + mfaPendingCredential: mfaCredential, + multiFactorInfo: nil, + currentUser: nil + ) } - init(mfaCredential: String?) { - mfaPendingCredential = mfaCredential + private init(idToken: String?, mfaPendingCredential: String?, multiFactorInfo: MultiFactorInfo?, + currentUser: User?) { + self.idToken = idToken + self.mfaPendingCredential = mfaPendingCredential + self.multiFactorInfo = multiFactorInfo + self.currentUser = currentUser } } diff --git a/FirebaseAuth/Sources/Swift/MultiFactor/Phone/PhoneMultiFactorInfo.swift b/FirebaseAuth/Sources/Swift/MultiFactor/Phone/PhoneMultiFactorInfo.swift index 58e5fc5fb8b..b847407c48a 100644 --- a/FirebaseAuth/Sources/Swift/MultiFactor/Phone/PhoneMultiFactorInfo.swift +++ b/FirebaseAuth/Sources/Swift/MultiFactor/Phone/PhoneMultiFactorInfo.swift @@ -14,6 +14,8 @@ import Foundation +// TODO(Swift 6 Breaking): Make checked Sendable. + #if os(iOS) /// Extends the MultiFactorInfo class for phone number second factors. @@ -21,7 +23,8 @@ import Foundation /// The identifier of this second factor is "phone". /// /// This class is available on iOS only. - @objc(FIRPhoneMultiFactorInfo) open class PhoneMultiFactorInfo: MultiFactorInfo { + @objc(FIRPhoneMultiFactorInfo) open class PhoneMultiFactorInfo: MultiFactorInfo, + @unchecked Sendable { /// The string identifier for using phone as a second factor. @objc(FIRPhoneMultiFactorID) public static let PhoneMultiFactorID = "phone" diff --git a/FirebaseAuth/Sources/Swift/MultiFactor/TOTP/TOTPMultiFactorInfo.swift b/FirebaseAuth/Sources/Swift/MultiFactor/TOTP/TOTPMultiFactorInfo.swift index b1c3f7b7d95..dbb2eeb7042 100644 --- a/FirebaseAuth/Sources/Swift/MultiFactor/TOTP/TOTPMultiFactorInfo.swift +++ b/FirebaseAuth/Sources/Swift/MultiFactor/TOTP/TOTPMultiFactorInfo.swift @@ -14,6 +14,9 @@ import Foundation +// TODO(Swift 6 Breaking): Make checked Sendable. Also, does this need +// to be public? + #if os(iOS) /// Extends the MultiFactorInfo class for time based one-time password second factors. @@ -21,7 +24,7 @@ import Foundation /// The identifier of this second factor is "totp". /// /// This class is available on iOS only. - class TOTPMultiFactorInfo: MultiFactorInfo { + class TOTPMultiFactorInfo: MultiFactorInfo, @unchecked Sendable { /// Initialize the AuthProtoMFAEnrollment instance with proto. /// - Parameter proto: AuthProtoMFAEnrollment proto object. init(proto: AuthProtoMFAEnrollment) { From 314feaecfc60fa9b09fbfa061e948f1c2063aba5 Mon Sep 17 00:00:00 2001 From: Andrew Heard Date: Tue, 20 May 2025 12:14:02 -0400 Subject: [PATCH 030/113] [CI] Update `Dangerfile` to set `api: firebaseai` label (#14870) --- Dangerfile | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/Dangerfile b/Dangerfile index 7b8bfac5803..1438a1d1010 100644 --- a/Dangerfile +++ b/Dangerfile @@ -56,6 +56,7 @@ def labelsForModifiedFiles() labels.push("api: crashlytics") if @has_crashlytics_changes labels.push("api: database") if @has_database_changes labels.push("api: dynamiclinks") if @has_dynamiclinks_changes + labels.push("api: firebaseai") if @has_firebaseai_changes labels.push("api: firestore") if @has_firestore_changes labels.push("api: functions") if @has_functions_changes labels.push("api: inappmessaging") if @has_inappmessaging_changes @@ -64,7 +65,6 @@ def labelsForModifiedFiles() labels.push("api: performance") if @has_performance_changes labels.push("api: remoteconfig") if @has_remoteconfig_changes labels.push("api: storage") if @has_storage_changes - labels.push("api: vertexai") if @has_vertexai_changes labels.push("release-tooling") if @has_releasetooling_changes labels.push("public-api-change") if @has_api_changes return labels @@ -94,6 +94,7 @@ has_license_changes = didModify(["LICENSE"]) "Crashlytics", "Database", "DynamicLinks", + "FirebaseAI", "Firestore", "Functions", "InAppMessaging", @@ -101,8 +102,7 @@ has_license_changes = didModify(["LICENSE"]) "Messaging", "Performance", "RemoteConfig", - "Storage", - "VertexAI" + "Storage" ] ## Product directories @@ -134,6 +134,10 @@ has_license_changes = didModify(["LICENSE"]) @has_database_api_changes = hasChangesIn("FirebaseDatabase/Sources/Public/") @has_dynamiclinks_changes = hasChangesIn("FirebaseDynamicLinks") @has_dynamiclinks_api_changes = hasChangesIn("FirebaseDynamicLinks/Sources/Public/") +@has_firebaseai_changes = hasChangesIn([ + "FirebaseAI", + "FirebaseVertexAI" +]) @has_firestore_changes = hasChangesIn(["Firestore/", "FirebaseFirestore.podspec"]) @has_firestore_api_changes = hasChangesIn("Firestore/Source/Public/") @has_functions_changes = hasChangesIn(["FirebaseFunctions"]) @@ -149,7 +153,6 @@ has_license_changes = didModify(["LICENSE"]) @has_remoteconfig_changes = hasChangesIn("FirebaseRemoteConfig") @has_remoteconfig_api_changes = hasChangesIn("FirebaseRemoteConfig/Sources/Public/") @has_storage_changes = hasChangesIn("FirebaseStorage") -@has_vertexai_changes = hasChangesIn("FirebaseVertexAI") @has_releasetooling_changes = hasChangesIn("ReleaseTooling/") @has_public_additions = hasAdditionsIn("Public/") From 946b16ef44db13932a6a650446c3bed16249f4bb Mon Sep 17 00:00:00 2001 From: Nick Cooke <36927374+ncooke3@users.noreply.github.com> Date: Tue, 20 May 2025 14:19:36 -0400 Subject: [PATCH 031/113] [Release] Carthage for 11.13.0 (#14872) --- ReleaseTooling/CarthageJSON/FirebaseABTestingBinary.json | 1 + ReleaseTooling/CarthageJSON/FirebaseAIBinary.json | 4 +++- ReleaseTooling/CarthageJSON/FirebaseAdMobBinary.json | 1 + ReleaseTooling/CarthageJSON/FirebaseAnalyticsBinary.json | 1 + .../FirebaseAnalyticsOnDeviceConversionBinary.json | 1 + ReleaseTooling/CarthageJSON/FirebaseAppCheckBinary.json | 1 + .../CarthageJSON/FirebaseAppDistributionBinary.json | 1 + ReleaseTooling/CarthageJSON/FirebaseAuthBinary.json | 1 + ReleaseTooling/CarthageJSON/FirebaseCrashlyticsBinary.json | 1 + ReleaseTooling/CarthageJSON/FirebaseDatabaseBinary.json | 1 + ReleaseTooling/CarthageJSON/FirebaseDynamicLinksBinary.json | 1 + ReleaseTooling/CarthageJSON/FirebaseFirestoreBinary.json | 1 + ReleaseTooling/CarthageJSON/FirebaseFunctionsBinary.json | 1 + ReleaseTooling/CarthageJSON/FirebaseGoogleSignInBinary.json | 1 + ReleaseTooling/CarthageJSON/FirebaseInAppMessagingBinary.json | 1 + .../CarthageJSON/FirebaseMLModelDownloaderBinary.json | 1 + ReleaseTooling/CarthageJSON/FirebaseMessagingBinary.json | 1 + ReleaseTooling/CarthageJSON/FirebasePerformanceBinary.json | 1 + ReleaseTooling/CarthageJSON/FirebaseRemoteConfigBinary.json | 1 + ReleaseTooling/CarthageJSON/FirebaseStorageBinary.json | 1 + ReleaseTooling/CarthageJSON/FirebaseVertexAIBinary.json | 1 + 21 files changed, 23 insertions(+), 1 deletion(-) diff --git a/ReleaseTooling/CarthageJSON/FirebaseABTestingBinary.json b/ReleaseTooling/CarthageJSON/FirebaseABTestingBinary.json index a4fd216f5b3..a0217f538d2 100644 --- a/ReleaseTooling/CarthageJSON/FirebaseABTestingBinary.json +++ b/ReleaseTooling/CarthageJSON/FirebaseABTestingBinary.json @@ -33,6 +33,7 @@ "11.10.0": "https://dl.google.com/dl/firebase/ios/carthage/11.10.0/FirebaseABTesting-63e10ff7cf44578c.zip", "11.11.0": "https://dl.google.com/dl/firebase/ios/carthage/11.11.0/FirebaseABTesting-1fa70f00533854e0.zip", "11.12.0": "https://dl.google.com/dl/firebase/ios/carthage/11.12.0/FirebaseABTesting-17c1a20424ac54c7.zip", + "11.13.0": "https://dl.google.com/dl/firebase/ios/carthage/11.13.0/FirebaseABTesting-1a75b2ffead6cd9d.zip", "11.2.0": "https://dl.google.com/dl/firebase/ios/carthage/11.2.0/FirebaseABTesting-0d51fde82d49f9e8.zip", "11.3.0": "https://dl.google.com/dl/firebase/ios/carthage/11.3.0/FirebaseABTesting-2233510ff87da3b6.zip", "11.4.0": "https://dl.google.com/dl/firebase/ios/carthage/11.4.0/FirebaseABTesting-4d0b187af6fd8d67.zip", diff --git a/ReleaseTooling/CarthageJSON/FirebaseAIBinary.json b/ReleaseTooling/CarthageJSON/FirebaseAIBinary.json index 0967ef424bc..169c47eee73 100644 --- a/ReleaseTooling/CarthageJSON/FirebaseAIBinary.json +++ b/ReleaseTooling/CarthageJSON/FirebaseAIBinary.json @@ -1 +1,3 @@ -{} +{ + "11.13.0": "https://dl.google.com/dl/firebase/ios/carthage/11.13.0/FirebaseAI-b1e75ff6284775b1.zip" +} diff --git a/ReleaseTooling/CarthageJSON/FirebaseAdMobBinary.json b/ReleaseTooling/CarthageJSON/FirebaseAdMobBinary.json index 6bb188f38c9..281802be59e 100644 --- a/ReleaseTooling/CarthageJSON/FirebaseAdMobBinary.json +++ b/ReleaseTooling/CarthageJSON/FirebaseAdMobBinary.json @@ -33,6 +33,7 @@ "11.10.0": "https://dl.google.com/dl/firebase/ios/carthage/11.10.0/Google-Mobile-Ads-SDK-de3ae4af5f64bcc2.zip", "11.11.0": "https://dl.google.com/dl/firebase/ios/carthage/11.11.0/Google-Mobile-Ads-SDK-3653cb73a799c206.zip", "11.12.0": "https://dl.google.com/dl/firebase/ios/carthage/11.12.0/Google-Mobile-Ads-SDK-f8af4dfdc3318376.zip", + "11.13.0": "https://dl.google.com/dl/firebase/ios/carthage/11.13.0/Google-Mobile-Ads-SDK-cafdcb68e4493534.zip", "11.2.0": "https://dl.google.com/dl/firebase/ios/carthage/11.2.0/Google-Mobile-Ads-SDK-4f24527af297e7f1.zip", "11.3.0": "https://dl.google.com/dl/firebase/ios/carthage/11.3.0/Google-Mobile-Ads-SDK-80ba4cb995505158.zip", "11.4.0": "https://dl.google.com/dl/firebase/ios/carthage/11.4.0/Google-Mobile-Ads-SDK-3df614a58e6a5fa6.zip", diff --git a/ReleaseTooling/CarthageJSON/FirebaseAnalyticsBinary.json b/ReleaseTooling/CarthageJSON/FirebaseAnalyticsBinary.json index f3d263e84f0..82951d390be 100644 --- a/ReleaseTooling/CarthageJSON/FirebaseAnalyticsBinary.json +++ b/ReleaseTooling/CarthageJSON/FirebaseAnalyticsBinary.json @@ -33,6 +33,7 @@ "11.10.0": "https://dl.google.com/dl/firebase/ios/carthage/11.10.0/FirebaseAnalytics-0b845322b94a28b6.zip", "11.11.0": "https://dl.google.com/dl/firebase/ios/carthage/11.11.0/FirebaseAnalytics-9555aba4c5a25d4f.zip", "11.12.0": "https://dl.google.com/dl/firebase/ios/carthage/11.12.0/FirebaseAnalytics-15d238d1b49f4aff.zip", + "11.13.0": "https://dl.google.com/dl/firebase/ios/carthage/11.13.0/FirebaseAnalytics-65ff9a1a6c9e6497.zip", "11.2.0": "https://dl.google.com/dl/firebase/ios/carthage/11.2.0/FirebaseAnalytics-a93a6c81da535385.zip", "11.3.0": "https://dl.google.com/dl/firebase/ios/carthage/11.3.0/FirebaseAnalytics-fd2c71a90d62b88a.zip", "11.4.0": "https://dl.google.com/dl/firebase/ios/carthage/11.4.0/FirebaseAnalytics-525b465eb296d09e.zip", diff --git a/ReleaseTooling/CarthageJSON/FirebaseAnalyticsOnDeviceConversionBinary.json b/ReleaseTooling/CarthageJSON/FirebaseAnalyticsOnDeviceConversionBinary.json index e7e6fb02f5b..75392d66afc 100644 --- a/ReleaseTooling/CarthageJSON/FirebaseAnalyticsOnDeviceConversionBinary.json +++ b/ReleaseTooling/CarthageJSON/FirebaseAnalyticsOnDeviceConversionBinary.json @@ -33,6 +33,7 @@ "11.10.0": "https://dl.google.com/dl/firebase/ios/carthage/11.10.0/FirebaseAnalyticsOnDeviceConversion-77dff0ae699ee1f6.zip", "11.11.0": "https://dl.google.com/dl/firebase/ios/carthage/11.11.0/FirebaseAnalyticsOnDeviceConversion-844b470f329d4e3b.zip", "11.12.0": "https://dl.google.com/dl/firebase/ios/carthage/11.12.0/FirebaseAnalyticsOnDeviceConversion-74e82e4c9ac69336.zip", + "11.13.0": "https://dl.google.com/dl/firebase/ios/carthage/11.13.0/FirebaseAnalyticsOnDeviceConversion-78d60e37985a869e.zip", "11.2.0": "https://dl.google.com/dl/firebase/ios/carthage/11.2.0/FirebaseAnalyticsOnDeviceConversion-09d94624a2de0ac8.zip", "11.3.0": "https://dl.google.com/dl/firebase/ios/carthage/11.3.0/FirebaseAnalyticsOnDeviceConversion-918bc6e0b7a2fd94.zip", "11.4.0": "https://dl.google.com/dl/firebase/ios/carthage/11.4.0/FirebaseAnalyticsOnDeviceConversion-1640c514418a23da.zip", diff --git a/ReleaseTooling/CarthageJSON/FirebaseAppCheckBinary.json b/ReleaseTooling/CarthageJSON/FirebaseAppCheckBinary.json index c6c6626e601..9b2b42c5131 100644 --- a/ReleaseTooling/CarthageJSON/FirebaseAppCheckBinary.json +++ b/ReleaseTooling/CarthageJSON/FirebaseAppCheckBinary.json @@ -33,6 +33,7 @@ "11.10.0": "https://dl.google.com/dl/firebase/ios/carthage/11.10.0/FirebaseAppCheck-fd4219676bad21cb.zip", "11.11.0": "https://dl.google.com/dl/firebase/ios/carthage/11.11.0/FirebaseAppCheck-53a4dc38e63d6624.zip", "11.12.0": "https://dl.google.com/dl/firebase/ios/carthage/11.12.0/FirebaseAppCheck-0c2c90b1b6b95fc9.zip", + "11.13.0": "https://dl.google.com/dl/firebase/ios/carthage/11.13.0/FirebaseAppCheck-11e2868920731911.zip", "11.2.0": "https://dl.google.com/dl/firebase/ios/carthage/11.2.0/FirebaseAppCheck-d0c5f46e6a2bf4a3.zip", "11.3.0": "https://dl.google.com/dl/firebase/ios/carthage/11.3.0/FirebaseAppCheck-89c39bdcf0bb90fe.zip", "11.4.0": "https://dl.google.com/dl/firebase/ios/carthage/11.4.0/FirebaseAppCheck-9b0c4a9489968b07.zip", diff --git a/ReleaseTooling/CarthageJSON/FirebaseAppDistributionBinary.json b/ReleaseTooling/CarthageJSON/FirebaseAppDistributionBinary.json index 3fffe7890b3..0a625872625 100644 --- a/ReleaseTooling/CarthageJSON/FirebaseAppDistributionBinary.json +++ b/ReleaseTooling/CarthageJSON/FirebaseAppDistributionBinary.json @@ -33,6 +33,7 @@ "11.10.0": "https://dl.google.com/dl/firebase/ios/carthage/11.10.0/FirebaseAppDistribution-e039cee13bf8daf2.zip", "11.11.0": "https://dl.google.com/dl/firebase/ios/carthage/11.11.0/FirebaseAppDistribution-2224206d63435182.zip", "11.12.0": "https://dl.google.com/dl/firebase/ios/carthage/11.12.0/FirebaseAppDistribution-7c36126c08bc3ffc.zip", + "11.13.0": "https://dl.google.com/dl/firebase/ios/carthage/11.13.0/FirebaseAppDistribution-e955d19576007871.zip", "11.2.0": "https://dl.google.com/dl/firebase/ios/carthage/11.2.0/FirebaseAppDistribution-9b05f4873b275347.zip", "11.3.0": "https://dl.google.com/dl/firebase/ios/carthage/11.3.0/FirebaseAppDistribution-6d2eccaccfd3145f.zip", "11.4.0": "https://dl.google.com/dl/firebase/ios/carthage/11.4.0/FirebaseAppDistribution-20ac94ca344af731.zip", diff --git a/ReleaseTooling/CarthageJSON/FirebaseAuthBinary.json b/ReleaseTooling/CarthageJSON/FirebaseAuthBinary.json index 3aa215f2db4..ec02b5a2abe 100644 --- a/ReleaseTooling/CarthageJSON/FirebaseAuthBinary.json +++ b/ReleaseTooling/CarthageJSON/FirebaseAuthBinary.json @@ -33,6 +33,7 @@ "11.10.0": "https://dl.google.com/dl/firebase/ios/carthage/11.10.0/FirebaseAuth-b89a6c5a009a66df.zip", "11.11.0": "https://dl.google.com/dl/firebase/ios/carthage/11.11.0/FirebaseAuth-c0fe98c6072e1eec.zip", "11.12.0": "https://dl.google.com/dl/firebase/ios/carthage/11.12.0/FirebaseAuth-eb54b6a712749cc9.zip", + "11.13.0": "https://dl.google.com/dl/firebase/ios/carthage/11.13.0/FirebaseAuth-88c4514b7d5eb6a2.zip", "11.2.0": "https://dl.google.com/dl/firebase/ios/carthage/11.2.0/FirebaseAuth-eade26b5390baf84.zip", "11.3.0": "https://dl.google.com/dl/firebase/ios/carthage/11.3.0/FirebaseAuth-93dd2965b3f79b98.zip", "11.4.0": "https://dl.google.com/dl/firebase/ios/carthage/11.4.0/FirebaseAuth-5faf6dc3bb16c732.zip", diff --git a/ReleaseTooling/CarthageJSON/FirebaseCrashlyticsBinary.json b/ReleaseTooling/CarthageJSON/FirebaseCrashlyticsBinary.json index 1ec4b573b9f..2979dbbc54e 100644 --- a/ReleaseTooling/CarthageJSON/FirebaseCrashlyticsBinary.json +++ b/ReleaseTooling/CarthageJSON/FirebaseCrashlyticsBinary.json @@ -33,6 +33,7 @@ "11.10.0": "https://dl.google.com/dl/firebase/ios/carthage/11.10.0/FirebaseCrashlytics-a77666e0777320c5.zip", "11.11.0": "https://dl.google.com/dl/firebase/ios/carthage/11.11.0/FirebaseCrashlytics-c5d0dc18d2183d76.zip", "11.12.0": "https://dl.google.com/dl/firebase/ios/carthage/11.12.0/FirebaseCrashlytics-6174ffabf4502bb8.zip", + "11.13.0": "https://dl.google.com/dl/firebase/ios/carthage/11.13.0/FirebaseCrashlytics-b653e61e196e22a4.zip", "11.2.0": "https://dl.google.com/dl/firebase/ios/carthage/11.2.0/FirebaseCrashlytics-13851523ad6df088.zip", "11.3.0": "https://dl.google.com/dl/firebase/ios/carthage/11.3.0/FirebaseCrashlytics-282a6f3cf3445787.zip", "11.4.0": "https://dl.google.com/dl/firebase/ios/carthage/11.4.0/FirebaseCrashlytics-d5c125d6416f6e0a.zip", diff --git a/ReleaseTooling/CarthageJSON/FirebaseDatabaseBinary.json b/ReleaseTooling/CarthageJSON/FirebaseDatabaseBinary.json index d89835a129a..18f1c65d3de 100644 --- a/ReleaseTooling/CarthageJSON/FirebaseDatabaseBinary.json +++ b/ReleaseTooling/CarthageJSON/FirebaseDatabaseBinary.json @@ -33,6 +33,7 @@ "11.10.0": "https://dl.google.com/dl/firebase/ios/carthage/11.10.0/FirebaseDatabase-4ecbbbf20e609fec.zip", "11.11.0": "https://dl.google.com/dl/firebase/ios/carthage/11.11.0/FirebaseDatabase-274d83ecf88f0312.zip", "11.12.0": "https://dl.google.com/dl/firebase/ios/carthage/11.12.0/FirebaseDatabase-f2f974b2b124d51a.zip", + "11.13.0": "https://dl.google.com/dl/firebase/ios/carthage/11.13.0/FirebaseDatabase-c90d9d681a963528.zip", "11.2.0": "https://dl.google.com/dl/firebase/ios/carthage/11.2.0/FirebaseDatabase-06dbb1f7d3c8a3e1.zip", "11.3.0": "https://dl.google.com/dl/firebase/ios/carthage/11.3.0/FirebaseDatabase-38634b55050b94fe.zip", "11.4.0": "https://dl.google.com/dl/firebase/ios/carthage/11.4.0/FirebaseDatabase-ed125984da534e96.zip", diff --git a/ReleaseTooling/CarthageJSON/FirebaseDynamicLinksBinary.json b/ReleaseTooling/CarthageJSON/FirebaseDynamicLinksBinary.json index 9d0a3142d63..02924c965af 100644 --- a/ReleaseTooling/CarthageJSON/FirebaseDynamicLinksBinary.json +++ b/ReleaseTooling/CarthageJSON/FirebaseDynamicLinksBinary.json @@ -33,6 +33,7 @@ "11.10.0": "https://dl.google.com/dl/firebase/ios/carthage/11.10.0/FirebaseDynamicLinks-d1dd0aa4cb2b5df1.zip", "11.11.0": "https://dl.google.com/dl/firebase/ios/carthage/11.11.0/FirebaseDynamicLinks-3bc027fc5b14a796.zip", "11.12.0": "https://dl.google.com/dl/firebase/ios/carthage/11.12.0/FirebaseDynamicLinks-f5c8594e8040c69a.zip", + "11.13.0": "https://dl.google.com/dl/firebase/ios/carthage/11.13.0/FirebaseDynamicLinks-cadebc4c288fe390.zip", "11.2.0": "https://dl.google.com/dl/firebase/ios/carthage/11.2.0/FirebaseDynamicLinks-e61c61fa80e5ea8a.zip", "11.3.0": "https://dl.google.com/dl/firebase/ios/carthage/11.3.0/FirebaseDynamicLinks-95f7e222d8456304.zip", "11.4.0": "https://dl.google.com/dl/firebase/ios/carthage/11.4.0/FirebaseDynamicLinks-f3f9d6cc60c8b832.zip", diff --git a/ReleaseTooling/CarthageJSON/FirebaseFirestoreBinary.json b/ReleaseTooling/CarthageJSON/FirebaseFirestoreBinary.json index 7fd8a13948a..51779ca7a89 100644 --- a/ReleaseTooling/CarthageJSON/FirebaseFirestoreBinary.json +++ b/ReleaseTooling/CarthageJSON/FirebaseFirestoreBinary.json @@ -33,6 +33,7 @@ "11.10.0": "https://dl.google.com/dl/firebase/ios/carthage/11.10.0/FirebaseFirestore-cb0e8707be86f01e.zip", "11.11.0": "https://dl.google.com/dl/firebase/ios/carthage/11.11.0/FirebaseFirestore-c1b73a8c2df88a5d.zip", "11.12.0": "https://dl.google.com/dl/firebase/ios/carthage/11.12.0/FirebaseFirestore-860c013c1e20d6f3.zip", + "11.13.0": "https://dl.google.com/dl/firebase/ios/carthage/11.13.0/FirebaseFirestore-c4f5b2c5b7a568a1.zip", "11.2.0": "https://dl.google.com/dl/firebase/ios/carthage/11.2.0/FirebaseFirestore-43af85b854ac842e.zip", "11.3.0": "https://dl.google.com/dl/firebase/ios/carthage/11.3.0/FirebaseFirestore-e1283f8cd2e0f3ec.zip", "11.4.0": "https://dl.google.com/dl/firebase/ios/carthage/11.4.0/FirebaseFirestore-f5864e67ddbbc9e8.zip", diff --git a/ReleaseTooling/CarthageJSON/FirebaseFunctionsBinary.json b/ReleaseTooling/CarthageJSON/FirebaseFunctionsBinary.json index 5290fe4cb85..e674a7d818c 100644 --- a/ReleaseTooling/CarthageJSON/FirebaseFunctionsBinary.json +++ b/ReleaseTooling/CarthageJSON/FirebaseFunctionsBinary.json @@ -33,6 +33,7 @@ "11.10.0": "https://dl.google.com/dl/firebase/ios/carthage/11.10.0/FirebaseFunctions-88c24c04d7a558d7.zip", "11.11.0": "https://dl.google.com/dl/firebase/ios/carthage/11.11.0/FirebaseFunctions-bb6ac03a35726822.zip", "11.12.0": "https://dl.google.com/dl/firebase/ios/carthage/11.12.0/FirebaseFunctions-5ab1be0d8d70d377.zip", + "11.13.0": "https://dl.google.com/dl/firebase/ios/carthage/11.13.0/FirebaseFunctions-63e0b73f4514e67f.zip", "11.2.0": "https://dl.google.com/dl/firebase/ios/carthage/11.2.0/FirebaseFunctions-307f00117c2efc62.zip", "11.3.0": "https://dl.google.com/dl/firebase/ios/carthage/11.3.0/FirebaseFunctions-02693a7583303912.zip", "11.4.0": "https://dl.google.com/dl/firebase/ios/carthage/11.4.0/FirebaseFunctions-8fce8623ed1c6b86.zip", diff --git a/ReleaseTooling/CarthageJSON/FirebaseGoogleSignInBinary.json b/ReleaseTooling/CarthageJSON/FirebaseGoogleSignInBinary.json index 9850cc1a423..6a4f7452ec6 100644 --- a/ReleaseTooling/CarthageJSON/FirebaseGoogleSignInBinary.json +++ b/ReleaseTooling/CarthageJSON/FirebaseGoogleSignInBinary.json @@ -33,6 +33,7 @@ "11.10.0": "https://dl.google.com/dl/firebase/ios/carthage/11.10.0/GoogleSignIn-7afef6880b412ca5.zip", "11.11.0": "https://dl.google.com/dl/firebase/ios/carthage/11.11.0/GoogleSignIn-53da1498f8e507e3.zip", "11.12.0": "https://dl.google.com/dl/firebase/ios/carthage/11.12.0/GoogleSignIn-359f9a827460f64a.zip", + "11.13.0": "https://dl.google.com/dl/firebase/ios/carthage/11.13.0/GoogleSignIn-865a20796d87317c.zip", "11.2.0": "https://dl.google.com/dl/firebase/ios/carthage/11.2.0/GoogleSignIn-4e8837ef9594b57b.zip", "11.3.0": "https://dl.google.com/dl/firebase/ios/carthage/11.3.0/GoogleSignIn-8ce1c31ca2236212.zip", "11.4.0": "https://dl.google.com/dl/firebase/ios/carthage/11.4.0/GoogleSignIn-59eb371d148a2e3a.zip", diff --git a/ReleaseTooling/CarthageJSON/FirebaseInAppMessagingBinary.json b/ReleaseTooling/CarthageJSON/FirebaseInAppMessagingBinary.json index 0a093214d99..1152d94805a 100644 --- a/ReleaseTooling/CarthageJSON/FirebaseInAppMessagingBinary.json +++ b/ReleaseTooling/CarthageJSON/FirebaseInAppMessagingBinary.json @@ -33,6 +33,7 @@ "11.10.0": "https://dl.google.com/dl/firebase/ios/carthage/11.10.0/FirebaseInAppMessaging-01cae82d542f9c95.zip", "11.11.0": "https://dl.google.com/dl/firebase/ios/carthage/11.11.0/FirebaseInAppMessaging-f877ac14815852ad.zip", "11.12.0": "https://dl.google.com/dl/firebase/ios/carthage/11.12.0/FirebaseInAppMessaging-713d93418e005e14.zip", + "11.13.0": "https://dl.google.com/dl/firebase/ios/carthage/11.13.0/FirebaseInAppMessaging-db00d9a8196980fe.zip", "11.2.0": "https://dl.google.com/dl/firebase/ios/carthage/11.2.0/FirebaseInAppMessaging-6fae0a778e9d3efa.zip", "11.3.0": "https://dl.google.com/dl/firebase/ios/carthage/11.3.0/FirebaseInAppMessaging-3a1a331c86520356.zip", "11.4.0": "https://dl.google.com/dl/firebase/ios/carthage/11.4.0/FirebaseInAppMessaging-a8054099dd2918b3.zip", diff --git a/ReleaseTooling/CarthageJSON/FirebaseMLModelDownloaderBinary.json b/ReleaseTooling/CarthageJSON/FirebaseMLModelDownloaderBinary.json index 432aa514283..2c7f3121910 100644 --- a/ReleaseTooling/CarthageJSON/FirebaseMLModelDownloaderBinary.json +++ b/ReleaseTooling/CarthageJSON/FirebaseMLModelDownloaderBinary.json @@ -33,6 +33,7 @@ "11.10.0": "https://dl.google.com/dl/firebase/ios/carthage/11.10.0/FirebaseMLModelDownloader-04432073f4438f19.zip", "11.11.0": "https://dl.google.com/dl/firebase/ios/carthage/11.11.0/FirebaseMLModelDownloader-9af14fef01f3233b.zip", "11.12.0": "https://dl.google.com/dl/firebase/ios/carthage/11.12.0/FirebaseMLModelDownloader-90a680269b1b7dc1.zip", + "11.13.0": "https://dl.google.com/dl/firebase/ios/carthage/11.13.0/FirebaseMLModelDownloader-680180005688845d.zip", "11.2.0": "https://dl.google.com/dl/firebase/ios/carthage/11.2.0/FirebaseMLModelDownloader-d8649822e63fbf7f.zip", "11.3.0": "https://dl.google.com/dl/firebase/ios/carthage/11.3.0/FirebaseMLModelDownloader-517f51af92733a7f.zip", "11.4.0": "https://dl.google.com/dl/firebase/ios/carthage/11.4.0/FirebaseMLModelDownloader-069609cbcde7e789.zip", diff --git a/ReleaseTooling/CarthageJSON/FirebaseMessagingBinary.json b/ReleaseTooling/CarthageJSON/FirebaseMessagingBinary.json index 6bfbb3fa602..5aebd39ca28 100644 --- a/ReleaseTooling/CarthageJSON/FirebaseMessagingBinary.json +++ b/ReleaseTooling/CarthageJSON/FirebaseMessagingBinary.json @@ -33,6 +33,7 @@ "11.10.0": "https://dl.google.com/dl/firebase/ios/carthage/11.10.0/FirebaseMessaging-841a38305aa0accd.zip", "11.11.0": "https://dl.google.com/dl/firebase/ios/carthage/11.11.0/FirebaseMessaging-00a1ed88e98f2d4e.zip", "11.12.0": "https://dl.google.com/dl/firebase/ios/carthage/11.12.0/FirebaseMessaging-c27934ab4d2ac145.zip", + "11.13.0": "https://dl.google.com/dl/firebase/ios/carthage/11.13.0/FirebaseMessaging-57ff2659837e66f7.zip", "11.2.0": "https://dl.google.com/dl/firebase/ios/carthage/11.2.0/FirebaseMessaging-70e63bb9d9590ded.zip", "11.3.0": "https://dl.google.com/dl/firebase/ios/carthage/11.3.0/FirebaseMessaging-8a39834fead3c581.zip", "11.4.0": "https://dl.google.com/dl/firebase/ios/carthage/11.4.0/FirebaseMessaging-2d09725e8b98d199.zip", diff --git a/ReleaseTooling/CarthageJSON/FirebasePerformanceBinary.json b/ReleaseTooling/CarthageJSON/FirebasePerformanceBinary.json index a945a3b857c..758c3975ae9 100644 --- a/ReleaseTooling/CarthageJSON/FirebasePerformanceBinary.json +++ b/ReleaseTooling/CarthageJSON/FirebasePerformanceBinary.json @@ -33,6 +33,7 @@ "11.10.0": "https://dl.google.com/dl/firebase/ios/carthage/11.10.0/FirebasePerformance-d740f89dee0bfb8e.zip", "11.11.0": "https://dl.google.com/dl/firebase/ios/carthage/11.11.0/FirebasePerformance-cd019e13c2f186dd.zip", "11.12.0": "https://dl.google.com/dl/firebase/ios/carthage/11.12.0/FirebasePerformance-d8b225f36b8cbf8b.zip", + "11.13.0": "https://dl.google.com/dl/firebase/ios/carthage/11.13.0/FirebasePerformance-916f67a44f64a09c.zip", "11.2.0": "https://dl.google.com/dl/firebase/ios/carthage/11.2.0/FirebasePerformance-aa174ee3102722d9.zip", "11.3.0": "https://dl.google.com/dl/firebase/ios/carthage/11.3.0/FirebasePerformance-a489ac7a27d9b53d.zip", "11.4.0": "https://dl.google.com/dl/firebase/ios/carthage/11.4.0/FirebasePerformance-9a6f62e80c2324f4.zip", diff --git a/ReleaseTooling/CarthageJSON/FirebaseRemoteConfigBinary.json b/ReleaseTooling/CarthageJSON/FirebaseRemoteConfigBinary.json index 92ed83f42a3..681664d0f4e 100644 --- a/ReleaseTooling/CarthageJSON/FirebaseRemoteConfigBinary.json +++ b/ReleaseTooling/CarthageJSON/FirebaseRemoteConfigBinary.json @@ -33,6 +33,7 @@ "11.10.0": "https://dl.google.com/dl/firebase/ios/carthage/11.10.0/FirebaseRemoteConfig-5bac8829c8bf2dd6.zip", "11.11.0": "https://dl.google.com/dl/firebase/ios/carthage/11.11.0/FirebaseRemoteConfig-e7e899bcddf7ab64.zip", "11.12.0": "https://dl.google.com/dl/firebase/ios/carthage/11.12.0/FirebaseRemoteConfig-10e4aac268e7dde2.zip", + "11.13.0": "https://dl.google.com/dl/firebase/ios/carthage/11.13.0/FirebaseRemoteConfig-cb344560e8a1a69e.zip", "11.2.0": "https://dl.google.com/dl/firebase/ios/carthage/11.2.0/FirebaseRemoteConfig-9a298869ce3cc6db.zip", "11.3.0": "https://dl.google.com/dl/firebase/ios/carthage/11.3.0/FirebaseRemoteConfig-940ed38696414882.zip", "11.4.0": "https://dl.google.com/dl/firebase/ios/carthage/11.4.0/FirebaseRemoteConfig-ec432e976582d0eb.zip", diff --git a/ReleaseTooling/CarthageJSON/FirebaseStorageBinary.json b/ReleaseTooling/CarthageJSON/FirebaseStorageBinary.json index 5221713d559..614545ab79d 100644 --- a/ReleaseTooling/CarthageJSON/FirebaseStorageBinary.json +++ b/ReleaseTooling/CarthageJSON/FirebaseStorageBinary.json @@ -33,6 +33,7 @@ "11.10.0": "https://dl.google.com/dl/firebase/ios/carthage/11.10.0/FirebaseStorage-1e298876c41afe08.zip", "11.11.0": "https://dl.google.com/dl/firebase/ios/carthage/11.11.0/FirebaseStorage-65b8d2495abb8eca.zip", "11.12.0": "https://dl.google.com/dl/firebase/ios/carthage/11.12.0/FirebaseStorage-3926226b5e3ec43d.zip", + "11.13.0": "https://dl.google.com/dl/firebase/ios/carthage/11.13.0/FirebaseStorage-d276ced3a4fd1b8c.zip", "11.2.0": "https://dl.google.com/dl/firebase/ios/carthage/11.2.0/FirebaseStorage-b9b969b0d1254065.zip", "11.3.0": "https://dl.google.com/dl/firebase/ios/carthage/11.3.0/FirebaseStorage-0435eeaa87324cd4.zip", "11.4.0": "https://dl.google.com/dl/firebase/ios/carthage/11.4.0/FirebaseStorage-0b7a2306152984a2.zip", diff --git a/ReleaseTooling/CarthageJSON/FirebaseVertexAIBinary.json b/ReleaseTooling/CarthageJSON/FirebaseVertexAIBinary.json index 1e87a80055f..8e5b156ee34 100644 --- a/ReleaseTooling/CarthageJSON/FirebaseVertexAIBinary.json +++ b/ReleaseTooling/CarthageJSON/FirebaseVertexAIBinary.json @@ -2,6 +2,7 @@ "11.10.0": "https://dl.google.com/dl/firebase/ios/carthage/11.10.0/FirebaseVertexAI-db589b3eaf60b8dd.zip", "11.11.0": "https://dl.google.com/dl/firebase/ios/carthage/11.11.0/FirebaseVertexAI-8e96d0389286185f.zip", "11.12.0": "https://dl.google.com/dl/firebase/ios/carthage/11.12.0/FirebaseVertexAI-7fabd201dfabab6f.zip", + "11.13.0": "https://dl.google.com/dl/firebase/ios/carthage/11.13.0/FirebaseVertexAI-3fc94c339df642e3.zip", "11.5.0": "https://dl.google.com/dl/firebase/ios/carthage/11.5.0/FirebaseVertexAI-d5d0ffd8010245da.zip", "11.6.0": "https://dl.google.com/dl/firebase/ios/carthage/11.6.0/FirebaseVertexAI-6f6520d750ba54c4.zip", "11.7.0": "https://dl.google.com/dl/firebase/ios/carthage/11.7.0/FirebaseVertexAI-bd6d038eb0cf85c6.zip", From 5eeffe5168d2e0f458809d8082f53b921780f83f Mon Sep 17 00:00:00 2001 From: Nick Cooke <36927374+ncooke3@users.noreply.github.com> Date: Tue, 20 May 2025 17:03:21 -0400 Subject: [PATCH 032/113] [Config] Fix Xcode 16.3 warning due to comparing two different enums (#14873) --- FirebaseRemoteConfig/CHANGELOG.md | 3 +++ FirebaseRemoteConfig/Sources/RCNConfigContent.m | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/FirebaseRemoteConfig/CHANGELOG.md b/FirebaseRemoteConfig/CHANGELOG.md index 9f8eb8da015..69fb96b49de 100644 --- a/FirebaseRemoteConfig/CHANGELOG.md +++ b/FirebaseRemoteConfig/CHANGELOG.md @@ -1,3 +1,6 @@ +# Unreleased +- [fixed] Fix build warning from comparison of different enumeration types. + # 11.13.0 - [fixed] Fix an issue where network requests would fail in the iOS 18.4 simulator due to a URLSession bug introduced in Xcode 16.3. (#14728) diff --git a/FirebaseRemoteConfig/Sources/RCNConfigContent.m b/FirebaseRemoteConfig/Sources/RCNConfigContent.m index bbc572dbd86..90eba544205 100644 --- a/FirebaseRemoteConfig/Sources/RCNConfigContent.m +++ b/FirebaseRemoteConfig/Sources/RCNConfigContent.m @@ -198,7 +198,7 @@ - (void)copyFromDictionary:(NSDictionary *)fromDict toDict[FIRNamespace] = [[NSMutableDictionary alloc] init]; NSDictionary *config = fromDict[FIRNamespace]; for (NSString *key in config) { - if (DBSource == FIRRemoteConfigSourceDefault) { + if (DBSource == RCNDBSourceDefault) { NSObject *value = config[key]; NSData *valueData; if ([value isKindOfClass:[NSData class]]) { From e70047d79a9eed63b632b947840bd52267bb8096 Mon Sep 17 00:00:00 2001 From: Nick Cooke <36927374+ncooke3@users.noreply.github.com> Date: Tue, 20 May 2025 17:50:38 -0400 Subject: [PATCH 033/113] [Infra] Update Xcode versions in remoteconfig.yml (#14869) --- .github/workflows/remoteconfig.yml | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/.github/workflows/remoteconfig.yml b/.github/workflows/remoteconfig.yml index d1b9bd1a9e5..97bc71bb88b 100644 --- a/.github/workflows/remoteconfig.yml +++ b/.github/workflows/remoteconfig.yml @@ -64,7 +64,7 @@ jobs: run: ([ -z $plist_secret ] || scripts/generate_access_token.sh "$plist_secret" scripts/gha-encrypted/RemoteConfigSwiftAPI/ServiceAccount.json.gpg FirebaseRemoteConfig/Tests/Swift/AccessToken.json) - name: Xcode - run: sudo xcode-select -s /Applications/Xcode_16.2.app/Contents/Developer + run: sudo xcode-select -s /Applications/Xcode_16.3.app/Contents/Developer - name: Fake Console API Tests run: scripts/third_party/travis/retry.sh scripts/build.sh RemoteConfig ${{ matrix.target }} fakeconsole - name: IntegrationTest @@ -84,11 +84,9 @@ jobs: build-env: - os: macos-14 xcode: Xcode_16.2 -# # TODO(#13078): Fix testing infra to enforce warnings again. -# tests: --allow-warnings # Flaky tests on CI - os: macos-15 - xcode: Xcode_16.2 + xcode: Xcode_16.3 tests: --skip-tests runs-on: ${{ matrix.build-env.os }} steps: @@ -114,7 +112,7 @@ jobs: - uses: actions/checkout@v4 - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1 - name: Xcode - run: sudo xcode-select -s /Applications/Xcode_16.2.app/Contents/Developer + run: sudo xcode-select -s /Applications/Xcode_16.3.app/Contents/Developer - name: Setup quickstart run: scripts/setup_quickstart.sh config - name: Install Secret GoogleService-Info.plist @@ -185,7 +183,7 @@ jobs: - uses: actions/checkout@v4 - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1 - name: Xcode - run: sudo xcode-select -s /Applications/Xcode_16.2.app/Contents/Developer + run: sudo xcode-select -s /Applications/Xcode_16.3.app/Contents/Developer - name: Setup Bundler run: scripts/setup_bundler.sh - name: PodLibLint RemoteConfig Cron From 2489cd0b417b41cca07053a2880d9cf7fa670dfc Mon Sep 17 00:00:00 2001 From: Morgan Chen Date: Tue, 20 May 2025 15:11:22 -0700 Subject: [PATCH 034/113] use devsite variables (#14874) --- scripts/make_release_notes.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/make_release_notes.py b/scripts/make_release_notes.py index bcda05d53c7..a372940e4bd 100755 --- a/scripts/make_release_notes.py +++ b/scripts/make_release_notes.py @@ -27,7 +27,7 @@ PRODUCTS = { 'FirebaseABTesting/CHANGELOG.md': '{{ab_testing}}', - 'FirebaseAI/CHANGELOG.md': 'Firebase AI Logic', # update with var + 'FirebaseAI/CHANGELOG.md': '{{firebase_ai_logic}}', 'FirebaseAppCheck/CHANGELOG.md': 'App Check', 'FirebaseAppDistribution/CHANGELOG.md': 'App Distribution', 'FirebaseAuth/CHANGELOG.md': '{{auth}}', @@ -43,7 +43,7 @@ 'FirebaseFunctions/CHANGELOG.md': '{{cloud_functions}}', 'FirebaseRemoteConfig/CHANGELOG.md': '{{remote_config}}', 'FirebasePerformance/CHANGELOG.md': '{{perfmon}}', - 'FirebaseVertexAI/CHANGELOG.md': '{{firebase_vertexai}}', + 'FirebaseVertexAI/CHANGELOG.md': '{{vertex_ai_in_firebase}}', # Assumes firebase-ios-sdk and data-connect-ios-sdk are cloned to the same # directory. From ca714bf661ffd21b4ef2fa6079b7fa638f6406e7 Mon Sep 17 00:00:00 2001 From: Nick Cooke <36927374+ncooke3@users.noreply.github.com> Date: Tue, 20 May 2025 20:07:51 -0400 Subject: [PATCH 035/113] [Infra] Update versions for Release 11.14.0 (#14875) --- Firebase.podspec | 48 +++++++++---------- FirebaseABTesting.podspec | 4 +- FirebaseAI.podspec | 6 +-- FirebaseAnalytics.podspec | 8 ++-- FirebaseAnalyticsOnDeviceConversion.podspec | 4 +- FirebaseAppCheck.podspec | 4 +- FirebaseAppCheckInterop.podspec | 2 +- FirebaseAppDistribution.podspec | 4 +- FirebaseAuth.podspec | 6 +-- FirebaseAuthInterop.podspec | 2 +- FirebaseCombineSwift.podspec | 4 +- FirebaseCore.podspec | 4 +- FirebaseCoreExtension.podspec | 4 +- FirebaseCoreInternal.podspec | 2 +- FirebaseCrashlytics.podspec | 4 +- FirebaseDatabase.podspec | 4 +- FirebaseDynamicLinks.podspec | 4 +- FirebaseFirestore.podspec | 8 ++-- FirebaseFirestoreInternal.podspec | 4 +- FirebaseFunctions.podspec | 6 +-- FirebaseInAppMessaging.podspec | 4 +- FirebaseInstallations.podspec | 4 +- FirebaseMLModelDownloader.podspec | 6 +-- FirebaseMessaging.podspec | 4 +- FirebaseMessagingInterop.podspec | 2 +- FirebasePerformance.podspec | 4 +- FirebaseRemoteConfig.podspec | 4 +- FirebaseRemoteConfigInterop.podspec | 2 +- FirebaseSessions.podspec | 6 +-- FirebaseSharedSwift.podspec | 2 +- FirebaseStorage.podspec | 6 +-- FirebaseVertexAI.podspec | 4 +- GoogleAppMeasurement.podspec | 4 +- ...leAppMeasurementOnDeviceConversion.podspec | 2 +- Package.swift | 2 +- .../FirebaseManifest/FirebaseManifest.swift | 2 +- 36 files changed, 95 insertions(+), 95 deletions(-) diff --git a/Firebase.podspec b/Firebase.podspec index e20903da021..e97905a5a03 100644 --- a/Firebase.podspec +++ b/Firebase.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'Firebase' - s.version = '11.13.0' + s.version = '11.14.0' s.summary = 'Firebase' s.description = <<-DESC @@ -36,14 +36,14 @@ Simplify your app development, grow your user base, and monetize more effectivel ss.ios.deployment_target = '12.0' ss.osx.deployment_target = '10.15' ss.tvos.deployment_target = '13.0' - ss.ios.dependency 'FirebaseAnalytics', '~> 11.13.0' - ss.osx.dependency 'FirebaseAnalytics', '~> 11.13.0' - ss.tvos.dependency 'FirebaseAnalytics', '~> 11.13.0' + ss.ios.dependency 'FirebaseAnalytics', '~> 11.14.0' + ss.osx.dependency 'FirebaseAnalytics', '~> 11.14.0' + ss.tvos.dependency 'FirebaseAnalytics', '~> 11.14.0' ss.dependency 'Firebase/CoreOnly' end s.subspec 'CoreOnly' do |ss| - ss.dependency 'FirebaseCore', '~> 11.13.0' + ss.dependency 'FirebaseCore', '~> 11.14.0' ss.source_files = 'CoreOnly/Sources/Firebase.h' ss.preserve_paths = 'CoreOnly/Sources/module.modulemap' if ENV['FIREBASE_POD_REPO_FOR_DEV_POD'] then @@ -79,13 +79,13 @@ Simplify your app development, grow your user base, and monetize more effectivel ss.ios.deployment_target = '12.0' ss.osx.deployment_target = '10.15' ss.tvos.deployment_target = '13.0' - ss.dependency 'FirebaseAnalytics/WithoutAdIdSupport', '~> 11.13.0' + ss.dependency 'FirebaseAnalytics/WithoutAdIdSupport', '~> 11.14.0' ss.dependency 'Firebase/CoreOnly' end s.subspec 'ABTesting' do |ss| ss.dependency 'Firebase/CoreOnly' - ss.dependency 'FirebaseABTesting', '~> 11.13.0' + ss.dependency 'FirebaseABTesting', '~> 11.14.0' # Standard platforms PLUS watchOS. ss.ios.deployment_target = '13.0' ss.osx.deployment_target = '10.15' @@ -95,13 +95,13 @@ Simplify your app development, grow your user base, and monetize more effectivel s.subspec 'AppDistribution' do |ss| ss.dependency 'Firebase/CoreOnly' - ss.ios.dependency 'FirebaseAppDistribution', '~> 11.13.0-beta' + ss.ios.dependency 'FirebaseAppDistribution', '~> 11.14.0-beta' ss.ios.deployment_target = '13.0' end s.subspec 'AppCheck' do |ss| ss.dependency 'Firebase/CoreOnly' - ss.dependency 'FirebaseAppCheck', '~> 11.13.0' + ss.dependency 'FirebaseAppCheck', '~> 11.14.0' ss.ios.deployment_target = '13.0' ss.osx.deployment_target = '10.15' ss.tvos.deployment_target = '13.0' @@ -110,7 +110,7 @@ Simplify your app development, grow your user base, and monetize more effectivel s.subspec 'Auth' do |ss| ss.dependency 'Firebase/CoreOnly' - ss.dependency 'FirebaseAuth', '~> 11.13.0' + ss.dependency 'FirebaseAuth', '~> 11.14.0' # Standard platforms PLUS watchOS. ss.ios.deployment_target = '13.0' ss.osx.deployment_target = '10.15' @@ -120,7 +120,7 @@ Simplify your app development, grow your user base, and monetize more effectivel s.subspec 'Crashlytics' do |ss| ss.dependency 'Firebase/CoreOnly' - ss.dependency 'FirebaseCrashlytics', '~> 11.13.0' + ss.dependency 'FirebaseCrashlytics', '~> 11.14.0' # Standard platforms PLUS watchOS. ss.ios.deployment_target = '12.0' ss.osx.deployment_target = '10.15' @@ -130,7 +130,7 @@ Simplify your app development, grow your user base, and monetize more effectivel s.subspec 'Database' do |ss| ss.dependency 'Firebase/CoreOnly' - ss.dependency 'FirebaseDatabase', '~> 11.13.0' + ss.dependency 'FirebaseDatabase', '~> 11.14.0' # Standard platforms PLUS watchOS 7. ss.ios.deployment_target = '13.0' ss.osx.deployment_target = '10.15' @@ -140,13 +140,13 @@ Simplify your app development, grow your user base, and monetize more effectivel s.subspec 'DynamicLinks' do |ss| ss.dependency 'Firebase/CoreOnly' - ss.ios.dependency 'FirebaseDynamicLinks', '~> 11.13.0' + ss.ios.dependency 'FirebaseDynamicLinks', '~> 11.14.0' ss.ios.deployment_target = '13.0' end s.subspec 'Firestore' do |ss| ss.dependency 'Firebase/CoreOnly' - ss.dependency 'FirebaseFirestore', '~> 11.13.0' + ss.dependency 'FirebaseFirestore', '~> 11.14.0' ss.ios.deployment_target = '13.0' ss.osx.deployment_target = '10.15' ss.tvos.deployment_target = '13.0' @@ -154,7 +154,7 @@ Simplify your app development, grow your user base, and monetize more effectivel s.subspec 'Functions' do |ss| ss.dependency 'Firebase/CoreOnly' - ss.dependency 'FirebaseFunctions', '~> 11.13.0' + ss.dependency 'FirebaseFunctions', '~> 11.14.0' # Standard platforms PLUS watchOS. ss.ios.deployment_target = '13.0' ss.osx.deployment_target = '10.15' @@ -164,20 +164,20 @@ Simplify your app development, grow your user base, and monetize more effectivel s.subspec 'InAppMessaging' do |ss| ss.dependency 'Firebase/CoreOnly' - ss.ios.dependency 'FirebaseInAppMessaging', '~> 11.13.0-beta' - ss.tvos.dependency 'FirebaseInAppMessaging', '~> 11.13.0-beta' + ss.ios.dependency 'FirebaseInAppMessaging', '~> 11.14.0-beta' + ss.tvos.dependency 'FirebaseInAppMessaging', '~> 11.14.0-beta' ss.ios.deployment_target = '13.0' ss.tvos.deployment_target = '13.0' end s.subspec 'Installations' do |ss| ss.dependency 'Firebase/CoreOnly' - ss.dependency 'FirebaseInstallations', '~> 11.13.0' + ss.dependency 'FirebaseInstallations', '~> 11.14.0' end s.subspec 'Messaging' do |ss| ss.dependency 'Firebase/CoreOnly' - ss.dependency 'FirebaseMessaging', '~> 11.13.0' + ss.dependency 'FirebaseMessaging', '~> 11.14.0' # Standard platforms PLUS watchOS. ss.ios.deployment_target = '13.0' ss.osx.deployment_target = '10.15' @@ -187,7 +187,7 @@ Simplify your app development, grow your user base, and monetize more effectivel s.subspec 'MLModelDownloader' do |ss| ss.dependency 'Firebase/CoreOnly' - ss.dependency 'FirebaseMLModelDownloader', '~> 11.13.0-beta' + ss.dependency 'FirebaseMLModelDownloader', '~> 11.14.0-beta' # Standard platforms PLUS watchOS. ss.ios.deployment_target = '13.0' ss.osx.deployment_target = '10.15' @@ -197,15 +197,15 @@ Simplify your app development, grow your user base, and monetize more effectivel s.subspec 'Performance' do |ss| ss.dependency 'Firebase/CoreOnly' - ss.ios.dependency 'FirebasePerformance', '~> 11.13.0' - ss.tvos.dependency 'FirebasePerformance', '~> 11.13.0' + ss.ios.dependency 'FirebasePerformance', '~> 11.14.0' + ss.tvos.dependency 'FirebasePerformance', '~> 11.14.0' ss.ios.deployment_target = '13.0' ss.tvos.deployment_target = '13.0' end s.subspec 'RemoteConfig' do |ss| ss.dependency 'Firebase/CoreOnly' - ss.dependency 'FirebaseRemoteConfig', '~> 11.13.0' + ss.dependency 'FirebaseRemoteConfig', '~> 11.14.0' # Standard platforms PLUS watchOS. ss.ios.deployment_target = '13.0' ss.osx.deployment_target = '10.15' @@ -215,7 +215,7 @@ Simplify your app development, grow your user base, and monetize more effectivel s.subspec 'Storage' do |ss| ss.dependency 'Firebase/CoreOnly' - ss.dependency 'FirebaseStorage', '~> 11.13.0' + ss.dependency 'FirebaseStorage', '~> 11.14.0' # Standard platforms PLUS watchOS. ss.ios.deployment_target = '13.0' ss.osx.deployment_target = '10.15' diff --git a/FirebaseABTesting.podspec b/FirebaseABTesting.podspec index 767da46ca85..2571e91fdda 100644 --- a/FirebaseABTesting.podspec +++ b/FirebaseABTesting.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseABTesting' - s.version = '11.13.0' + s.version = '11.14.0' s.summary = 'Firebase ABTesting' s.description = <<-DESC @@ -52,7 +52,7 @@ Firebase Cloud Messaging and Firebase Remote Config in your app. 'GCC_C_LANGUAGE_STANDARD' => 'c99', 'HEADER_SEARCH_PATHS' => '"${PODS_TARGET_SRCROOT}"' } - s.dependency 'FirebaseCore', '~> 11.13.0' + s.dependency 'FirebaseCore', '~> 11.14.0' s.test_spec 'unit' do |unit_tests| unit_tests.scheme = { :code_coverage => true } diff --git a/FirebaseAI.podspec b/FirebaseAI.podspec index 65fa42d28f6..9d7bba0e9eb 100644 --- a/FirebaseAI.podspec +++ b/FirebaseAI.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseAI' - s.version = '11.13.0' + s.version = '11.14.0' s.summary = 'Firebase AI SDK' s.description = <<-DESC @@ -45,8 +45,8 @@ Build AI-powered apps and features with the Gemini API using the Firebase AI SDK s.dependency 'FirebaseAppCheckInterop', '~> 11.4' s.dependency 'FirebaseAuthInterop', '~> 11.4' - s.dependency 'FirebaseCore', '~> 11.13.0' - s.dependency 'FirebaseCoreExtension', '~> 11.13.0' + s.dependency 'FirebaseCore', '~> 11.14.0' + s.dependency 'FirebaseCoreExtension', '~> 11.14.0' s.test_spec 'unit' do |unit_tests| unit_tests_dir = 'FirebaseAI/Tests/Unit/' diff --git a/FirebaseAnalytics.podspec b/FirebaseAnalytics.podspec index dcd6a9ee85b..f2531640828 100644 --- a/FirebaseAnalytics.podspec +++ b/FirebaseAnalytics.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseAnalytics' - s.version = '11.13.0' + s.version = '11.14.0' s.summary = 'Firebase Analytics for iOS' s.description = <<-DESC @@ -26,7 +26,7 @@ Pod::Spec.new do |s| s.libraries = 'c++', 'sqlite3', 'z' s.frameworks = 'StoreKit' - s.dependency 'FirebaseCore', '~> 11.13.0' + s.dependency 'FirebaseCore', '~> 11.14.0' s.dependency 'FirebaseInstallations', '~> 11.0' s.dependency 'GoogleUtilities/AppDelegateSwizzler', '~> 8.1' s.dependency 'GoogleUtilities/MethodSwizzler', '~> 8.1' @@ -37,12 +37,12 @@ Pod::Spec.new do |s| s.default_subspecs = 'AdIdSupport' s.subspec 'AdIdSupport' do |ss| - ss.dependency 'GoogleAppMeasurement', '11.13.0' + ss.dependency 'GoogleAppMeasurement', '11.14.0' ss.vendored_frameworks = 'Frameworks/FirebaseAnalytics.xcframework' end s.subspec 'WithoutAdIdSupport' do |ss| - ss.dependency 'GoogleAppMeasurement/WithoutAdIdSupport', '11.13.0' + ss.dependency 'GoogleAppMeasurement/WithoutAdIdSupport', '11.14.0' ss.vendored_frameworks = 'Frameworks/FirebaseAnalytics.xcframework' end diff --git a/FirebaseAnalyticsOnDeviceConversion.podspec b/FirebaseAnalyticsOnDeviceConversion.podspec index 65cdb06ab8a..ea20a084a1e 100644 --- a/FirebaseAnalyticsOnDeviceConversion.podspec +++ b/FirebaseAnalyticsOnDeviceConversion.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseAnalyticsOnDeviceConversion' - s.version = '11.13.0' + s.version = '11.14.0' s.summary = 'On device conversion measurement plugin for FirebaseAnalytics. Not intended for direct use.' s.description = <<-DESC @@ -18,7 +18,7 @@ Pod::Spec.new do |s| s.cocoapods_version = '>= 1.12.0' - s.dependency 'GoogleAppMeasurementOnDeviceConversion', '11.13.0' + s.dependency 'GoogleAppMeasurementOnDeviceConversion', '11.14.0' s.static_framework = true diff --git a/FirebaseAppCheck.podspec b/FirebaseAppCheck.podspec index 3b22cf6f5c3..ed39fd0f653 100644 --- a/FirebaseAppCheck.podspec +++ b/FirebaseAppCheck.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseAppCheck' - s.version = '11.13.0' + s.version = '11.14.0' s.summary = 'Firebase App Check SDK.' s.description = <<-DESC @@ -46,7 +46,7 @@ Pod::Spec.new do |s| s.dependency 'AppCheckCore', '~> 11.0' s.dependency 'FirebaseAppCheckInterop', '~> 11.0' - s.dependency 'FirebaseCore', '~> 11.13.0' + s.dependency 'FirebaseCore', '~> 11.14.0' s.dependency 'GoogleUtilities/Environment', '~> 8.1' s.dependency 'GoogleUtilities/UserDefaults', '~> 8.1' diff --git a/FirebaseAppCheckInterop.podspec b/FirebaseAppCheckInterop.podspec index 6193b9b21d5..0fab9e7950f 100644 --- a/FirebaseAppCheckInterop.podspec +++ b/FirebaseAppCheckInterop.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseAppCheckInterop' - s.version = '11.13.0' + s.version = '11.14.0' s.summary = 'Interfaces that allow other Firebase SDKs to use AppCheck functionality.' s.description = <<-DESC diff --git a/FirebaseAppDistribution.podspec b/FirebaseAppDistribution.podspec index e9ca3a73ed0..8dfba67069a 100644 --- a/FirebaseAppDistribution.podspec +++ b/FirebaseAppDistribution.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseAppDistribution' - s.version = '11.13.0-beta' + s.version = '11.14.0-beta' s.summary = 'App Distribution for Firebase iOS SDK.' s.description = <<-DESC @@ -30,7 +30,7 @@ iOS SDK for App Distribution for Firebase. ] s.public_header_files = base_dir + 'Public/FirebaseAppDistribution/*.h' - s.dependency 'FirebaseCore', '~> 11.13.0' + s.dependency 'FirebaseCore', '~> 11.14.0' s.dependency 'GoogleUtilities/AppDelegateSwizzler', '~> 8.1' s.dependency 'GoogleUtilities/UserDefaults', '~> 8.1' s.dependency 'FirebaseInstallations', '~> 11.0' diff --git a/FirebaseAuth.podspec b/FirebaseAuth.podspec index db99c757eba..74b987a5f76 100644 --- a/FirebaseAuth.podspec +++ b/FirebaseAuth.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseAuth' - s.version = '11.13.0' + s.version = '11.14.0' s.summary = 'Apple platform client for Firebase Authentication' s.description = <<-DESC @@ -58,8 +58,8 @@ supports email and password accounts, as well as several 3rd party authenticatio s.ios.framework = 'SafariServices' s.dependency 'FirebaseAuthInterop', '~> 11.0' s.dependency 'FirebaseAppCheckInterop', '~> 11.0' - s.dependency 'FirebaseCore', '~> 11.13.0' - s.dependency 'FirebaseCoreExtension', '~> 11.13.0' + s.dependency 'FirebaseCore', '~> 11.14.0' + s.dependency 'FirebaseCoreExtension', '~> 11.14.0' s.dependency 'GoogleUtilities/AppDelegateSwizzler', '~> 8.1' s.dependency 'GoogleUtilities/Environment', '~> 8.1' s.dependency 'GTMSessionFetcher/Core', '>= 3.4', '< 5.0' diff --git a/FirebaseAuthInterop.podspec b/FirebaseAuthInterop.podspec index aa29bc7d177..35c976adee1 100644 --- a/FirebaseAuthInterop.podspec +++ b/FirebaseAuthInterop.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseAuthInterop' - s.version = '11.13.0' + s.version = '11.14.0' s.summary = 'Interfaces that allow other Firebase SDKs to use Auth functionality.' s.description = <<-DESC diff --git a/FirebaseCombineSwift.podspec b/FirebaseCombineSwift.podspec index dc198ef47e0..02ce5fa2cd4 100644 --- a/FirebaseCombineSwift.podspec +++ b/FirebaseCombineSwift.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseCombineSwift' - s.version = '11.13.0' + s.version = '11.14.0' s.summary = 'Swift extensions with Combine support for Firebase' s.description = <<-DESC @@ -51,7 +51,7 @@ for internal testing only. It should not be published. s.osx.framework = 'AppKit' s.tvos.framework = 'UIKit' - s.dependency 'FirebaseCore', '~> 11.13.0' + s.dependency 'FirebaseCore', '~> 11.14.0' s.dependency 'FirebaseAuth', '~> 11.0' s.dependency 'FirebaseFunctions', '~> 11.0' s.dependency 'FirebaseFirestore', '~> 11.0' diff --git a/FirebaseCore.podspec b/FirebaseCore.podspec index e0a86f26df0..4e84de8a31b 100644 --- a/FirebaseCore.podspec +++ b/FirebaseCore.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseCore' - s.version = '11.13.0' + s.version = '11.14.0' s.summary = 'Firebase Core' s.description = <<-DESC @@ -53,7 +53,7 @@ Firebase Core includes FIRApp and FIROptions which provide central configuration # Remember to also update version in `cmake/external/GoogleUtilities.cmake` s.dependency 'GoogleUtilities/Environment', '~> 8.1' s.dependency 'GoogleUtilities/Logger', '~> 8.1' - s.dependency 'FirebaseCoreInternal', '~> 11.13.0' + s.dependency 'FirebaseCoreInternal', '~> 11.14.0' s.pod_target_xcconfig = { 'GCC_C_LANGUAGE_STANDARD' => 'c99', diff --git a/FirebaseCoreExtension.podspec b/FirebaseCoreExtension.podspec index 480568da10c..6ed71182654 100644 --- a/FirebaseCoreExtension.podspec +++ b/FirebaseCoreExtension.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseCoreExtension' - s.version = '11.13.0' + s.version = '11.14.0' s.summary = 'Extended FirebaseCore APIs for Firebase product SDKs' s.description = <<-DESC @@ -34,5 +34,5 @@ Pod::Spec.new do |s| "#{s.module_name}_Privacy" => 'FirebaseCore/Extension/Resources/PrivacyInfo.xcprivacy' } - s.dependency 'FirebaseCore', '~> 11.13.0' + s.dependency 'FirebaseCore', '~> 11.14.0' end diff --git a/FirebaseCoreInternal.podspec b/FirebaseCoreInternal.podspec index 18c528b5e39..b4ff179b38d 100644 --- a/FirebaseCoreInternal.podspec +++ b/FirebaseCoreInternal.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseCoreInternal' - s.version = '11.13.0' + s.version = '11.14.0' s.summary = 'APIs for internal FirebaseCore usage.' s.description = <<-DESC diff --git a/FirebaseCrashlytics.podspec b/FirebaseCrashlytics.podspec index 9e1c2cbcc70..e55bcbb37a3 100644 --- a/FirebaseCrashlytics.podspec +++ b/FirebaseCrashlytics.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseCrashlytics' - s.version = '11.13.0' + s.version = '11.14.0' s.summary = 'Best and lightest-weight crash reporting for mobile, desktop and tvOS.' s.description = 'Firebase Crashlytics helps you track, prioritize, and fix stability issues that erode app quality.' s.homepage = 'https://firebase.google.com/' @@ -59,7 +59,7 @@ Pod::Spec.new do |s| cp -f ./Crashlytics/CrashlyticsInputFiles.xcfilelist ./CrashlyticsInputFiles.xcfilelist PREPARE_COMMAND_END - s.dependency 'FirebaseCore', '~> 11.13.0' + s.dependency 'FirebaseCore', '~> 11.14.0' s.dependency 'FirebaseInstallations', '~> 11.0' s.dependency 'FirebaseSessions', '~> 11.0' s.dependency 'FirebaseRemoteConfigInterop', '~> 11.0' diff --git a/FirebaseDatabase.podspec b/FirebaseDatabase.podspec index 3a2a9b899f2..8a39ee33c9a 100644 --- a/FirebaseDatabase.podspec +++ b/FirebaseDatabase.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseDatabase' - s.version = '11.13.0' + s.version = '11.14.0' s.summary = 'Firebase Realtime Database' s.description = <<-DESC @@ -48,7 +48,7 @@ Simplify your iOS development, grow your user base, and monetize more effectivel s.macos.frameworks = 'CFNetwork', 'Security', 'SystemConfiguration' s.watchos.frameworks = 'CFNetwork', 'Security', 'WatchKit' s.dependency 'leveldb-library', '~> 1.22' - s.dependency 'FirebaseCore', '~> 11.13.0' + s.dependency 'FirebaseCore', '~> 11.14.0' s.dependency 'FirebaseAppCheckInterop', '~> 11.0' s.dependency 'FirebaseSharedSwift', '~> 11.0' s.dependency 'GoogleUtilities/UserDefaults', '~> 8.1' diff --git a/FirebaseDynamicLinks.podspec b/FirebaseDynamicLinks.podspec index bd7db3429db..e2f8f9421e6 100644 --- a/FirebaseDynamicLinks.podspec +++ b/FirebaseDynamicLinks.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseDynamicLinks' - s.version = '11.13.0' + s.version = '11.14.0' s.summary = 'Firebase Dynamic Links' s.description = <<-DESC @@ -37,7 +37,7 @@ Firebase Dynamic Links are deep links that enhance user experience and increase } s.frameworks = 'QuartzCore' s.weak_framework = 'WebKit' - s.dependency 'FirebaseCore', '~> 11.13.0' + s.dependency 'FirebaseCore', '~> 11.14.0' s.pod_target_xcconfig = { 'GCC_C_LANGUAGE_STANDARD' => 'c99', diff --git a/FirebaseFirestore.podspec b/FirebaseFirestore.podspec index a582e1c1aaa..cb6eea4169a 100644 --- a/FirebaseFirestore.podspec +++ b/FirebaseFirestore.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseFirestore' - s.version = '11.13.0' + s.version = '11.14.0' s.summary = 'Google Cloud Firestore' s.description = <<-DESC Google Cloud Firestore is a NoSQL document database built for automatic scaling, high performance, and ease of application development. @@ -35,9 +35,9 @@ Google Cloud Firestore is a NoSQL document database built for automatic scaling, "#{s.module_name}_Privacy" => 'Firestore/Swift/Source/Resources/PrivacyInfo.xcprivacy' } - s.dependency 'FirebaseCore', '~> 11.13.0' - s.dependency 'FirebaseCoreExtension', '~> 11.13.0' - s.dependency 'FirebaseFirestoreInternal', '11.13.0' + s.dependency 'FirebaseCore', '~> 11.14.0' + s.dependency 'FirebaseCoreExtension', '~> 11.14.0' + s.dependency 'FirebaseFirestoreInternal', '11.14.0' s.dependency 'FirebaseSharedSwift', '~> 11.0' end diff --git a/FirebaseFirestoreInternal.podspec b/FirebaseFirestoreInternal.podspec index 8567f74fe7d..5362cf20699 100644 --- a/FirebaseFirestoreInternal.podspec +++ b/FirebaseFirestoreInternal.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseFirestoreInternal' - s.version = '11.13.0' + s.version = '11.14.0' s.summary = 'Google Cloud Firestore' s.description = <<-DESC @@ -93,7 +93,7 @@ Google Cloud Firestore is a NoSQL document database built for automatic scaling, } s.dependency 'FirebaseAppCheckInterop', '~> 11.0' - s.dependency 'FirebaseCore', '~> 11.13.0' + s.dependency 'FirebaseCore', '~> 11.14.0' abseil_version = '~> 1.20240722.0' s.dependency 'abseil/algorithm', abseil_version diff --git a/FirebaseFunctions.podspec b/FirebaseFunctions.podspec index 5bd8f2c5990..d1df6871066 100644 --- a/FirebaseFunctions.podspec +++ b/FirebaseFunctions.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseFunctions' - s.version = '11.13.0' + s.version = '11.14.0' s.summary = 'Cloud Functions for Firebase' s.description = <<-DESC @@ -35,8 +35,8 @@ Cloud Functions for Firebase. 'FirebaseFunctions/Sources/**/*.swift', ] - s.dependency 'FirebaseCore', '~> 11.13.0' - s.dependency 'FirebaseCoreExtension', '~> 11.13.0' + s.dependency 'FirebaseCore', '~> 11.14.0' + s.dependency 'FirebaseCoreExtension', '~> 11.14.0' s.dependency 'FirebaseAppCheckInterop', '~> 11.0' s.dependency 'FirebaseAuthInterop', '~> 11.0' s.dependency 'FirebaseMessagingInterop', '~> 11.0' diff --git a/FirebaseInAppMessaging.podspec b/FirebaseInAppMessaging.podspec index 52b9b0b79cd..99570fd5158 100644 --- a/FirebaseInAppMessaging.podspec +++ b/FirebaseInAppMessaging.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseInAppMessaging' - s.version = '11.13.0-beta' + s.version = '11.14.0-beta' s.summary = 'Firebase In-App Messaging for iOS' s.description = <<-DESC @@ -80,7 +80,7 @@ See more product details at https://firebase.google.com/products/in-app-messagin s.framework = 'UIKit' - s.dependency 'FirebaseCore', '~> 11.13.0' + s.dependency 'FirebaseCore', '~> 11.14.0' s.dependency 'FirebaseInstallations', '~> 11.0' s.dependency 'FirebaseABTesting', '~> 11.0' s.dependency 'GoogleUtilities/Environment', '~> 8.1' diff --git a/FirebaseInstallations.podspec b/FirebaseInstallations.podspec index 328da56178e..dca6b03b114 100644 --- a/FirebaseInstallations.podspec +++ b/FirebaseInstallations.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseInstallations' - s.version = '11.13.0' + s.version = '11.14.0' s.summary = 'Firebase Installations' s.description = <<-DESC @@ -45,7 +45,7 @@ Pod::Spec.new do |s| } s.framework = 'Security' - s.dependency 'FirebaseCore', '~> 11.13.0' + s.dependency 'FirebaseCore', '~> 11.14.0' s.dependency 'PromisesObjC', '~> 2.4' s.dependency 'GoogleUtilities/Environment', '~> 8.1' s.dependency 'GoogleUtilities/UserDefaults', '~> 8.1' diff --git a/FirebaseMLModelDownloader.podspec b/FirebaseMLModelDownloader.podspec index 38b3563d84b..37681cc168e 100644 --- a/FirebaseMLModelDownloader.podspec +++ b/FirebaseMLModelDownloader.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseMLModelDownloader' - s.version = '11.13.0-beta' + s.version = '11.14.0-beta' s.summary = 'Firebase ML Model Downloader' s.description = <<-DESC @@ -36,8 +36,8 @@ Pod::Spec.new do |s| ] s.framework = 'Foundation' - s.dependency 'FirebaseCore', '~> 11.13.0' - s.dependency 'FirebaseCoreExtension', '~> 11.13.0' + s.dependency 'FirebaseCore', '~> 11.14.0' + s.dependency 'FirebaseCoreExtension', '~> 11.14.0' s.dependency 'FirebaseInstallations', '~> 11.0' s.dependency 'GoogleDataTransport', '~> 10.0' s.dependency 'GoogleUtilities/UserDefaults', '~> 8.1' diff --git a/FirebaseMessaging.podspec b/FirebaseMessaging.podspec index 79eabe7f453..40c124b4deb 100644 --- a/FirebaseMessaging.podspec +++ b/FirebaseMessaging.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseMessaging' - s.version = '11.13.0' + s.version = '11.14.0' s.summary = 'Firebase Messaging' s.description = <<-DESC @@ -62,7 +62,7 @@ device, and it is completely free. s.osx.framework = 'SystemConfiguration' s.weak_framework = 'UserNotifications' s.dependency 'FirebaseInstallations', '~> 11.0' - s.dependency 'FirebaseCore', '~> 11.13.0' + s.dependency 'FirebaseCore', '~> 11.14.0' s.dependency 'GoogleUtilities/AppDelegateSwizzler', '~> 8.1' s.dependency 'GoogleUtilities/Reachability', '~> 8.1' s.dependency 'GoogleUtilities/Environment', '~> 8.1' diff --git a/FirebaseMessagingInterop.podspec b/FirebaseMessagingInterop.podspec index 4dcd29b4e12..a2df2355386 100644 --- a/FirebaseMessagingInterop.podspec +++ b/FirebaseMessagingInterop.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseMessagingInterop' - s.version = '11.13.0' + s.version = '11.14.0' s.summary = 'Interfaces that allow other Firebase SDKs to use Messaging functionality.' s.description = <<-DESC diff --git a/FirebasePerformance.podspec b/FirebasePerformance.podspec index b6ce91be3b4..6524934ceba 100644 --- a/FirebasePerformance.podspec +++ b/FirebasePerformance.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebasePerformance' - s.version = '11.13.0' + s.version = '11.14.0' s.summary = 'Firebase Performance' s.description = <<-DESC @@ -59,7 +59,7 @@ Firebase Performance library to measure performance of Mobile and Web Apps. s.ios.framework = 'CoreTelephony' s.framework = 'QuartzCore' s.framework = 'SystemConfiguration' - s.dependency 'FirebaseCore', '~> 11.13.0' + s.dependency 'FirebaseCore', '~> 11.14.0' s.dependency 'FirebaseInstallations', '~> 11.0' s.dependency 'FirebaseRemoteConfig', '~> 11.0' s.dependency 'FirebaseSessions', '~> 11.0' diff --git a/FirebaseRemoteConfig.podspec b/FirebaseRemoteConfig.podspec index 7866379e8ae..185cb5043e0 100644 --- a/FirebaseRemoteConfig.podspec +++ b/FirebaseRemoteConfig.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseRemoteConfig' - s.version = '11.13.0' + s.version = '11.14.0' s.summary = 'Firebase Remote Config' s.description = <<-DESC @@ -52,7 +52,7 @@ app update. } s.dependency 'FirebaseABTesting', '~> 11.0' s.dependency 'FirebaseSharedSwift', '~> 11.0' - s.dependency 'FirebaseCore', '~> 11.13.0' + s.dependency 'FirebaseCore', '~> 11.14.0' s.dependency 'FirebaseInstallations', '~> 11.0' s.dependency 'GoogleUtilities/Environment', '~> 8.1' s.dependency 'GoogleUtilities/NSData+zlib', '~> 8.1' diff --git a/FirebaseRemoteConfigInterop.podspec b/FirebaseRemoteConfigInterop.podspec index e1eb447a4db..52eb79c4060 100644 --- a/FirebaseRemoteConfigInterop.podspec +++ b/FirebaseRemoteConfigInterop.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseRemoteConfigInterop' - s.version = '11.13.0' + s.version = '11.14.0' s.summary = 'Interfaces that allow other Firebase SDKs to use Remote Config functionality.' s.description = <<-DESC diff --git a/FirebaseSessions.podspec b/FirebaseSessions.podspec index 9f7729162dc..5a65feb6b53 100644 --- a/FirebaseSessions.podspec +++ b/FirebaseSessions.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseSessions' - s.version = '11.13.0' + s.version = '11.14.0' s.summary = 'Firebase Sessions' s.description = <<-DESC @@ -39,8 +39,8 @@ Pod::Spec.new do |s| base_dir + 'SourcesObjC/**/*.{c,h,m,mm}', ] - s.dependency 'FirebaseCore', '~> 11.13.0' - s.dependency 'FirebaseCoreExtension', '~> 11.13.0' + s.dependency 'FirebaseCore', '~> 11.14.0' + s.dependency 'FirebaseCoreExtension', '~> 11.14.0' s.dependency 'FirebaseInstallations', '~> 11.0' s.dependency 'GoogleDataTransport', '~> 10.0' s.dependency 'GoogleUtilities/Environment', '~> 8.1' diff --git a/FirebaseSharedSwift.podspec b/FirebaseSharedSwift.podspec index fd5ded5eafd..48f9c4c70a6 100644 --- a/FirebaseSharedSwift.podspec +++ b/FirebaseSharedSwift.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseSharedSwift' - s.version = '11.13.0' + s.version = '11.14.0' s.summary = 'Shared Swift Extensions for Firebase' s.description = <<-DESC diff --git a/FirebaseStorage.podspec b/FirebaseStorage.podspec index d8563d48502..1fe7d989556 100644 --- a/FirebaseStorage.podspec +++ b/FirebaseStorage.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseStorage' - s.version = '11.13.0' + s.version = '11.14.0' s.summary = 'Firebase Storage' s.description = <<-DESC @@ -39,8 +39,8 @@ Firebase Storage provides robust, secure file uploads and downloads from Firebas s.dependency 'FirebaseAppCheckInterop', '~> 11.0' s.dependency 'FirebaseAuthInterop', '~> 11.0' - s.dependency 'FirebaseCore', '~> 11.13.0' - s.dependency 'FirebaseCoreExtension', '~> 11.13.0' + s.dependency 'FirebaseCore', '~> 11.14.0' + s.dependency 'FirebaseCoreExtension', '~> 11.14.0' s.dependency 'GTMSessionFetcher/Core', '>= 3.4', '< 5.0' s.dependency 'GoogleUtilities/Environment', '~> 8.1' diff --git a/FirebaseVertexAI.podspec b/FirebaseVertexAI.podspec index 4305c116ad5..d5781cf613c 100644 --- a/FirebaseVertexAI.podspec +++ b/FirebaseVertexAI.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseVertexAI' - s.version = '11.13.0' + s.version = '11.14.0' s.summary = 'Vertex AI in Firebase SDK' s.description = <<-DESC @@ -44,7 +44,7 @@ Firebase SDK. s.tvos.framework = 'UIKit' s.watchos.framework = 'WatchKit' - s.dependency 'FirebaseAI', '~> 11.13.0' + s.dependency 'FirebaseAI', '~> 11.14.0' s.test_spec 'unit' do |unit_tests| unit_tests_dir = 'FirebaseVertexAI/Tests/Unit/' diff --git a/GoogleAppMeasurement.podspec b/GoogleAppMeasurement.podspec index fd6bc282d10..e388a56c778 100644 --- a/GoogleAppMeasurement.podspec +++ b/GoogleAppMeasurement.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'GoogleAppMeasurement' - s.version = '11.13.0' + s.version = '11.14.0' s.summary = 'Shared measurement methods for Google libraries. Not intended for direct use.' s.description = <<-DESC @@ -37,7 +37,7 @@ Pod::Spec.new do |s| s.default_subspecs = 'AdIdSupport' s.subspec 'AdIdSupport' do |ss| - ss.dependency 'GoogleAppMeasurement/WithoutAdIdSupport', '11.13.0' + ss.dependency 'GoogleAppMeasurement/WithoutAdIdSupport', '11.14.0' ss.vendored_frameworks = 'Frameworks/GoogleAppMeasurementIdentitySupport.xcframework' end diff --git a/GoogleAppMeasurementOnDeviceConversion.podspec b/GoogleAppMeasurementOnDeviceConversion.podspec index 79681916fd1..97e3e26e584 100644 --- a/GoogleAppMeasurementOnDeviceConversion.podspec +++ b/GoogleAppMeasurementOnDeviceConversion.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'GoogleAppMeasurementOnDeviceConversion' - s.version = '11.13.0' + s.version = '11.14.0' s.summary = <<-SUMMARY On device conversion measurement plugin for Google App Measurement. Not intended for direct use. diff --git a/Package.swift b/Package.swift index 451abb8dcb8..7d8b1306601 100644 --- a/Package.swift +++ b/Package.swift @@ -19,7 +19,7 @@ import class Foundation.ProcessInfo import PackageDescription -let firebaseVersion = "11.13.0" +let firebaseVersion = "11.14.0" let package = Package( name: "Firebase", diff --git a/ReleaseTooling/Sources/FirebaseManifest/FirebaseManifest.swift b/ReleaseTooling/Sources/FirebaseManifest/FirebaseManifest.swift index 66a8381128e..c00b28decd9 100755 --- a/ReleaseTooling/Sources/FirebaseManifest/FirebaseManifest.swift +++ b/ReleaseTooling/Sources/FirebaseManifest/FirebaseManifest.swift @@ -21,7 +21,7 @@ import Foundation /// The version and releasing fields of the non-Firebase pods should be reviewed every release. /// The array should be ordered so that any pod's dependencies precede it in the list. public let shared = Manifest( - version: "11.13.0", + version: "11.14.0", pods: [ Pod("FirebaseSharedSwift"), Pod("FirebaseCoreInternal"), From 7682cb990117349b9601d66b0dfae055bd32592d Mon Sep 17 00:00:00 2001 From: Nick Cooke <36927374+ncooke3@users.noreply.github.com> Date: Tue, 20 May 2025 20:46:35 -0400 Subject: [PATCH 036/113] [Infra] Do not float dependency on FirebaseAI (#14877) --- .../Sources/FirebaseReleaser/InitializeRelease.swift | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ReleaseTooling/Sources/FirebaseReleaser/InitializeRelease.swift b/ReleaseTooling/Sources/FirebaseReleaser/InitializeRelease.swift index 93e4d643fe7..3e5c5190212 100644 --- a/ReleaseTooling/Sources/FirebaseReleaser/InitializeRelease.swift +++ b/ReleaseTooling/Sources/FirebaseReleaser/InitializeRelease.swift @@ -56,7 +56,8 @@ enum InitializeRelease { pod.name == "FirebaseCore" || pod.name == "FirebaseCoreExtension" || pod.name == "FirebaseCoreInternal" || - pod.name == "FirebaseFirestoreInternal" { + pod.name == "FirebaseFirestoreInternal" || + pod.name == "FirebaseAI" { updateDependenciesToLatest( dependency: pod.name, pods: manifest.pods, From c04eb6212114b1bbdc87140ce3cb36cc109ad1f3 Mon Sep 17 00:00:00 2001 From: Andrew Heard Date: Thu, 22 May 2025 11:06:41 -0400 Subject: [PATCH 037/113] [Firebase AI] Run quickstart build test using branch (#14879) --- .github/workflows/firebaseai.yml | 4 +-- scripts/quickstart_spm_xcodeproj.sh | 46 ++++++++++++++++++++++------- 2 files changed, 36 insertions(+), 14 deletions(-) diff --git a/.github/workflows/firebaseai.yml b/.github/workflows/firebaseai.yml index 0dd842615cc..71c0f1341e6 100644 --- a/.github/workflows/firebaseai.yml +++ b/.github/workflows/firebaseai.yml @@ -175,11 +175,9 @@ jobs: run: scripts/third_party/travis/retry.sh scripts/pod_lib_lint.rb FirebaseAI.podspec --platforms=${{ matrix.target }} ${{ matrix.warnings }} quickstart: - # Verifies the quickstart builds with this PR. Only run on pulls where branch is available. - if: github.event_name == 'pull_request' runs-on: macos-15 env: - BRANCH_NAME: ${{ github.head_ref || github.ref_name }} + BRANCH_NAME: ${{ github.head_ref || github.ref_name || 'main' }} steps: - uses: actions/checkout@v4 - name: Build Quickstart diff --git a/scripts/quickstart_spm_xcodeproj.sh b/scripts/quickstart_spm_xcodeproj.sh index f0cbd0073be..c9387c4cd5d 100755 --- a/scripts/quickstart_spm_xcodeproj.sh +++ b/scripts/quickstart_spm_xcodeproj.sh @@ -16,21 +16,45 @@ # Modify a .xcodeproj to use a specific branch. -# TODO: Update to transform from a release, as well as from `main`. set -xeuo pipefail SAMPLE=$1 -XCODEPROJ=${SAMPLE}/${SAMPLE}Example.xcodeproj/project.pbxproj +SAMPLE_DIR=$(echo "$SAMPLE" | perl -ne 'print lc') +XCODEPROJ=${SAMPLE_DIR}/${SAMPLE}Example.xcodeproj/project.pbxproj -if grep -q "branch = main;" "$XCODEPROJ"; then - sed -i "" "s#branch = main;#branch = $BRANCH_NAME;#" "$XCODEPROJ" +# Regex matches SemVer `firebase-ios-sdk` dependency in project.pbxproj: +# { +# isa = XCRemoteSwiftPackageReference; +# repositoryURL = "https://github.com/firebase/firebase-ios-sdk.git"; +# requirement = { +# kind = upToNextMajorVersion; +# minimumVersion = xx.yy.zz; +# }; +# }; +REQUIREMENT_REGEX='({'\ +'\s*isa = XCRemoteSwiftPackageReference;'\ +'\s*repositoryURL = "https://github\.com/firebase/firebase-ios-sdk\.git";'\ +'\s*requirement = {\s*)kind = upToNextMajorVersion;'\ +'\s*minimumVersion = \d+\.\d+\.\d+;'\ +'(\s*};'\ +'\s*};)' - # Point SPM CI to the tip of `main` of - # https://github.com/google/GoogleAppMeasurement so that the release process - # can defer publishing the `GoogleAppMeasurement` tag until after testing. - export FIREBASECI_USE_LATEST_GOOGLEAPPMEASUREMENT=1 -else - echo "Failed to update quickstart's Xcode project to the current branch" +# Replaces the minimumVersion requirement with a branch requirement. +REPLACEMENT_REGEX="\1branch = $BRANCH_NAME;\n\t\t\t\tkind = branch;\2" + +# Performs the replacement using Perl. +# +# -0777 Enables reading all input in one go (slurp), rather than line-by-line. +# -p Causes Perl to loop through the input line by line. +# -i Edits the file in place. +# -e Provides the expression to execute. +perl -0777 -i -pe "s#$REQUIREMENT_REGEX#$REPLACEMENT_REGEX#g" "$XCODEPROJ" || { + echo "Failed to update quickstart's Xcode project to the branch: $BRANCH_NAME" exit 1 -fi +} + +# Point SPM CI to the tip of `main` of +# https://github.com/google/GoogleAppMeasurement so that the release process +# can defer publishing the `GoogleAppMeasurement` tag until after testing. +export FIREBASECI_USE_LATEST_GOOGLEAPPMEASUREMENT=1 From f57e553105274ba207942f97d9a50d99f22eff8b Mon Sep 17 00:00:00 2001 From: pcfba <111909874+pcfba@users.noreply.github.com> Date: Thu, 22 May 2025 16:25:37 -0700 Subject: [PATCH 038/113] New and clearer FirebaseAnalytics subspecs (#14882) The new subspecs: Default, Core, and IdentitySupport. The previous subspecs that are now deprecated: AdIdSupport (use IdentitySupport) and WithoutAdIdSupport (use Core). --- FirebaseAnalytics.podspec | 21 +++++- FirebaseAnalyticsCoreWrapper/dummy.m | 17 +++++ FirebaseAnalyticsCoreWrapper/include/dummy.h | 18 +++++ .../dummy.m | 17 +++++ .../include/dummy.h | 18 +++++ .../dummy.m | 3 + .../dummy.m | 2 + GoogleAppMeasurement.podspec | 26 +++++-- Package.swift | 75 +++++++++++++++++++ .../FirebaseAnalyticsCoreWrap/dummy.m | 18 +++++ .../FirebaseAnalyticsCoreWrap/include/dummy.h | 15 ++++ 11 files changed, 223 insertions(+), 7 deletions(-) create mode 100644 FirebaseAnalyticsCoreWrapper/dummy.m create mode 100644 FirebaseAnalyticsCoreWrapper/include/dummy.h create mode 100644 FirebaseAnalyticsIdentitySupportWrapper/dummy.m create mode 100644 FirebaseAnalyticsIdentitySupportWrapper/include/dummy.h create mode 100644 SwiftPM-PlatformExclude/FirebaseAnalyticsCoreWrap/dummy.m create mode 100644 SwiftPM-PlatformExclude/FirebaseAnalyticsCoreWrap/include/dummy.h diff --git a/FirebaseAnalytics.podspec b/FirebaseAnalytics.podspec index f2531640828..137752c9671 100644 --- a/FirebaseAnalytics.podspec +++ b/FirebaseAnalytics.podspec @@ -34,13 +34,30 @@ Pod::Spec.new do |s| s.dependency 'GoogleUtilities/Network', '~> 8.1' s.dependency 'nanopb', '~> 3.30910.0' - s.default_subspecs = 'AdIdSupport' + s.default_subspecs = 'Default' + s.subspec 'Default' do |ss| + ss.dependency 'GoogleAppMeasurement/Default', '11.14.0' + ss.vendored_frameworks = 'Frameworks/FirebaseAnalytics.xcframework' + end + + s.subspec 'Core' do |ss| + ss.dependency 'GoogleAppMeasurement/Core', '11.14.0' + ss.vendored_frameworks = 'Frameworks/FirebaseAnalytics.xcframework' + end + + s.subspec 'IdentitySupport' do |ss| + ss.dependency 'GoogleAppMeasurement/IdentitySupport', '11.14.0' + ss.vendored_frameworks = 'Frameworks/FirebaseAnalytics.xcframework' + end + + # Deprecated. Use IdentitySupport subspec instead. s.subspec 'AdIdSupport' do |ss| - ss.dependency 'GoogleAppMeasurement', '11.14.0' + ss.dependency 'GoogleAppMeasurement/AdIdSupport', '11.14.0' ss.vendored_frameworks = 'Frameworks/FirebaseAnalytics.xcframework' end + # Deprecated. Use Core subspec instead. s.subspec 'WithoutAdIdSupport' do |ss| ss.dependency 'GoogleAppMeasurement/WithoutAdIdSupport', '11.14.0' ss.vendored_frameworks = 'Frameworks/FirebaseAnalytics.xcframework' diff --git a/FirebaseAnalyticsCoreWrapper/dummy.m b/FirebaseAnalyticsCoreWrapper/dummy.m new file mode 100644 index 00000000000..f340cb75e04 --- /dev/null +++ b/FirebaseAnalyticsCoreWrapper/dummy.m @@ -0,0 +1,17 @@ +/* + * 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. + */ + +// Swift Package Manager needs at least one source file. diff --git a/FirebaseAnalyticsCoreWrapper/include/dummy.h b/FirebaseAnalyticsCoreWrapper/include/dummy.h new file mode 100644 index 00000000000..4fe40eb40cd --- /dev/null +++ b/FirebaseAnalyticsCoreWrapper/include/dummy.h @@ -0,0 +1,18 @@ +/* + * 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. + */ + +// Swift Package Manager needs at least one header to prevent a warning. See +// https://github.com/firebase/firebase-ios-sdk/pull/6504. diff --git a/FirebaseAnalyticsIdentitySupportWrapper/dummy.m b/FirebaseAnalyticsIdentitySupportWrapper/dummy.m new file mode 100644 index 00000000000..f340cb75e04 --- /dev/null +++ b/FirebaseAnalyticsIdentitySupportWrapper/dummy.m @@ -0,0 +1,17 @@ +/* + * 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. + */ + +// Swift Package Manager needs at least one source file. diff --git a/FirebaseAnalyticsIdentitySupportWrapper/include/dummy.h b/FirebaseAnalyticsIdentitySupportWrapper/include/dummy.h new file mode 100644 index 00000000000..4fe40eb40cd --- /dev/null +++ b/FirebaseAnalyticsIdentitySupportWrapper/include/dummy.h @@ -0,0 +1,18 @@ +/* + * 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. + */ + +// Swift Package Manager needs at least one header to prevent a warning. See +// https://github.com/firebase/firebase-ios-sdk/pull/6504. diff --git a/FirebaseAnalyticsOnDeviceConversionWrapper/dummy.m b/FirebaseAnalyticsOnDeviceConversionWrapper/dummy.m index 2e503fe69d0..cddc196e0e5 100644 --- a/FirebaseAnalyticsOnDeviceConversionWrapper/dummy.m +++ b/FirebaseAnalyticsOnDeviceConversionWrapper/dummy.m @@ -15,3 +15,6 @@ */ // Swift Package Manager needs at least one source file. + +// #warning "FirebaseAnalyticsOnDeviceConversion is deprecated. Use GoogleAdsOnDeviceConversion from +// https://github.com/googleads/google-ads-on-device-conversion-ios-sdk/ instead." diff --git a/FirebaseAnalyticsWithoutAdIdSupportWrapper/dummy.m b/FirebaseAnalyticsWithoutAdIdSupportWrapper/dummy.m index f340cb75e04..fe29ea88ecf 100644 --- a/FirebaseAnalyticsWithoutAdIdSupportWrapper/dummy.m +++ b/FirebaseAnalyticsWithoutAdIdSupportWrapper/dummy.m @@ -15,3 +15,5 @@ */ // Swift Package Manager needs at least one source file. + +// #warning "FirebaseAnalyticsWithoutAdIdSupport is deprecated. Use FirebaseAnalyticsCore instead." diff --git a/GoogleAppMeasurement.podspec b/GoogleAppMeasurement.podspec index e388a56c778..760533a9c5a 100644 --- a/GoogleAppMeasurement.podspec +++ b/GoogleAppMeasurement.podspec @@ -34,15 +34,31 @@ Pod::Spec.new do |s| s.dependency 'GoogleUtilities/Network', '~> 8.1' s.dependency 'nanopb', '~> 3.30910.0' - s.default_subspecs = 'AdIdSupport' + s.default_subspecs = 'Default' - s.subspec 'AdIdSupport' do |ss| - ss.dependency 'GoogleAppMeasurement/WithoutAdIdSupport', '11.14.0' - ss.vendored_frameworks = 'Frameworks/GoogleAppMeasurementIdentitySupport.xcframework' + s.subspec 'Default' do |ss| + ss.dependency 'GoogleAppMeasurement/Core', '11.14.0' + ss.dependency 'GoogleAppMeasurement/IdentitySupport', '11.14.0' + # TODO Update to 2.0.0 + ss.ios.dependency 'GoogleAdsOnDeviceConversion', '1.3.0' end - s.subspec 'WithoutAdIdSupport' do |ss| + s.subspec 'Core' do |ss| ss.vendored_frameworks = 'Frameworks/GoogleAppMeasurement.xcframework' end + s.subspec 'IdentitySupport' do |ss| + ss.dependency 'GoogleAppMeasurement/Core', '11.14.0' + ss.vendored_frameworks = 'Frameworks/GoogleAppMeasurementIdentitySupport.xcframework' + end + + # Deprecated. Use IdentitySupport subspec instead. + s.subspec 'AdIdSupport' do |ss| + ss.dependency 'GoogleAppMeasurement/IdentitySupport', '11.14.0' + end + + # Deprecated. Use Core subspec instead. + s.subspec 'WithoutAdIdSupport' do |ss| + ss.dependency 'GoogleAppMeasurement/Core', '11.14.0' + end end diff --git a/Package.swift b/Package.swift index 7d8b1306601..9a7ac52f702 100644 --- a/Package.swift +++ b/Package.swift @@ -43,10 +43,25 @@ let package = Package( ), // Adding this library to your project is enough for it to take effect. The module // does not need to be imported into any source files. + .library( + name: "FirebaseAnalyticsCore", + targets: ["FirebaseAnalyticsCoreTarget"] + ), + // Adding this library to your project is enough for it to take effect. The module + // does not need to be imported into any source files. + .library( + name: "FirebaseAnalyticsIdentitySupport", + targets: ["FirebaseAnalyticsIdentitySupportTarget"] + ), + // Deprecated. Use FirebaseAnalyticsCore instead. + // Adding this library to your project is enough for it to take effect. The module + // does not need to be imported into any source files. .library( name: "FirebaseAnalyticsWithoutAdIdSupport", targets: ["FirebaseAnalyticsWithoutAdIdSupportTarget"] ), + // Deprecated. Use GoogleAdsOnDeviceConversion from + // https://github.com/googleads/google-ads-on-device-conversion-ios-sdk/ instead. // Adding this library to your project is enough for it to take effect. The module // does not need to be imported into any source files. .library( @@ -374,6 +389,66 @@ let package = Package( path: "FirebaseAnalytics/Tests/ObjCAPI" ), + .target( + name: "FirebaseAnalyticsCoreTarget", + dependencies: [.target(name: "FirebaseAnalyticsCoreWrapper", + condition: .when(platforms: [.iOS, .macCatalyst, .macOS, .tvOS]))], + path: "SwiftPM-PlatformExclude/FirebaseAnalyticsCoreWrap" + ), + .target( + name: "FirebaseAnalyticsCoreWrapper", + dependencies: [ + .target( + name: "FirebaseAnalytics", + condition: .when(platforms: [.iOS, .macCatalyst, .macOS, .tvOS]) + ), + .product(name: "GoogleAppMeasurementCore", + package: "GoogleAppMeasurement", + condition: .when(platforms: [.iOS, .macCatalyst, .macOS, .tvOS])), + "FirebaseCore", + "FirebaseInstallations", + .product(name: "GULAppDelegateSwizzler", package: "GoogleUtilities"), + .product(name: "GULMethodSwizzler", package: "GoogleUtilities"), + .product(name: "GULNSData", package: "GoogleUtilities"), + .product(name: "GULNetwork", package: "GoogleUtilities"), + .product(name: "nanopb", package: "nanopb"), + ], + path: "FirebaseAnalyticsCoreWrapper", + linkerSettings: [ + .linkedLibrary("sqlite3"), + .linkedLibrary("c++"), + .linkedLibrary("z"), + .linkedFramework("StoreKit"), + ] + ), + + .target( + name: "FirebaseAnalyticsIdentitySupportTarget", + dependencies: [ + .target( + name: "FirebaseAnalytics", + condition: .when(platforms: [.iOS, .macCatalyst, .macOS, .tvOS]) + ), + .product(name: "GoogleAppMeasurementIdentitySupport", + package: "GoogleAppMeasurement", + condition: .when(platforms: [.iOS, .macCatalyst, .macOS, .tvOS])), + "FirebaseCore", + "FirebaseInstallations", + .product(name: "GULAppDelegateSwizzler", package: "GoogleUtilities"), + .product(name: "GULMethodSwizzler", package: "GoogleUtilities"), + .product(name: "GULNSData", package: "GoogleUtilities"), + .product(name: "GULNetwork", package: "GoogleUtilities"), + .product(name: "nanopb", package: "nanopb"), + ], + path: "FirebaseAnalyticsIdentitySupportWrapper", + linkerSettings: [ + .linkedLibrary("sqlite3"), + .linkedLibrary("c++"), + .linkedLibrary("z"), + .linkedFramework("StoreKit"), + ] + ), + .target( name: "FirebaseAnalyticsWithoutAdIdSupportTarget", dependencies: [.target(name: "FirebaseAnalyticsWithoutAdIdSupportWrapper", diff --git a/SwiftPM-PlatformExclude/FirebaseAnalyticsCoreWrap/dummy.m b/SwiftPM-PlatformExclude/FirebaseAnalyticsCoreWrap/dummy.m new file mode 100644 index 00000000000..5197e17486a --- /dev/null +++ b/SwiftPM-PlatformExclude/FirebaseAnalyticsCoreWrap/dummy.m @@ -0,0 +1,18 @@ +// Copyright 2020 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 +#if TARGET_OS_WATCH +#warning "Firebase Analytics does not support the watchOS platform" +#endif diff --git a/SwiftPM-PlatformExclude/FirebaseAnalyticsCoreWrap/include/dummy.h b/SwiftPM-PlatformExclude/FirebaseAnalyticsCoreWrap/include/dummy.h new file mode 100644 index 00000000000..5224d0b2249 --- /dev/null +++ b/SwiftPM-PlatformExclude/FirebaseAnalyticsCoreWrap/include/dummy.h @@ -0,0 +1,15 @@ +// Copyright 2020 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. + +// Prevent a missing umbrella header warning. From 0cf3d55834fddbe1ba5dc99453d08d74c4a9d56b Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 27 May 2025 10:47:33 -0400 Subject: [PATCH 039/113] NOTICES Change (#14894) Co-authored-by: Anka --- CoreOnly/NOTICES | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CoreOnly/NOTICES b/CoreOnly/NOTICES index ff13635db3e..2442b90fb98 100644 --- a/CoreOnly/NOTICES +++ b/CoreOnly/NOTICES @@ -1930,6 +1930,9 @@ FirebaseSharedSwift limitations under the License. +GoogleAdsOnDeviceConversion +Copyright 2024 Google + GoogleUtilities Apache License From b4d58b20b75b569f1d768e9fd2879a4f9a822d27 Mon Sep 17 00:00:00 2001 From: Nick Cooke <36927374+ncooke3@users.noreply.github.com> Date: Tue, 27 May 2025 11:10:07 -0400 Subject: [PATCH 040/113] [Auth] Fix 'PhoneAuthProviderFake.swift' following Swift 6 changes (#14895) --- .github/workflows/combine.yml | 13 +++++++------ .../Auth/Sources/PhoneAuthProviderFake.swift | 6 +++--- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/.github/workflows/combine.yml b/.github/workflows/combine.yml index fd3eddcd8e6..268d7c21d8c 100644 --- a/.github/workflows/combine.yml +++ b/.github/workflows/combine.yml @@ -33,12 +33,13 @@ on: # Rebuild on Ruby infrastructure changes. - 'Gemfile' - # Dependencies (Disabled to avoid building Firestore in presubmits) - # - 'FirebaseCore/**' - # - 'FirebaseAuth/**' - # - 'FirebaseFunctions/**' - # - 'Firestore/**' - # - 'FirebaseStorage/**' + # Dependencies + - 'FirebaseCore/**' + - 'FirebaseTestingSupport/**' + - 'FirebaseAuth/**' + - 'FirebaseFunctions/**' + - 'FirebaseStorage/**' + # - 'Firestore/**' # (Disabled to avoid building Firestore in presubmits) schedule: # Run every day at 11pm (PST) - cron uses UTC times diff --git a/FirebaseTestingSupport/Auth/Sources/PhoneAuthProviderFake.swift b/FirebaseTestingSupport/Auth/Sources/PhoneAuthProviderFake.swift index fa6e9d9aa4f..ef564725950 100644 --- a/FirebaseTestingSupport/Auth/Sources/PhoneAuthProviderFake.swift +++ b/FirebaseTestingSupport/Auth/Sources/PhoneAuthProviderFake.swift @@ -16,16 +16,16 @@ import Foundation /// A fake object to replace a real `AuthAPNSTokenManager` in tests. -public class PhoneAuthProviderFake: PhoneAuthProvider { +public class PhoneAuthProviderFake: PhoneAuthProvider, @unchecked Sendable { override init(auth: Auth) { super.init(auth: auth) } - var verifyPhoneNumberHandler: (((String?, Error?) -> Void) -> Void)? + var verifyPhoneNumberHandler: ((@MainActor (String?, Error?) -> Void) -> Void)? override public func verifyPhoneNumber(_ phoneNumber: String, uiDelegate: AuthUIDelegate? = nil, - completion: ((_: String?, _: Error?) -> Void)?) { + completion: (@MainActor (String?, Error?) -> Void)?) { if let verifyPhoneNumberHandler, let completion { verifyPhoneNumberHandler(completion) From fbb845856d03dd5176e65b56412ad97c03b2f537 Mon Sep 17 00:00:00 2001 From: Andrew Heard Date: Tue, 27 May 2025 17:35:20 -0400 Subject: [PATCH 041/113] [Release] Update `Unreleased` CHANGELOG entries (#14898) --- FirebaseAuth/CHANGELOG.md | 2 +- FirebaseMessaging/CHANGELOG.md | 2 +- FirebaseRemoteConfig/CHANGELOG.md | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/FirebaseAuth/CHANGELOG.md b/FirebaseAuth/CHANGELOG.md index 0d7a15811b6..01e82591381 100644 --- a/FirebaseAuth/CHANGELOG.md +++ b/FirebaseAuth/CHANGELOG.md @@ -1,4 +1,4 @@ -# Unreleased +# 11.14.0 - [fixed] Synchronize internal `AuthKeychainServices` class to prevent crashes from concurrent access. (#14835) diff --git a/FirebaseMessaging/CHANGELOG.md b/FirebaseMessaging/CHANGELOG.md index 93e20e17717..00b746df27a 100644 --- a/FirebaseMessaging/CHANGELOG.md +++ b/FirebaseMessaging/CHANGELOG.md @@ -1,4 +1,4 @@ -# Unreleased +# 11.14.0 - [fixed] Fix a potential SQL injection issue. (#14846). # 11.9.0 diff --git a/FirebaseRemoteConfig/CHANGELOG.md b/FirebaseRemoteConfig/CHANGELOG.md index 69fb96b49de..b1ca12b48c3 100644 --- a/FirebaseRemoteConfig/CHANGELOG.md +++ b/FirebaseRemoteConfig/CHANGELOG.md @@ -1,4 +1,4 @@ -# Unreleased +# 11.14.0 - [fixed] Fix build warning from comparison of different enumeration types. # 11.13.0 From 61f6af375b216ccdf81e8a9b8e9c73f485eda006 Mon Sep 17 00:00:00 2001 From: Nick Cooke <36927374+ncooke3@users.noreply.github.com> Date: Tue, 27 May 2025 17:47:54 -0400 Subject: [PATCH 042/113] [Infra] Update template README with new min. supported Xcode version (#14899) --- ReleaseTooling/Template/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ReleaseTooling/Template/README.md b/ReleaseTooling/Template/README.md index 55c97b9b536..2b02fa7177a 100644 --- a/ReleaseTooling/Template/README.md +++ b/ReleaseTooling/Template/README.md @@ -19,7 +19,7 @@ Each Firebase component requires several xcframeworks in order to function properly. Each section below lists the xcframeworks you'll need to include in your project in order to use that Firebase SDK in your application. -Xcode 15.2 or newer is required. +Xcode 16.2 or newer is required. To integrate a Firebase SDK with your app: @@ -43,7 +43,7 @@ To integrate a Firebase SDK with your app: box that appears, make sure the target you want this framework to be added to has a checkmark next to it, and that you've selected "Copy items if needed." -7. If using Xcode 15, embed each framework that was dragged in. Navigate to the +7. Embed each framework that was dragged in. Navigate to the target's _General_ settings and find _Frameworks, Libraries, & Embedded Content_. For each framework dragged in from the `Firebase.zip`, select **Embed & Sign**. This step will enable privacy manifests to be picked up by From 35e0adbcea8ef1f7838735b04399fbf50de43a55 Mon Sep 17 00:00:00 2001 From: pcfba <111909874+pcfba@users.noreply.github.com> Date: Tue, 27 May 2025 16:00:45 -0700 Subject: [PATCH 043/113] Analytics 11.14.0 (#14897) --- FirebaseAnalytics.podspec | 2 +- GoogleAppMeasurement.podspec | 5 ++--- GoogleAppMeasurementOnDeviceConversion.podspec | 2 +- Package.swift | 6 +++--- 4 files changed, 7 insertions(+), 8 deletions(-) diff --git a/FirebaseAnalytics.podspec b/FirebaseAnalytics.podspec index 137752c9671..edd1099f316 100644 --- a/FirebaseAnalytics.podspec +++ b/FirebaseAnalytics.podspec @@ -13,7 +13,7 @@ Pod::Spec.new do |s| s.authors = 'Google, Inc.' s.source = { - :http => 'https://dl.google.com/firebase/ios/analytics/925f34cf030a1cdf/FirebaseAnalytics-11.13.0.tar.gz' + :http => 'https://dl.google.com/firebase/ios/analytics/928ced72694a6548/FirebaseAnalytics-11.14.0.tar.gz' } s.cocoapods_version = '>= 1.12.0' diff --git a/GoogleAppMeasurement.podspec b/GoogleAppMeasurement.podspec index 760533a9c5a..64644f21ece 100644 --- a/GoogleAppMeasurement.podspec +++ b/GoogleAppMeasurement.podspec @@ -16,7 +16,7 @@ Pod::Spec.new do |s| s.authors = 'Google, Inc.' s.source = { - :http => 'https://dl.google.com/firebase/ios/analytics/2af6a14a3c1e0357/GoogleAppMeasurement-11.13.0.tar.gz' + :http => 'https://dl.google.com/firebase/ios/analytics/947bee486051ffca/GoogleAppMeasurement-11.14.0.tar.gz' } s.cocoapods_version = '>= 1.12.0' @@ -39,8 +39,7 @@ Pod::Spec.new do |s| s.subspec 'Default' do |ss| ss.dependency 'GoogleAppMeasurement/Core', '11.14.0' ss.dependency 'GoogleAppMeasurement/IdentitySupport', '11.14.0' - # TODO Update to 2.0.0 - ss.ios.dependency 'GoogleAdsOnDeviceConversion', '1.3.0' + ss.ios.dependency 'GoogleAdsOnDeviceConversion', '2.0.0' end s.subspec 'Core' do |ss| diff --git a/GoogleAppMeasurementOnDeviceConversion.podspec b/GoogleAppMeasurementOnDeviceConversion.podspec index 97e3e26e584..983a8c091ba 100644 --- a/GoogleAppMeasurementOnDeviceConversion.podspec +++ b/GoogleAppMeasurementOnDeviceConversion.podspec @@ -17,7 +17,7 @@ Pod::Spec.new do |s| s.authors = 'Google, Inc.' s.source = { - :http => 'https://dl.google.com/firebase/ios/analytics/d8a25f0d55c82700/GoogleAppMeasurementOnDeviceConversion-11.13.0.tar.gz' + :http => 'https://dl.google.com/firebase/ios/analytics/af5df76743613a77/GoogleAppMeasurementOnDeviceConversion-11.14.0.tar.gz' } s.cocoapods_version = '>= 1.12.0' diff --git a/Package.swift b/Package.swift index 9a7ac52f702..2595bc2f8bc 100644 --- a/Package.swift +++ b/Package.swift @@ -375,8 +375,8 @@ let package = Package( ), .binaryTarget( name: "FirebaseAnalytics", - url: "https://dl.google.com/firebase/ios/swiftpm/11.13.0/FirebaseAnalytics.zip", - checksum: "3c23a870df5fe9d7c36f2cfb9fb26e1cbccaa5fa0b12a28bc42d36cbc92bf909" + url: "https://dl.google.com/firebase/ios/swiftpm/11.14.0/FirebaseAnalytics.zip", + checksum: "b86d668ff8b5e0df396d1a5711632b542247e03c8dda8ab4722185090d47300c" ), .testTarget( name: "AnalyticsSwiftUnit", @@ -1445,7 +1445,7 @@ func googleAppMeasurementDependency() -> Package.Dependency { return .package(url: appMeasurementURL, branch: "main") } - return .package(url: appMeasurementURL, exact: "11.13.0") + return .package(url: appMeasurementURL, exact: "11.14.0") } func abseilDependency() -> Package.Dependency { From f3075b17993a651f548e83748ae5f239bebb80b6 Mon Sep 17 00:00:00 2001 From: Nick Cooke <36927374+ncooke3@users.noreply.github.com> Date: Tue, 27 May 2025 20:15:35 -0400 Subject: [PATCH 044/113] [Infra] Fix logic used to find transitive dependencies (#14896) --- ReleaseTooling/Sources/ZipBuilder/CocoaPodUtils.swift | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/ReleaseTooling/Sources/ZipBuilder/CocoaPodUtils.swift b/ReleaseTooling/Sources/ZipBuilder/CocoaPodUtils.swift index 9647db287fd..f789f5e69b9 100644 --- a/ReleaseTooling/Sources/ZipBuilder/CocoaPodUtils.swift +++ b/ReleaseTooling/Sources/ZipBuilder/CocoaPodUtils.swift @@ -365,7 +365,10 @@ enum CocoaPodUtils { repeat { var foundDeps = Set() for dep in newDeps { - let childDeps = installedPods[dep]?.dependencies ?? [] + // The `dep` may be a subspec, so get root spec name to lookup it's + // dependencies in the `installedPods` dictionary. + let rootDep = dep.components(separatedBy: "/")[0] + let childDeps = installedPods[rootDep]?.dependencies ?? [] foundDeps.formUnion(Set(childDeps)) } newDeps = foundDeps.subtracting(returnDeps) From e9427cc41c288e887cdb5853c6895f59ae728a28 Mon Sep 17 00:00:00 2001 From: Nick Cooke <36927374+ncooke3@users.noreply.github.com> Date: Wed, 28 May 2025 16:57:27 -0400 Subject: [PATCH 045/113] [Infra] Common cocoapods pod lib lint job (#14876) --- .github/workflows/abtesting.yml | 48 ++----- .github/workflows/appdistribution.yml | 35 ++--- .github/workflows/auth.yml | 38 ++---- .github/workflows/common.yml | 22 +++- .github/workflows/common_cocoapods.yml | 116 +++++++++++++++++ .github/workflows/core.yml | 36 ++--- .github/workflows/core_extension.yml | 36 ++--- .github/workflows/core_internal.yml | 40 ++---- .github/workflows/crashlytics.yml | 48 ++----- .github/workflows/database.yml | 34 ++--- .github/workflows/dynamiclinks.yml | 30 ++--- .github/workflows/firebase_app_check.yml | 31 ++--- .github/workflows/firebaseai.yml | 123 +++--------------- .github/workflows/functions.yml | 41 ++---- .github/workflows/inappmessaging.yml | 30 ++--- .github/workflows/messaging.yml | 39 ++---- .github/workflows/performance.yml | 39 ++---- .github/workflows/remoteconfig.yml | 39 ++---- .github/workflows/sessions.yml | 49 ++----- .github/workflows/shared-swift.yml | 39 ++---- .github/workflows/vertexai.yml | 116 ++--------------- ...FIRMessagingRemoteNotificationsProxyTest.m | 6 +- 22 files changed, 357 insertions(+), 678 deletions(-) create mode 100644 .github/workflows/common_cocoapods.yml diff --git a/.github/workflows/abtesting.yml b/.github/workflows/abtesting.yml index bdf390a761a..f874410e988 100644 --- a/.github/workflows/abtesting.yml +++ b/.github/workflows/abtesting.yml @@ -1,5 +1,8 @@ name: abtesting +permissions: + contents: read + on: workflow_dispatch: pull_request: @@ -7,6 +10,8 @@ on: - 'FirebaseABTesting**' - 'Interop/Analytics/Public/*.h' - '.github/workflows/abtesting.yml' + - '.github/workflows/common.yml' + - '.github/workflows/common_cocoapods.yml' - 'Gemfile*' schedule: # Run every day at 1am(PST) - cron uses UTC times @@ -28,43 +33,10 @@ jobs: product: FirebaseABTesting target: FirebaseABTesting-Unit-unit - pod-lib-lint: - # Don't run on private repo unless it is a PR. - if: (github.repository == 'Firebase/firebase-ios-sdk' && github.event_name == 'schedule') || github.event_name == 'pull_request' - - strategy: - matrix: - include: - - os: macos-14 - xcode: Xcode_16.2 - target: ios - - os: macos-15 - xcode: Xcode_16.2 - target: ios - - os: macos-15 - xcode: Xcode_16.2 - target: tvos - - os: macos-15 - xcode: Xcode_16.2 - target: macos - - os: macos-15 - xcode: Xcode_16.2 - target: watchos - runs-on: ${{ matrix.os }} - steps: - - uses: actions/checkout@v4 - - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1 - - name: Setup Bundler - run: scripts/setup_bundler.sh - - name: Xcode - run: sudo xcode-select -s /Applications/${{ matrix.xcode }}.app/Contents/Developer - - uses: nick-fields/retry@ce71cc2ab81d554ebbe88c79ab5975992d79ba08 # v3 - with: - timeout_minutes: 120 - max_attempts: 3 - retry_on: error - retry_wait_seconds: 120 - command: scripts/pod_lib_lint.rb FirebaseABTesting.podspec --platforms=${{ matrix.target }} + pod_lib_lint: + uses: ./.github/workflows/common_cocoapods.yml + with: + product: FirebaseABTesting quickstart: # Don't run on private repo unless it is a PR. @@ -136,7 +108,7 @@ jobs: flags: [ '--use-static-frameworks' ] - needs: pod-lib-lint + needs: pod_lib_lint steps: - uses: actions/checkout@v4 - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1 diff --git a/.github/workflows/appdistribution.yml b/.github/workflows/appdistribution.yml index 670f670e183..059a5ab88b6 100644 --- a/.github/workflows/appdistribution.yml +++ b/.github/workflows/appdistribution.yml @@ -1,11 +1,16 @@ name: appdistribution +permissions: + contents: read + on: workflow_dispatch: pull_request: paths: - 'FirebaseAppDistribution**' - '.github/workflows/appdistribution.yml' + - '.github/workflows/common.yml' + - '.github/workflows/common_cocoapods.yml' - 'Gemfile*' schedule: # Run every day at 1am (PST) - cron uses UTC times @@ -28,29 +33,11 @@ jobs: product: FirebaseAppDistribution target: FirebaseAppDistribution-Unit-unit - pod-lib-lint: - # Don't run on private repo unless it is a PR. - if: (github.repository == 'Firebase/firebase-ios-sdk' && github.event_name == 'schedule') || github.event_name == 'pull_request' - - strategy: - matrix: - include: - - os: macos-14 - xcode: Xcode_16.2 - - os: macos-15 - xcode: Xcode_16.3 - runs-on: ${{ matrix.os }} - steps: - - uses: actions/checkout@v4 - - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1 - - name: Setup Bundler - run: scripts/setup_bundler.sh - - name: Xcode - run: sudo xcode-select -s /Applications/${{ matrix.xcode }}.app/Contents/Developer - - name: Build and test - run: | - scripts/third_party/travis/retry.sh scripts/pod_lib_lint.rb FirebaseAppDistribution.podspec \ - --platforms=ios + pod_lib_lint: + uses: ./.github/workflows/common_cocoapods.yml + with: + product: FirebaseAppDistribution + platforms: iOS # App Distro only supports iOS. appdistribution-cron-only: if: github.event_name == 'schedule' && github.repository == 'Firebase/firebase-ios-sdk' @@ -62,7 +49,7 @@ jobs: flags: [ '--use-static-frameworks' ] - needs: pod-lib-lint + needs: pod_lib_lint steps: - uses: actions/checkout@v4 - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1 diff --git a/.github/workflows/auth.yml b/.github/workflows/auth.yml index 1f2055c1499..31a5f7584e9 100644 --- a/.github/workflows/auth.yml +++ b/.github/workflows/auth.yml @@ -1,5 +1,8 @@ name: auth +permissions: + contents: read + on: workflow_dispatch: pull_request: @@ -7,6 +10,8 @@ on: - 'FirebaseAuth**' - 'FirebaseAuth/Interop/*.h' - '.github/workflows/auth.yml' + - '.github/workflows/common.yml' + - '.github/workflows/common_cocoapods.yml' - 'scripts/gha-encrypted/AuthSample/SwiftApplication.plist.gpg' - 'Gemfile*' schedule: @@ -34,33 +39,14 @@ jobs: target: FirebaseAuth-Unit-unit buildonly: true - pod-lib-lint: - # Don't run on private repo unless it is a PR. - if: (github.repository == 'Firebase/firebase-ios-sdk' && github.event_name == 'schedule') || github.event_name == 'pull_request' - + pod_lib_lint: strategy: matrix: - podspec: [FirebaseAuthInterop.podspec, FirebaseAuth.podspec] - target: [ios, tvos, macos --skip-tests, watchos] - os: [macos-15] - xcode: [Xcode_16.3] - runs-on: ${{ matrix.os }} - steps: - - uses: actions/checkout@v4 - - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1 - - name: Setup Bundler - run: scripts/setup_bundler.sh - - name: Configure test keychain - run: scripts/configure_test_keychain.sh - - name: Xcode - run: sudo xcode-select -s /Applications/${{ matrix.xcode }}.app/Contents/Developer - - uses: nick-fields/retry@ce71cc2ab81d554ebbe88c79ab5975992d79ba08 # v3 - with: - timeout_minutes: 120 - max_attempts: 3 - retry_on: error - retry_wait_seconds: 120 - command: scripts/pod_lib_lint.rb ${{ matrix.podspec }} --platforms=${{ matrix.target }} ${{ matrix.tests }} + product: [FirebaseAuthInterop, FirebaseAuth] + uses: ./.github/workflows/common_cocoapods.yml + with: + product: ${{ matrix.product }} + buildonly_platforms: macOS spm-package-resolved: env: @@ -190,7 +176,7 @@ jobs: flags: [ '--use-static-frameworks' ] - needs: pod-lib-lint + needs: pod_lib_lint steps: - uses: actions/checkout@v4 - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1 diff --git a/.github/workflows/common.yml b/.github/workflows/common.yml index d9eac3c9a12..40ba550d095 100644 --- a/.github/workflows/common.yml +++ b/.github/workflows/common.yml @@ -41,6 +41,22 @@ on: required: false default: "" + # A command to execute before testing. + # + # This is useful for additional set up, like starting an emulator or + # downloading test data. + # + # Example: `FirebaseFunctions/Backend/start.sh synchronous` + setup_command: + type: string + required: false + default: "" + + outputs: + cache_key: + description: "The cache key for the Swift package resolution." + value: ${{ jobs.spm-package-resolved.outputs.cache_key }} + jobs: spm-package-resolved: env: @@ -54,8 +70,7 @@ jobs: run: sudo xcode-select -s /Applications/Xcode_16.2.app/Contents/Developer - name: Generate Swift Package.resolved id: swift_package_resolve - run: | - swift package resolve + run: swift package resolve - name: Generate cache key id: generate_cache_key run: | @@ -92,6 +107,9 @@ jobs: - name: Install visionOS, if needed. if: matrix.platform == 'visionOS' run: xcodebuild -downloadPlatform visionOS + - name: Run setup command, if needed. + if: inputs.setup_command != '' + run: ${{ inputs.setup_command }} - name: Initialize xcodebuild run: scripts/setup_spm_tests.sh - uses: nick-fields/retry@ce71cc2ab81d554ebbe88c79ab5975992d79ba08 # v3 diff --git a/.github/workflows/common_cocoapods.yml b/.github/workflows/common_cocoapods.yml new file mode 100644 index 00000000000..6a575554bb4 --- /dev/null +++ b/.github/workflows/common_cocoapods.yml @@ -0,0 +1,116 @@ +name: common_cocoapods + +permissions: + contents: read + +on: + workflow_call: + inputs: + # The product to test be tested (e.g. `FirebaseABTesting`). + product: + type: string + required: true + + # The platforms to build on. Defaults to all. + # To target specific platforms, pass a comma or space separated string of + # platforms. + # + # Examples: + # - build/test only for macOS: `macOS` + # - build/test only for macOS and tvOS: `macOS, tvOS` + platforms: + type: string + required: false + default: "iOS, tvOS, macOS, watchOS" + + # By default, all platforms will be tested (see matrix in `spm` job). + # To build instead of test, pass a comma or space separated string of + # platforms. + # + # Platform options: [iOS, tvOS, macOS, watchOS, catalyst, visionOS] + # + # Note: Build-only platforms must be represented in the `platforms` input + # (which defaults to all platforms) in order to take effect. + # + # Examples: + # - build only for macOS: `macOS` + # - build only for macOS and tvOS: `macOS, tvOS` + # - build only for all platforms: `all` + buildonly_platforms: + type: string + required: false + default: "" + + # Whether to lint with `--allow-warnings`. Defaults to false. + allow_warnings: + type: boolean + required: false + default: false + + # Whether to additionally build with Swift 6. Defaults to false. + supports_swift6: + type: boolean + required: false + default: false + + # A comma separated (no spaces) string that will be passed to + # pod lib lint's `--test-specs=` argument. By default, all + # test specs will be tested. + test_specs: + type: string + required: false + default: "" + + # A command to execute before testing. + # + # This is useful for additional set up, like starting an emulator or + # downloading test data. + # + # Example: `FirebaseFunctions/Backend/start.sh synchronous` + setup_command: + type: string + required: false + default: "" + +jobs: + pod-lib-lint: + # Run on the main repo's scheduled jobs or pull requests and manual workflow invocations. + if: (github.repository == 'firebase/firebase-ios-sdk' && github.event_name == 'schedule') || contains(fromJSON('["pull_request", "workflow_dispatch"]'), github.event_name) + strategy: + matrix: + os: [macos-15] + xcode: [Xcode_16.3] + platform: [iOS, tvOS, macOS, watchOS] + include: + - os: macos-14 + xcode: Xcode_16.2 + platform: iOS + runs-on: ${{ matrix.os }} + steps: + - uses: actions/checkout@v4 + - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1 + - name: Setup Bundler + run: scripts/setup_bundler.sh + - name: Xcode + run: sudo xcode-select -s /Applications/${{ matrix.xcode }}.app/Contents/Developer + - name: Set conditional environment variable, if needed. + if: inputs.product == 'FirebaseAuth' + run: echo "FIREBASE_CI=true" >> $GITHUB_ENV + - name: Set podspec Swift version to 6.0, if supported. + if: inputs.supports_swift6 == true && matrix.os != 'macos-14' + run: sed -i "" "s/s.swift_version[[:space:]]*=[[:space:]]*'5.9'/s.swift_version = '6.0'/" ${{ inputs.product }}.podspec + - name: Run setup command, if needed. + if: inputs.setup_command != '' + run: ${{ inputs.setup_command }} + - uses: nick-fields/retry@ce71cc2ab81d554ebbe88c79ab5975992d79ba08 # v3 + if: contains(join(inputs.platforms), matrix.platform) || matrix.os == 'macos-14' + with: + timeout_minutes: 120 + max_attempts: 3 + retry_on: error + retry_wait_seconds: 120 + command: | + scripts/pod_lib_lint.rb ${{ inputs.product }}.podspec --platforms=${{ matrix.platform }} \ + ${{ inputs.allow_warnings == true && '--allow-warnings' || '' }} \ + ${{ inputs.test_specs != '' && format('--test-specs={0}', inputs.test_specs) || '' }} \ + ${{ (contains(inputs.buildonly_platforms, matrix.platform) || contains(inputs.buildonly_platforms, 'all')) && '--skip-tests' || '' }} diff --git a/.github/workflows/core.yml b/.github/workflows/core.yml index 5c827cdfabc..70b8cb92612 100644 --- a/.github/workflows/core.yml +++ b/.github/workflows/core.yml @@ -1,11 +1,16 @@ name: core +permissions: + contents: read + on: workflow_dispatch: pull_request: paths: - 'FirebaseCore**' - '.github/workflows/core.yml' + - '.github/workflows/common.yml' + - '.github/workflows/common_cocoapods.yml' - 'Gemfile*' schedule: # Run every day at 2am (PST) - cron uses UTC times @@ -27,31 +32,10 @@ jobs: product: FirebaseCore target: FirebaseCore-Unit-unit - pod-lib-lint: - # Don't run on private repo unless it is a PR. - if: (github.repository == 'Firebase/firebase-ios-sdk' && github.event_name == 'schedule') || github.event_name == 'pull_request' - strategy: - matrix: - # TODO: macos tests are blocked by https://github.com/erikdoe/ocmock/pull/532 - target: [ios, tvos, macos --skip-tests, watchos] - build-env: - - os: macos-14 - xcode: Xcode_16.2 - - os: macos-15 - xcode: Xcode_16.2 - # TODO: Add Xcode matrix when Xcode 16 is ubiquitous on CI runners. -# - os: macos-15 -# xcode: Xcode_16.3 - runs-on: ${{ matrix.build-env.os }} - steps: - - uses: actions/checkout@v4 - - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1 - - name: Setup Bundler - run: scripts/setup_bundler.sh - - name: Xcode - run: sudo xcode-select -s /Applications/${{ matrix.build-env.xcode }}.app/Contents/Developer - - name: Build and test - run: scripts/third_party/travis/retry.sh scripts/pod_lib_lint.rb FirebaseCore.podspec --platforms=${{ matrix.target }} + pod_lib_lint: + uses: ./.github/workflows/common_cocoapods.yml + with: + product: FirebaseCore spm-package-resolved: env: @@ -89,7 +73,7 @@ jobs: flags: [ '--use-static-frameworks' ] - needs: pod-lib-lint + needs: pod_lib_lint steps: - uses: actions/checkout@v4 - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1 diff --git a/.github/workflows/core_extension.yml b/.github/workflows/core_extension.yml index 72189156eaf..15b86f38538 100644 --- a/.github/workflows/core_extension.yml +++ b/.github/workflows/core_extension.yml @@ -1,5 +1,8 @@ name: core_extension +permissions: + contents: read + on: workflow_dispatch: pull_request: @@ -7,6 +10,8 @@ on: - 'FirebaseCoreExtension.podspec' - 'FirebaseCore/Extension/**' - '.github/workflows/core_extension.yml' + - '.github/workflows/common.yml' + - '.github/workflows/common_cocoapods.yml' - 'Gemfile*' schedule: # Run every day at 2am (PST) - cron uses UTC times @@ -14,31 +19,10 @@ on: jobs: # Since `FirebaseCoreExtension` only contains headers, linting is sufficient for testing. - - pod-lib-lint: - # Don't run on private repo unless it is a PR. - if: (github.repository == 'Firebase/firebase-ios-sdk' && github.event_name == 'schedule') || github.event_name == 'pull_request' - strategy: - matrix: - target: [ios, tvos, macos, watchos] - build-env: - - os: macos-14 - xcode: Xcode_16.2 - - os: macos-15 - xcode: Xcode_16.2 - # TODO: Enable when Xcode 16 is ubiquitous on CI runners. -# - os: macos-15 -# xcode: Xcode_16.3 - runs-on: ${{ matrix.build-env.os }} - steps: - - uses: actions/checkout@v4 - - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1 - - name: Setup Bundler - run: scripts/setup_bundler.sh - - name: Xcode - run: sudo xcode-select -s /Applications/${{ matrix.build-env.xcode }}.app/Contents/Developer - - name: Build and test - run: scripts/third_party/travis/retry.sh scripts/pod_lib_lint.rb FirebaseCoreExtension.podspec --platforms=${{ matrix.target }} + pod_lib_lint: + uses: ./.github/workflows/common_cocoapods.yml + with: + product: FirebaseCoreExtension core-internal-cron-only: # Don't run on private repo. @@ -50,7 +34,7 @@ jobs: flags: [ '--use-static-frameworks' ] - needs: pod-lib-lint + needs: pod_lib_lint steps: - uses: actions/checkout@v4 - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1 diff --git a/.github/workflows/core_internal.yml b/.github/workflows/core_internal.yml index 19f5c4d9e29..02ae537a6ff 100644 --- a/.github/workflows/core_internal.yml +++ b/.github/workflows/core_internal.yml @@ -1,5 +1,8 @@ name: core_internal +permissions: + contents: read + on: workflow_dispatch: pull_request: @@ -7,6 +10,8 @@ on: - 'FirebaseCoreInternal.podspec' - 'FirebaseCore/Internal/**' - '.github/workflows/core_internal.yml' + - '.github/workflows/common.yml' + - '.github/workflows/common_cocoapods.yml' - 'Gemfile*' schedule: # Run every day at 2am (PST) - cron uses UTC times @@ -27,34 +32,11 @@ jobs: product: FirebaseCoreInternal target: ${{ matrix.target }} - pod-lib-lint: - # Don't run on private repo unless it is a PR. - if: (github.repository == 'Firebase/firebase-ios-sdk' && github.event_name == 'schedule') || github.event_name == 'pull_request' - strategy: - matrix: - target: [ios, tvos, macos, watchos] - build-env: - - os: macos-14 - xcode: Xcode_16.2 - swift_version: 5.9 - - os: macos-15 - xcode: Xcode_16.2 - swift_version: 5.9 - - os: macos-15 - xcode: Xcode_16.2 - swift_version: 6.0 - runs-on: ${{ matrix.build-env.os }} - steps: - - uses: actions/checkout@v4 - - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1 - - name: Setup Bundler - run: scripts/setup_bundler.sh - - name: Xcode - run: sudo xcode-select -s /Applications/${{ matrix.build-env.xcode }}.app/Contents/Developer - - name: Set Swift swift_version - run: sed -i "" "s/s.swift_version[[:space:]]*=[[:space:]]*'5.9'/s.swift_version = '${{ matrix.build-env.swift_version }}'/" FirebaseCoreInternal.podspec - - name: Build and test - run: scripts/third_party/travis/retry.sh scripts/pod_lib_lint.rb FirebaseCoreInternal.podspec --platforms=${{ matrix.target }} + pod_lib_lint: + uses: ./.github/workflows/common_cocoapods.yml + with: + product: FirebaseCoreInternal + supports_swift6: true core-internal-cron-only: # Don't run on private repo. @@ -66,7 +48,7 @@ jobs: flags: [ '--use-static-frameworks' ] - needs: pod-lib-lint + needs: pod_lib_lint steps: - uses: actions/checkout@v4 - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1 diff --git a/.github/workflows/crashlytics.yml b/.github/workflows/crashlytics.yml index 6c1489bc269..05f492d68d3 100644 --- a/.github/workflows/crashlytics.yml +++ b/.github/workflows/crashlytics.yml @@ -1,5 +1,8 @@ name: crashlytics +permissions: + contents: read + on: workflow_dispatch: pull_request: @@ -7,6 +10,8 @@ on: - 'Crashlytics**' - 'FirebaseCrashlytics.podspec' - '.github/workflows/crashlytics.yml' + - '.github/workflows/common.yml' + - '.github/workflows/common_cocoapods.yml' - 'Interop/Analytics/Public/*.h' - 'Gemfile*' schedule: @@ -29,39 +34,11 @@ jobs: product: FirebaseCrashlytics target: FirebaseCrashlytics-Unit-unit - pod-lib-lint: - # Don't run on private repo unless it is a PR. - if: (github.repository == 'Firebase/firebase-ios-sdk' && github.event_name == 'schedule') || github.event_name == 'pull_request' - - strategy: - matrix: - target: [ios, tvos, macos, watchos --skip-tests] - flags: [ - '--use-modular-headers --skip-tests', - '' - ] - build-env: - - os: macos-14 - xcode: Xcode_16.2 - tests: - - os: macos-15 - xcode: Xcode_16.2 - tests: - runs-on: ${{ matrix.build-env.os }} - steps: - - uses: actions/checkout@v4 - - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1 - - name: Setup Bundler - run: scripts/setup_bundler.sh - - name: Xcode - run: sudo xcode-select -s /Applications/${{ matrix.build-env.xcode }}.app/Contents/Developer - - uses: nick-fields/retry@ce71cc2ab81d554ebbe88c79ab5975992d79ba08 # v3 - with: - timeout_minutes: 120 - max_attempts: 3 - retry_on: error - retry_wait_seconds: 120 - command: scripts/pod_lib_lint.rb FirebaseCrashlytics.podspec --platforms=${{ matrix.target }} ${{ matrix.build-env.tests }} ${{ matrix.flags }} + pod_lib_lint: + uses: ./.github/workflows/common_cocoapods.yml + with: + product: FirebaseCrashlytics + buildonly_platforms: tvOS, macOS, watchOS quickstart: # Don't run on private repo unless it is a PR. @@ -142,9 +119,10 @@ jobs: # Disable watchos because it does not support XCTest. target: [ios, tvos, macos, watchos --skip-tests] flags: [ - '--use-static-frameworks' + '--use-static-frameworks', + '--use-modular-headers --skip-tests' ] - needs: pod-lib-lint + needs: pod_lib_lint steps: - uses: actions/checkout@v4 - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1 diff --git a/.github/workflows/database.yml b/.github/workflows/database.yml index daa245a17f6..694ed7b48e5 100644 --- a/.github/workflows/database.yml +++ b/.github/workflows/database.yml @@ -1,5 +1,8 @@ name: database +permissions: + contents: read + on: workflow_dispatch: pull_request: @@ -10,6 +13,8 @@ on: - 'Example/Database/**' - 'FirebaseAuth/Interop/*.h' - '.github/workflows/database.yml' + - '.github/workflows/common.yml' + - '.github/workflows/common_cocoapods.yml' - 'Gemfile*' - 'scripts/run_database_emulator.sh' schedule: @@ -35,27 +40,12 @@ jobs: product: FirebaseDatabase target: FirebaseDatabase-Unit-unit - pod-lib-lint: - # Don't run on private repo unless it is a PR. - if: (github.repository == 'Firebase/firebase-ios-sdk' && github.event_name == 'schedule') || github.event_name == 'pull_request' - strategy: - matrix: - target: [ios, tvos, macos --skip-tests, watchos] - build-env: - - os: macos-14 - xcode: Xcode_16.2 - - os: macos-15 - xcode: Xcode_16.2 - runs-on: ${{ matrix.build-env.os }} - steps: - - uses: actions/checkout@v4 - - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1 - - name: Setup Bundler - run: scripts/setup_bundler.sh - - name: Xcode - run: sudo xcode-select -s /Applications/${{ matrix.build-env.xcode }}.app/Contents/Developer - - name: Build and test - run: scripts/third_party/travis/retry.sh scripts/pod_lib_lint.rb FirebaseDatabase.podspec --test-specs=unit --platforms=${{ matrix.target }} + pod_lib_lint: + uses: ./.github/workflows/common_cocoapods.yml + with: + product: FirebaseDatabase + test_specs: unit + buildonly_platforms: macOS integration: # Don't run on private repo unless it is a PR. @@ -110,7 +100,7 @@ jobs: flags: [ '--skip-tests --use-static-frameworks' ] - needs: pod-lib-lint + needs: pod_lib_lint steps: - uses: actions/checkout@v4 - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1 diff --git a/.github/workflows/dynamiclinks.yml b/.github/workflows/dynamiclinks.yml index f13dacfd968..b6c2ff19c0b 100644 --- a/.github/workflows/dynamiclinks.yml +++ b/.github/workflows/dynamiclinks.yml @@ -1,5 +1,8 @@ name: dynamiclinks +permissions: + contents: read + on: workflow_dispatch: pull_request: @@ -7,6 +10,8 @@ on: - 'FirebaseDynamicLinks**' - '.github/workflows/dynamiclinks.yml' - 'Interop/Analytics/Public/*.h' + - '.github/workflows/common.yml' + - '.github/workflows/common_cocoapods.yml' - 'Gemfile*' schedule: # Run every day at 1am (PST) - cron uses UTC times @@ -28,26 +33,11 @@ jobs: platforms: iOS pod_lib_lint: - # Don't run on private repo unless it is a PR. - if: (github.repository == 'Firebase/firebase-ios-sdk' && github.event_name == 'schedule') || github.event_name == 'pull_request' - - strategy: - matrix: - include: - - os: macos-14 - xcode: Xcode_16.2 - - os: macos-15 - xcode: Xcode_16.2 - runs-on: ${{ matrix.os }} - steps: - - uses: actions/checkout@v4 - - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1 - - name: Setup Bundler - run: scripts/setup_bundler.sh - - name: Xcode - run: sudo xcode-select -s /Applications/${{ matrix.xcode }}.app/Contents/Developer - - name: FirebaseDynamicLinks - run: scripts/third_party/travis/retry.sh scripts/pod_lib_lint.rb FirebaseDynamicLinks.podspec --allow-warnings + uses: ./.github/workflows/common_cocoapods.yml + with: + product: FirebaseDynamicLinks + platforms: iOS # Dynamic Links only supports iOS. + allow_warnings: true dynamiclinks-cron-only: # Don't run on private repo. diff --git a/.github/workflows/firebase_app_check.yml b/.github/workflows/firebase_app_check.yml index aca14b2671b..5e5c749d808 100644 --- a/.github/workflows/firebase_app_check.yml +++ b/.github/workflows/firebase_app_check.yml @@ -1,11 +1,16 @@ name: firebase_app_check +permissions: + contents: read + on: workflow_dispatch: pull_request: paths: - 'FirebaseAppCheck**' - '.github/workflows/firebase_app_check.yml' + - '.github/workflows/common.yml' + - '.github/workflows/common_cocoapods.yml' - 'Gemfile*' schedule: # Run every day at 11pm (PST) - cron uses UTC times @@ -31,29 +36,13 @@ jobs: target: FirebaseAppCheck-Unit-unit pod_lib_lint: - # Don't run on private repo unless it is a PR. - if: (github.repository == 'Firebase/firebase-ios-sdk' && github.event_name == 'schedule') || github.event_name == 'pull_request' strategy: matrix: - podspec: [FirebaseAppCheckInterop.podspec, FirebaseAppCheck.podspec] - target: [ios, tvos, macos --skip-tests, watchos] - build-env: - - os: macos-14 - xcode: Xcode_16.2 - - os: macos-15 - xcode: Xcode_16.2 - runs-on: ${{ matrix.build-env.os }} - steps: - - uses: actions/checkout@v4 - - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1 - - name: Setup Bundler - run: scripts/setup_bundler.sh - - name: Configure test keychain - run: scripts/configure_test_keychain.sh - - name: Xcode - run: sudo xcode-select -s /Applications/${{ matrix.build-env.xcode }}.app/Contents/Developer - - name: FirebaseAppCheck - run: scripts/third_party/travis/retry.sh scripts/pod_lib_lint.rb ${{ matrix.podspec }} --platforms=${{ matrix.target }} + product: [FirebaseAppCheckInterop, FirebaseAppCheck] + uses: ./.github/workflows/common_cocoapods.yml + with: + product: ${{ matrix.product }} + buildonly_platforms: macOS diagnostics: # Don't run on private repo unless it is a PR. diff --git a/.github/workflows/firebaseai.yml b/.github/workflows/firebaseai.yml index 71c0f1341e6..1184ce74897 100644 --- a/.github/workflows/firebaseai.yml +++ b/.github/workflows/firebaseai.yml @@ -5,6 +5,8 @@ on: paths: - 'FirebaseAI**' - '.github/workflows/firebaseai.yml' + - '.github/workflows/common.yml' + - '.github/workflows/common_cocoapods.yml' - 'scripts/quickstart_build_spm.sh' - 'scripts/quickstart_spm_xcodeproj.sh' - 'Gemfile*' @@ -24,80 +26,11 @@ permissions: actions: write # Needed for actions/cache (save and restore) jobs: - spm-package-resolved: - runs-on: macos-14 - outputs: - cache_key: ${{ steps.generate_cache_key.outputs.cache_key }} - env: - FIREBASECI_USE_LATEST_GOOGLEAPPMEASUREMENT: 1 - steps: - - uses: actions/checkout@v4 - - name: Generate Swift Package.resolved - id: swift_package_resolve - run: | - swift package resolve - - name: Generate cache key - id: generate_cache_key - run: | - cache_key="${{ runner.os }}-spm-${{ hashFiles('**/Package.resolved') }}" - echo "cache_key=${cache_key}" >> "$GITHUB_OUTPUT" - - uses: actions/cache/save@v4 - id: cache - with: - path: .build - key: ${{ steps.generate_cache_key.outputs.cache_key }} - - spm-unit: - strategy: - matrix: - include: - - os: macos-14 - xcode: Xcode_16.2 - target: iOS - - os: macos-15 - xcode: Xcode_16.3 - target: iOS - - os: macos-15 - xcode: Xcode_16.3 - target: tvOS - - os: macos-15 - xcode: Xcode_16.3 - target: macOS - - os: macos-15 - xcode: Xcode_16.3 - target: watchOS - - os: macos-15 - xcode: Xcode_16.3 - target: catalyst - - os: macos-15 - xcode: Xcode_16.3 - target: visionOS - runs-on: ${{ matrix.os }} - needs: spm-package-resolved - env: - FIREBASECI_USE_LATEST_GOOGLEAPPMEASUREMENT: 1 - steps: - - uses: actions/checkout@v4 - - uses: actions/cache/restore@v4 - with: - path: .build - key: ${{needs.spm-package-resolved.outputs.cache_key}} - - name: Clone mock responses - run: scripts/update_vertexai_responses.sh - - name: Xcode - run: sudo xcode-select -s /Applications/${{ matrix.xcode }}.app/Contents/Developer - - name: Install visionOS, if needed. - if: matrix.target == 'visionOS' - run: xcodebuild -downloadPlatform visionOS - - name: Initialize xcodebuild - run: scripts/setup_spm_tests.sh - - uses: nick-fields/retry@ce71cc2ab81d554ebbe88c79ab5975992d79ba08 # v3 - with: - timeout_minutes: 120 - max_attempts: 3 - retry_on: error - retry_wait_seconds: 120 - command: scripts/build.sh FirebaseAIUnit ${{ matrix.target }} spm + spm: + uses: ./.github/workflows/common.yml + with: + target: FirebaseAIUnit + setup_command: scripts/update_vertexai_responses.sh testapp-integration: strategy: @@ -108,7 +41,7 @@ jobs: - os: macos-15 xcode: Xcode_16.3 runs-on: ${{ matrix.os }} - needs: spm-package-resolved + needs: spm env: TEST_RUNNER_FIRAAppCheckDebugToken: ${{ secrets.VERTEXAI_INTEGRATION_FAC_DEBUG_TOKEN }} TEST_RUNNER_VTXIntegrationImagen: ${{ github.event_name == 'schedule' || github.event_name == 'workflow_dispatch' }} @@ -119,7 +52,7 @@ jobs: - uses: actions/cache/restore@v4 with: path: .build - key: ${{needs.spm-package-resolved.outputs.cache_key}} + key: ${{ needs.spm.outputs.cache_key }} - name: Install Secret GoogleService-Info.plist run: scripts/decrypt_gha_secret.sh scripts/gha-encrypted/VertexAI/TestApp-GoogleService-Info.plist.gpg \ FirebaseAI/Tests/TestApp/Resources/GoogleService-Info.plist "$secrets_passphrase" @@ -141,38 +74,12 @@ jobs: path: xcodebuild-*.log retention-days: 2 - pod-lib-lint: - # Don't run on private repo unless it is a PR. - if: (github.repository == 'Firebase/firebase-ios-sdk' && github.event_name == 'schedule') || github.event_name == 'pull_request' - strategy: - matrix: - include: - - os: macos-14 - xcode: Xcode_16.2 - swift_version: 5.9 - warnings: - - os: macos-15 - xcode: Xcode_16.3 - swift_version: 5.9 - warnings: - - os: macos-15 - xcode: Xcode_16.3 - swift_version: 6.0 - warnings: - runs-on: ${{ matrix.os }} - steps: - - uses: actions/checkout@v4 - - name: Clone mock responses - run: scripts/update_vertexai_responses.sh - - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1 - - name: Setup Bundler - run: scripts/setup_bundler.sh - - name: Xcode - run: sudo xcode-select -s /Applications/${{ matrix.xcode }}.app/Contents/Developer - - name: Set Swift swift_version - run: sed -i "" "s#s.swift_version = '5.9'#s.swift_version = '${{ matrix.swift_version}}'#" FirebaseAI.podspec - - name: Build and test - run: scripts/third_party/travis/retry.sh scripts/pod_lib_lint.rb FirebaseAI.podspec --platforms=${{ matrix.target }} ${{ matrix.warnings }} + pod_lib_lint: + uses: ./.github/workflows/common_cocoapods.yml + with: + product: FirebaseAI + supports_swift6: true + setup_command: scripts/update_vertexai_responses.sh quickstart: runs-on: macos-15 diff --git a/.github/workflows/functions.yml b/.github/workflows/functions.yml index ffb82914e53..bd279cb3f55 100644 --- a/.github/workflows/functions.yml +++ b/.github/workflows/functions.yml @@ -1,5 +1,8 @@ name: functions +permissions: + contents: read + on: workflow_dispatch: pull_request: @@ -7,6 +10,8 @@ on: - 'FirebaseFunctions**' - 'FirebaseSharedSwift**' - '.github/workflows/functions.yml' + - '.github/workflows/common.yml' + - '.github/workflows/common_cocoapods.yml' - 'FirebaseAuth/Interop/*.h' - 'FirebaseMessaging/Interop/*.h' - 'FirebaseTestingSupport/Functions/**' @@ -23,34 +28,12 @@ concurrency: cancel-in-progress: true jobs: - - pod-lib-lint: - # Don't run on private repo unless it is a PR. - if: (github.repository == 'Firebase/firebase-ios-sdk' && github.event_name == 'schedule') || github.event_name == 'pull_request' - - strategy: - matrix: - target: [ios, tvos, macos, watchos] - swift_version: [5.9, 6.0] - build-env: - - os: macos-15 - xcode: Xcode_16.3 - runs-on: ${{ matrix.build-env.os }} - steps: - - uses: actions/checkout@v4 - - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1 - - name: Xcode - run: sudo xcode-select -s /Applications/${{ matrix.build-env.xcode }}.app/Contents/Developer - - name: Setup Bundler - run: scripts/setup_bundler.sh - - name: Integration Test Server - run: FirebaseFunctions/Backend/start.sh synchronous - - name: Set Swift swift_version - run: sed -i "" "s/s.swift_version[[:space:]]*=[[:space:]]*'5.9'/s.swift_version = '${{ matrix.swift_version }}'/" FirebaseFunctions.podspec - - name: Build and test - run: | - scripts/third_party/travis/retry.sh scripts/pod_lib_lint.rb FirebaseFunctions.podspec \ - --platforms=${{ matrix.target }} + pod_lib_lint: + uses: ./.github/workflows/common_cocoapods.yml + with: + product: FirebaseFunctions + supports_swift6: true + setup_command: FirebaseFunctions/Backend/start.sh synchronous spm-package-resolved: runs-on: macos-14 @@ -227,7 +210,7 @@ jobs: flags: [ '--use-static-frameworks', ] - needs: pod-lib-lint + needs: pod_lib_lint steps: - uses: actions/checkout@v4 - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1 diff --git a/.github/workflows/inappmessaging.yml b/.github/workflows/inappmessaging.yml index 363b0f16ba6..6650fbb8fc9 100644 --- a/.github/workflows/inappmessaging.yml +++ b/.github/workflows/inappmessaging.yml @@ -1,5 +1,8 @@ name: inappmessaging +permissions: + contents: read + on: workflow_dispatch: pull_request: @@ -7,6 +10,8 @@ on: - 'FirebaseInAppMessaging**' - 'Interop/Analytics/Public/*.h' - '.github/workflows/inappmessaging.yml' + - '.github/workflows/common.yml' + - '.github/workflows/common_cocoapods.yml' - 'Gemfile*' schedule: # Run every day at 10pm (PST) - cron uses UTC times @@ -25,27 +30,10 @@ jobs: buildonly_platforms: iOS pod_lib_lint: - # Don't run on private repo unless it is a PR. - if: (github.repository == 'Firebase/firebase-ios-sdk' && github.event_name == 'schedule') || github.event_name == 'pull_request' - - strategy: - matrix: - podspec: [FirebaseInAppMessaging.podspec] - build-env: - - os: macos-14 - xcode: Xcode_16.2 - - os: macos-15 - xcode: Xcode_16.2 - runs-on: ${{ matrix.build-env.os }} - steps: - - uses: actions/checkout@v4 - - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1 - - name: Xcode - run: sudo xcode-select -s /Applications/${{ matrix.build-env.xcode }}.app/Contents/Developer - - name: Setup Bundler - run: scripts/setup_bundler.sh - - name: FirebaseInAppMessaging - run: scripts/third_party/travis/retry.sh scripts/pod_lib_lint.rb ${{ matrix.podspec}} + uses: ./.github/workflows/common_cocoapods.yml + with: + product: FirebaseInAppMessaging + platforms: iOS, tvOS tests: # Don't run on private repo unless it is a PR. diff --git a/.github/workflows/messaging.yml b/.github/workflows/messaging.yml index 22728cbfa03..71d8c111578 100644 --- a/.github/workflows/messaging.yml +++ b/.github/workflows/messaging.yml @@ -1,5 +1,8 @@ name: messaging +permissions: + contents: read + on: workflow_dispatch: pull_request: @@ -12,6 +15,9 @@ on: - 'FirebaseMessaging.podspec' # This file - '.github/workflows/messaging.yml' + # Re-usable workflows being used by this file. + - '.github/workflows/common.yml' + - '.github/workflows/common_cocoapods.yml' # Rebuild on Ruby infrastructure changes - 'Gemfile*' schedule: @@ -35,6 +41,14 @@ jobs: product: FirebaseMessaging target: FirebaseMessaging-Unit-unit + pod_lib_lint: + strategy: + matrix: + product: [FirebaseMessagingInterop, FirebaseMessaging] + uses: ./.github/workflows/common_cocoapods.yml + with: + product: ${{ matrix.product }} + # TODO(#12205) Update the build.sh script for this job from "test" instead of "build" messaging-integration-tests: # Don't run on private repo unless it is a PR. @@ -64,31 +78,6 @@ jobs: - name: BuildAndTest run: ([ -z $plist_secret ] || scripts/third_party/travis/retry.sh scripts/build.sh Messaging all) - pod-lib-lint: - # Don't run on private repo unless it is a PR. - if: (github.repository == 'Firebase/firebase-ios-sdk' && github.event_name == 'schedule') || github.event_name == 'pull_request' - strategy: - matrix: - podspec: [FirebaseMessagingInterop.podspec, FirebaseMessaging.podspec] - target: [ios, tvos, macos --skip-tests, watchos --skip-tests] # skipping tests on mac because of keychain access - build-env: - - os: macos-14 - xcode: Xcode_16.2 - tests: --test-specs=unit - - os: macos-15 - xcode: Xcode_16.3 - tests: --skip-tests - runs-on: ${{ matrix.build-env.os }} - steps: - - uses: actions/checkout@v4 - - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1 - - name: Setup Bundler - run: scripts/setup_bundler.sh - - name: Xcode - run: sudo xcode-select -s /Applications/${{ matrix.build-env.xcode }}.app/Contents/Developer - - name: Build and test - run: scripts/third_party/travis/retry.sh scripts/pod_lib_lint.rb ${{ matrix.podspec }} ${{ matrix.build-env.tests }} --platforms=${{ matrix.target }} - quickstart: # Don't run on private repo unless it is a PR. if: (github.repository == 'Firebase/firebase-ios-sdk' && github.event_name == 'schedule') || github.event_name == 'pull_request' diff --git a/.github/workflows/performance.yml b/.github/workflows/performance.yml index cefd7fb083c..b5e0beea295 100644 --- a/.github/workflows/performance.yml +++ b/.github/workflows/performance.yml @@ -2,6 +2,9 @@ # Reference: https://github.community/t/on-schedule-per-branch/17525 name: performance +permissions: + contents: read + on: workflow_dispatch: pull_request: @@ -12,6 +15,9 @@ on: - 'FirebasePerformance.podspec' # YML configuration file - '.github/workflows/performance.yml' + # Re-usable workflows depended on by this file. + - '.github/workflows/common.yml' + - '.github/workflows/common_cocoapods.yml' # Rebuild on Ruby infrastructure changes - 'Gemfile*' schedule: @@ -61,30 +67,13 @@ jobs: - name: BuildAndTest # can be replaced with pod lib lint with CocoaPods 1.10 run: scripts/third_party/travis/retry.sh scripts/build.sh Performance ${{ matrix.target }} ${{ matrix.test }} - # Podspec lint check for Firebase Performance - pod-lib-lint: - # Don't run on private repo unless it is a PR. - if: (github.repository == 'Firebase/firebase-ios-sdk' && github.event_name == 'schedule') || github.event_name == 'pull_request' - - strategy: - matrix: - target: [ios, tvos] - build-env: - - os: macos-14 - xcode: Xcode_16.2 - - os: macos-15 - xcode: Xcode_16.3 - runs-on: ${{ matrix.build-env.os }} - steps: - - uses: actions/checkout@v4 - - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1 - - name: Setup Bundler - run: scripts/setup_bundler.sh - - name: Xcode - run: sudo xcode-select -s /Applications/${{ matrix.build-env.xcode }}.app/Contents/Developer - - name: Build - #TODO: tests are not supported with Xcode 15 because the test spec depends on the iOS 8 GDCWebServer - run: scripts/third_party/travis/retry.sh scripts/pod_lib_lint.rb FirebasePerformance.podspec --skip-tests --platforms=${{ matrix.target }} + pod_lib_lint: + uses: ./.github/workflows/common_cocoapods.yml + with: + product: FirebasePerformance + platforms: iOS, tvOS + #TODO: tests are not supported with Xcode 15 because the test spec depends on the iOS 8 GDCWebServer + buildonly_platforms: iOS, tvOS quickstart: if: (github.repository == 'Firebase/firebase-ios-sdk' && github.event_name == 'schedule') || github.event_name == 'pull_request' @@ -150,7 +139,7 @@ jobs: flags: [ '--skip-tests --use-static-frameworks' ] - needs: pod-lib-lint + needs: pod_lib_lint steps: - uses: actions/checkout@v4 - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1 diff --git a/.github/workflows/remoteconfig.yml b/.github/workflows/remoteconfig.yml index 97bc71bb88b..3f23f427b3a 100644 --- a/.github/workflows/remoteconfig.yml +++ b/.github/workflows/remoteconfig.yml @@ -1,5 +1,8 @@ name: remoteconfig +permissions: + contents: read + on: workflow_dispatch: pull_request: @@ -7,6 +10,8 @@ on: - 'FirebaseRemoteConfig**' - 'Interop/Analytics/Public/*.h' - '.github/workflows/remoteconfig.yml' + - '.github/workflows/common.yml' + - '.github/workflows/common_cocoapods.yml' - 'Gemfile*' - 'scripts/generate_access_token.sh' - 'scripts/gha-encrypted/RemoteConfigSwiftAPI/**' @@ -72,34 +77,10 @@ jobs: # No retry to avoid exhausting AccessToken quota. run: ([ -z $plist_secret ] || scripts/build.sh RemoteConfig iOS integration) - pod-lib-lint: - # Don't run on private repo unless it is a PR. - if: (github.repository == 'Firebase/firebase-ios-sdk' && github.event_name == 'schedule') || github.event_name == 'pull_request' - - strategy: - matrix: - # TODO: macos tests are blocked by https://github.com/erikdoe/ocmock/pull/532 - target: [ios, tvos, macos --skip-tests, watchos] - podspec: [FirebaseRemoteConfig.podspec] - build-env: - - os: macos-14 - xcode: Xcode_16.2 - # Flaky tests on CI - - os: macos-15 - xcode: Xcode_16.3 - tests: --skip-tests - runs-on: ${{ matrix.build-env.os }} - steps: - - uses: actions/checkout@v4 - - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1 - - name: Setup Bundler - run: scripts/setup_bundler.sh - - name: Xcode - run: sudo xcode-select -s /Applications/${{ matrix.build-env.xcode }}.app/Contents/Developer - - name: Build and test - run: | - scripts/third_party/travis/retry.sh scripts/pod_lib_lint.rb ${{ matrix.podspec }} --platforms=${{ matrix.target }} \ - ${{ matrix.build-env.tests }} + pod_lib_lint: + uses: ./.github/workflows/common_cocoapods.yml + with: + product: FirebaseRemoteConfig quickstart: # Don't run on private repo unless it is a PR. @@ -178,7 +159,7 @@ jobs: flags: [ '--skip-tests --use-static-frameworks' ] - needs: pod-lib-lint + needs: pod_lib_lint steps: - uses: actions/checkout@v4 - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1 diff --git a/.github/workflows/sessions.yml b/.github/workflows/sessions.yml index 055f604457b..976b3886c1f 100644 --- a/.github/workflows/sessions.yml +++ b/.github/workflows/sessions.yml @@ -1,5 +1,8 @@ name: sessions +permissions: + contents: read + on: workflow_dispatch: pull_request: @@ -7,6 +10,8 @@ on: - 'FirebaseSessions**' - 'FirebaseSessions.podspec' - '.github/workflows/sessions.yml' + - '.github/workflows/common.yml' + - '.github/workflows/common_cocoapods.yml' - 'Gemfile*' schedule: # Run every day at 9am (PST) - cron uses UTC times @@ -28,42 +33,8 @@ jobs: product: FirebaseSessions target: FirebaseSessions-Unit-unit - pod-lib-lint: - # Don't run on private repo unless it is a PR. - if: (github.repository == 'Firebase/firebase-ios-sdk' && github.event_name == 'schedule') || github.event_name == 'pull_request' - - strategy: - matrix: - target: [ios, tvos, macos, watchos] - build-env: - - os: macos-14 - xcode: Xcode_16.2 - tests: - swift_version: 5.9 - # Flaky tests on CI - - os: macos-15 - xcode: Xcode_16.3 - tests: --skip-tests - swift_version: 5.9 - # Flaky tests on CI - - os: macos-15 - xcode: Xcode_16.2 - tests: --skip-tests - swift_version: 6.0 - runs-on: ${{ matrix.build-env.os }} - steps: - - uses: actions/checkout@v4 - - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1 - - name: Setup Bundler - run: scripts/setup_bundler.sh - - name: Xcode - run: sudo xcode-select -s /Applications/${{ matrix.build-env.xcode }}.app/Contents/Developer - - name: Set Swift swift_version - run: sed -i "" "s/s.swift_version[[:space:]]*=[[:space:]]*'5.9'/s.swift_version = '${{ matrix.build-env.swift_version }}'/" FirebaseSessions.podspec - - uses: nick-fields/retry@ce71cc2ab81d554ebbe88c79ab5975992d79ba08 # v3 - with: - timeout_minutes: 120 - max_attempts: 3 - retry_on: error - retry_wait_seconds: 120 - command: scripts/third_party/travis/retry.sh scripts/pod_lib_lint.rb FirebaseSessions.podspec --platforms=${{ matrix.target }} ${{ matrix.build-env.tests }} + pod_lib_lint: + uses: ./.github/workflows/common_cocoapods.yml + with: + product: FirebaseSessions + supports_swift6: true diff --git a/.github/workflows/shared-swift.yml b/.github/workflows/shared-swift.yml index 2cba3d10649..b1292ebb253 100644 --- a/.github/workflows/shared-swift.yml +++ b/.github/workflows/shared-swift.yml @@ -1,11 +1,16 @@ name: shared-swift +permissions: + contents: read + on: workflow_dispatch: pull_request: paths: - 'FirebaseSharedSwift**' - '.github/workflows/shared-swift.yml' + - '.github/workflows/common.yml' + - '.github/workflows/common_cocoapods.yml' - 'Gemfile*' schedule: @@ -22,32 +27,8 @@ jobs: with: target: FirebaseSharedSwiftTests - pod-lib-lint: - # Don't run on private repo unless it is a PR. - if: (github.repository == 'Firebase/firebase-ios-sdk' && github.event_name == 'schedule') || github.event_name == 'pull_request' - - strategy: - matrix: - target: [ios, tvos, macos, watchos] - build-env: - - os: macos-14 - xcode: Xcode_16.2 - swift_version: 5.9 - - os: macos-15 - xcode: Xcode_16.2 - swift_version: 5.9 - - os: macos-15 - xcode: Xcode_16.3 - swift_version: 6.0 - runs-on: ${{ matrix.build-env.os }} - steps: - - uses: actions/checkout@v4 - - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1 - - name: Setup Bundler - run: scripts/setup_bundler.sh - - name: Xcode - run: sudo xcode-select -s /Applications/${{ matrix.build-env.xcode }}.app/Contents/Developer - - name: Set Swift swift_version - run: sed -i "" "s/s.swift_version[[:space:]]*=[[:space:]]*'5.9'/s.swift_version = '${{ matrix.build-env.swift_version }}'/" FirebaseSharedSwift.podspec - - name: Build and test - run: scripts/third_party/travis/retry.sh scripts/pod_lib_lint.rb FirebaseSharedSwift.podspec --platforms=${{ matrix.target }} + pod_lib_lint: + uses: ./.github/workflows/common_cocoapods.yml + with: + product: FirebaseSharedSwift + supports_swift6: true diff --git a/.github/workflows/vertexai.yml b/.github/workflows/vertexai.yml index 32d25b6a2fd..c5db31d75df 100644 --- a/.github/workflows/vertexai.yml +++ b/.github/workflows/vertexai.yml @@ -1,11 +1,16 @@ name: vertexai +permissions: + contents: read + on: pull_request: paths: - 'FirebaseAI**' - 'FirebaseVertexAI**' - '.github/workflows/vertexai.yml' + - '.github/workflows/common.yml' + - '.github/workflows/common_cocoapods.yml' - 'Gemfile*' schedule: # Run every day at 11pm (PST) - cron uses UTC times @@ -17,106 +22,13 @@ concurrency: cancel-in-progress: true jobs: - spm-package-resolved: - runs-on: macos-14 - outputs: - cache_key: ${{ steps.generate_cache_key.outputs.cache_key }} - env: - FIREBASECI_USE_LATEST_GOOGLEAPPMEASUREMENT: 1 - steps: - - uses: actions/checkout@v4 - - name: Generate Swift Package.resolved - id: swift_package_resolve - run: | - swift package resolve - - name: Generate cache key - id: generate_cache_key - run: | - cache_key="${{ runner.os }}-spm-${{ hashFiles('**/Package.resolved') }}" - echo "cache_key=${cache_key}" >> "$GITHUB_OUTPUT" - - uses: actions/cache/save@v4 - id: cache - with: - path: .build - key: ${{ steps.generate_cache_key.outputs.cache_key }} - - spm-unit: - strategy: - matrix: - include: - - os: macos-14 - xcode: Xcode_16.2 - target: iOS - - os: macos-15 - xcode: Xcode_16.3 - target: iOS - - os: macos-15 - xcode: Xcode_16.3 - target: tvOS - - os: macos-15 - xcode: Xcode_16.3 - target: macOS - - os: macos-15 - xcode: Xcode_16.3 - target: watchOS - - os: macos-15 - xcode: Xcode_16.3 - target: catalyst - - os: macos-15 - xcode: Xcode_16.3 - target: visionOS - runs-on: ${{ matrix.os }} - needs: spm-package-resolved - env: - FIREBASECI_USE_LATEST_GOOGLEAPPMEASUREMENT: 1 - steps: - - uses: actions/checkout@v4 - - uses: actions/cache/restore@v4 - with: - path: .build - key: ${{needs.spm-package-resolved.outputs.cache_key}} - - name: Xcode - run: sudo xcode-select -s /Applications/${{ matrix.xcode }}.app/Contents/Developer - - name: Install visionOS, if needed. - if: matrix.target == 'visionOS' - run: xcodebuild -downloadPlatform visionOS - - name: Initialize xcodebuild - run: scripts/setup_spm_tests.sh - - uses: nick-fields/retry@ce71cc2ab81d554ebbe88c79ab5975992d79ba08 # v3 - with: - timeout_minutes: 120 - max_attempts: 3 - retry_on: error - retry_wait_seconds: 120 - command: scripts/build.sh FirebaseVertexAIUnit ${{ matrix.target }} spm + spm: + uses: ./.github/workflows/common.yml + with: + target: FirebaseVertexAIUnit - pod-lib-lint: - # Don't run on private repo unless it is a PR. - if: (github.repository == 'Firebase/firebase-ios-sdk' && github.event_name == 'schedule') || github.event_name == 'pull_request' - strategy: - matrix: - include: - - os: macos-14 - xcode: Xcode_16.2 - swift_version: 5.9 - warnings: - - os: macos-15 - xcode: Xcode_16.3 - swift_version: 5.9 - warnings: - - os: macos-15 - xcode: Xcode_16.3 - swift_version: 6.0 - warnings: - runs-on: ${{ matrix.os }} - steps: - - uses: actions/checkout@v4 - - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1 - - name: Setup Bundler - run: scripts/setup_bundler.sh - - name: Xcode - run: sudo xcode-select -s /Applications/${{ matrix.xcode }}.app/Contents/Developer - - name: Set Swift swift_version - run: sed -i "" "s#s.swift_version = '5.9'#s.swift_version = '${{ matrix.swift_version}}'#" FirebaseVertexAI.podspec - - name: Build and test - run: scripts/third_party/travis/retry.sh scripts/pod_lib_lint.rb FirebaseVertexAI.podspec --platforms=${{ matrix.target }} ${{ matrix.warnings }} + pod_lib_lint: + uses: ./.github/workflows/common_cocoapods.yml + with: + product: FirebaseVertexAI + supports_swift6: true diff --git a/FirebaseMessaging/Tests/UnitTests/FIRMessagingRemoteNotificationsProxyTest.m b/FirebaseMessaging/Tests/UnitTests/FIRMessagingRemoteNotificationsProxyTest.m index 3233358a2d0..a8ed4fa3032 100644 --- a/FirebaseMessaging/Tests/UnitTests/FIRMessagingRemoteNotificationsProxyTest.m +++ b/FirebaseMessaging/Tests/UnitTests/FIRMessagingRemoteNotificationsProxyTest.m @@ -191,6 +191,8 @@ - (void)testSwizzlingNonAppDelegate { #if !SWIFT_PACKAGE // The next 3 tests depend on a sharedApplication which is not available in the Swift PM test env. + +#if !TARGET_OS_OSX - (void)testSwizzledIncompleteAppDelegateRemoteNotificationMethod { XCTestExpectation *expectation = [self expectationWithDescription:@"completion"]; IncompleteAppDelegate *incompleteAppDelegate = [[IncompleteAppDelegate alloc] init]; @@ -209,6 +211,7 @@ - (void)testSwizzledIncompleteAppDelegateRemoteNotificationMethod { [self.mockMessaging verify]; [self waitForExpectationsWithTimeout:0.5 handler:nil]; } +#endif // !TARGET_OS_OSX // This test demonstrates the difference between Firebase 10 and 11. In 10 and earlier the // swizzler inserts the old `didReceiveRemoteNotification` method. In 11, the new. @@ -232,10 +235,9 @@ - (void)testSwizzledAppDelegateRemoteNotificationMethods { [[GULAppDelegateSwizzler sharedApplication] setDelegate:appDelegate]; [self.proxy swizzleMethodsIfPossible]; - NSDictionary *notification = @{@"test" : @""}; - // Test application:didReceiveRemoteNotification:fetchCompletionHandler: #if TARGET_OS_IOS || TARGET_OS_TV + NSDictionary *notification = @{@"test" : @""}; // Verify our swizzled method was called OCMExpect([self.mockMessaging appDidReceiveMessage:notification]); From 379bcc9abfe7a221d04041d68cc01d0060b486d8 Mon Sep 17 00:00:00 2001 From: Nick Cooke <36927374+ncooke3@users.noreply.github.com> Date: Wed, 28 May 2025 17:53:49 -0400 Subject: [PATCH 046/113] [Infra] Migrate .github/workflows/functions.yml to reusable workflows (#14906) --- .github/workflows/functions.yml | 103 +++----------------------------- 1 file changed, 9 insertions(+), 94 deletions(-) diff --git a/.github/workflows/functions.yml b/.github/workflows/functions.yml index bd279cb3f55..c7a8b6e54ca 100644 --- a/.github/workflows/functions.yml +++ b/.github/workflows/functions.yml @@ -35,105 +35,20 @@ jobs: supports_swift6: true setup_command: FirebaseFunctions/Backend/start.sh synchronous - spm-package-resolved: - runs-on: macos-14 - env: - FIREBASECI_USE_LATEST_GOOGLEAPPMEASUREMENT: 1 - outputs: - cache_key: ${{ steps.generate_cache_key.outputs.cache_key }} - steps: - - uses: actions/checkout@v4 - - name: Xcode - run: sudo xcode-select -s /Applications/Xcode_16.2.app/Contents/Developer - - name: Generate Swift Package.resolved - id: swift_package_resolve - run: | - swift package resolve - - name: Generate cache key - id: generate_cache_key - run: | - cache_key="${{ runner.os }}-spm-${{ hashFiles('**/Package.resolved') }}" - echo "cache_key=${cache_key}" >> "$GITHUB_OUTPUT" - - uses: actions/cache/save@v4 - id: cache - with: - path: .build - key: ${{ steps.generate_cache_key.outputs.cache_key }} - spm-integration: - # Don't run on private repo unless it is a PR. - if: (github.repository == 'Firebase/firebase-ios-sdk' && github.event_name == 'schedule') || github.event_name == 'pull_request' - needs: [spm-package-resolved] + uses: ./.github/workflows/common.yml strategy: matrix: - os: [macos-15] - xcode: [Xcode_16.3] - runs-on: ${{ matrix.os }} - env: - FIREBASECI_USE_LATEST_GOOGLEAPPMEASUREMENT: 1 - steps: - - uses: actions/checkout@v4 - - uses: actions/cache/restore@v4 - with: - path: .build - key: ${{needs.spm-package-resolved.outputs.cache_key}} - - name: Initialize xcodebuild - run: scripts/setup_spm_tests.sh - - name: Integration Test Server - run: FirebaseFunctions/Backend/start.sh synchronous - - name: Xcode - run: sudo xcode-select -s /Applications/${{ matrix.xcode }}.app/Contents/Developer - - name: iOS Swift Integration Tests (including Swift library) - run: scripts/third_party/travis/retry.sh ./scripts/build.sh FirebaseFunctionsIntegration iOS spm - - name: iOS ObjC Integration Tests (using Swift library) - run: scripts/third_party/travis/retry.sh ./scripts/build.sh FirebaseFunctionsObjCIntegration iOS spm - - name: Combine Unit Tests - run: scripts/third_party/travis/retry.sh ./scripts/build.sh FunctionsCombineUnit iOS spm + target: [FirebaseFunctionsIntegration, FirebaseFunctionsObjCIntegration, FunctionsCombineUnit] + with: + target: ${{ matrix.target }} + platforms: iOS + setup_command: FirebaseFunctions/Backend/start.sh synchronous spm-unit: - # Don't run on private repo. - if: (github.repository == 'Firebase/firebase-ios-sdk' && github.event_name == 'schedule') || github.event_name == 'pull_request' - needs: [spm-package-resolved] - strategy: - matrix: - include: - - os: macos-14 - xcode: Xcode_16.2 - target: iOS - - os: macos-15 - xcode: Xcode_16.3 - target: iOS - - os: macos-15 - xcode: Xcode_16.3 - target: tvOS - - os: macos-15 - xcode: Xcode_16.3 - target: macOS - - os: macos-15 - xcode: Xcode_16.3 - target: watchOS - - os: macos-15 - xcode: Xcode_16.3 - target: catalyst - - os: macos-15 - xcode: Xcode_16.3 - target: visionOS - runs-on: ${{ matrix.os }} - steps: - - uses: actions/checkout@v4 - - uses: actions/cache/restore@v4 - with: - path: .build - key: ${{needs.spm-package-resolved.outputs.cache_key}} - - name: Xcode - run: sudo xcode-select -s /Applications/${{ matrix.xcode }}.app/Contents/Developer - - name: Install visionOS, if needed. - if: matrix.target == 'visionOS' - run: xcodebuild -downloadPlatform visionOS - - name: Initialize xcodebuild - run: scripts/setup_spm_tests.sh - - name: Unit Tests - run: scripts/third_party/travis/retry.sh ./scripts/build.sh FirebaseFunctionsUnit ${{ matrix.target }} spm + uses: ./.github/workflows/common.yml + with: + target: FirebaseFunctionsUnit # TODO: Move to macos-14 and Xcode 15. The legacy quickstart uses material which doesn't build on Xcode 15. # quickstart: From 19f6c364fd9caee5e139d887ff39c22c62c75784 Mon Sep 17 00:00:00 2001 From: Nick Cooke <36927374+ncooke3@users.noreply.github.com> Date: Wed, 28 May 2025 17:54:19 -0400 Subject: [PATCH 047/113] [Infra] Remove dupe job in .github/workflows/auth.yml (#14907) --- .github/workflows/auth.yml | 29 ++--------------------------- 1 file changed, 2 insertions(+), 27 deletions(-) diff --git a/.github/workflows/auth.yml b/.github/workflows/auth.yml index 31a5f7584e9..8426fefcfbe 100644 --- a/.github/workflows/auth.yml +++ b/.github/workflows/auth.yml @@ -48,35 +48,10 @@ jobs: product: ${{ matrix.product }} buildonly_platforms: macOS - spm-package-resolved: - env: - FIREBASECI_USE_LATEST_GOOGLEAPPMEASUREMENT: 1 - runs-on: macos-15 - outputs: - cache_key: ${{ steps.generate_cache_key.outputs.cache_key }} - steps: - - uses: actions/checkout@v4 - - name: Xcode - run: sudo xcode-select -s /Applications/Xcode_16.2.app/Contents/Developer - - name: Generate Swift Package.resolved - id: swift_package_resolve - run: | - swift package resolve - - name: Generate cache key - id: generate_cache_key - run: | - cache_key="${{ runner.os }}-spm-${{ hashFiles('**/Package.resolved') }}" - echo "cache_key=${cache_key}" >> "$GITHUB_OUTPUT" - - uses: actions/cache/save@v4 - id: cache - with: - path: .build - key: ${{ steps.generate_cache_key.outputs.cache_key }} - integration-tests: # Don't run on private repo unless it is a PR. if: (github.repository == 'Firebase/firebase-ios-sdk' && github.event_name == 'schedule') || github.event_name == 'pull_request' - needs: [spm-package-resolved] + needs: spm strategy: matrix: scheme: [ObjCApiTests, SwiftApiTests, AuthenticationExampleUITests] @@ -89,7 +64,7 @@ jobs: - uses: actions/cache/restore@v4 with: path: .build - key: ${{needs.spm-package-resolved.outputs.cache_key}} + key: ${{ needs.spm.outputs.cache_key }} - name: Install Secrets run: | scripts/decrypt_gha_secret.sh scripts/gha-encrypted/AuthCredentials.h.gpg \ From f8d111e3313907f57c27e8e58f6ddbb5f5f1e2b3 Mon Sep 17 00:00:00 2001 From: Nick Cooke <36927374+ncooke3@users.noreply.github.com> Date: Wed, 28 May 2025 17:54:42 -0400 Subject: [PATCH 048/113] [Infra] Remove dupe job in .github/workflows/core.yml (#14905) --- .github/workflows/core.yml | 25 ------------------------- 1 file changed, 25 deletions(-) diff --git a/.github/workflows/core.yml b/.github/workflows/core.yml index 70b8cb92612..ccaeb26736b 100644 --- a/.github/workflows/core.yml +++ b/.github/workflows/core.yml @@ -37,31 +37,6 @@ jobs: with: product: FirebaseCore - spm-package-resolved: - env: - FIREBASECI_USE_LATEST_GOOGLEAPPMEASUREMENT: 1 - runs-on: macos-15 - outputs: - cache_key: ${{ steps.generate_cache_key.outputs.cache_key }} - steps: - - uses: actions/checkout@v4 - - name: Xcode - run: sudo xcode-select -s /Applications/Xcode_16.2.app/Contents/Developer - - name: Generate Swift Package.resolved - id: swift_package_resolve - run: | - swift package resolve - - name: Generate cache key - id: generate_cache_key - run: | - cache_key="${{ runner.os }}-spm-${{ hashFiles('**/Package.resolved') }}" - echo "cache_key=${cache_key}" >> "$GITHUB_OUTPUT" - - uses: actions/cache/save@v4 - id: cache - with: - path: .build - key: ${{ steps.generate_cache_key.outputs.cache_key }} - core-cron-only: # Don't run on private repo. if: github.event_name == 'schedule' && github.repository == 'Firebase/firebase-ios-sdk' From dba523833392952a6e23a53869c677b59c02ec38 Mon Sep 17 00:00:00 2001 From: Paul Beusterien Date: Wed, 28 May 2025 16:13:01 -0700 Subject: [PATCH 049/113] Update bug report template for Firebase AI Logic (#14908) --- .github/ISSUE_TEMPLATE/BUG_REPORT.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/ISSUE_TEMPLATE/BUG_REPORT.yml b/.github/ISSUE_TEMPLATE/BUG_REPORT.yml index 83e260c83f1..0bf195312d7 100644 --- a/.github/ISSUE_TEMPLATE/BUG_REPORT.yml +++ b/.github/ISSUE_TEMPLATE/BUG_REPORT.yml @@ -68,6 +68,7 @@ body: multiple: true options: - AB Testing + - AI Logic - Analytics - App Check - App Distribution @@ -85,7 +86,6 @@ body: - Performance - Remote Config - Storage - - VertexAI - All - Infrastructure validations: From 4f6ea2463beda57819f003814b619bea0a294cc8 Mon Sep 17 00:00:00 2001 From: Andrew Heard Date: Thu, 29 May 2025 15:32:48 -0400 Subject: [PATCH 050/113] [Release] Firestore binaries for `11.14.0` (#14915) --- Package.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Package.swift b/Package.swift index 2595bc2f8bc..84d9b3b3147 100644 --- a/Package.swift +++ b/Package.swift @@ -1614,8 +1614,8 @@ func firestoreTargets() -> [Target] { } else { return .binaryTarget( name: "FirebaseFirestoreInternal", - url: "https://dl.google.com/firebase/ios/bin/firestore/11.13.0/rc0/FirebaseFirestoreInternal.zip", - checksum: "badb559c67f683d546873051642db7eaab3598e50f8095dc15d965d63a695145" + url: "https://dl.google.com/firebase/ios/bin/firestore/11.14.0/rc0/FirebaseFirestoreInternal.zip", + checksum: "c653dfa7f51fc54629bf38ef743831fedeaed251d1b02c0bbb6ecf86dad03929" ) } }() From 16a0fef43fefefc61e698efde3ffc6bae8fee86d Mon Sep 17 00:00:00 2001 From: Nick Cooke <36927374+ncooke3@users.noreply.github.com> Date: Thu, 29 May 2025 15:51:54 -0400 Subject: [PATCH 051/113] [Infra] Make mlmodeldownloader.yml use reusable CocoaPods workflow (#14904) --- .github/workflows/common_cocoapods.yml | 28 +++++++++++++++++ .github/workflows/mlmodeldownloader.yml | 40 ++++++++----------------- 2 files changed, 41 insertions(+), 27 deletions(-) diff --git a/.github/workflows/common_cocoapods.yml b/.github/workflows/common_cocoapods.yml index 6a575554bb4..50834b04431 100644 --- a/.github/workflows/common_cocoapods.yml +++ b/.github/workflows/common_cocoapods.yml @@ -5,6 +5,28 @@ permissions: on: workflow_call: + # Re-usable workflows do not automatically inherit the caller's secrets. + # + # If the calling workflow uses a secret in the `setup_command` input, then + # it also must pass the secret to the re-usable workflow. + # + # Example: + # + # pod_lib_lint: + # uses: ./.github/workflows/common_cocoapods.yml + # with: + # product: FirebaseFoo + # setup_command: | + # scripts/decrypt_gha_secret.sh \ + # /path/to/GoogleService-Info.plist.gpg \ + # /path/to/dest/GoogleService-Info.plist "$plist_secret" + # secrets: + # plist_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} + # + secrets: + plist_secret: + required: false + inputs: # The product to test be tested (e.g. `FirebaseABTesting`). product: @@ -66,6 +88,10 @@ on: # This is useful for additional set up, like starting an emulator or # downloading test data. # + # Note, this step has an env var set to decrypt plists. Use + # "$plist_secret" in the given command. See `secrets` documentation + # at top of this file. + # # Example: `FirebaseFunctions/Backend/start.sh synchronous` setup_command: type: string @@ -101,6 +127,8 @@ jobs: run: sed -i "" "s/s.swift_version[[:space:]]*=[[:space:]]*'5.9'/s.swift_version = '6.0'/" ${{ inputs.product }}.podspec - name: Run setup command, if needed. if: inputs.setup_command != '' + env: + plist_secret: ${{ secrets.plist_secret }} run: ${{ inputs.setup_command }} - uses: nick-fields/retry@ce71cc2ab81d554ebbe88c79ab5975992d79ba08 # v3 if: contains(join(inputs.platforms), matrix.platform) || matrix.os == 'macos-14' diff --git a/.github/workflows/mlmodeldownloader.yml b/.github/workflows/mlmodeldownloader.yml index 7569188c374..6e16642d311 100644 --- a/.github/workflows/mlmodeldownloader.yml +++ b/.github/workflows/mlmodeldownloader.yml @@ -1,11 +1,16 @@ name: mlmodeldownloader +permissions: + contents: read + on: workflow_dispatch: pull_request: paths: - 'FirebaseMLModelDownloader**' - '.github/workflows/mlmodeldownloader.yml' + - '.github/workflows/common.yml' + - '.github/workflows/common_cocoapods.yml' - 'Gemfile*' schedule: # Run every day at 11pm (PST) - cron uses UTC times @@ -27,35 +32,16 @@ jobs: product: FirebaseMLModelDownloader target: FirebaseMLModelDownloader-Unit-unit - pod-lib-lint: - if: (github.repository == 'Firebase/firebase-ios-sdk' && github.event_name == 'schedule') || github.event_name == 'pull_request' - env: - plist_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} - strategy: - matrix: - target: [ios, tvos, macos, watchos] - build-env: - - os: macos-14 - xcode: Xcode_16.2 - - os: macos-15 - xcode: Xcode_16.2 - runs-on: ${{ matrix.build-env.os }} - steps: - - uses: actions/checkout@v4 - - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1 - - name: Setup Bundler - run: scripts/setup_bundler.sh - - name: Configure test keychain - run: scripts/configure_test_keychain.sh - - name: Install GoogleService-Info.plist - run: | + pod_lib_lint: + uses: ./.github/workflows/common_cocoapods.yml + with: + product: FirebaseMLModelDownloader + setup_command: | mkdir FirebaseMLModelDownloader/Tests/Integration/Resources scripts/decrypt_gha_secret.sh scripts/gha-encrypted/MLModelDownloader/GoogleService-Info.plist.gpg \ FirebaseMLModelDownloader/Tests/Integration/Resources/GoogleService-Info.plist "$plist_secret" - - name: Xcode - run: sudo xcode-select -s /Applications/${{ matrix.build-env.xcode }}.app/Contents/Developer - - name: Build and test - run: ([ -z $plist_secret ] || scripts/third_party/travis/retry.sh scripts/pod_lib_lint.rb FirebaseMLModelDownloader.podspec --platforms=${{ matrix.target }}) + secrets: + plist_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} mlmodeldownloader-cron-only: if: github.event_name == 'schedule' && github.repository == 'Firebase/firebase-ios-sdk' @@ -65,7 +51,7 @@ jobs: strategy: matrix: target: [ios, tvos, macos] - needs: pod-lib-lint + needs: pod_lib_lint steps: - uses: actions/checkout@v4 - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1 From 02300e2871ac163b24e41331973c2b06dad23b71 Mon Sep 17 00:00:00 2001 From: Nick Cooke <36927374+ncooke3@users.noreply.github.com> Date: Fri, 30 May 2025 10:37:53 -0400 Subject: [PATCH 052/113] [Infra] Move Storage over to common linting job (#14912) --- .github/workflows/storage.yml | 39 ++++++++++------------------------- 1 file changed, 11 insertions(+), 28 deletions(-) diff --git a/.github/workflows/storage.yml b/.github/workflows/storage.yml index 14577436e56..4b87c836b63 100644 --- a/.github/workflows/storage.yml +++ b/.github/workflows/storage.yml @@ -1,5 +1,8 @@ name: storage +permissions: + contents: read + on: workflow_dispatch: pull_request: @@ -7,6 +10,8 @@ on: - 'FirebaseStorage**' - 'FirebaseAuth/Interop/*.h' - '.github/workflows/storage.yml' + - '.github/workflows/common.yml' + - '.github/workflows/common_cocoapods.yml' # Rebuild on Ruby infrastructure changes. - 'Gemfile*' schedule: @@ -131,33 +136,11 @@ jobs: testapp_dir: quickstart-ios/build-for-testing test_type: "xctest" - pod-lib-lint: - # Don't run on private repo unless it is a PR. - if: (github.repository == 'Firebase/firebase-ios-sdk' && github.event_name == 'schedule') || github.event_name == 'pull_request' - strategy: - matrix: - target: [ios, tvos, macos, watchos] - build-env: - - os: macos-15 - xcode: Xcode_16.2 - tests: --skip-tests - - os: macos-15 - xcode: Xcode_16.2 - tests: --test-specs=unit - runs-on: ${{ matrix.build-env.os }} - steps: - - uses: actions/checkout@v4 - - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1 - - name: Setup Bundler - run: scripts/setup_bundler.sh - - name: Xcodes - run: ls -l /Applications/Xcode* - - name: Xcode - run: sudo xcode-select -s /Applications/${{ matrix.build-env.xcode }}.app/Contents/Developer - - name: Build and test - run: | - scripts/third_party/travis/retry.sh scripts/pod_lib_lint.rb FirebaseStorage.podspec ${{ matrix.build-env.tests }} \ - --platforms=${{ matrix.target }} + pod_lib_lint: + uses: ./.github/workflows/common_cocoapods.yml + with: + product: FirebaseStorage + test_specs: unit storage-cron-only: # Don't run on private repo. @@ -171,7 +154,7 @@ jobs: - os: macos-15 xcode: Xcode_16.2 runs-on: ${{ matrix.build-env.os }} - needs: pod-lib-lint + needs: pod_lib_lint steps: - uses: actions/checkout@v4 - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1 From b170155d16bc15c61bcf8f11d7b67e7612c8fb19 Mon Sep 17 00:00:00 2001 From: Nick Cooke <36927374+ncooke3@users.noreply.github.com> Date: Fri, 30 May 2025 10:38:55 -0400 Subject: [PATCH 053/113] [Infra] Make firebaseinstallations.yml use reusable CocoaPods workflow (#14913) --- .github/workflows/installations.yml | 53 ++++++++--------------------- 1 file changed, 15 insertions(+), 38 deletions(-) diff --git a/.github/workflows/installations.yml b/.github/workflows/installations.yml index 6c97e8b82fc..3defdd7af2f 100644 --- a/.github/workflows/installations.yml +++ b/.github/workflows/installations.yml @@ -1,11 +1,16 @@ name: installations +permissions: + contents: read + on: workflow_dispatch: pull_request: paths: - 'FirebaseInstallations**' - '.github/workflows/installations.yml' + - '.github/workflows/common.yml' + - '.github/workflows/common_cocoapods.yml' - 'Gemfile*' schedule: # Run every day at 10pm (PST) - cron uses UTC times @@ -28,46 +33,18 @@ jobs: product: FirebaseInstallations target: FirebaseInstallations-Unit-unit - pod-lib-lint: - # Don't run on private repo unless it is a PR. - if: (github.repository == 'Firebase/firebase-ios-sdk' && github.event_name == 'schedule') || github.event_name == 'pull_request' - - env: - plist_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} - strategy: - matrix: - # TODO: macos tests are blocked by https://github.com/erikdoe/ocmock/pull/532 - target: [ios, tvos, macos --skip-tests, watchos] - build-env: - - os: macos-14 - xcode: Xcode_16.2 - test-specs: unit,integration - - os: macos-15 - xcode: Xcode_16.3 - test-specs: unit - runs-on: ${{ matrix.build-env.os }} - steps: - - uses: actions/checkout@v4 - - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1 - - name: Setup Bundler - run: scripts/setup_bundler.sh - - name: Configure test keychain - run: scripts/configure_test_keychain.sh - - name: Install GoogleService-Info.plist - run: | + pod_lib_lint: + uses: ./.github/workflows/common_cocoapods.yml + with: + product: FirebaseInstallations + setup_command: | + scripts/configure_test_keychain.sh mkdir -p FirebaseInstallations/Source/Tests/Resources scripts/decrypt_gha_secret.sh scripts/gha-encrypted/Installations/GoogleService-Info.plist.gpg \ FirebaseInstallations/Source/Tests/Resources/GoogleService-Info.plist "$plist_secret" - - name: Get boolean for secrets available - id: secrets - run: echo "::set-output name=val::$([[ -z $plist_secret ]] && echo "0" || echo "1")" - - name: Xcode - run: sudo xcode-select -s /Applications/${{ matrix.build-env.xcode }}.app/Contents/Developer - - name: Build and test - run: | - export FIS_INTEGRATION_TESTS_REQUIRED=${{ steps.secrets.outputs.val }} - scripts/third_party/travis/retry.sh scripts/pod_lib_lint.rb FirebaseInstallations.podspec \ - --platforms=${{ matrix.target }} --test-specs=${{ matrix.build-env.test-specs }} + export FIS_INTEGRATION_TESTS_REQUIRED=1 + secrets: + plist_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} quickstart: # Don't run on private repo unless it is a PR. @@ -129,7 +106,7 @@ jobs: flags: [ '--use-static-frameworks' ] - needs: pod-lib-lint + needs: pod_lib_lint steps: - uses: actions/checkout@v4 - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1 From 9bb64a2d505c2784f4f0609f286a2c3417d2ca21 Mon Sep 17 00:00:00 2001 From: Nick Cooke <36927374+ncooke3@users.noreply.github.com> Date: Fri, 30 May 2025 11:13:09 -0400 Subject: [PATCH 054/113] [Docs] Update min. Xcode version in README.md and SwiftPackageManager.md (#14918) --- README.md | 2 +- SwiftPackageManager.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 7ab3b4ba615..8c98212b4d9 100644 --- a/README.md +++ b/README.md @@ -86,7 +86,7 @@ For details on using Firebase from a Framework or a library, refer to [firebase_ To develop Firebase software in this repository, ensure that you have at least the following software: -* Xcode 15.2 (or later) +* Xcode 16.2 (or later) CocoaPods is still the canonical way to develop, but much of the repo now supports development with Swift Package Manager. diff --git a/SwiftPackageManager.md b/SwiftPackageManager.md index 55cb3d8231d..d94a6517489 100644 --- a/SwiftPackageManager.md +++ b/SwiftPackageManager.md @@ -2,7 +2,7 @@ ## Requirements -- Requires Xcode 15.2 or above +- Requires Xcode 16.2 or above - Analytics requires clients to add `-ObjC` linker option. - See [Package.swift](Package.swift) for supported platform versions. From f991be1abd7ca27453f75d815d7e244fab60cfec Mon Sep 17 00:00:00 2001 From: Nick Cooke <36927374+ncooke3@users.noreply.github.com> Date: Fri, 30 May 2025 11:49:11 -0400 Subject: [PATCH 055/113] [Infra] Trigger dependent workflows when .github/workflows/common_catalyst.yml changes (#14919) --- .github/workflows/abtesting.yml | 1 + .github/workflows/appdistribution.yml | 1 + .github/workflows/auth.yml | 1 + .github/workflows/core.yml | 1 + .github/workflows/core_internal.yml | 1 + .github/workflows/crashlytics.yml | 1 + .github/workflows/database.yml | 1 + .github/workflows/firebase_app_check.yml | 1 + .github/workflows/installations.yml | 1 + .github/workflows/messaging.yml | 1 + .github/workflows/mlmodeldownloader.yml | 1 + .github/workflows/performance.yml | 1 + .github/workflows/remoteconfig.yml | 1 + .github/workflows/sessions.yml | 1 + .github/workflows/storage.yml | 1 + 15 files changed, 15 insertions(+) diff --git a/.github/workflows/abtesting.yml b/.github/workflows/abtesting.yml index f874410e988..a8701041b72 100644 --- a/.github/workflows/abtesting.yml +++ b/.github/workflows/abtesting.yml @@ -12,6 +12,7 @@ on: - '.github/workflows/abtesting.yml' - '.github/workflows/common.yml' - '.github/workflows/common_cocoapods.yml' + - '.github/workflows/common_catalyst.yml' - 'Gemfile*' schedule: # Run every day at 1am(PST) - cron uses UTC times diff --git a/.github/workflows/appdistribution.yml b/.github/workflows/appdistribution.yml index 059a5ab88b6..026e95f81ac 100644 --- a/.github/workflows/appdistribution.yml +++ b/.github/workflows/appdistribution.yml @@ -11,6 +11,7 @@ on: - '.github/workflows/appdistribution.yml' - '.github/workflows/common.yml' - '.github/workflows/common_cocoapods.yml' + - '.github/workflows/common_catalyst.yml' - 'Gemfile*' schedule: # Run every day at 1am (PST) - cron uses UTC times diff --git a/.github/workflows/auth.yml b/.github/workflows/auth.yml index 8426fefcfbe..9f207d650f5 100644 --- a/.github/workflows/auth.yml +++ b/.github/workflows/auth.yml @@ -12,6 +12,7 @@ on: - '.github/workflows/auth.yml' - '.github/workflows/common.yml' - '.github/workflows/common_cocoapods.yml' + - '.github/workflows/common_catalyst.yml' - 'scripts/gha-encrypted/AuthSample/SwiftApplication.plist.gpg' - 'Gemfile*' schedule: diff --git a/.github/workflows/core.yml b/.github/workflows/core.yml index ccaeb26736b..f380a85947b 100644 --- a/.github/workflows/core.yml +++ b/.github/workflows/core.yml @@ -11,6 +11,7 @@ on: - '.github/workflows/core.yml' - '.github/workflows/common.yml' - '.github/workflows/common_cocoapods.yml' + - '.github/workflows/common_catalyst.yml' - 'Gemfile*' schedule: # Run every day at 2am (PST) - cron uses UTC times diff --git a/.github/workflows/core_internal.yml b/.github/workflows/core_internal.yml index 02ae537a6ff..d1b8dd6cf73 100644 --- a/.github/workflows/core_internal.yml +++ b/.github/workflows/core_internal.yml @@ -12,6 +12,7 @@ on: - '.github/workflows/core_internal.yml' - '.github/workflows/common.yml' - '.github/workflows/common_cocoapods.yml' + - '.github/workflows/common_catalyst.yml' - 'Gemfile*' schedule: # Run every day at 2am (PST) - cron uses UTC times diff --git a/.github/workflows/crashlytics.yml b/.github/workflows/crashlytics.yml index 05f492d68d3..a32d474a61b 100644 --- a/.github/workflows/crashlytics.yml +++ b/.github/workflows/crashlytics.yml @@ -12,6 +12,7 @@ on: - '.github/workflows/crashlytics.yml' - '.github/workflows/common.yml' - '.github/workflows/common_cocoapods.yml' + - '.github/workflows/common_catalyst.yml' - 'Interop/Analytics/Public/*.h' - 'Gemfile*' schedule: diff --git a/.github/workflows/database.yml b/.github/workflows/database.yml index 694ed7b48e5..6177b637cae 100644 --- a/.github/workflows/database.yml +++ b/.github/workflows/database.yml @@ -15,6 +15,7 @@ on: - '.github/workflows/database.yml' - '.github/workflows/common.yml' - '.github/workflows/common_cocoapods.yml' + - '.github/workflows/common_catalyst.yml' - 'Gemfile*' - 'scripts/run_database_emulator.sh' schedule: diff --git a/.github/workflows/firebase_app_check.yml b/.github/workflows/firebase_app_check.yml index 5e5c749d808..ff30db15a66 100644 --- a/.github/workflows/firebase_app_check.yml +++ b/.github/workflows/firebase_app_check.yml @@ -11,6 +11,7 @@ on: - '.github/workflows/firebase_app_check.yml' - '.github/workflows/common.yml' - '.github/workflows/common_cocoapods.yml' + - '.github/workflows/common_catalyst.yml' - 'Gemfile*' schedule: # Run every day at 11pm (PST) - cron uses UTC times diff --git a/.github/workflows/installations.yml b/.github/workflows/installations.yml index 3defdd7af2f..cf4f6795b18 100644 --- a/.github/workflows/installations.yml +++ b/.github/workflows/installations.yml @@ -11,6 +11,7 @@ on: - '.github/workflows/installations.yml' - '.github/workflows/common.yml' - '.github/workflows/common_cocoapods.yml' + - '.github/workflows/common_catalyst.yml' - 'Gemfile*' schedule: # Run every day at 10pm (PST) - cron uses UTC times diff --git a/.github/workflows/messaging.yml b/.github/workflows/messaging.yml index 71d8c111578..cd89ca840fc 100644 --- a/.github/workflows/messaging.yml +++ b/.github/workflows/messaging.yml @@ -18,6 +18,7 @@ on: # Re-usable workflows being used by this file. - '.github/workflows/common.yml' - '.github/workflows/common_cocoapods.yml' + - '.github/workflows/common_catalyst.yml' # Rebuild on Ruby infrastructure changes - 'Gemfile*' schedule: diff --git a/.github/workflows/mlmodeldownloader.yml b/.github/workflows/mlmodeldownloader.yml index 6e16642d311..3eddabeadec 100644 --- a/.github/workflows/mlmodeldownloader.yml +++ b/.github/workflows/mlmodeldownloader.yml @@ -11,6 +11,7 @@ on: - '.github/workflows/mlmodeldownloader.yml' - '.github/workflows/common.yml' - '.github/workflows/common_cocoapods.yml' + - '.github/workflows/common_catalyst.yml' - 'Gemfile*' schedule: # Run every day at 11pm (PST) - cron uses UTC times diff --git a/.github/workflows/performance.yml b/.github/workflows/performance.yml index b5e0beea295..b1073dfd11f 100644 --- a/.github/workflows/performance.yml +++ b/.github/workflows/performance.yml @@ -18,6 +18,7 @@ on: # Re-usable workflows depended on by this file. - '.github/workflows/common.yml' - '.github/workflows/common_cocoapods.yml' + - '.github/workflows/common_catalyst.yml' # Rebuild on Ruby infrastructure changes - 'Gemfile*' schedule: diff --git a/.github/workflows/remoteconfig.yml b/.github/workflows/remoteconfig.yml index 3f23f427b3a..dc764c6a88d 100644 --- a/.github/workflows/remoteconfig.yml +++ b/.github/workflows/remoteconfig.yml @@ -12,6 +12,7 @@ on: - '.github/workflows/remoteconfig.yml' - '.github/workflows/common.yml' - '.github/workflows/common_cocoapods.yml' + - '.github/workflows/common_catalyst.yml' - 'Gemfile*' - 'scripts/generate_access_token.sh' - 'scripts/gha-encrypted/RemoteConfigSwiftAPI/**' diff --git a/.github/workflows/sessions.yml b/.github/workflows/sessions.yml index 976b3886c1f..d3ec5adb7f1 100644 --- a/.github/workflows/sessions.yml +++ b/.github/workflows/sessions.yml @@ -12,6 +12,7 @@ on: - '.github/workflows/sessions.yml' - '.github/workflows/common.yml' - '.github/workflows/common_cocoapods.yml' + - '.github/workflows/common_catalyst.yml' - 'Gemfile*' schedule: # Run every day at 9am (PST) - cron uses UTC times diff --git a/.github/workflows/storage.yml b/.github/workflows/storage.yml index 4b87c836b63..f9ffcc0aa73 100644 --- a/.github/workflows/storage.yml +++ b/.github/workflows/storage.yml @@ -12,6 +12,7 @@ on: - '.github/workflows/storage.yml' - '.github/workflows/common.yml' - '.github/workflows/common_cocoapods.yml' + - '.github/workflows/common_catalyst.yml' # Rebuild on Ruby infrastructure changes. - 'Gemfile*' schedule: From b4b6c81c7dbf1e4aa13eabed3165d53ebe95528c Mon Sep 17 00:00:00 2001 From: Andrew Heard Date: Fri, 30 May 2025 15:42:53 -0400 Subject: [PATCH 056/113] [Auth] Re-add `import Foundation` in `SecureTokenService.swift` (#14920) --- .../Sources/Swift/SystemService/SecureTokenService.swift | 1 + 1 file changed, 1 insertion(+) diff --git a/FirebaseAuth/Sources/Swift/SystemService/SecureTokenService.swift b/FirebaseAuth/Sources/Swift/SystemService/SecureTokenService.swift index 0faa99e25f7..34f52a60a28 100644 --- a/FirebaseAuth/Sources/Swift/SystemService/SecureTokenService.swift +++ b/FirebaseAuth/Sources/Swift/SystemService/SecureTokenService.swift @@ -13,6 +13,7 @@ // limitations under the License. import FirebaseCoreInternal +import Foundation private let kFiveMinutes = 5 * 60.0 From 81745444aaebd6dba00c454abe2e6c854aef5b0b Mon Sep 17 00:00:00 2001 From: dmaclach Date: Sun, 1 Jun 2025 11:14:33 -0700 Subject: [PATCH 057/113] Skip test due to being a bad test (#14923) --- .../Tests/UnitTests/FIRMessagingRemoteNotificationsProxyTest.m | 1 + 1 file changed, 1 insertion(+) diff --git a/FirebaseMessaging/Tests/UnitTests/FIRMessagingRemoteNotificationsProxyTest.m b/FirebaseMessaging/Tests/UnitTests/FIRMessagingRemoteNotificationsProxyTest.m index a8ed4fa3032..aeec6002d1c 100644 --- a/FirebaseMessaging/Tests/UnitTests/FIRMessagingRemoteNotificationsProxyTest.m +++ b/FirebaseMessaging/Tests/UnitTests/FIRMessagingRemoteNotificationsProxyTest.m @@ -275,6 +275,7 @@ - (void)testSwizzledAppDelegateRemoteNotificationMethods { #endif // !SWIFT_PACKAGE - (void)testListeningForDelegateChangesOnInvalidUserNotificationCenter { + XCTSkip(@"https://github.com/firebase/firebase-ios-sdk/issues/14922"); if (@available(macOS 10.14, iOS 10.0, *)) { RandomObject *invalidNotificationCenter = [[RandomObject alloc] init]; OCMStub([self.mockUserNotificationCenter currentNotificationCenter]) From 572228da4cc705c606a72dcaa89973e52d311ea9 Mon Sep 17 00:00:00 2001 From: Yakov Manshin Date: Tue, 3 Jun 2025 16:59:42 +0200 Subject: [PATCH 058/113] Refactored Number Coding in `FunctionsSerializer` (#14889) --- .../Internal/FunctionsSerializer.swift | 144 ++++++++---------- .../Tests/Unit/FunctionsSerializerTests.swift | 36 ++++- 2 files changed, 100 insertions(+), 80 deletions(-) diff --git a/FirebaseFunctions/Sources/Internal/FunctionsSerializer.swift b/FirebaseFunctions/Sources/Internal/FunctionsSerializer.swift index 00415cfa341..6220f031252 100644 --- a/FirebaseFunctions/Sources/Internal/FunctionsSerializer.swift +++ b/FirebaseFunctions/Sources/Internal/FunctionsSerializer.swift @@ -14,17 +14,10 @@ import Foundation -private enum Constants { - static let longType = "type.googleapis.com/google.protobuf.Int64Value" - static let unsignedLongType = "type.googleapis.com/google.protobuf.UInt64Value" - static let dateType = "type.googleapis.com/google.protobuf.Timestamp" -} - extension FunctionsSerializer { enum Error: Swift.Error { case unsupportedType(typeName: String) - case unknownNumberType(charValue: String, number: NSNumber) - case invalidValueForType(value: String, requestedType: String) + case failedToParseWrappedNumber(value: String, type: String) } } @@ -41,8 +34,8 @@ final class FunctionsSerializer: Sendable { func encode(_ object: Any) throws -> Any { if object is NSNull { return object - } else if object is NSNumber { - return try encodeNumber(object as! NSNumber) + } else if let number = object as? NSNumber { + return wrapNumberIfNeeded(number) } else if object is NSString { return object } else if let dict = object as? NSDictionary { @@ -70,16 +63,8 @@ final class FunctionsSerializer: Sendable { func decode(_ object: Any) throws -> Any { // Return these types as is. PORTING NOTE: Moved from the bottom of the func for readability. if let dict = object as? NSDictionary { - if let requestedType = dict["@type"] as? String { - guard let value = dict["value"] as? String else { - // Seems like we should throw here - but this maintains compatibility. - return dict - } - if let result = try decodeWrappedType(requestedType, value) { - return result - } - - // Treat unknown types as dictionaries, so we don't crash old clients when we add types. + if let wrappedNumber = WrappedNumber(from: dict) { + return try unwrapNumber(wrappedNumber) } let decoded = NSMutableDictionary() @@ -106,73 +91,76 @@ final class FunctionsSerializer: Sendable { String(describing: type(of: value)) } - private func encodeNumber(_ number: NSNumber) throws -> AnyObject { - // Recover the underlying type of the number, using the method described here: - // http://stackoverflow.com/questions/2518761/get-type-of-nsnumber - let cType = number.objCType - - // Type Encoding values taken from - // https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/ObjCRuntimeGuide/ - // Articles/ocrtTypeEncodings.html - switch cType[0] { - case CChar("q".utf8.first!): - // "long long" might be larger than JS supports, so make it a string. - return ["@type": Constants.longType, "value": "\(number)"] as AnyObject - - case CChar("Q".utf8.first!): - // "unsigned long long" might be larger than JS supports, so make it a string. - return ["@type": Constants.unsignedLongType, - "value": "\(number)"] as AnyObject - - case CChar("i".utf8.first!), - CChar("s".utf8.first!), - CChar("l".utf8.first!), - CChar("I".utf8.first!), - CChar("S".utf8.first!): - // If it"s an integer that isn"t too long, so just use the number. - return number - - case CChar("f".utf8.first!), CChar("d".utf8.first!): - // It"s a float/double that"s not too large. - return number - - case CChar("B".utf8.first!), CChar("c".utf8.first!), CChar("C".utf8.first!): - // Boolean values are weird. - // - // On arm64, objCType of a BOOL-valued NSNumber will be "c", even though @encode(BOOL) - // returns "B". "c" is the same as @encode(signed char). Unfortunately this means that - // legitimate usage of signed chars is impossible, but this should be rare. - // - // Just return Boolean values as-is. - return number - + private func wrapNumberIfNeeded(_ number: NSNumber) -> Any { + switch String(cString: number.objCType) { + case "q": + // "long long" might be larger than JS supports, so make it a string: + return WrappedNumber(type: .long, value: "\(number)").encoded + case "Q": + // "unsigned long long" might be larger than JS supports, so make it a string: + return WrappedNumber(type: .unsignedLong, value: "\(number)").encoded default: - // All documented codes should be handled above, so this shouldn"t happen. - throw Error.unknownNumberType(charValue: String(cType[0]), number: number) + // All other types should fit JS limits, so return the number as is: + return number } } - private func decodeWrappedType(_ type: String, _ value: String) throws -> AnyObject? { - switch type { - case Constants.longType: - let formatter = NumberFormatter() - guard let n = formatter.number(from: value) else { - throw Error.invalidValueForType(value: value, requestedType: type) + private func unwrapNumber(_ wrapped: WrappedNumber) throws(Error) -> any Numeric { + switch wrapped.type { + case .long: + guard let n = Int(wrapped.value) else { + throw .failedToParseWrappedNumber( + value: wrapped.value, + type: wrapped.type.rawValue + ) + } + return n + case .unsignedLong: + guard let n = UInt(wrapped.value) else { + throw .failedToParseWrappedNumber( + value: wrapped.value, + type: wrapped.type.rawValue + ) } return n + } + } +} + +// MARK: - WrappedNumber + +extension FunctionsSerializer { + private struct WrappedNumber { + let type: NumberType + let value: String + + // When / if objects are encoded / decoded using `Codable`, + // these two `init`s and `encoded` won’t be needed anymore: + + init(type: NumberType, value: String) { + self.type = type + self.value = value + } - case Constants.unsignedLongType: - // NSNumber formatter doesn't handle unsigned long long, so we have to parse it. - let str = (value as NSString).utf8String - var endPtr: UnsafeMutablePointer? - let returnValue = UInt64(strtoul(str, &endPtr, 10)) - guard String(returnValue) == value else { - throw Error.invalidValueForType(value: value, requestedType: type) + init?(from dictionary: NSDictionary) { + guard + let typeString = dictionary["@type"] as? String, + let type = NumberType(rawValue: typeString), + let value = dictionary["value"] as? String + else { + return nil } - return NSNumber(value: returnValue) - default: - return nil + self.init(type: type, value: value) + } + + var encoded: [String: String] { + ["@type": type.rawValue, "value": value] + } + + enum NumberType: String { + case long = "type.googleapis.com/google.protobuf.Int64Value" + case unsignedLong = "type.googleapis.com/google.protobuf.UInt64Value" } } } diff --git a/FirebaseFunctions/Tests/Unit/FunctionsSerializerTests.swift b/FirebaseFunctions/Tests/Unit/FunctionsSerializerTests.swift index 7fe77fd4dd9..b15448e92cc 100644 --- a/FirebaseFunctions/Tests/Unit/FunctionsSerializerTests.swift +++ b/FirebaseFunctions/Tests/Unit/FunctionsSerializerTests.swift @@ -98,7 +98,7 @@ class FunctionsSerializerTests: XCTestCase { let dictLowLong = ["@type": typeString, "value": badVal] do { _ = try serializer.decode(dictLowLong) as? NSNumber - } catch let FunctionsSerializer.Error.invalidValueForType(value, type) { + } catch let FunctionsSerializer.Error.failedToParseWrappedNumber(value, type) { XCTAssertEqual(value, badVal) XCTAssertEqual(type, typeString) return @@ -136,7 +136,7 @@ class FunctionsSerializerTests: XCTestCase { let coded = ["@type": typeString, "value": tooHighVal] do { _ = try serializer.decode(coded) as? NSNumber - } catch let FunctionsSerializer.Error.invalidValueForType(value, type) { + } catch let FunctionsSerializer.Error.failedToParseWrappedNumber(value, type) { XCTAssertEqual(value, tooHighVal) XCTAssertEqual(type, typeString) return @@ -283,6 +283,38 @@ class FunctionsSerializerTests: XCTestCase { try assert(serializer.decode(input), throwsUnsupportedTypeErrorWithName: "CustomObject") } + + // If the object can be decoded as a wrapped number, all other properties are ignored: + func testDecodeValidWrappedNumberWithUnsupportedExtra() throws { + let input = [ + "@type": "type.googleapis.com/google.protobuf.Int64Value", + "value": "1234567890", + "extra": CustomObject(), + ] as NSDictionary + + XCTAssertEqual(NSNumber(1_234_567_890), try serializer.decode(input) as? NSNumber) + } + + // If the object is not a valid wrapped number, it’s processed as a generic array: + func testDecodeWrappedNumberWithUnsupportedValue() throws { + let input = [ + "@type": "type.googleapis.com/google.protobuf.Int64Value", + "value": CustomObject(), + ] as NSDictionary + + try assert(serializer.decode(input), throwsUnsupportedTypeErrorWithName: "CustomObject") + } + + // If the object is not a valid wrapped number, it’s processed as a generic array: + func testDecodeInvalidWrappedNumberWithUnsupportedExtra() throws { + let input = [ + "@type": "CUSTOM_TYPE", + "value": "1234567890", + "extra": CustomObject(), + ] as NSDictionary + + try assert(serializer.decode(input), throwsUnsupportedTypeErrorWithName: "CustomObject") + } } // MARK: - Utilities From 4aba3651d180d4d09274050ff1599e5c4cb52f32 Mon Sep 17 00:00:00 2001 From: Nick Cooke <36927374+ncooke3@users.noreply.github.com> Date: Tue, 3 Jun 2025 12:02:48 -0400 Subject: [PATCH 059/113] [Infra] Migrate firestore.yml to use reusable workflow jobs (#14917) --- .github/workflows/common_cocoapods.yml | 7 +++ .github/workflows/firestore.yml | 62 +++++++------------------- 2 files changed, 24 insertions(+), 45 deletions(-) diff --git a/.github/workflows/common_cocoapods.yml b/.github/workflows/common_cocoapods.yml index 50834b04431..6536c5a3f47 100644 --- a/.github/workflows/common_cocoapods.yml +++ b/.github/workflows/common_cocoapods.yml @@ -69,6 +69,12 @@ on: required: false default: false + # Whether to lint with `--analyze`. Defaults to true. + analyze: + type: boolean + required: false + default: true + # Whether to additionally build with Swift 6. Defaults to false. supports_swift6: type: boolean @@ -140,5 +146,6 @@ jobs: command: | scripts/pod_lib_lint.rb ${{ inputs.product }}.podspec --platforms=${{ matrix.platform }} \ ${{ inputs.allow_warnings == true && '--allow-warnings' || '' }} \ + ${{ inputs.analyze == false && '--no-analyze' || '' }} \ ${{ inputs.test_specs != '' && format('--test-specs={0}', inputs.test_specs) || '' }} \ ${{ (contains(inputs.buildonly_platforms, matrix.platform) || contains(inputs.buildonly_platforms, 'all')) && '--skip-tests' || '' }} diff --git a/.github/workflows/firestore.yml b/.github/workflows/firestore.yml index 6282b0511d5..8f4ac2b1264 100644 --- a/.github/workflows/firestore.yml +++ b/.github/workflows/firestore.yml @@ -83,6 +83,10 @@ jobs: # This workflow - '.github/workflows/firestore.yml' + # Workflows this one depends on. + - '.github/workflows/common.yml' + - '.github/workflows/common_cocoapods.yml' + # Rebuild on Ruby infrastructure changes. - 'Gemfile*' @@ -379,37 +383,17 @@ jobs: export EXPERIMENTAL_MODE=true scripts/third_party/travis/retry.sh scripts/build.sh Firestore ${{ matrix.target }} xcodebuild - - pod-lib-lint: + pod_lib_lint: needs: check - # Either a scheduled run from public repo, or a pull request with firestore changes. - if: | - (github.repository == 'Firebase/firebase-ios-sdk' && github.event_name == 'schedule') || - (github.event_name == 'pull_request') - runs-on: macos-15 strategy: matrix: - podspec: [ - 'FirebaseFirestoreInternal.podspec', - 'FirebaseFirestore.podspec', - ] - - steps: - - uses: actions/checkout@v4 - - - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1 - - name: Setup Bundler - run: ./scripts/setup_bundler.sh - - name: Xcode - run: sudo xcode-select -s /Applications/Xcode_16.3.app/Contents/Developer - - - name: Pod lib lint - # TODO(#9565, b/227461966): Remove --no-analyze when absl is fixed. - run: | - scripts/third_party/travis/retry.sh scripts/pod_lib_lint.rb ${{ matrix.podspec }} \ - --platforms=ios \ - --allow-warnings \ - --no-analyze + product: ['FirebaseFirestoreInternal', 'FirebaseFirestore'] + uses: ./.github/workflows/common_cocoapods.yml + with: + product: ${{ matrix.product }} + platforms: iOS + allow_warnings: true + analyze: false # TODO(#9565, b/227461966): Remove when absl is fixed. # `pod lib lint` takes a long time so only run the other platforms and static frameworks build in the cron. pod-lib-lint-cron: @@ -524,23 +508,11 @@ jobs: run: scripts/third_party/travis/retry.sh ./scripts/build.sh FirebaseFirestore ${{ matrix.target }} spmbuildonly spm-binary: - needs: check - # Either a scheduled run from public repo, or a pull request with firestore changes. - if: | - (github.repository == 'Firebase/firebase-ios-sdk' && github.event_name == 'schedule') || - (github.event_name == 'pull_request' && needs.changes.outputs.changed == 'true') - runs-on: macos-15 - steps: - - uses: actions/checkout@v4 - - uses: mikehardy/buildcache-action@c87cea0ccd718971d6cc39e672c4f26815b6c126 - with: - cache_key: spm-binary - - name: Xcode - run: sudo xcode-select -s /Applications/Xcode_16.2.app/Contents/Developer - - name: Initialize xcodebuild - run: scripts/setup_spm_tests.sh - - name: iOS Build Test - run: scripts/third_party/travis/retry.sh ./scripts/build.sh FirebaseFirestore iOS spmbuildonly + uses: ./.github/workflows/common.yml + with: + target: FirebaseFirestore + platforms: iOS + buildonly_platforms: iOS check-firestore-internal-public-headers: needs: check From de72981c54079704e805c390a42a400dac7570dd Mon Sep 17 00:00:00 2001 From: Andrew Heard Date: Tue, 3 Jun 2025 16:23:43 -0400 Subject: [PATCH 060/113] [Release] Carthage updates for M165 / 11.14.0 (#14927) --- ReleaseTooling/CarthageJSON/FirebaseABTestingBinary.json | 1 + ReleaseTooling/CarthageJSON/FirebaseAIBinary.json | 3 ++- ReleaseTooling/CarthageJSON/FirebaseAdMobBinary.json | 1 + ReleaseTooling/CarthageJSON/FirebaseAnalyticsBinary.json | 1 + .../FirebaseAnalyticsOnDeviceConversionBinary.json | 1 + ReleaseTooling/CarthageJSON/FirebaseAppCheckBinary.json | 1 + ReleaseTooling/CarthageJSON/FirebaseAppDistributionBinary.json | 1 + ReleaseTooling/CarthageJSON/FirebaseAuthBinary.json | 1 + ReleaseTooling/CarthageJSON/FirebaseCrashlyticsBinary.json | 1 + ReleaseTooling/CarthageJSON/FirebaseDatabaseBinary.json | 1 + ReleaseTooling/CarthageJSON/FirebaseDynamicLinksBinary.json | 1 + ReleaseTooling/CarthageJSON/FirebaseFirestoreBinary.json | 1 + ReleaseTooling/CarthageJSON/FirebaseFunctionsBinary.json | 1 + ReleaseTooling/CarthageJSON/FirebaseGoogleSignInBinary.json | 1 + ReleaseTooling/CarthageJSON/FirebaseInAppMessagingBinary.json | 1 + .../CarthageJSON/FirebaseMLModelDownloaderBinary.json | 1 + ReleaseTooling/CarthageJSON/FirebaseMessagingBinary.json | 1 + ReleaseTooling/CarthageJSON/FirebasePerformanceBinary.json | 1 + ReleaseTooling/CarthageJSON/FirebaseRemoteConfigBinary.json | 1 + ReleaseTooling/CarthageJSON/FirebaseStorageBinary.json | 1 + ReleaseTooling/CarthageJSON/FirebaseVertexAIBinary.json | 1 + 21 files changed, 22 insertions(+), 1 deletion(-) diff --git a/ReleaseTooling/CarthageJSON/FirebaseABTestingBinary.json b/ReleaseTooling/CarthageJSON/FirebaseABTestingBinary.json index a0217f538d2..8350853be9b 100644 --- a/ReleaseTooling/CarthageJSON/FirebaseABTestingBinary.json +++ b/ReleaseTooling/CarthageJSON/FirebaseABTestingBinary.json @@ -34,6 +34,7 @@ "11.11.0": "https://dl.google.com/dl/firebase/ios/carthage/11.11.0/FirebaseABTesting-1fa70f00533854e0.zip", "11.12.0": "https://dl.google.com/dl/firebase/ios/carthage/11.12.0/FirebaseABTesting-17c1a20424ac54c7.zip", "11.13.0": "https://dl.google.com/dl/firebase/ios/carthage/11.13.0/FirebaseABTesting-1a75b2ffead6cd9d.zip", + "11.14.0": "https://dl.google.com/dl/firebase/ios/carthage/11.14.0/FirebaseABTesting-d4a41d6f862a8547.zip", "11.2.0": "https://dl.google.com/dl/firebase/ios/carthage/11.2.0/FirebaseABTesting-0d51fde82d49f9e8.zip", "11.3.0": "https://dl.google.com/dl/firebase/ios/carthage/11.3.0/FirebaseABTesting-2233510ff87da3b6.zip", "11.4.0": "https://dl.google.com/dl/firebase/ios/carthage/11.4.0/FirebaseABTesting-4d0b187af6fd8d67.zip", diff --git a/ReleaseTooling/CarthageJSON/FirebaseAIBinary.json b/ReleaseTooling/CarthageJSON/FirebaseAIBinary.json index 169c47eee73..bb2bd796541 100644 --- a/ReleaseTooling/CarthageJSON/FirebaseAIBinary.json +++ b/ReleaseTooling/CarthageJSON/FirebaseAIBinary.json @@ -1,3 +1,4 @@ { - "11.13.0": "https://dl.google.com/dl/firebase/ios/carthage/11.13.0/FirebaseAI-b1e75ff6284775b1.zip" + "11.13.0": "https://dl.google.com/dl/firebase/ios/carthage/11.13.0/FirebaseAI-b1e75ff6284775b1.zip", + "11.14.0": "https://dl.google.com/dl/firebase/ios/carthage/11.14.0/FirebaseAI-0991ef5c3a83833a.zip" } diff --git a/ReleaseTooling/CarthageJSON/FirebaseAdMobBinary.json b/ReleaseTooling/CarthageJSON/FirebaseAdMobBinary.json index 281802be59e..4f6b05e5a87 100644 --- a/ReleaseTooling/CarthageJSON/FirebaseAdMobBinary.json +++ b/ReleaseTooling/CarthageJSON/FirebaseAdMobBinary.json @@ -34,6 +34,7 @@ "11.11.0": "https://dl.google.com/dl/firebase/ios/carthage/11.11.0/Google-Mobile-Ads-SDK-3653cb73a799c206.zip", "11.12.0": "https://dl.google.com/dl/firebase/ios/carthage/11.12.0/Google-Mobile-Ads-SDK-f8af4dfdc3318376.zip", "11.13.0": "https://dl.google.com/dl/firebase/ios/carthage/11.13.0/Google-Mobile-Ads-SDK-cafdcb68e4493534.zip", + "11.14.0": "https://dl.google.com/dl/firebase/ios/carthage/11.14.0/Google-Mobile-Ads-SDK-9667edd0361b0417.zip", "11.2.0": "https://dl.google.com/dl/firebase/ios/carthage/11.2.0/Google-Mobile-Ads-SDK-4f24527af297e7f1.zip", "11.3.0": "https://dl.google.com/dl/firebase/ios/carthage/11.3.0/Google-Mobile-Ads-SDK-80ba4cb995505158.zip", "11.4.0": "https://dl.google.com/dl/firebase/ios/carthage/11.4.0/Google-Mobile-Ads-SDK-3df614a58e6a5fa6.zip", diff --git a/ReleaseTooling/CarthageJSON/FirebaseAnalyticsBinary.json b/ReleaseTooling/CarthageJSON/FirebaseAnalyticsBinary.json index 82951d390be..ee48b39c89c 100644 --- a/ReleaseTooling/CarthageJSON/FirebaseAnalyticsBinary.json +++ b/ReleaseTooling/CarthageJSON/FirebaseAnalyticsBinary.json @@ -34,6 +34,7 @@ "11.11.0": "https://dl.google.com/dl/firebase/ios/carthage/11.11.0/FirebaseAnalytics-9555aba4c5a25d4f.zip", "11.12.0": "https://dl.google.com/dl/firebase/ios/carthage/11.12.0/FirebaseAnalytics-15d238d1b49f4aff.zip", "11.13.0": "https://dl.google.com/dl/firebase/ios/carthage/11.13.0/FirebaseAnalytics-65ff9a1a6c9e6497.zip", + "11.14.0": "https://dl.google.com/dl/firebase/ios/carthage/11.14.0/FirebaseAnalytics-12acfc103ccaf7a6.zip", "11.2.0": "https://dl.google.com/dl/firebase/ios/carthage/11.2.0/FirebaseAnalytics-a93a6c81da535385.zip", "11.3.0": "https://dl.google.com/dl/firebase/ios/carthage/11.3.0/FirebaseAnalytics-fd2c71a90d62b88a.zip", "11.4.0": "https://dl.google.com/dl/firebase/ios/carthage/11.4.0/FirebaseAnalytics-525b465eb296d09e.zip", diff --git a/ReleaseTooling/CarthageJSON/FirebaseAnalyticsOnDeviceConversionBinary.json b/ReleaseTooling/CarthageJSON/FirebaseAnalyticsOnDeviceConversionBinary.json index 75392d66afc..0fc94414c96 100644 --- a/ReleaseTooling/CarthageJSON/FirebaseAnalyticsOnDeviceConversionBinary.json +++ b/ReleaseTooling/CarthageJSON/FirebaseAnalyticsOnDeviceConversionBinary.json @@ -34,6 +34,7 @@ "11.11.0": "https://dl.google.com/dl/firebase/ios/carthage/11.11.0/FirebaseAnalyticsOnDeviceConversion-844b470f329d4e3b.zip", "11.12.0": "https://dl.google.com/dl/firebase/ios/carthage/11.12.0/FirebaseAnalyticsOnDeviceConversion-74e82e4c9ac69336.zip", "11.13.0": "https://dl.google.com/dl/firebase/ios/carthage/11.13.0/FirebaseAnalyticsOnDeviceConversion-78d60e37985a869e.zip", + "11.14.0": "https://dl.google.com/dl/firebase/ios/carthage/11.14.0/FirebaseAnalyticsOnDeviceConversion-5b8b3b9300f67f33.zip", "11.2.0": "https://dl.google.com/dl/firebase/ios/carthage/11.2.0/FirebaseAnalyticsOnDeviceConversion-09d94624a2de0ac8.zip", "11.3.0": "https://dl.google.com/dl/firebase/ios/carthage/11.3.0/FirebaseAnalyticsOnDeviceConversion-918bc6e0b7a2fd94.zip", "11.4.0": "https://dl.google.com/dl/firebase/ios/carthage/11.4.0/FirebaseAnalyticsOnDeviceConversion-1640c514418a23da.zip", diff --git a/ReleaseTooling/CarthageJSON/FirebaseAppCheckBinary.json b/ReleaseTooling/CarthageJSON/FirebaseAppCheckBinary.json index 9b2b42c5131..cc437682f19 100644 --- a/ReleaseTooling/CarthageJSON/FirebaseAppCheckBinary.json +++ b/ReleaseTooling/CarthageJSON/FirebaseAppCheckBinary.json @@ -34,6 +34,7 @@ "11.11.0": "https://dl.google.com/dl/firebase/ios/carthage/11.11.0/FirebaseAppCheck-53a4dc38e63d6624.zip", "11.12.0": "https://dl.google.com/dl/firebase/ios/carthage/11.12.0/FirebaseAppCheck-0c2c90b1b6b95fc9.zip", "11.13.0": "https://dl.google.com/dl/firebase/ios/carthage/11.13.0/FirebaseAppCheck-11e2868920731911.zip", + "11.14.0": "https://dl.google.com/dl/firebase/ios/carthage/11.14.0/FirebaseAppCheck-4eff92b9a211beb7.zip", "11.2.0": "https://dl.google.com/dl/firebase/ios/carthage/11.2.0/FirebaseAppCheck-d0c5f46e6a2bf4a3.zip", "11.3.0": "https://dl.google.com/dl/firebase/ios/carthage/11.3.0/FirebaseAppCheck-89c39bdcf0bb90fe.zip", "11.4.0": "https://dl.google.com/dl/firebase/ios/carthage/11.4.0/FirebaseAppCheck-9b0c4a9489968b07.zip", diff --git a/ReleaseTooling/CarthageJSON/FirebaseAppDistributionBinary.json b/ReleaseTooling/CarthageJSON/FirebaseAppDistributionBinary.json index 0a625872625..cb9a34c1c13 100644 --- a/ReleaseTooling/CarthageJSON/FirebaseAppDistributionBinary.json +++ b/ReleaseTooling/CarthageJSON/FirebaseAppDistributionBinary.json @@ -34,6 +34,7 @@ "11.11.0": "https://dl.google.com/dl/firebase/ios/carthage/11.11.0/FirebaseAppDistribution-2224206d63435182.zip", "11.12.0": "https://dl.google.com/dl/firebase/ios/carthage/11.12.0/FirebaseAppDistribution-7c36126c08bc3ffc.zip", "11.13.0": "https://dl.google.com/dl/firebase/ios/carthage/11.13.0/FirebaseAppDistribution-e955d19576007871.zip", + "11.14.0": "https://dl.google.com/dl/firebase/ios/carthage/11.14.0/FirebaseAppDistribution-c472cb29b072dcb7.zip", "11.2.0": "https://dl.google.com/dl/firebase/ios/carthage/11.2.0/FirebaseAppDistribution-9b05f4873b275347.zip", "11.3.0": "https://dl.google.com/dl/firebase/ios/carthage/11.3.0/FirebaseAppDistribution-6d2eccaccfd3145f.zip", "11.4.0": "https://dl.google.com/dl/firebase/ios/carthage/11.4.0/FirebaseAppDistribution-20ac94ca344af731.zip", diff --git a/ReleaseTooling/CarthageJSON/FirebaseAuthBinary.json b/ReleaseTooling/CarthageJSON/FirebaseAuthBinary.json index ec02b5a2abe..46ea1d6a93e 100644 --- a/ReleaseTooling/CarthageJSON/FirebaseAuthBinary.json +++ b/ReleaseTooling/CarthageJSON/FirebaseAuthBinary.json @@ -34,6 +34,7 @@ "11.11.0": "https://dl.google.com/dl/firebase/ios/carthage/11.11.0/FirebaseAuth-c0fe98c6072e1eec.zip", "11.12.0": "https://dl.google.com/dl/firebase/ios/carthage/11.12.0/FirebaseAuth-eb54b6a712749cc9.zip", "11.13.0": "https://dl.google.com/dl/firebase/ios/carthage/11.13.0/FirebaseAuth-88c4514b7d5eb6a2.zip", + "11.14.0": "https://dl.google.com/dl/firebase/ios/carthage/11.14.0/FirebaseAuth-db785a3ce2245ee8.zip", "11.2.0": "https://dl.google.com/dl/firebase/ios/carthage/11.2.0/FirebaseAuth-eade26b5390baf84.zip", "11.3.0": "https://dl.google.com/dl/firebase/ios/carthage/11.3.0/FirebaseAuth-93dd2965b3f79b98.zip", "11.4.0": "https://dl.google.com/dl/firebase/ios/carthage/11.4.0/FirebaseAuth-5faf6dc3bb16c732.zip", diff --git a/ReleaseTooling/CarthageJSON/FirebaseCrashlyticsBinary.json b/ReleaseTooling/CarthageJSON/FirebaseCrashlyticsBinary.json index 2979dbbc54e..d83ca12cc27 100644 --- a/ReleaseTooling/CarthageJSON/FirebaseCrashlyticsBinary.json +++ b/ReleaseTooling/CarthageJSON/FirebaseCrashlyticsBinary.json @@ -34,6 +34,7 @@ "11.11.0": "https://dl.google.com/dl/firebase/ios/carthage/11.11.0/FirebaseCrashlytics-c5d0dc18d2183d76.zip", "11.12.0": "https://dl.google.com/dl/firebase/ios/carthage/11.12.0/FirebaseCrashlytics-6174ffabf4502bb8.zip", "11.13.0": "https://dl.google.com/dl/firebase/ios/carthage/11.13.0/FirebaseCrashlytics-b653e61e196e22a4.zip", + "11.14.0": "https://dl.google.com/dl/firebase/ios/carthage/11.14.0/FirebaseCrashlytics-c1b09641c4cde67d.zip", "11.2.0": "https://dl.google.com/dl/firebase/ios/carthage/11.2.0/FirebaseCrashlytics-13851523ad6df088.zip", "11.3.0": "https://dl.google.com/dl/firebase/ios/carthage/11.3.0/FirebaseCrashlytics-282a6f3cf3445787.zip", "11.4.0": "https://dl.google.com/dl/firebase/ios/carthage/11.4.0/FirebaseCrashlytics-d5c125d6416f6e0a.zip", diff --git a/ReleaseTooling/CarthageJSON/FirebaseDatabaseBinary.json b/ReleaseTooling/CarthageJSON/FirebaseDatabaseBinary.json index 18f1c65d3de..3ca76074eea 100644 --- a/ReleaseTooling/CarthageJSON/FirebaseDatabaseBinary.json +++ b/ReleaseTooling/CarthageJSON/FirebaseDatabaseBinary.json @@ -34,6 +34,7 @@ "11.11.0": "https://dl.google.com/dl/firebase/ios/carthage/11.11.0/FirebaseDatabase-274d83ecf88f0312.zip", "11.12.0": "https://dl.google.com/dl/firebase/ios/carthage/11.12.0/FirebaseDatabase-f2f974b2b124d51a.zip", "11.13.0": "https://dl.google.com/dl/firebase/ios/carthage/11.13.0/FirebaseDatabase-c90d9d681a963528.zip", + "11.14.0": "https://dl.google.com/dl/firebase/ios/carthage/11.14.0/FirebaseDatabase-d2469ab8369633b1.zip", "11.2.0": "https://dl.google.com/dl/firebase/ios/carthage/11.2.0/FirebaseDatabase-06dbb1f7d3c8a3e1.zip", "11.3.0": "https://dl.google.com/dl/firebase/ios/carthage/11.3.0/FirebaseDatabase-38634b55050b94fe.zip", "11.4.0": "https://dl.google.com/dl/firebase/ios/carthage/11.4.0/FirebaseDatabase-ed125984da534e96.zip", diff --git a/ReleaseTooling/CarthageJSON/FirebaseDynamicLinksBinary.json b/ReleaseTooling/CarthageJSON/FirebaseDynamicLinksBinary.json index 02924c965af..bd082b476fd 100644 --- a/ReleaseTooling/CarthageJSON/FirebaseDynamicLinksBinary.json +++ b/ReleaseTooling/CarthageJSON/FirebaseDynamicLinksBinary.json @@ -34,6 +34,7 @@ "11.11.0": "https://dl.google.com/dl/firebase/ios/carthage/11.11.0/FirebaseDynamicLinks-3bc027fc5b14a796.zip", "11.12.0": "https://dl.google.com/dl/firebase/ios/carthage/11.12.0/FirebaseDynamicLinks-f5c8594e8040c69a.zip", "11.13.0": "https://dl.google.com/dl/firebase/ios/carthage/11.13.0/FirebaseDynamicLinks-cadebc4c288fe390.zip", + "11.14.0": "https://dl.google.com/dl/firebase/ios/carthage/11.14.0/FirebaseDynamicLinks-d0cf6dba1f1d395c.zip", "11.2.0": "https://dl.google.com/dl/firebase/ios/carthage/11.2.0/FirebaseDynamicLinks-e61c61fa80e5ea8a.zip", "11.3.0": "https://dl.google.com/dl/firebase/ios/carthage/11.3.0/FirebaseDynamicLinks-95f7e222d8456304.zip", "11.4.0": "https://dl.google.com/dl/firebase/ios/carthage/11.4.0/FirebaseDynamicLinks-f3f9d6cc60c8b832.zip", diff --git a/ReleaseTooling/CarthageJSON/FirebaseFirestoreBinary.json b/ReleaseTooling/CarthageJSON/FirebaseFirestoreBinary.json index 51779ca7a89..bff1e093edf 100644 --- a/ReleaseTooling/CarthageJSON/FirebaseFirestoreBinary.json +++ b/ReleaseTooling/CarthageJSON/FirebaseFirestoreBinary.json @@ -34,6 +34,7 @@ "11.11.0": "https://dl.google.com/dl/firebase/ios/carthage/11.11.0/FirebaseFirestore-c1b73a8c2df88a5d.zip", "11.12.0": "https://dl.google.com/dl/firebase/ios/carthage/11.12.0/FirebaseFirestore-860c013c1e20d6f3.zip", "11.13.0": "https://dl.google.com/dl/firebase/ios/carthage/11.13.0/FirebaseFirestore-c4f5b2c5b7a568a1.zip", + "11.14.0": "https://dl.google.com/dl/firebase/ios/carthage/11.14.0/FirebaseFirestore-f5ff5063a1f53d77.zip", "11.2.0": "https://dl.google.com/dl/firebase/ios/carthage/11.2.0/FirebaseFirestore-43af85b854ac842e.zip", "11.3.0": "https://dl.google.com/dl/firebase/ios/carthage/11.3.0/FirebaseFirestore-e1283f8cd2e0f3ec.zip", "11.4.0": "https://dl.google.com/dl/firebase/ios/carthage/11.4.0/FirebaseFirestore-f5864e67ddbbc9e8.zip", diff --git a/ReleaseTooling/CarthageJSON/FirebaseFunctionsBinary.json b/ReleaseTooling/CarthageJSON/FirebaseFunctionsBinary.json index e674a7d818c..785c35655db 100644 --- a/ReleaseTooling/CarthageJSON/FirebaseFunctionsBinary.json +++ b/ReleaseTooling/CarthageJSON/FirebaseFunctionsBinary.json @@ -34,6 +34,7 @@ "11.11.0": "https://dl.google.com/dl/firebase/ios/carthage/11.11.0/FirebaseFunctions-bb6ac03a35726822.zip", "11.12.0": "https://dl.google.com/dl/firebase/ios/carthage/11.12.0/FirebaseFunctions-5ab1be0d8d70d377.zip", "11.13.0": "https://dl.google.com/dl/firebase/ios/carthage/11.13.0/FirebaseFunctions-63e0b73f4514e67f.zip", + "11.14.0": "https://dl.google.com/dl/firebase/ios/carthage/11.14.0/FirebaseFunctions-581350611b7e5c69.zip", "11.2.0": "https://dl.google.com/dl/firebase/ios/carthage/11.2.0/FirebaseFunctions-307f00117c2efc62.zip", "11.3.0": "https://dl.google.com/dl/firebase/ios/carthage/11.3.0/FirebaseFunctions-02693a7583303912.zip", "11.4.0": "https://dl.google.com/dl/firebase/ios/carthage/11.4.0/FirebaseFunctions-8fce8623ed1c6b86.zip", diff --git a/ReleaseTooling/CarthageJSON/FirebaseGoogleSignInBinary.json b/ReleaseTooling/CarthageJSON/FirebaseGoogleSignInBinary.json index 6a4f7452ec6..6fb7e093f8f 100644 --- a/ReleaseTooling/CarthageJSON/FirebaseGoogleSignInBinary.json +++ b/ReleaseTooling/CarthageJSON/FirebaseGoogleSignInBinary.json @@ -34,6 +34,7 @@ "11.11.0": "https://dl.google.com/dl/firebase/ios/carthage/11.11.0/GoogleSignIn-53da1498f8e507e3.zip", "11.12.0": "https://dl.google.com/dl/firebase/ios/carthage/11.12.0/GoogleSignIn-359f9a827460f64a.zip", "11.13.0": "https://dl.google.com/dl/firebase/ios/carthage/11.13.0/GoogleSignIn-865a20796d87317c.zip", + "11.14.0": "https://dl.google.com/dl/firebase/ios/carthage/11.14.0/GoogleSignIn-c95d586e8128eb80.zip", "11.2.0": "https://dl.google.com/dl/firebase/ios/carthage/11.2.0/GoogleSignIn-4e8837ef9594b57b.zip", "11.3.0": "https://dl.google.com/dl/firebase/ios/carthage/11.3.0/GoogleSignIn-8ce1c31ca2236212.zip", "11.4.0": "https://dl.google.com/dl/firebase/ios/carthage/11.4.0/GoogleSignIn-59eb371d148a2e3a.zip", diff --git a/ReleaseTooling/CarthageJSON/FirebaseInAppMessagingBinary.json b/ReleaseTooling/CarthageJSON/FirebaseInAppMessagingBinary.json index 1152d94805a..89d1cfb02b0 100644 --- a/ReleaseTooling/CarthageJSON/FirebaseInAppMessagingBinary.json +++ b/ReleaseTooling/CarthageJSON/FirebaseInAppMessagingBinary.json @@ -34,6 +34,7 @@ "11.11.0": "https://dl.google.com/dl/firebase/ios/carthage/11.11.0/FirebaseInAppMessaging-f877ac14815852ad.zip", "11.12.0": "https://dl.google.com/dl/firebase/ios/carthage/11.12.0/FirebaseInAppMessaging-713d93418e005e14.zip", "11.13.0": "https://dl.google.com/dl/firebase/ios/carthage/11.13.0/FirebaseInAppMessaging-db00d9a8196980fe.zip", + "11.14.0": "https://dl.google.com/dl/firebase/ios/carthage/11.14.0/FirebaseInAppMessaging-934596e813fe5d6e.zip", "11.2.0": "https://dl.google.com/dl/firebase/ios/carthage/11.2.0/FirebaseInAppMessaging-6fae0a778e9d3efa.zip", "11.3.0": "https://dl.google.com/dl/firebase/ios/carthage/11.3.0/FirebaseInAppMessaging-3a1a331c86520356.zip", "11.4.0": "https://dl.google.com/dl/firebase/ios/carthage/11.4.0/FirebaseInAppMessaging-a8054099dd2918b3.zip", diff --git a/ReleaseTooling/CarthageJSON/FirebaseMLModelDownloaderBinary.json b/ReleaseTooling/CarthageJSON/FirebaseMLModelDownloaderBinary.json index 2c7f3121910..f1cd1300ef8 100644 --- a/ReleaseTooling/CarthageJSON/FirebaseMLModelDownloaderBinary.json +++ b/ReleaseTooling/CarthageJSON/FirebaseMLModelDownloaderBinary.json @@ -34,6 +34,7 @@ "11.11.0": "https://dl.google.com/dl/firebase/ios/carthage/11.11.0/FirebaseMLModelDownloader-9af14fef01f3233b.zip", "11.12.0": "https://dl.google.com/dl/firebase/ios/carthage/11.12.0/FirebaseMLModelDownloader-90a680269b1b7dc1.zip", "11.13.0": "https://dl.google.com/dl/firebase/ios/carthage/11.13.0/FirebaseMLModelDownloader-680180005688845d.zip", + "11.14.0": "https://dl.google.com/dl/firebase/ios/carthage/11.14.0/FirebaseMLModelDownloader-a4329595e01513a5.zip", "11.2.0": "https://dl.google.com/dl/firebase/ios/carthage/11.2.0/FirebaseMLModelDownloader-d8649822e63fbf7f.zip", "11.3.0": "https://dl.google.com/dl/firebase/ios/carthage/11.3.0/FirebaseMLModelDownloader-517f51af92733a7f.zip", "11.4.0": "https://dl.google.com/dl/firebase/ios/carthage/11.4.0/FirebaseMLModelDownloader-069609cbcde7e789.zip", diff --git a/ReleaseTooling/CarthageJSON/FirebaseMessagingBinary.json b/ReleaseTooling/CarthageJSON/FirebaseMessagingBinary.json index 5aebd39ca28..776615f4ea6 100644 --- a/ReleaseTooling/CarthageJSON/FirebaseMessagingBinary.json +++ b/ReleaseTooling/CarthageJSON/FirebaseMessagingBinary.json @@ -34,6 +34,7 @@ "11.11.0": "https://dl.google.com/dl/firebase/ios/carthage/11.11.0/FirebaseMessaging-00a1ed88e98f2d4e.zip", "11.12.0": "https://dl.google.com/dl/firebase/ios/carthage/11.12.0/FirebaseMessaging-c27934ab4d2ac145.zip", "11.13.0": "https://dl.google.com/dl/firebase/ios/carthage/11.13.0/FirebaseMessaging-57ff2659837e66f7.zip", + "11.14.0": "https://dl.google.com/dl/firebase/ios/carthage/11.14.0/FirebaseMessaging-a49d55ace7976c99.zip", "11.2.0": "https://dl.google.com/dl/firebase/ios/carthage/11.2.0/FirebaseMessaging-70e63bb9d9590ded.zip", "11.3.0": "https://dl.google.com/dl/firebase/ios/carthage/11.3.0/FirebaseMessaging-8a39834fead3c581.zip", "11.4.0": "https://dl.google.com/dl/firebase/ios/carthage/11.4.0/FirebaseMessaging-2d09725e8b98d199.zip", diff --git a/ReleaseTooling/CarthageJSON/FirebasePerformanceBinary.json b/ReleaseTooling/CarthageJSON/FirebasePerformanceBinary.json index 758c3975ae9..19ba1f6da82 100644 --- a/ReleaseTooling/CarthageJSON/FirebasePerformanceBinary.json +++ b/ReleaseTooling/CarthageJSON/FirebasePerformanceBinary.json @@ -34,6 +34,7 @@ "11.11.0": "https://dl.google.com/dl/firebase/ios/carthage/11.11.0/FirebasePerformance-cd019e13c2f186dd.zip", "11.12.0": "https://dl.google.com/dl/firebase/ios/carthage/11.12.0/FirebasePerformance-d8b225f36b8cbf8b.zip", "11.13.0": "https://dl.google.com/dl/firebase/ios/carthage/11.13.0/FirebasePerformance-916f67a44f64a09c.zip", + "11.14.0": "https://dl.google.com/dl/firebase/ios/carthage/11.14.0/FirebasePerformance-0a23b7bfbd3f251e.zip", "11.2.0": "https://dl.google.com/dl/firebase/ios/carthage/11.2.0/FirebasePerformance-aa174ee3102722d9.zip", "11.3.0": "https://dl.google.com/dl/firebase/ios/carthage/11.3.0/FirebasePerformance-a489ac7a27d9b53d.zip", "11.4.0": "https://dl.google.com/dl/firebase/ios/carthage/11.4.0/FirebasePerformance-9a6f62e80c2324f4.zip", diff --git a/ReleaseTooling/CarthageJSON/FirebaseRemoteConfigBinary.json b/ReleaseTooling/CarthageJSON/FirebaseRemoteConfigBinary.json index 681664d0f4e..e59f01d63a9 100644 --- a/ReleaseTooling/CarthageJSON/FirebaseRemoteConfigBinary.json +++ b/ReleaseTooling/CarthageJSON/FirebaseRemoteConfigBinary.json @@ -34,6 +34,7 @@ "11.11.0": "https://dl.google.com/dl/firebase/ios/carthage/11.11.0/FirebaseRemoteConfig-e7e899bcddf7ab64.zip", "11.12.0": "https://dl.google.com/dl/firebase/ios/carthage/11.12.0/FirebaseRemoteConfig-10e4aac268e7dde2.zip", "11.13.0": "https://dl.google.com/dl/firebase/ios/carthage/11.13.0/FirebaseRemoteConfig-cb344560e8a1a69e.zip", + "11.14.0": "https://dl.google.com/dl/firebase/ios/carthage/11.14.0/FirebaseRemoteConfig-010bc32e24c1e227.zip", "11.2.0": "https://dl.google.com/dl/firebase/ios/carthage/11.2.0/FirebaseRemoteConfig-9a298869ce3cc6db.zip", "11.3.0": "https://dl.google.com/dl/firebase/ios/carthage/11.3.0/FirebaseRemoteConfig-940ed38696414882.zip", "11.4.0": "https://dl.google.com/dl/firebase/ios/carthage/11.4.0/FirebaseRemoteConfig-ec432e976582d0eb.zip", diff --git a/ReleaseTooling/CarthageJSON/FirebaseStorageBinary.json b/ReleaseTooling/CarthageJSON/FirebaseStorageBinary.json index 614545ab79d..83a8c4af6d0 100644 --- a/ReleaseTooling/CarthageJSON/FirebaseStorageBinary.json +++ b/ReleaseTooling/CarthageJSON/FirebaseStorageBinary.json @@ -34,6 +34,7 @@ "11.11.0": "https://dl.google.com/dl/firebase/ios/carthage/11.11.0/FirebaseStorage-65b8d2495abb8eca.zip", "11.12.0": "https://dl.google.com/dl/firebase/ios/carthage/11.12.0/FirebaseStorage-3926226b5e3ec43d.zip", "11.13.0": "https://dl.google.com/dl/firebase/ios/carthage/11.13.0/FirebaseStorage-d276ced3a4fd1b8c.zip", + "11.14.0": "https://dl.google.com/dl/firebase/ios/carthage/11.14.0/FirebaseStorage-109dd1d20a0c531e.zip", "11.2.0": "https://dl.google.com/dl/firebase/ios/carthage/11.2.0/FirebaseStorage-b9b969b0d1254065.zip", "11.3.0": "https://dl.google.com/dl/firebase/ios/carthage/11.3.0/FirebaseStorage-0435eeaa87324cd4.zip", "11.4.0": "https://dl.google.com/dl/firebase/ios/carthage/11.4.0/FirebaseStorage-0b7a2306152984a2.zip", diff --git a/ReleaseTooling/CarthageJSON/FirebaseVertexAIBinary.json b/ReleaseTooling/CarthageJSON/FirebaseVertexAIBinary.json index 8e5b156ee34..14875d530ce 100644 --- a/ReleaseTooling/CarthageJSON/FirebaseVertexAIBinary.json +++ b/ReleaseTooling/CarthageJSON/FirebaseVertexAIBinary.json @@ -3,6 +3,7 @@ "11.11.0": "https://dl.google.com/dl/firebase/ios/carthage/11.11.0/FirebaseVertexAI-8e96d0389286185f.zip", "11.12.0": "https://dl.google.com/dl/firebase/ios/carthage/11.12.0/FirebaseVertexAI-7fabd201dfabab6f.zip", "11.13.0": "https://dl.google.com/dl/firebase/ios/carthage/11.13.0/FirebaseVertexAI-3fc94c339df642e3.zip", + "11.14.0": "https://dl.google.com/dl/firebase/ios/carthage/11.14.0/FirebaseVertexAI-4ec0e98c460030e1.zip", "11.5.0": "https://dl.google.com/dl/firebase/ios/carthage/11.5.0/FirebaseVertexAI-d5d0ffd8010245da.zip", "11.6.0": "https://dl.google.com/dl/firebase/ios/carthage/11.6.0/FirebaseVertexAI-6f6520d750ba54c4.zip", "11.7.0": "https://dl.google.com/dl/firebase/ios/carthage/11.7.0/FirebaseVertexAI-bd6d038eb0cf85c6.zip", From d5e993c7c74125a90938f869033789389a3ed052 Mon Sep 17 00:00:00 2001 From: Andrew Heard Date: Tue, 3 Jun 2025 16:24:11 -0400 Subject: [PATCH 061/113] [Firebase AI] Add Firebase AI Logic SDK to Carthage docs (#14928) --- Carthage.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Carthage.md b/Carthage.md index 52094c1c4c1..d9c8a144c6e 100644 --- a/Carthage.md +++ b/Carthage.md @@ -31,6 +31,7 @@ Firebase components that you want to include in your app. Note that ``` binary "https://dl.google.com/dl/firebase/ios/carthage/FirebaseABTestingBinary.json" +binary "https://dl.google.com/dl/firebase/ios/carthage/FirebaseAIBinary.json" binary "https://dl.google.com/dl/firebase/ios/carthage/FirebaseAdMobBinary.json" binary "https://dl.google.com/dl/firebase/ios/carthage/FirebaseAnalyticsBinary.json" binary "https://dl.google.com/dl/firebase/ios/carthage/FirebaseAppCheckBinary.json" @@ -48,6 +49,7 @@ binary "https://dl.google.com/dl/firebase/ios/carthage/FirebaseMessagingBinary.j binary "https://dl.google.com/dl/firebase/ios/carthage/FirebasePerformanceBinary.json" binary "https://dl.google.com/dl/firebase/ios/carthage/FirebaseRemoteConfigBinary.json" binary "https://dl.google.com/dl/firebase/ios/carthage/FirebaseStorageBinary.json" +binary "https://dl.google.com/dl/firebase/ios/carthage/FirebaseVertexAIBinary.json" ``` - Run `carthage update` - Use Finder to open `Carthage/Build`. From 1045d4493d86210e92e4b2b3082e91e921069369 Mon Sep 17 00:00:00 2001 From: Andrew Heard Date: Tue, 3 Jun 2025 21:16:45 -0400 Subject: [PATCH 062/113] [Release] Update versions for `11.15.0` (#14930) --- Firebase.podspec | 48 +++++++++---------- FirebaseABTesting.podspec | 4 +- FirebaseAI.podspec | 6 +-- FirebaseAnalytics.podspec | 14 +++--- FirebaseAnalyticsOnDeviceConversion.podspec | 4 +- FirebaseAppCheck.podspec | 4 +- FirebaseAppCheckInterop.podspec | 2 +- FirebaseAppDistribution.podspec | 4 +- FirebaseAuth.podspec | 6 +-- FirebaseAuthInterop.podspec | 2 +- FirebaseCombineSwift.podspec | 4 +- FirebaseCore.podspec | 4 +- FirebaseCoreExtension.podspec | 4 +- FirebaseCoreInternal.podspec | 2 +- FirebaseCrashlytics.podspec | 4 +- FirebaseDatabase.podspec | 4 +- FirebaseDynamicLinks.podspec | 4 +- FirebaseFirestore.podspec | 8 ++-- FirebaseFirestoreInternal.podspec | 4 +- FirebaseFunctions.podspec | 6 +-- FirebaseInAppMessaging.podspec | 4 +- FirebaseInstallations.podspec | 4 +- FirebaseMLModelDownloader.podspec | 6 +-- FirebaseMessaging.podspec | 4 +- FirebaseMessagingInterop.podspec | 2 +- FirebasePerformance.podspec | 4 +- FirebaseRemoteConfig.podspec | 4 +- FirebaseRemoteConfigInterop.podspec | 2 +- FirebaseSessions.podspec | 6 +-- FirebaseSharedSwift.podspec | 2 +- FirebaseStorage.podspec | 6 +-- FirebaseVertexAI.podspec | 4 +- GoogleAppMeasurement.podspec | 12 ++--- ...leAppMeasurementOnDeviceConversion.podspec | 2 +- Package.swift | 2 +- .../FirebaseManifest/FirebaseManifest.swift | 2 +- 36 files changed, 102 insertions(+), 102 deletions(-) diff --git a/Firebase.podspec b/Firebase.podspec index e97905a5a03..2417f0dcb38 100644 --- a/Firebase.podspec +++ b/Firebase.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'Firebase' - s.version = '11.14.0' + s.version = '11.15.0' s.summary = 'Firebase' s.description = <<-DESC @@ -36,14 +36,14 @@ Simplify your app development, grow your user base, and monetize more effectivel ss.ios.deployment_target = '12.0' ss.osx.deployment_target = '10.15' ss.tvos.deployment_target = '13.0' - ss.ios.dependency 'FirebaseAnalytics', '~> 11.14.0' - ss.osx.dependency 'FirebaseAnalytics', '~> 11.14.0' - ss.tvos.dependency 'FirebaseAnalytics', '~> 11.14.0' + ss.ios.dependency 'FirebaseAnalytics', '~> 11.15.0' + ss.osx.dependency 'FirebaseAnalytics', '~> 11.15.0' + ss.tvos.dependency 'FirebaseAnalytics', '~> 11.15.0' ss.dependency 'Firebase/CoreOnly' end s.subspec 'CoreOnly' do |ss| - ss.dependency 'FirebaseCore', '~> 11.14.0' + ss.dependency 'FirebaseCore', '~> 11.15.0' ss.source_files = 'CoreOnly/Sources/Firebase.h' ss.preserve_paths = 'CoreOnly/Sources/module.modulemap' if ENV['FIREBASE_POD_REPO_FOR_DEV_POD'] then @@ -79,13 +79,13 @@ Simplify your app development, grow your user base, and monetize more effectivel ss.ios.deployment_target = '12.0' ss.osx.deployment_target = '10.15' ss.tvos.deployment_target = '13.0' - ss.dependency 'FirebaseAnalytics/WithoutAdIdSupport', '~> 11.14.0' + ss.dependency 'FirebaseAnalytics/WithoutAdIdSupport', '~> 11.15.0' ss.dependency 'Firebase/CoreOnly' end s.subspec 'ABTesting' do |ss| ss.dependency 'Firebase/CoreOnly' - ss.dependency 'FirebaseABTesting', '~> 11.14.0' + ss.dependency 'FirebaseABTesting', '~> 11.15.0' # Standard platforms PLUS watchOS. ss.ios.deployment_target = '13.0' ss.osx.deployment_target = '10.15' @@ -95,13 +95,13 @@ Simplify your app development, grow your user base, and monetize more effectivel s.subspec 'AppDistribution' do |ss| ss.dependency 'Firebase/CoreOnly' - ss.ios.dependency 'FirebaseAppDistribution', '~> 11.14.0-beta' + ss.ios.dependency 'FirebaseAppDistribution', '~> 11.15.0-beta' ss.ios.deployment_target = '13.0' end s.subspec 'AppCheck' do |ss| ss.dependency 'Firebase/CoreOnly' - ss.dependency 'FirebaseAppCheck', '~> 11.14.0' + ss.dependency 'FirebaseAppCheck', '~> 11.15.0' ss.ios.deployment_target = '13.0' ss.osx.deployment_target = '10.15' ss.tvos.deployment_target = '13.0' @@ -110,7 +110,7 @@ Simplify your app development, grow your user base, and monetize more effectivel s.subspec 'Auth' do |ss| ss.dependency 'Firebase/CoreOnly' - ss.dependency 'FirebaseAuth', '~> 11.14.0' + ss.dependency 'FirebaseAuth', '~> 11.15.0' # Standard platforms PLUS watchOS. ss.ios.deployment_target = '13.0' ss.osx.deployment_target = '10.15' @@ -120,7 +120,7 @@ Simplify your app development, grow your user base, and monetize more effectivel s.subspec 'Crashlytics' do |ss| ss.dependency 'Firebase/CoreOnly' - ss.dependency 'FirebaseCrashlytics', '~> 11.14.0' + ss.dependency 'FirebaseCrashlytics', '~> 11.15.0' # Standard platforms PLUS watchOS. ss.ios.deployment_target = '12.0' ss.osx.deployment_target = '10.15' @@ -130,7 +130,7 @@ Simplify your app development, grow your user base, and monetize more effectivel s.subspec 'Database' do |ss| ss.dependency 'Firebase/CoreOnly' - ss.dependency 'FirebaseDatabase', '~> 11.14.0' + ss.dependency 'FirebaseDatabase', '~> 11.15.0' # Standard platforms PLUS watchOS 7. ss.ios.deployment_target = '13.0' ss.osx.deployment_target = '10.15' @@ -140,13 +140,13 @@ Simplify your app development, grow your user base, and monetize more effectivel s.subspec 'DynamicLinks' do |ss| ss.dependency 'Firebase/CoreOnly' - ss.ios.dependency 'FirebaseDynamicLinks', '~> 11.14.0' + ss.ios.dependency 'FirebaseDynamicLinks', '~> 11.15.0' ss.ios.deployment_target = '13.0' end s.subspec 'Firestore' do |ss| ss.dependency 'Firebase/CoreOnly' - ss.dependency 'FirebaseFirestore', '~> 11.14.0' + ss.dependency 'FirebaseFirestore', '~> 11.15.0' ss.ios.deployment_target = '13.0' ss.osx.deployment_target = '10.15' ss.tvos.deployment_target = '13.0' @@ -154,7 +154,7 @@ Simplify your app development, grow your user base, and monetize more effectivel s.subspec 'Functions' do |ss| ss.dependency 'Firebase/CoreOnly' - ss.dependency 'FirebaseFunctions', '~> 11.14.0' + ss.dependency 'FirebaseFunctions', '~> 11.15.0' # Standard platforms PLUS watchOS. ss.ios.deployment_target = '13.0' ss.osx.deployment_target = '10.15' @@ -164,20 +164,20 @@ Simplify your app development, grow your user base, and monetize more effectivel s.subspec 'InAppMessaging' do |ss| ss.dependency 'Firebase/CoreOnly' - ss.ios.dependency 'FirebaseInAppMessaging', '~> 11.14.0-beta' - ss.tvos.dependency 'FirebaseInAppMessaging', '~> 11.14.0-beta' + ss.ios.dependency 'FirebaseInAppMessaging', '~> 11.15.0-beta' + ss.tvos.dependency 'FirebaseInAppMessaging', '~> 11.15.0-beta' ss.ios.deployment_target = '13.0' ss.tvos.deployment_target = '13.0' end s.subspec 'Installations' do |ss| ss.dependency 'Firebase/CoreOnly' - ss.dependency 'FirebaseInstallations', '~> 11.14.0' + ss.dependency 'FirebaseInstallations', '~> 11.15.0' end s.subspec 'Messaging' do |ss| ss.dependency 'Firebase/CoreOnly' - ss.dependency 'FirebaseMessaging', '~> 11.14.0' + ss.dependency 'FirebaseMessaging', '~> 11.15.0' # Standard platforms PLUS watchOS. ss.ios.deployment_target = '13.0' ss.osx.deployment_target = '10.15' @@ -187,7 +187,7 @@ Simplify your app development, grow your user base, and monetize more effectivel s.subspec 'MLModelDownloader' do |ss| ss.dependency 'Firebase/CoreOnly' - ss.dependency 'FirebaseMLModelDownloader', '~> 11.14.0-beta' + ss.dependency 'FirebaseMLModelDownloader', '~> 11.15.0-beta' # Standard platforms PLUS watchOS. ss.ios.deployment_target = '13.0' ss.osx.deployment_target = '10.15' @@ -197,15 +197,15 @@ Simplify your app development, grow your user base, and monetize more effectivel s.subspec 'Performance' do |ss| ss.dependency 'Firebase/CoreOnly' - ss.ios.dependency 'FirebasePerformance', '~> 11.14.0' - ss.tvos.dependency 'FirebasePerformance', '~> 11.14.0' + ss.ios.dependency 'FirebasePerformance', '~> 11.15.0' + ss.tvos.dependency 'FirebasePerformance', '~> 11.15.0' ss.ios.deployment_target = '13.0' ss.tvos.deployment_target = '13.0' end s.subspec 'RemoteConfig' do |ss| ss.dependency 'Firebase/CoreOnly' - ss.dependency 'FirebaseRemoteConfig', '~> 11.14.0' + ss.dependency 'FirebaseRemoteConfig', '~> 11.15.0' # Standard platforms PLUS watchOS. ss.ios.deployment_target = '13.0' ss.osx.deployment_target = '10.15' @@ -215,7 +215,7 @@ Simplify your app development, grow your user base, and monetize more effectivel s.subspec 'Storage' do |ss| ss.dependency 'Firebase/CoreOnly' - ss.dependency 'FirebaseStorage', '~> 11.14.0' + ss.dependency 'FirebaseStorage', '~> 11.15.0' # Standard platforms PLUS watchOS. ss.ios.deployment_target = '13.0' ss.osx.deployment_target = '10.15' diff --git a/FirebaseABTesting.podspec b/FirebaseABTesting.podspec index 2571e91fdda..5750efc2fbc 100644 --- a/FirebaseABTesting.podspec +++ b/FirebaseABTesting.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseABTesting' - s.version = '11.14.0' + s.version = '11.15.0' s.summary = 'Firebase ABTesting' s.description = <<-DESC @@ -52,7 +52,7 @@ Firebase Cloud Messaging and Firebase Remote Config in your app. 'GCC_C_LANGUAGE_STANDARD' => 'c99', 'HEADER_SEARCH_PATHS' => '"${PODS_TARGET_SRCROOT}"' } - s.dependency 'FirebaseCore', '~> 11.14.0' + s.dependency 'FirebaseCore', '~> 11.15.0' s.test_spec 'unit' do |unit_tests| unit_tests.scheme = { :code_coverage => true } diff --git a/FirebaseAI.podspec b/FirebaseAI.podspec index 9d7bba0e9eb..faa8db5f0c0 100644 --- a/FirebaseAI.podspec +++ b/FirebaseAI.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseAI' - s.version = '11.14.0' + s.version = '11.15.0' s.summary = 'Firebase AI SDK' s.description = <<-DESC @@ -45,8 +45,8 @@ Build AI-powered apps and features with the Gemini API using the Firebase AI SDK s.dependency 'FirebaseAppCheckInterop', '~> 11.4' s.dependency 'FirebaseAuthInterop', '~> 11.4' - s.dependency 'FirebaseCore', '~> 11.14.0' - s.dependency 'FirebaseCoreExtension', '~> 11.14.0' + s.dependency 'FirebaseCore', '~> 11.15.0' + s.dependency 'FirebaseCoreExtension', '~> 11.15.0' s.test_spec 'unit' do |unit_tests| unit_tests_dir = 'FirebaseAI/Tests/Unit/' diff --git a/FirebaseAnalytics.podspec b/FirebaseAnalytics.podspec index edd1099f316..a4569b8588f 100644 --- a/FirebaseAnalytics.podspec +++ b/FirebaseAnalytics.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseAnalytics' - s.version = '11.14.0' + s.version = '11.15.0' s.summary = 'Firebase Analytics for iOS' s.description = <<-DESC @@ -26,7 +26,7 @@ Pod::Spec.new do |s| s.libraries = 'c++', 'sqlite3', 'z' s.frameworks = 'StoreKit' - s.dependency 'FirebaseCore', '~> 11.14.0' + s.dependency 'FirebaseCore', '~> 11.15.0' s.dependency 'FirebaseInstallations', '~> 11.0' s.dependency 'GoogleUtilities/AppDelegateSwizzler', '~> 8.1' s.dependency 'GoogleUtilities/MethodSwizzler', '~> 8.1' @@ -37,29 +37,29 @@ Pod::Spec.new do |s| s.default_subspecs = 'Default' s.subspec 'Default' do |ss| - ss.dependency 'GoogleAppMeasurement/Default', '11.14.0' + ss.dependency 'GoogleAppMeasurement/Default', '11.15.0' ss.vendored_frameworks = 'Frameworks/FirebaseAnalytics.xcframework' end s.subspec 'Core' do |ss| - ss.dependency 'GoogleAppMeasurement/Core', '11.14.0' + ss.dependency 'GoogleAppMeasurement/Core', '11.15.0' ss.vendored_frameworks = 'Frameworks/FirebaseAnalytics.xcframework' end s.subspec 'IdentitySupport' do |ss| - ss.dependency 'GoogleAppMeasurement/IdentitySupport', '11.14.0' + ss.dependency 'GoogleAppMeasurement/IdentitySupport', '11.15.0' ss.vendored_frameworks = 'Frameworks/FirebaseAnalytics.xcframework' end # Deprecated. Use IdentitySupport subspec instead. s.subspec 'AdIdSupport' do |ss| - ss.dependency 'GoogleAppMeasurement/AdIdSupport', '11.14.0' + ss.dependency 'GoogleAppMeasurement/AdIdSupport', '11.15.0' ss.vendored_frameworks = 'Frameworks/FirebaseAnalytics.xcframework' end # Deprecated. Use Core subspec instead. s.subspec 'WithoutAdIdSupport' do |ss| - ss.dependency 'GoogleAppMeasurement/WithoutAdIdSupport', '11.14.0' + ss.dependency 'GoogleAppMeasurement/WithoutAdIdSupport', '11.15.0' ss.vendored_frameworks = 'Frameworks/FirebaseAnalytics.xcframework' end diff --git a/FirebaseAnalyticsOnDeviceConversion.podspec b/FirebaseAnalyticsOnDeviceConversion.podspec index ea20a084a1e..7eb70670266 100644 --- a/FirebaseAnalyticsOnDeviceConversion.podspec +++ b/FirebaseAnalyticsOnDeviceConversion.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseAnalyticsOnDeviceConversion' - s.version = '11.14.0' + s.version = '11.15.0' s.summary = 'On device conversion measurement plugin for FirebaseAnalytics. Not intended for direct use.' s.description = <<-DESC @@ -18,7 +18,7 @@ Pod::Spec.new do |s| s.cocoapods_version = '>= 1.12.0' - s.dependency 'GoogleAppMeasurementOnDeviceConversion', '11.14.0' + s.dependency 'GoogleAppMeasurementOnDeviceConversion', '11.15.0' s.static_framework = true diff --git a/FirebaseAppCheck.podspec b/FirebaseAppCheck.podspec index ed39fd0f653..a12e8bd7d99 100644 --- a/FirebaseAppCheck.podspec +++ b/FirebaseAppCheck.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseAppCheck' - s.version = '11.14.0' + s.version = '11.15.0' s.summary = 'Firebase App Check SDK.' s.description = <<-DESC @@ -46,7 +46,7 @@ Pod::Spec.new do |s| s.dependency 'AppCheckCore', '~> 11.0' s.dependency 'FirebaseAppCheckInterop', '~> 11.0' - s.dependency 'FirebaseCore', '~> 11.14.0' + s.dependency 'FirebaseCore', '~> 11.15.0' s.dependency 'GoogleUtilities/Environment', '~> 8.1' s.dependency 'GoogleUtilities/UserDefaults', '~> 8.1' diff --git a/FirebaseAppCheckInterop.podspec b/FirebaseAppCheckInterop.podspec index 0fab9e7950f..68f2a2871dc 100644 --- a/FirebaseAppCheckInterop.podspec +++ b/FirebaseAppCheckInterop.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseAppCheckInterop' - s.version = '11.14.0' + s.version = '11.15.0' s.summary = 'Interfaces that allow other Firebase SDKs to use AppCheck functionality.' s.description = <<-DESC diff --git a/FirebaseAppDistribution.podspec b/FirebaseAppDistribution.podspec index 8dfba67069a..700028f9a4a 100644 --- a/FirebaseAppDistribution.podspec +++ b/FirebaseAppDistribution.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseAppDistribution' - s.version = '11.14.0-beta' + s.version = '11.15.0-beta' s.summary = 'App Distribution for Firebase iOS SDK.' s.description = <<-DESC @@ -30,7 +30,7 @@ iOS SDK for App Distribution for Firebase. ] s.public_header_files = base_dir + 'Public/FirebaseAppDistribution/*.h' - s.dependency 'FirebaseCore', '~> 11.14.0' + s.dependency 'FirebaseCore', '~> 11.15.0' s.dependency 'GoogleUtilities/AppDelegateSwizzler', '~> 8.1' s.dependency 'GoogleUtilities/UserDefaults', '~> 8.1' s.dependency 'FirebaseInstallations', '~> 11.0' diff --git a/FirebaseAuth.podspec b/FirebaseAuth.podspec index 74b987a5f76..e11eaf47c0e 100644 --- a/FirebaseAuth.podspec +++ b/FirebaseAuth.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseAuth' - s.version = '11.14.0' + s.version = '11.15.0' s.summary = 'Apple platform client for Firebase Authentication' s.description = <<-DESC @@ -58,8 +58,8 @@ supports email and password accounts, as well as several 3rd party authenticatio s.ios.framework = 'SafariServices' s.dependency 'FirebaseAuthInterop', '~> 11.0' s.dependency 'FirebaseAppCheckInterop', '~> 11.0' - s.dependency 'FirebaseCore', '~> 11.14.0' - s.dependency 'FirebaseCoreExtension', '~> 11.14.0' + s.dependency 'FirebaseCore', '~> 11.15.0' + s.dependency 'FirebaseCoreExtension', '~> 11.15.0' s.dependency 'GoogleUtilities/AppDelegateSwizzler', '~> 8.1' s.dependency 'GoogleUtilities/Environment', '~> 8.1' s.dependency 'GTMSessionFetcher/Core', '>= 3.4', '< 5.0' diff --git a/FirebaseAuthInterop.podspec b/FirebaseAuthInterop.podspec index 35c976adee1..d08a9e2024d 100644 --- a/FirebaseAuthInterop.podspec +++ b/FirebaseAuthInterop.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseAuthInterop' - s.version = '11.14.0' + s.version = '11.15.0' s.summary = 'Interfaces that allow other Firebase SDKs to use Auth functionality.' s.description = <<-DESC diff --git a/FirebaseCombineSwift.podspec b/FirebaseCombineSwift.podspec index 02ce5fa2cd4..b027ae2edd3 100644 --- a/FirebaseCombineSwift.podspec +++ b/FirebaseCombineSwift.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseCombineSwift' - s.version = '11.14.0' + s.version = '11.15.0' s.summary = 'Swift extensions with Combine support for Firebase' s.description = <<-DESC @@ -51,7 +51,7 @@ for internal testing only. It should not be published. s.osx.framework = 'AppKit' s.tvos.framework = 'UIKit' - s.dependency 'FirebaseCore', '~> 11.14.0' + s.dependency 'FirebaseCore', '~> 11.15.0' s.dependency 'FirebaseAuth', '~> 11.0' s.dependency 'FirebaseFunctions', '~> 11.0' s.dependency 'FirebaseFirestore', '~> 11.0' diff --git a/FirebaseCore.podspec b/FirebaseCore.podspec index 4e84de8a31b..63a0a5b27fa 100644 --- a/FirebaseCore.podspec +++ b/FirebaseCore.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseCore' - s.version = '11.14.0' + s.version = '11.15.0' s.summary = 'Firebase Core' s.description = <<-DESC @@ -53,7 +53,7 @@ Firebase Core includes FIRApp and FIROptions which provide central configuration # Remember to also update version in `cmake/external/GoogleUtilities.cmake` s.dependency 'GoogleUtilities/Environment', '~> 8.1' s.dependency 'GoogleUtilities/Logger', '~> 8.1' - s.dependency 'FirebaseCoreInternal', '~> 11.14.0' + s.dependency 'FirebaseCoreInternal', '~> 11.15.0' s.pod_target_xcconfig = { 'GCC_C_LANGUAGE_STANDARD' => 'c99', diff --git a/FirebaseCoreExtension.podspec b/FirebaseCoreExtension.podspec index 6ed71182654..2741cd941bf 100644 --- a/FirebaseCoreExtension.podspec +++ b/FirebaseCoreExtension.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseCoreExtension' - s.version = '11.14.0' + s.version = '11.15.0' s.summary = 'Extended FirebaseCore APIs for Firebase product SDKs' s.description = <<-DESC @@ -34,5 +34,5 @@ Pod::Spec.new do |s| "#{s.module_name}_Privacy" => 'FirebaseCore/Extension/Resources/PrivacyInfo.xcprivacy' } - s.dependency 'FirebaseCore', '~> 11.14.0' + s.dependency 'FirebaseCore', '~> 11.15.0' end diff --git a/FirebaseCoreInternal.podspec b/FirebaseCoreInternal.podspec index b4ff179b38d..77bf1d633d6 100644 --- a/FirebaseCoreInternal.podspec +++ b/FirebaseCoreInternal.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseCoreInternal' - s.version = '11.14.0' + s.version = '11.15.0' s.summary = 'APIs for internal FirebaseCore usage.' s.description = <<-DESC diff --git a/FirebaseCrashlytics.podspec b/FirebaseCrashlytics.podspec index e55bcbb37a3..6955088b69e 100644 --- a/FirebaseCrashlytics.podspec +++ b/FirebaseCrashlytics.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseCrashlytics' - s.version = '11.14.0' + s.version = '11.15.0' s.summary = 'Best and lightest-weight crash reporting for mobile, desktop and tvOS.' s.description = 'Firebase Crashlytics helps you track, prioritize, and fix stability issues that erode app quality.' s.homepage = 'https://firebase.google.com/' @@ -59,7 +59,7 @@ Pod::Spec.new do |s| cp -f ./Crashlytics/CrashlyticsInputFiles.xcfilelist ./CrashlyticsInputFiles.xcfilelist PREPARE_COMMAND_END - s.dependency 'FirebaseCore', '~> 11.14.0' + s.dependency 'FirebaseCore', '~> 11.15.0' s.dependency 'FirebaseInstallations', '~> 11.0' s.dependency 'FirebaseSessions', '~> 11.0' s.dependency 'FirebaseRemoteConfigInterop', '~> 11.0' diff --git a/FirebaseDatabase.podspec b/FirebaseDatabase.podspec index 8a39ee33c9a..128a19ba904 100644 --- a/FirebaseDatabase.podspec +++ b/FirebaseDatabase.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseDatabase' - s.version = '11.14.0' + s.version = '11.15.0' s.summary = 'Firebase Realtime Database' s.description = <<-DESC @@ -48,7 +48,7 @@ Simplify your iOS development, grow your user base, and monetize more effectivel s.macos.frameworks = 'CFNetwork', 'Security', 'SystemConfiguration' s.watchos.frameworks = 'CFNetwork', 'Security', 'WatchKit' s.dependency 'leveldb-library', '~> 1.22' - s.dependency 'FirebaseCore', '~> 11.14.0' + s.dependency 'FirebaseCore', '~> 11.15.0' s.dependency 'FirebaseAppCheckInterop', '~> 11.0' s.dependency 'FirebaseSharedSwift', '~> 11.0' s.dependency 'GoogleUtilities/UserDefaults', '~> 8.1' diff --git a/FirebaseDynamicLinks.podspec b/FirebaseDynamicLinks.podspec index e2f8f9421e6..13d0a340d4d 100644 --- a/FirebaseDynamicLinks.podspec +++ b/FirebaseDynamicLinks.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseDynamicLinks' - s.version = '11.14.0' + s.version = '11.15.0' s.summary = 'Firebase Dynamic Links' s.description = <<-DESC @@ -37,7 +37,7 @@ Firebase Dynamic Links are deep links that enhance user experience and increase } s.frameworks = 'QuartzCore' s.weak_framework = 'WebKit' - s.dependency 'FirebaseCore', '~> 11.14.0' + s.dependency 'FirebaseCore', '~> 11.15.0' s.pod_target_xcconfig = { 'GCC_C_LANGUAGE_STANDARD' => 'c99', diff --git a/FirebaseFirestore.podspec b/FirebaseFirestore.podspec index cb6eea4169a..d82d3525034 100644 --- a/FirebaseFirestore.podspec +++ b/FirebaseFirestore.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseFirestore' - s.version = '11.14.0' + s.version = '11.15.0' s.summary = 'Google Cloud Firestore' s.description = <<-DESC Google Cloud Firestore is a NoSQL document database built for automatic scaling, high performance, and ease of application development. @@ -35,9 +35,9 @@ Google Cloud Firestore is a NoSQL document database built for automatic scaling, "#{s.module_name}_Privacy" => 'Firestore/Swift/Source/Resources/PrivacyInfo.xcprivacy' } - s.dependency 'FirebaseCore', '~> 11.14.0' - s.dependency 'FirebaseCoreExtension', '~> 11.14.0' - s.dependency 'FirebaseFirestoreInternal', '11.14.0' + s.dependency 'FirebaseCore', '~> 11.15.0' + s.dependency 'FirebaseCoreExtension', '~> 11.15.0' + s.dependency 'FirebaseFirestoreInternal', '11.15.0' s.dependency 'FirebaseSharedSwift', '~> 11.0' end diff --git a/FirebaseFirestoreInternal.podspec b/FirebaseFirestoreInternal.podspec index 5362cf20699..0f71bd8dbe0 100644 --- a/FirebaseFirestoreInternal.podspec +++ b/FirebaseFirestoreInternal.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseFirestoreInternal' - s.version = '11.14.0' + s.version = '11.15.0' s.summary = 'Google Cloud Firestore' s.description = <<-DESC @@ -93,7 +93,7 @@ Google Cloud Firestore is a NoSQL document database built for automatic scaling, } s.dependency 'FirebaseAppCheckInterop', '~> 11.0' - s.dependency 'FirebaseCore', '~> 11.14.0' + s.dependency 'FirebaseCore', '~> 11.15.0' abseil_version = '~> 1.20240722.0' s.dependency 'abseil/algorithm', abseil_version diff --git a/FirebaseFunctions.podspec b/FirebaseFunctions.podspec index d1df6871066..7fd85e241d1 100644 --- a/FirebaseFunctions.podspec +++ b/FirebaseFunctions.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseFunctions' - s.version = '11.14.0' + s.version = '11.15.0' s.summary = 'Cloud Functions for Firebase' s.description = <<-DESC @@ -35,8 +35,8 @@ Cloud Functions for Firebase. 'FirebaseFunctions/Sources/**/*.swift', ] - s.dependency 'FirebaseCore', '~> 11.14.0' - s.dependency 'FirebaseCoreExtension', '~> 11.14.0' + s.dependency 'FirebaseCore', '~> 11.15.0' + s.dependency 'FirebaseCoreExtension', '~> 11.15.0' s.dependency 'FirebaseAppCheckInterop', '~> 11.0' s.dependency 'FirebaseAuthInterop', '~> 11.0' s.dependency 'FirebaseMessagingInterop', '~> 11.0' diff --git a/FirebaseInAppMessaging.podspec b/FirebaseInAppMessaging.podspec index 99570fd5158..c6e0e263968 100644 --- a/FirebaseInAppMessaging.podspec +++ b/FirebaseInAppMessaging.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseInAppMessaging' - s.version = '11.14.0-beta' + s.version = '11.15.0-beta' s.summary = 'Firebase In-App Messaging for iOS' s.description = <<-DESC @@ -80,7 +80,7 @@ See more product details at https://firebase.google.com/products/in-app-messagin s.framework = 'UIKit' - s.dependency 'FirebaseCore', '~> 11.14.0' + s.dependency 'FirebaseCore', '~> 11.15.0' s.dependency 'FirebaseInstallations', '~> 11.0' s.dependency 'FirebaseABTesting', '~> 11.0' s.dependency 'GoogleUtilities/Environment', '~> 8.1' diff --git a/FirebaseInstallations.podspec b/FirebaseInstallations.podspec index dca6b03b114..0adffd04b85 100644 --- a/FirebaseInstallations.podspec +++ b/FirebaseInstallations.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseInstallations' - s.version = '11.14.0' + s.version = '11.15.0' s.summary = 'Firebase Installations' s.description = <<-DESC @@ -45,7 +45,7 @@ Pod::Spec.new do |s| } s.framework = 'Security' - s.dependency 'FirebaseCore', '~> 11.14.0' + s.dependency 'FirebaseCore', '~> 11.15.0' s.dependency 'PromisesObjC', '~> 2.4' s.dependency 'GoogleUtilities/Environment', '~> 8.1' s.dependency 'GoogleUtilities/UserDefaults', '~> 8.1' diff --git a/FirebaseMLModelDownloader.podspec b/FirebaseMLModelDownloader.podspec index 37681cc168e..004a74143be 100644 --- a/FirebaseMLModelDownloader.podspec +++ b/FirebaseMLModelDownloader.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseMLModelDownloader' - s.version = '11.14.0-beta' + s.version = '11.15.0-beta' s.summary = 'Firebase ML Model Downloader' s.description = <<-DESC @@ -36,8 +36,8 @@ Pod::Spec.new do |s| ] s.framework = 'Foundation' - s.dependency 'FirebaseCore', '~> 11.14.0' - s.dependency 'FirebaseCoreExtension', '~> 11.14.0' + s.dependency 'FirebaseCore', '~> 11.15.0' + s.dependency 'FirebaseCoreExtension', '~> 11.15.0' s.dependency 'FirebaseInstallations', '~> 11.0' s.dependency 'GoogleDataTransport', '~> 10.0' s.dependency 'GoogleUtilities/UserDefaults', '~> 8.1' diff --git a/FirebaseMessaging.podspec b/FirebaseMessaging.podspec index 40c124b4deb..9e66e74b205 100644 --- a/FirebaseMessaging.podspec +++ b/FirebaseMessaging.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseMessaging' - s.version = '11.14.0' + s.version = '11.15.0' s.summary = 'Firebase Messaging' s.description = <<-DESC @@ -62,7 +62,7 @@ device, and it is completely free. s.osx.framework = 'SystemConfiguration' s.weak_framework = 'UserNotifications' s.dependency 'FirebaseInstallations', '~> 11.0' - s.dependency 'FirebaseCore', '~> 11.14.0' + s.dependency 'FirebaseCore', '~> 11.15.0' s.dependency 'GoogleUtilities/AppDelegateSwizzler', '~> 8.1' s.dependency 'GoogleUtilities/Reachability', '~> 8.1' s.dependency 'GoogleUtilities/Environment', '~> 8.1' diff --git a/FirebaseMessagingInterop.podspec b/FirebaseMessagingInterop.podspec index a2df2355386..c79f294d70e 100644 --- a/FirebaseMessagingInterop.podspec +++ b/FirebaseMessagingInterop.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseMessagingInterop' - s.version = '11.14.0' + s.version = '11.15.0' s.summary = 'Interfaces that allow other Firebase SDKs to use Messaging functionality.' s.description = <<-DESC diff --git a/FirebasePerformance.podspec b/FirebasePerformance.podspec index 6524934ceba..a95ad9fbd2f 100644 --- a/FirebasePerformance.podspec +++ b/FirebasePerformance.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebasePerformance' - s.version = '11.14.0' + s.version = '11.15.0' s.summary = 'Firebase Performance' s.description = <<-DESC @@ -59,7 +59,7 @@ Firebase Performance library to measure performance of Mobile and Web Apps. s.ios.framework = 'CoreTelephony' s.framework = 'QuartzCore' s.framework = 'SystemConfiguration' - s.dependency 'FirebaseCore', '~> 11.14.0' + s.dependency 'FirebaseCore', '~> 11.15.0' s.dependency 'FirebaseInstallations', '~> 11.0' s.dependency 'FirebaseRemoteConfig', '~> 11.0' s.dependency 'FirebaseSessions', '~> 11.0' diff --git a/FirebaseRemoteConfig.podspec b/FirebaseRemoteConfig.podspec index 185cb5043e0..3d90a14b950 100644 --- a/FirebaseRemoteConfig.podspec +++ b/FirebaseRemoteConfig.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseRemoteConfig' - s.version = '11.14.0' + s.version = '11.15.0' s.summary = 'Firebase Remote Config' s.description = <<-DESC @@ -52,7 +52,7 @@ app update. } s.dependency 'FirebaseABTesting', '~> 11.0' s.dependency 'FirebaseSharedSwift', '~> 11.0' - s.dependency 'FirebaseCore', '~> 11.14.0' + s.dependency 'FirebaseCore', '~> 11.15.0' s.dependency 'FirebaseInstallations', '~> 11.0' s.dependency 'GoogleUtilities/Environment', '~> 8.1' s.dependency 'GoogleUtilities/NSData+zlib', '~> 8.1' diff --git a/FirebaseRemoteConfigInterop.podspec b/FirebaseRemoteConfigInterop.podspec index 52eb79c4060..49a101bf6bf 100644 --- a/FirebaseRemoteConfigInterop.podspec +++ b/FirebaseRemoteConfigInterop.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseRemoteConfigInterop' - s.version = '11.14.0' + s.version = '11.15.0' s.summary = 'Interfaces that allow other Firebase SDKs to use Remote Config functionality.' s.description = <<-DESC diff --git a/FirebaseSessions.podspec b/FirebaseSessions.podspec index 5a65feb6b53..8c92c6b6172 100644 --- a/FirebaseSessions.podspec +++ b/FirebaseSessions.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseSessions' - s.version = '11.14.0' + s.version = '11.15.0' s.summary = 'Firebase Sessions' s.description = <<-DESC @@ -39,8 +39,8 @@ Pod::Spec.new do |s| base_dir + 'SourcesObjC/**/*.{c,h,m,mm}', ] - s.dependency 'FirebaseCore', '~> 11.14.0' - s.dependency 'FirebaseCoreExtension', '~> 11.14.0' + s.dependency 'FirebaseCore', '~> 11.15.0' + s.dependency 'FirebaseCoreExtension', '~> 11.15.0' s.dependency 'FirebaseInstallations', '~> 11.0' s.dependency 'GoogleDataTransport', '~> 10.0' s.dependency 'GoogleUtilities/Environment', '~> 8.1' diff --git a/FirebaseSharedSwift.podspec b/FirebaseSharedSwift.podspec index 48f9c4c70a6..8ead4e75ddc 100644 --- a/FirebaseSharedSwift.podspec +++ b/FirebaseSharedSwift.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseSharedSwift' - s.version = '11.14.0' + s.version = '11.15.0' s.summary = 'Shared Swift Extensions for Firebase' s.description = <<-DESC diff --git a/FirebaseStorage.podspec b/FirebaseStorage.podspec index 1fe7d989556..07954bf0b9b 100644 --- a/FirebaseStorage.podspec +++ b/FirebaseStorage.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseStorage' - s.version = '11.14.0' + s.version = '11.15.0' s.summary = 'Firebase Storage' s.description = <<-DESC @@ -39,8 +39,8 @@ Firebase Storage provides robust, secure file uploads and downloads from Firebas s.dependency 'FirebaseAppCheckInterop', '~> 11.0' s.dependency 'FirebaseAuthInterop', '~> 11.0' - s.dependency 'FirebaseCore', '~> 11.14.0' - s.dependency 'FirebaseCoreExtension', '~> 11.14.0' + s.dependency 'FirebaseCore', '~> 11.15.0' + s.dependency 'FirebaseCoreExtension', '~> 11.15.0' s.dependency 'GTMSessionFetcher/Core', '>= 3.4', '< 5.0' s.dependency 'GoogleUtilities/Environment', '~> 8.1' diff --git a/FirebaseVertexAI.podspec b/FirebaseVertexAI.podspec index d5781cf613c..655bf991e21 100644 --- a/FirebaseVertexAI.podspec +++ b/FirebaseVertexAI.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseVertexAI' - s.version = '11.14.0' + s.version = '11.15.0' s.summary = 'Vertex AI in Firebase SDK' s.description = <<-DESC @@ -44,7 +44,7 @@ Firebase SDK. s.tvos.framework = 'UIKit' s.watchos.framework = 'WatchKit' - s.dependency 'FirebaseAI', '~> 11.14.0' + s.dependency 'FirebaseAI', '~> 11.15.0' s.test_spec 'unit' do |unit_tests| unit_tests_dir = 'FirebaseVertexAI/Tests/Unit/' diff --git a/GoogleAppMeasurement.podspec b/GoogleAppMeasurement.podspec index 64644f21ece..437923cd679 100644 --- a/GoogleAppMeasurement.podspec +++ b/GoogleAppMeasurement.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'GoogleAppMeasurement' - s.version = '11.14.0' + s.version = '11.15.0' s.summary = 'Shared measurement methods for Google libraries. Not intended for direct use.' s.description = <<-DESC @@ -37,8 +37,8 @@ Pod::Spec.new do |s| s.default_subspecs = 'Default' s.subspec 'Default' do |ss| - ss.dependency 'GoogleAppMeasurement/Core', '11.14.0' - ss.dependency 'GoogleAppMeasurement/IdentitySupport', '11.14.0' + ss.dependency 'GoogleAppMeasurement/Core', '11.15.0' + ss.dependency 'GoogleAppMeasurement/IdentitySupport', '11.15.0' ss.ios.dependency 'GoogleAdsOnDeviceConversion', '2.0.0' end @@ -47,17 +47,17 @@ Pod::Spec.new do |s| end s.subspec 'IdentitySupport' do |ss| - ss.dependency 'GoogleAppMeasurement/Core', '11.14.0' + ss.dependency 'GoogleAppMeasurement/Core', '11.15.0' ss.vendored_frameworks = 'Frameworks/GoogleAppMeasurementIdentitySupport.xcframework' end # Deprecated. Use IdentitySupport subspec instead. s.subspec 'AdIdSupport' do |ss| - ss.dependency 'GoogleAppMeasurement/IdentitySupport', '11.14.0' + ss.dependency 'GoogleAppMeasurement/IdentitySupport', '11.15.0' end # Deprecated. Use Core subspec instead. s.subspec 'WithoutAdIdSupport' do |ss| - ss.dependency 'GoogleAppMeasurement/Core', '11.14.0' + ss.dependency 'GoogleAppMeasurement/Core', '11.15.0' end end diff --git a/GoogleAppMeasurementOnDeviceConversion.podspec b/GoogleAppMeasurementOnDeviceConversion.podspec index 983a8c091ba..368e0618644 100644 --- a/GoogleAppMeasurementOnDeviceConversion.podspec +++ b/GoogleAppMeasurementOnDeviceConversion.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'GoogleAppMeasurementOnDeviceConversion' - s.version = '11.14.0' + s.version = '11.15.0' s.summary = <<-SUMMARY On device conversion measurement plugin for Google App Measurement. Not intended for direct use. diff --git a/Package.swift b/Package.swift index 84d9b3b3147..1a46f5a94ab 100644 --- a/Package.swift +++ b/Package.swift @@ -19,7 +19,7 @@ import class Foundation.ProcessInfo import PackageDescription -let firebaseVersion = "11.14.0" +let firebaseVersion = "11.15.0" let package = Package( name: "Firebase", diff --git a/ReleaseTooling/Sources/FirebaseManifest/FirebaseManifest.swift b/ReleaseTooling/Sources/FirebaseManifest/FirebaseManifest.swift index c00b28decd9..ae578987656 100755 --- a/ReleaseTooling/Sources/FirebaseManifest/FirebaseManifest.swift +++ b/ReleaseTooling/Sources/FirebaseManifest/FirebaseManifest.swift @@ -21,7 +21,7 @@ import Foundation /// The version and releasing fields of the non-Firebase pods should be reviewed every release. /// The array should be ordered so that any pod's dependencies precede it in the list. public let shared = Manifest( - version: "11.14.0", + version: "11.15.0", pods: [ Pod("FirebaseSharedSwift"), Pod("FirebaseCoreInternal"), From 78461e8bfb169c2323e9fe50b8d142c8c20029ec Mon Sep 17 00:00:00 2001 From: Andrew Heard Date: Thu, 5 Jun 2025 15:59:12 -0400 Subject: [PATCH 063/113] [Firebase AI] Add code snippets for `countTokens` (#14940) --- .../Unit/Snippets/CountTokensSnippets.swift | 63 +++++++++++++++++++ 1 file changed, 63 insertions(+) create mode 100644 FirebaseAI/Tests/Unit/Snippets/CountTokensSnippets.swift diff --git a/FirebaseAI/Tests/Unit/Snippets/CountTokensSnippets.swift b/FirebaseAI/Tests/Unit/Snippets/CountTokensSnippets.swift new file mode 100644 index 00000000000..8b8e37368f9 --- /dev/null +++ b/FirebaseAI/Tests/Unit/Snippets/CountTokensSnippets.swift @@ -0,0 +1,63 @@ +// Copyright 2025 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 FirebaseAI +import FirebaseCore +import XCTest + +// These snippet tests are intentionally skipped in CI jobs; see the README file in this directory +// for instructions on running them manually. + +@available(iOS 15.0, macOS 12.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) +final class CountTokensSnippets: XCTestCase { + let bundle = BundleTestUtil.bundle() + lazy var model = FirebaseAI.firebaseAI().generativeModel(modelName: "gemini-2.0-flash") + lazy var imageURL = { + guard let url = bundle.url(forResource: "blue", withExtension: "png") else { + fatalError("Image file blue.png not found in Resources.") + } + return url + }() + + lazy var image = { + guard let imageData = try? Data(contentsOf: imageURL) else { + fatalError("Failed to load image from URL: \(imageURL)") + } + return InlineDataPart(data: imageData, mimeType: "image/png") + }() + + override func setUpWithError() throws { + try FirebaseApp.configureDefaultAppForSnippets() + } + + override func tearDown() async throws { + await FirebaseApp.deleteDefaultAppForSnippets() + } + + func testTextOnlyInput() async throws { + let response = try await model.countTokens("Write a story about a magic backpack.") + + print("Total Tokens: \(response.totalTokens)") + } + + func testMultimodalInput() async throws { + let response = try await model.countTokens(image, "What's in this picture?") + + print("Total Tokens: \(response.totalTokens)") + // Print tokens by modality, for example "TEXT Tokens: 7" and "IMAGE Tokens: 258" + for promptTokensDetail in response.promptTokensDetails { + print("\(promptTokensDetail.modality.rawValue) Tokens: \(promptTokensDetail.tokenCount)") + } + } +} From 62942a194caf869e1a447f5b376d1fdc8f14acdc Mon Sep 17 00:00:00 2001 From: Nick Cooke <36927374+ncooke3@users.noreply.github.com> Date: Thu, 5 Jun 2025 17:21:45 -0400 Subject: [PATCH 064/113] [Auth] NFC - AuthRecaptchaVerifier.swift (#14938) --- .../Utilities/AuthRecaptchaVerifier.swift | 90 +++++++++---------- 1 file changed, 45 insertions(+), 45 deletions(-) diff --git a/FirebaseAuth/Sources/Swift/Utilities/AuthRecaptchaVerifier.swift b/FirebaseAuth/Sources/Swift/Utilities/AuthRecaptchaVerifier.swift index b0c61e4dfb4..c16175d0703 100644 --- a/FirebaseAuth/Sources/Swift/Utilities/AuthRecaptchaVerifier.swift +++ b/FirebaseAuth/Sources/Swift/Utilities/AuthRecaptchaVerifier.swift @@ -71,8 +71,10 @@ private(set) weak var auth: Auth? private(set) var agentConfig: AuthRecaptchaConfig? private(set) var tenantConfigs: [String: AuthRecaptchaConfig] = [:] + // Only initialized once. Recpatcha SDK does not support multiple clients. private(set) var recaptchaClient: RCARecaptchaClientProtocol? private static var _shared = AuthRecaptchaVerifier() + private let kRecaptchaVersion = "RECAPTCHA_ENTERPRISE" init() {} @@ -91,16 +93,6 @@ _ = shared(auth: auth) } - func siteKey() -> String? { - if let tenantID = auth?.tenantID { - if let config = tenantConfigs[tenantID] { - return config.siteKey - } - return nil - } - return agentConfig?.siteKey - } - func enablementStatus(forProvider provider: AuthRecaptchaProvider) -> AuthRecaptchaEnablementStatus { if let tenantID = auth?.tenantID, @@ -154,7 +146,48 @@ #endif // !(COCOAPODS || SWIFT_PACKAGE) } - private static var recaptchaClient: (any RCARecaptchaClientProtocol)? + func retrieveRecaptchaConfig(forceRefresh: Bool) async throws { + if !forceRefresh { + if let tenantID = auth?.tenantID { + if tenantConfigs[tenantID] != nil { + return + } + } else if agentConfig != nil { + return + } + } + + guard let auth = auth else { + throw AuthErrorUtils.error(code: .recaptchaNotEnabled, + message: "No requestConfiguration for Auth instance") + } + let request = GetRecaptchaConfigRequest(requestConfiguration: auth.requestConfiguration) + let response = try await auth.backend.call(with: request) + AuthLog.logInfo(code: "I-AUT000029", message: "reCAPTCHA config retrieval succeeded.") + try await parseRecaptchaConfigFromResponse(response: response) + } + + private func siteKey() -> String? { + if let tenantID = auth?.tenantID { + if let config = tenantConfigs[tenantID] { + return config.siteKey + } + return nil + } + return agentConfig?.siteKey + } + + func injectRecaptchaFields(request: any AuthRPCRequest, + provider: AuthRecaptchaProvider, + action: AuthRecaptchaAction) async throws { + try await retrieveRecaptchaConfig(forceRefresh: false) + if enablementStatus(forProvider: provider) != .off { + let token = try await verify(forceRefresh: false, action: action) + request.injectRecaptchaFields(recaptchaResponse: token, recaptchaVersion: kRecaptchaVersion) + } else { + request.injectRecaptchaFields(recaptchaResponse: nil, recaptchaVersion: kRecaptchaVersion) + } + } #if COCOAPODS || SWIFT_PACKAGE // No recaptcha on internal build system. private func recaptchaToken(siteKey: String, @@ -206,28 +239,7 @@ } } - func retrieveRecaptchaConfig(forceRefresh: Bool) async throws { - if !forceRefresh { - if let tenantID = auth?.tenantID { - if tenantConfigs[tenantID] != nil { - return - } - } else if agentConfig != nil { - return - } - } - - guard let auth = auth else { - throw AuthErrorUtils.error(code: .recaptchaNotEnabled, - message: "No requestConfiguration for Auth instance") - } - let request = GetRecaptchaConfigRequest(requestConfiguration: auth.requestConfiguration) - let response = try await auth.backend.call(with: request) - AuthLog.logInfo(code: "I-AUT000029", message: "reCAPTCHA config retrieval succeeded.") - try await parseRecaptchaConfigFromResponse(response: response) - } - - func parseRecaptchaConfigFromResponse(response: GetRecaptchaConfigResponse) async throws { + private func parseRecaptchaConfigFromResponse(response: GetRecaptchaConfigResponse) async throws { var enablementStatus: [AuthRecaptchaProvider: AuthRecaptchaEnablementStatus] = [:] var isRecaptchaEnabled = false if let enforcementState = response.enforcementState { @@ -263,17 +275,5 @@ agentConfig = config } } - - func injectRecaptchaFields(request: any AuthRPCRequest, - provider: AuthRecaptchaProvider, - action: AuthRecaptchaAction) async throws { - try await retrieveRecaptchaConfig(forceRefresh: false) - if enablementStatus(forProvider: provider) != .off { - let token = try await verify(forceRefresh: false, action: action) - request.injectRecaptchaFields(recaptchaResponse: token, recaptchaVersion: kRecaptchaVersion) - } else { - request.injectRecaptchaFields(recaptchaResponse: nil, recaptchaVersion: kRecaptchaVersion) - } - } } #endif From 4238479f88eae4170a889aa68306d9346f72e1dc Mon Sep 17 00:00:00 2001 From: Paul Beusterien Date: Mon, 9 Jun 2025 08:05:43 -0700 Subject: [PATCH 065/113] Rename VertexAITestApp to FirebaseAITestApp (#14943) --- .../project.pbxproj | 46 ++++----- .../xcschemes/FirebaseAITestApp-SPM.xcscheme | 97 +++++++++++++++++++ .../CountTokensIntegrationTests.swift | 2 +- .../GenerateContentIntegrationTests.swift | 2 +- .../Integration/ImagenIntegrationTests.swift | 2 +- .../Tests/Integration/IntegrationTests.swift | 2 +- .../Tests/Integration/SchemaTests.swift | 2 +- .../Tests/Utilities/InstanceConfig.swift | 2 +- scripts/build.sh | 8 +- 9 files changed, 130 insertions(+), 33 deletions(-) rename FirebaseAI/Tests/TestApp/{VertexAITestApp.xcodeproj => FirebaseAITestApp.xcodeproj}/project.pbxproj (94%) create mode 100644 FirebaseAI/Tests/TestApp/FirebaseAITestApp.xcodeproj/xcshareddata/xcschemes/FirebaseAITestApp-SPM.xcscheme diff --git a/FirebaseAI/Tests/TestApp/VertexAITestApp.xcodeproj/project.pbxproj b/FirebaseAI/Tests/TestApp/FirebaseAITestApp.xcodeproj/project.pbxproj similarity index 94% rename from FirebaseAI/Tests/TestApp/VertexAITestApp.xcodeproj/project.pbxproj rename to FirebaseAI/Tests/TestApp/FirebaseAITestApp.xcodeproj/project.pbxproj index 50303ad511b..fc62b25f132 100644 --- a/FirebaseAI/Tests/TestApp/VertexAITestApp.xcodeproj/project.pbxproj +++ b/FirebaseAI/Tests/TestApp/FirebaseAITestApp.xcodeproj/project.pbxproj @@ -37,14 +37,14 @@ containerPortal = 866138502CC943DD00F4B78E /* Project object */; proxyType = 1; remoteGlobalIDString = 866138572CC943DD00F4B78E; - remoteInfo = VertexAITestApp; + remoteInfo = FirebaseAITestApp; }; /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ 862218802D04E08D007ED2D4 /* IntegrationTestUtils.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IntegrationTestUtils.swift; sourceTree = ""; }; 864F8F702D4980D60002EA7E /* ImagenIntegrationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImagenIntegrationTests.swift; sourceTree = ""; }; - 866138582CC943DD00F4B78E /* VertexAITestApp-SPM.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "VertexAITestApp-SPM.app"; sourceTree = BUILT_PRODUCTS_DIR; }; + 866138582CC943DD00F4B78E /* FirebaseAITestApp-SPM.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "FirebaseAITestApp-SPM.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 8661385B2CC943DD00F4B78E /* TestApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TestApp.swift; sourceTree = ""; }; 8661385D2CC943DD00F4B78E /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = ""; }; 866138692CC943DE00F4B78E /* IntegrationTests-SPM.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "IntegrationTests-SPM.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -100,7 +100,7 @@ 866138592CC943DD00F4B78E /* Products */ = { isa = PBXGroup; children = ( - 866138582CC943DD00F4B78E /* VertexAITestApp-SPM.app */, + 866138582CC943DD00F4B78E /* FirebaseAITestApp-SPM.app */, 866138692CC943DE00F4B78E /* IntegrationTests-SPM.xctest */, ); name = Products; @@ -173,9 +173,9 @@ /* End PBXGroup section */ /* Begin PBXNativeTarget section */ - 866138572CC943DD00F4B78E /* VertexAITestApp-SPM */ = { + 866138572CC943DD00F4B78E /* FirebaseAITestApp-SPM */ = { isa = PBXNativeTarget; - buildConfigurationList = 8661387D2CC943DE00F4B78E /* Build configuration list for PBXNativeTarget "VertexAITestApp-SPM" */; + buildConfigurationList = 8661387D2CC943DE00F4B78E /* Build configuration list for PBXNativeTarget "FirebaseAITestApp-SPM" */; buildPhases = ( 866138542CC943DD00F4B78E /* Sources */, 866138552CC943DD00F4B78E /* Frameworks */, @@ -185,15 +185,15 @@ ); dependencies = ( ); - name = "VertexAITestApp-SPM"; + name = "FirebaseAITestApp-SPM"; packageProductDependencies = ( 86E8505A2DBAFBC3002E8D94 /* FirebaseAI */, 86E8505C2DBAFBC3002E8D94 /* FirebaseAppCheck */, 86E8505E2DBAFBC3002E8D94 /* FirebaseAuth */, 86E850602DBAFBC3002E8D94 /* FirebaseStorage */, ); - productName = VertexAITestApp; - productReference = 866138582CC943DD00F4B78E /* VertexAITestApp-SPM.app */; + productName = FirebaseAITestApp; + productReference = 866138582CC943DD00F4B78E /* FirebaseAITestApp-SPM.app */; productType = "com.apple.product-type.application"; }; 866138682CC943DE00F4B78E /* IntegrationTests-SPM */ = { @@ -210,7 +210,7 @@ 8661386B2CC943DE00F4B78E /* PBXTargetDependency */, ); name = "IntegrationTests-SPM"; - productName = VertexAITestAppTests; + productName = FirebaseAITestAppTests; productReference = 866138692CC943DE00F4B78E /* IntegrationTests-SPM.xctest */; productType = "com.apple.product-type.bundle.unit-test"; }; @@ -233,7 +233,7 @@ }; }; }; - buildConfigurationList = 866138532CC943DD00F4B78E /* Build configuration list for PBXProject "VertexAITestApp" */; + buildConfigurationList = 866138532CC943DD00F4B78E /* Build configuration list for PBXProject "FirebaseAITestApp" */; compatibilityVersion = "Xcode 15.0"; developmentRegion = en; hasScannedForEncodings = 0; @@ -249,7 +249,7 @@ projectDirPath = ""; projectRoot = ""; targets = ( - 866138572CC943DD00F4B78E /* VertexAITestApp-SPM */, + 866138572CC943DD00F4B78E /* FirebaseAITestApp-SPM */, 866138682CC943DE00F4B78E /* IntegrationTests-SPM */, ); }; @@ -310,7 +310,7 @@ /* Begin PBXTargetDependency section */ 8661386B2CC943DE00F4B78E /* PBXTargetDependency */ = { isa = PBXTargetDependency; - target = 866138572CC943DD00F4B78E /* VertexAITestApp-SPM */; + target = 866138572CC943DD00F4B78E /* FirebaseAITestApp-SPM */; targetProxy = 8661386A2CC943DE00F4B78E /* PBXContainerItemProxy */; }; /* End PBXTargetDependency section */ @@ -459,8 +459,8 @@ "LD_RUNPATH_SEARCH_PATHS[sdk=macosx*]" = "@executable_path/../Frameworks"; MACOSX_DEPLOYMENT_TARGET = 12.0; MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = com.google.firebase.VertexAITestApp; - PRODUCT_MODULE_NAME = VertexAITestApp; + PRODUCT_BUNDLE_IDENTIFIER = com.google.firebase.FirebaseAITestApp; + PRODUCT_MODULE_NAME = FirebaseAITestApp; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = auto; SUPPORTED_PLATFORMS = "iphoneos iphonesimulator macosx"; @@ -497,8 +497,8 @@ "LD_RUNPATH_SEARCH_PATHS[sdk=macosx*]" = "@executable_path/../Frameworks"; MACOSX_DEPLOYMENT_TARGET = 12.0; MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = com.google.firebase.VertexAITestApp; - PRODUCT_MODULE_NAME = VertexAITestApp; + PRODUCT_BUNDLE_IDENTIFIER = com.google.firebase.FirebaseAITestApp; + PRODUCT_MODULE_NAME = FirebaseAITestApp; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = auto; SUPPORTED_PLATFORMS = "iphoneos iphonesimulator macosx"; @@ -519,14 +519,14 @@ IPHONEOS_DEPLOYMENT_TARGET = 15.0; MACOSX_DEPLOYMENT_TARGET = 12.0; MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = com.google.firebase.VertexAITestAppTests; + PRODUCT_BUNDLE_IDENTIFIER = com.google.firebase.FirebaseAITestAppTests; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = auto; SUPPORTED_PLATFORMS = "iphoneos iphonesimulator macosx"; SWIFT_EMIT_LOC_STRINGS = NO; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; - TEST_HOST = "$(BUILT_PRODUCTS_DIR)/VertexAITestApp-SPM.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/VertexAITestApp-SPM"; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/FirebaseAITestApp-SPM.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/FirebaseAITestApp-SPM"; }; name = Debug; }; @@ -541,21 +541,21 @@ IPHONEOS_DEPLOYMENT_TARGET = 15.0; MACOSX_DEPLOYMENT_TARGET = 12.0; MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = com.google.firebase.VertexAITestAppTests; + PRODUCT_BUNDLE_IDENTIFIER = com.google.firebase.FirebaseAITestAppTests; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = auto; SUPPORTED_PLATFORMS = "iphoneos iphonesimulator macosx"; SWIFT_EMIT_LOC_STRINGS = NO; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; - TEST_HOST = "$(BUILT_PRODUCTS_DIR)/VertexAITestApp-SPM.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/VertexAITestApp-SPM"; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/FirebaseAITestApp-SPM.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/FirebaseAITestApp-SPM"; }; name = Release; }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ - 866138532CC943DD00F4B78E /* Build configuration list for PBXProject "VertexAITestApp" */ = { + 866138532CC943DD00F4B78E /* Build configuration list for PBXProject "FirebaseAITestApp" */ = { isa = XCConfigurationList; buildConfigurations = ( 8661387B2CC943DE00F4B78E /* Debug */, @@ -564,7 +564,7 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; - 8661387D2CC943DE00F4B78E /* Build configuration list for PBXNativeTarget "VertexAITestApp-SPM" */ = { + 8661387D2CC943DE00F4B78E /* Build configuration list for PBXNativeTarget "FirebaseAITestApp-SPM" */ = { isa = XCConfigurationList; buildConfigurations = ( 8661387E2CC943DE00F4B78E /* Debug */, @@ -587,7 +587,7 @@ /* Begin XCLocalSwiftPackageReference section */ 86E850592DBAFBC3002E8D94 /* XCLocalSwiftPackageReference "../../.." */ = { isa = XCLocalSwiftPackageReference; - relativePath = "../../.."; + relativePath = ../../..; }; /* End XCLocalSwiftPackageReference section */ diff --git a/FirebaseAI/Tests/TestApp/FirebaseAITestApp.xcodeproj/xcshareddata/xcschemes/FirebaseAITestApp-SPM.xcscheme b/FirebaseAI/Tests/TestApp/FirebaseAITestApp.xcodeproj/xcshareddata/xcschemes/FirebaseAITestApp-SPM.xcscheme new file mode 100644 index 00000000000..8d78bfa6563 --- /dev/null +++ b/FirebaseAI/Tests/TestApp/FirebaseAITestApp.xcodeproj/xcshareddata/xcschemes/FirebaseAITestApp-SPM.xcscheme @@ -0,0 +1,97 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/FirebaseAI/Tests/TestApp/Tests/Integration/CountTokensIntegrationTests.swift b/FirebaseAI/Tests/TestApp/Tests/Integration/CountTokensIntegrationTests.swift index 9be7f1dcb02..7d849c9f0bc 100644 --- a/FirebaseAI/Tests/TestApp/Tests/Integration/CountTokensIntegrationTests.swift +++ b/FirebaseAI/Tests/TestApp/Tests/Integration/CountTokensIntegrationTests.swift @@ -13,11 +13,11 @@ // limitations under the License. import FirebaseAI +import FirebaseAITestApp import FirebaseAuth import FirebaseCore import FirebaseStorage import Testing -import VertexAITestApp @testable import struct FirebaseAI.APIConfig diff --git a/FirebaseAI/Tests/TestApp/Tests/Integration/GenerateContentIntegrationTests.swift b/FirebaseAI/Tests/TestApp/Tests/Integration/GenerateContentIntegrationTests.swift index 608c28b4833..f5288733da7 100644 --- a/FirebaseAI/Tests/TestApp/Tests/Integration/GenerateContentIntegrationTests.swift +++ b/FirebaseAI/Tests/TestApp/Tests/Integration/GenerateContentIntegrationTests.swift @@ -13,11 +13,11 @@ // limitations under the License. import FirebaseAI +import FirebaseAITestApp import FirebaseAuth import FirebaseCore import FirebaseStorage import Testing -import VertexAITestApp #if canImport(UIKit) import UIKit diff --git a/FirebaseAI/Tests/TestApp/Tests/Integration/ImagenIntegrationTests.swift b/FirebaseAI/Tests/TestApp/Tests/Integration/ImagenIntegrationTests.swift index b7533c08aa1..ade781e6176 100644 --- a/FirebaseAI/Tests/TestApp/Tests/Integration/ImagenIntegrationTests.swift +++ b/FirebaseAI/Tests/TestApp/Tests/Integration/ImagenIntegrationTests.swift @@ -13,11 +13,11 @@ // limitations under the License. import FirebaseAI +import FirebaseAITestApp import FirebaseAuth import FirebaseCore import FirebaseStorage import Testing -import VertexAITestApp #if canImport(UIKit) import UIKit diff --git a/FirebaseAI/Tests/TestApp/Tests/Integration/IntegrationTests.swift b/FirebaseAI/Tests/TestApp/Tests/Integration/IntegrationTests.swift index e61b5ed3470..0cfe64d3086 100644 --- a/FirebaseAI/Tests/TestApp/Tests/Integration/IntegrationTests.swift +++ b/FirebaseAI/Tests/TestApp/Tests/Integration/IntegrationTests.swift @@ -13,10 +13,10 @@ // limitations under the License. import FirebaseAI +import FirebaseAITestApp import FirebaseAuth import FirebaseCore import FirebaseStorage -import VertexAITestApp import XCTest // TODO(#14405): Migrate to Swift Testing and parameterize tests to run on both `v1` and `v1beta`. diff --git a/FirebaseAI/Tests/TestApp/Tests/Integration/SchemaTests.swift b/FirebaseAI/Tests/TestApp/Tests/Integration/SchemaTests.swift index 431134d315a..4382a8e76dc 100644 --- a/FirebaseAI/Tests/TestApp/Tests/Integration/SchemaTests.swift +++ b/FirebaseAI/Tests/TestApp/Tests/Integration/SchemaTests.swift @@ -13,11 +13,11 @@ // limitations under the License. import FirebaseAI +import FirebaseAITestApp import FirebaseAuth import FirebaseCore import FirebaseStorage import Testing -import VertexAITestApp #if canImport(UIKit) import UIKit diff --git a/FirebaseAI/Tests/TestApp/Tests/Utilities/InstanceConfig.swift b/FirebaseAI/Tests/TestApp/Tests/Utilities/InstanceConfig.swift index ebafa1be61c..1acbcb1925a 100644 --- a/FirebaseAI/Tests/TestApp/Tests/Utilities/InstanceConfig.swift +++ b/FirebaseAI/Tests/TestApp/Tests/Utilities/InstanceConfig.swift @@ -13,9 +13,9 @@ // limitations under the License. import FirebaseAI +import FirebaseAITestApp import FirebaseCore import Testing -import VertexAITestApp @testable import struct FirebaseAI.APIConfig diff --git a/scripts/build.sh b/scripts/build.sh index b11fba7d804..80cc79f0bb5 100755 --- a/scripts/build.sh +++ b/scripts/build.sh @@ -510,15 +510,15 @@ case "$product-$platform-$method" in FirebaseAIIntegration-*-*) # Build RunXcodebuild \ - -project 'FirebaseAI/Tests/TestApp/VertexAITestApp.xcodeproj' \ - -scheme "VertexAITestApp-SPM" \ + -project 'FirebaseAI/Tests/TestApp/FirebaseAITestApp.xcodeproj' \ + -scheme "FirebaseAITestApp-SPM" \ "${xcb_flags[@]}" \ build # Run tests RunXcodebuild \ - -project 'FirebaseAI/Tests/TestApp/VertexAITestApp.xcodeproj' \ - -scheme "VertexAITestApp-SPM" \ + -project 'FirebaseAI/Tests/TestApp/FirebaseAITestApp.xcodeproj' \ + -scheme "FirebaseAITestApp-SPM" \ "${xcb_flags[@]}" \ -parallel-testing-enabled NO \ test From 4b6959519a0fecfbb2d2f1e3f1b55ca4a8f2336a Mon Sep 17 00:00:00 2001 From: Andrew Heard Date: Mon, 9 Jun 2025 19:38:37 -0400 Subject: [PATCH 066/113] [Firebase AI] Make `GenerativeAIRequest.Response` `Sendable` (#14947) --- FirebaseAI/CHANGELOG.md | 3 +++ FirebaseAI/Sources/GenerativeAIRequest.swift | 2 +- FirebaseAI/Sources/Types/Internal/Imagen/ImagenGCSImage.swift | 2 +- .../Sources/Types/Internal/Requests/CountTokensRequest.swift | 2 +- .../Sources/Types/Public/Imagen/ImagenGenerationResponse.swift | 2 +- FirebaseAI/Sources/Types/Public/Imagen/ImagenInlineImage.swift | 2 +- 6 files changed, 8 insertions(+), 5 deletions(-) diff --git a/FirebaseAI/CHANGELOG.md b/FirebaseAI/CHANGELOG.md index d7b7ac5536e..9b1ba5c782b 100644 --- a/FirebaseAI/CHANGELOG.md +++ b/FirebaseAI/CHANGELOG.md @@ -1,3 +1,6 @@ +# Unreleased +- [fixed] Fixed `Sendable` warnings introduced in the Xcode 26 beta. (#14947) + # 11.13.0 - [feature] Initial release of the Firebase AI Logic SDK (`FirebaseAI`). This SDK *replaces* the previous Vertex AI in Firebase SDK (`FirebaseVertexAI`) to diff --git a/FirebaseAI/Sources/GenerativeAIRequest.swift b/FirebaseAI/Sources/GenerativeAIRequest.swift index 4f3291e1913..148e989db40 100644 --- a/FirebaseAI/Sources/GenerativeAIRequest.swift +++ b/FirebaseAI/Sources/GenerativeAIRequest.swift @@ -16,7 +16,7 @@ import Foundation @available(iOS 15.0, macOS 12.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) protocol GenerativeAIRequest: Sendable, Encodable { - associatedtype Response: Decodable + associatedtype Response: Sendable, Decodable var url: URL { get } diff --git a/FirebaseAI/Sources/Types/Internal/Imagen/ImagenGCSImage.swift b/FirebaseAI/Sources/Types/Internal/Imagen/ImagenGCSImage.swift index 8715cbb12bd..030fe76c681 100644 --- a/FirebaseAI/Sources/Types/Internal/Imagen/ImagenGCSImage.swift +++ b/FirebaseAI/Sources/Types/Internal/Imagen/ImagenGCSImage.swift @@ -18,7 +18,7 @@ import Foundation /// /// TODO(#14451): Make this `public` and move to the `Public` directory when ready. @available(iOS 15.0, macOS 12.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) -struct ImagenGCSImage { +struct ImagenGCSImage: Sendable { /// The IANA standard MIME type of the image file; either `"image/png"` or `"image/jpeg"`. /// /// > Note: To request a different format, set ``ImagenGenerationConfig/imageFormat`` in diff --git a/FirebaseAI/Sources/Types/Internal/Requests/CountTokensRequest.swift b/FirebaseAI/Sources/Types/Internal/Requests/CountTokensRequest.swift index dbd0049c457..ba3c082f297 100644 --- a/FirebaseAI/Sources/Types/Internal/Requests/CountTokensRequest.swift +++ b/FirebaseAI/Sources/Types/Internal/Requests/CountTokensRequest.swift @@ -38,7 +38,7 @@ extension CountTokensRequest: GenerativeAIRequest { /// The model's response to a count tokens request. @available(iOS 15.0, macOS 12.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) -public struct CountTokensResponse { +public struct CountTokensResponse: Sendable { /// The total number of tokens in the input given to the model as a prompt. public let totalTokens: Int diff --git a/FirebaseAI/Sources/Types/Public/Imagen/ImagenGenerationResponse.swift b/FirebaseAI/Sources/Types/Public/Imagen/ImagenGenerationResponse.swift index 48d14a79872..f9816908c6d 100644 --- a/FirebaseAI/Sources/Types/Public/Imagen/ImagenGenerationResponse.swift +++ b/FirebaseAI/Sources/Types/Public/Imagen/ImagenGenerationResponse.swift @@ -23,7 +23,7 @@ import Foundation @available(iOS 15.0, macOS 12.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) // TODO(#14451): Re-add "- ``ImagenModel/generateImages(prompt:gcsURI:)`` where `T` is // ``ImagenGCSImage``" in the DocC above. -public struct ImagenGenerationResponse { +public struct ImagenGenerationResponse: Sendable where T: Sendable { /// The images generated by Imagen; see ``ImagenInlineImage``. /// /// > Important: The number of images generated may be fewer than the number requested if one or diff --git a/FirebaseAI/Sources/Types/Public/Imagen/ImagenInlineImage.swift b/FirebaseAI/Sources/Types/Public/Imagen/ImagenInlineImage.swift index a526dca3e56..4f9a1d9d74f 100644 --- a/FirebaseAI/Sources/Types/Public/Imagen/ImagenInlineImage.swift +++ b/FirebaseAI/Sources/Types/Public/Imagen/ImagenInlineImage.swift @@ -16,7 +16,7 @@ import Foundation /// An image generated by Imagen, represented as inline data. @available(iOS 15.0, macOS 12.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) -public struct ImagenInlineImage { +public struct ImagenInlineImage: Sendable { /// The IANA standard MIME type of the image file; either `"image/png"` or `"image/jpeg"`. /// /// > Note: To request a different format, set ``ImagenGenerationConfig/imageFormat`` in From 8752b16fff55acacd6acfa4b1825206f3d68f320 Mon Sep 17 00:00:00 2001 From: Nick Cooke <36927374+ncooke3@users.noreply.github.com> Date: Tue, 10 Jun 2025 16:47:52 -0400 Subject: [PATCH 067/113] [Sessions] Fix Sendability warnings (#14952) --- .../Installations+InstallationsProtocol.swift | 27 ++++++++++--------- 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/FirebaseSessions/Sources/Installations+InstallationsProtocol.swift b/FirebaseSessions/Sources/Installations+InstallationsProtocol.swift index 98f54771411..5a13dcfb838 100644 --- a/FirebaseSessions/Sources/Installations+InstallationsProtocol.swift +++ b/FirebaseSessions/Sources/Installations+InstallationsProtocol.swift @@ -16,15 +16,16 @@ import Foundation internal import FirebaseInstallations +internal import FirebaseCoreInternal protocol InstallationsProtocol: Sendable { var installationsWaitTimeInSecond: Int { get } /// Override Installation function for testing - func authToken(completion: @escaping (InstallationsAuthTokenResult?, Error?) -> Void) + func authToken(completion: @escaping @Sendable (InstallationsAuthTokenResult?, Error?) -> Void) /// Override Installation function for testing - func installationID(completion: @escaping (String?, Error?) -> Void) + func installationID(completion: @escaping @Sendable (String?, Error?) -> Void) /// Return a tuple: (installationID, authenticationToken) for success result func installationID(completion: @escaping (Result<(String, String), Error>) -> Void) @@ -35,25 +36,27 @@ extension InstallationsProtocol { return 10 } + // TODO(ncooke3): Convert o async await ahead of Firebase 12. + func installationID(completion: @escaping (Result<(String, String), Error>) -> Void) { - var authTokenComplete = "" - var installationComplete: String? - var errorComplete: Error? + let authTokenComplete = FIRAllocatedUnfairLock(initialState: "") + let installationComplete = FIRAllocatedUnfairLock(initialState: nil) + let errorComplete = FIRAllocatedUnfairLock(initialState: nil) let workingGroup = DispatchGroup() workingGroup.enter() authToken { (authTokenResult: InstallationsAuthTokenResult?, error: Error?) in - authTokenComplete = authTokenResult?.authToken ?? "" + authTokenComplete.withLock { $0 = authTokenResult?.authToken ?? "" } workingGroup.leave() } workingGroup.enter() installationID { (installationID: String?, error: Error?) in if let installationID { - installationComplete = installationID - } else if let error = error { - errorComplete = error + installationComplete.withLock { $0 = installationID } + } else if let error { + errorComplete.withLock { $0 = error } } workingGroup.leave() } @@ -67,9 +70,9 @@ extension InstallationsProtocol { completion(.failure(FirebaseSessionsError.SessionInstallationsTimeOutError)) return default: - if let installationComplete { - completion(.success((installationComplete, authTokenComplete))) - } else if let errorComplete { + if let installationComplete = installationComplete.value() { + completion(.success((installationComplete, authTokenComplete.value()))) + } else if let errorComplete = errorComplete.value() { completion(.failure(errorComplete)) } } From 5f2ba2630617fb8ba28799712e95fd74669d2a25 Mon Sep 17 00:00:00 2001 From: Paul Beusterien Date: Wed, 11 Jun 2025 09:46:02 -0700 Subject: [PATCH 068/113] Update Xcode version in CONTRIBUTING.md (#14954) --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 578ffb947fc..0a460cbdd87 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -119,7 +119,7 @@ the preferred workflow for Firebase development. To develop Firebase software, **install**: -* [Xcode] (v12.2 or later) (for Googlers, visit [go/xcode](go/xcode)) to +* [Xcode] (v16.2 or later) (for Googlers, visit [go/xcode](go/xcode)) to download. *
Code styling tools: clang-format, swiftformat and From 3dad2f18625a7c7d218cd761bbf9023ac2bb6cae Mon Sep 17 00:00:00 2001 From: Andrew Heard Date: Wed, 11 Jun 2025 17:15:05 -0400 Subject: [PATCH 069/113] [Firebase AI] Upgrade Gemini 1.x models in integration tests (#14956) Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com> --- .../Tests/TestApp/Tests/Integration/IntegrationTests.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/FirebaseAI/Tests/TestApp/Tests/Integration/IntegrationTests.swift b/FirebaseAI/Tests/TestApp/Tests/Integration/IntegrationTests.swift index 0cfe64d3086..da2bdfa555e 100644 --- a/FirebaseAI/Tests/TestApp/Tests/Integration/IntegrationTests.swift +++ b/FirebaseAI/Tests/TestApp/Tests/Integration/IntegrationTests.swift @@ -67,7 +67,7 @@ final class IntegrationTests: XCTestCase { func testCountTokens_text() async throws { let prompt = "Why is the sky blue?" model = vertex.generativeModel( - modelName: "gemini-1.5-pro", + modelName: ModelNames.gemini2Flash, generationConfig: generationConfig, safetySettings: [ SafetySetting(harmCategory: .harassment, threshold: .blockLowAndAbove, method: .severity), From 97562e7c7e6c741d479bb2e199b2eb8699f19334 Mon Sep 17 00:00:00 2001 From: Andrew Heard Date: Wed, 11 Jun 2025 21:56:40 -0400 Subject: [PATCH 070/113] [Firebase AI] Remove `v1` integration tests (#14959) --- .../CountTokensIntegrationTests.swift | 34 ++----------------- .../GenerateContentIntegrationTests.swift | 16 +++------ .../Tests/Integration/IntegrationTests.swift | 2 +- .../Tests/Integration/SchemaTests.swift | 8 ++--- .../Tests/Utilities/InstanceConfig.swift | 21 ------------ 5 files changed, 12 insertions(+), 69 deletions(-) diff --git a/FirebaseAI/Tests/TestApp/Tests/Integration/CountTokensIntegrationTests.swift b/FirebaseAI/Tests/TestApp/Tests/Integration/CountTokensIntegrationTests.swift index 7d849c9f0bc..4c7c1a49a86 100644 --- a/FirebaseAI/Tests/TestApp/Tests/Integration/CountTokensIntegrationTests.swift +++ b/FirebaseAI/Tests/TestApp/Tests/Integration/CountTokensIntegrationTests.swift @@ -69,16 +69,13 @@ struct CountTokensIntegrationTests { #expect(promptTokensDetails.tokenCount == response.totalTokens) } - @Test( - /* System instructions are not supported on the v1 Developer API. */ - arguments: InstanceConfig.allConfigsExceptGoogleAI_v1 - ) + @Test(arguments: InstanceConfig.allConfigs) func countTokens_text_systemInstruction(_ config: InstanceConfig) async throws { let model = FirebaseAI.componentInstance(config).generativeModel( modelName: ModelNames.gemini2Flash, generationConfig: generationConfig, safetySettings: safetySettings, - systemInstruction: systemInstruction // Not supported on the v1 Developer API + systemInstruction: systemInstruction ) let response = try await model.countTokens("What is your favourite colour?") @@ -96,32 +93,7 @@ struct CountTokensIntegrationTests { #expect(promptTokensDetails.tokenCount == response.totalTokens) } - @Test(arguments: [ - /* System instructions are not supported on the v1 Developer API. */ - InstanceConfig.googleAI_v1_freeTier_bypassProxy, - ]) - func countTokens_text_systemInstruction_unsupported(_ config: InstanceConfig) async throws { - let model = FirebaseAI.componentInstance(config).generativeModel( - modelName: ModelNames.gemini2Flash, - systemInstruction: systemInstruction // Not supported on the v1 Developer API - ) - - try await #require( - throws: BackendError.self, - """ - If this test fails (i.e., `countTokens` succeeds), remove \(config) from this test and add it - to `countTokens_text_systemInstruction`. - """, - performing: { - try await model.countTokens("What is your favourite colour?") - } - ) - } - - @Test( - /* System instructions are not supported on the v1 Developer API. */ - arguments: InstanceConfig.allConfigsExceptGoogleAI_v1 - ) + @Test(arguments: InstanceConfig.allConfigs) func countTokens_jsonSchema(_ config: InstanceConfig) async throws { let model = FirebaseAI.componentInstance(config).generativeModel( modelName: ModelNames.gemini2Flash, diff --git a/FirebaseAI/Tests/TestApp/Tests/Integration/GenerateContentIntegrationTests.swift b/FirebaseAI/Tests/TestApp/Tests/Integration/GenerateContentIntegrationTests.swift index f5288733da7..8513ddfa484 100644 --- a/FirebaseAI/Tests/TestApp/Tests/Integration/GenerateContentIntegrationTests.swift +++ b/FirebaseAI/Tests/TestApp/Tests/Integration/GenerateContentIntegrationTests.swift @@ -48,15 +48,12 @@ struct GenerateContentIntegrationTests { } @Test(arguments: [ - (InstanceConfig.vertexAI_v1, ModelNames.gemini2FlashLite), - (InstanceConfig.vertexAI_v1_staging, ModelNames.gemini2FlashLite), (InstanceConfig.vertexAI_v1beta, ModelNames.gemini2FlashLite), (InstanceConfig.vertexAI_v1beta_staging, ModelNames.gemini2FlashLite), (InstanceConfig.googleAI_v1beta, ModelNames.gemini2FlashLite), (InstanceConfig.googleAI_v1beta, ModelNames.gemma3_4B), (InstanceConfig.googleAI_v1beta_staging, ModelNames.gemini2FlashLite), (InstanceConfig.googleAI_v1beta_staging, ModelNames.gemma3_4B), - (InstanceConfig.googleAI_v1_freeTier_bypassProxy, ModelNames.gemini2FlashLite), (InstanceConfig.googleAI_v1beta_freeTier_bypassProxy, ModelNames.gemini2FlashLite), (InstanceConfig.googleAI_v1beta_freeTier_bypassProxy, ModelNames.gemma3_4B), ]) @@ -98,19 +95,18 @@ struct GenerateContentIntegrationTests { @Test( "Generate an enum and provide a system instruction", - /* System instructions are not supported on the v1 Developer API. */ - arguments: InstanceConfig.allConfigsExceptGoogleAI_v1 + arguments: InstanceConfig.allConfigs ) func generateContentEnum(_ config: InstanceConfig) async throws { let model = FirebaseAI.componentInstance(config).generativeModel( modelName: ModelNames.gemini2FlashLite, generationConfig: GenerationConfig( - responseMIMEType: "text/x.enum", // Not supported on the v1 Developer API + responseMIMEType: "text/x.enum", responseSchema: .enumeration(values: ["Red", "Green", "Blue"]) ), safetySettings: safetySettings, - tools: [], // Not supported on the v1 Developer API - toolConfig: .init(functionCallingConfig: .none()), // Not supported on the v1 Developer API + tools: [], + toolConfig: .init(functionCallingConfig: .none()), systemInstruction: ModelContent(role: "system", parts: "Always pick blue.") ) let prompt = "What is your favourite colour?" @@ -136,7 +132,6 @@ struct GenerateContentIntegrationTests { } @Test(arguments: [ - InstanceConfig.vertexAI_v1, InstanceConfig.vertexAI_v1beta, InstanceConfig.googleAI_v1beta, InstanceConfig.googleAI_v1beta_staging, @@ -190,15 +185,12 @@ struct GenerateContentIntegrationTests { // MARK: Streaming Tests @Test(arguments: [ - (InstanceConfig.vertexAI_v1, ModelNames.gemini2FlashLite), - (InstanceConfig.vertexAI_v1_staging, ModelNames.gemini2FlashLite), (InstanceConfig.vertexAI_v1beta, ModelNames.gemini2FlashLite), (InstanceConfig.vertexAI_v1beta_staging, ModelNames.gemini2FlashLite), (InstanceConfig.googleAI_v1beta, ModelNames.gemini2FlashLite), (InstanceConfig.googleAI_v1beta, ModelNames.gemma3_4B), (InstanceConfig.googleAI_v1beta_staging, ModelNames.gemini2FlashLite), (InstanceConfig.googleAI_v1beta_staging, ModelNames.gemma3_4B), - (InstanceConfig.googleAI_v1_freeTier_bypassProxy, ModelNames.gemini2FlashLite), (InstanceConfig.googleAI_v1beta_freeTier_bypassProxy, ModelNames.gemini2FlashLite), (InstanceConfig.googleAI_v1beta_freeTier_bypassProxy, ModelNames.gemma3_4B), ]) diff --git a/FirebaseAI/Tests/TestApp/Tests/Integration/IntegrationTests.swift b/FirebaseAI/Tests/TestApp/Tests/Integration/IntegrationTests.swift index da2bdfa555e..e870a52d7a6 100644 --- a/FirebaseAI/Tests/TestApp/Tests/Integration/IntegrationTests.swift +++ b/FirebaseAI/Tests/TestApp/Tests/Integration/IntegrationTests.swift @@ -19,7 +19,7 @@ import FirebaseCore import FirebaseStorage import XCTest -// TODO(#14405): Migrate to Swift Testing and parameterize tests to run on both `v1` and `v1beta`. +// TODO(#14405): Migrate to Swift Testing and parameterize tests. final class IntegrationTests: XCTestCase { // Set temperature, topP and topK to lowest allowed values to make responses more deterministic. let generationConfig = GenerationConfig( diff --git a/FirebaseAI/Tests/TestApp/Tests/Integration/SchemaTests.swift b/FirebaseAI/Tests/TestApp/Tests/Integration/SchemaTests.swift index 4382a8e76dc..640b353dc2f 100644 --- a/FirebaseAI/Tests/TestApp/Tests/Integration/SchemaTests.swift +++ b/FirebaseAI/Tests/TestApp/Tests/Integration/SchemaTests.swift @@ -48,7 +48,7 @@ struct SchemaTests { storage = Storage.storage() } - @Test(arguments: InstanceConfig.allConfigsExceptGoogleAI_v1) + @Test(arguments: InstanceConfig.allConfigs) func generateContentSchemaItems(_ config: InstanceConfig) async throws { let model = FirebaseAI.componentInstance(config).generativeModel( modelName: ModelNames.gemini2FlashLite, @@ -73,7 +73,7 @@ struct SchemaTests { #expect(decodedJSON.count <= 5, "Expected at most 5 cities, but got \(decodedJSON.count)") } - @Test(arguments: InstanceConfig.allConfigsExceptGoogleAI_v1) + @Test(arguments: InstanceConfig.allConfigs) func generateContentSchemaNumberRange(_ config: InstanceConfig) async throws { let model = FirebaseAI.componentInstance(config).generativeModel( modelName: ModelNames.gemini2FlashLite, @@ -96,7 +96,7 @@ struct SchemaTests { #expect(decodedNumber <= 120.0, "Expected a number <= 120, but got \(decodedNumber)") } - @Test(arguments: InstanceConfig.allConfigsExceptGoogleAI_v1) + @Test(arguments: InstanceConfig.allConfigs) func generateContentSchemaNumberRangeMultiType(_ config: InstanceConfig) async throws { struct ProductInfo: Codable { let productName: String @@ -149,7 +149,7 @@ struct SchemaTests { #expect(rating <= 5, "Expected a rating <= 5, but got \(rating)") } - @Test(arguments: InstanceConfig.allConfigsExceptGoogleAI_v1) + @Test(arguments: InstanceConfig.allConfigs) func generateContentAnyOfSchema(_ config: InstanceConfig) async throws { struct MailingAddress: Decodable { let streetAddress: String diff --git a/FirebaseAI/Tests/TestApp/Tests/Utilities/InstanceConfig.swift b/FirebaseAI/Tests/TestApp/Tests/Utilities/InstanceConfig.swift index 1acbcb1925a..82f345d99fc 100644 --- a/FirebaseAI/Tests/TestApp/Tests/Utilities/InstanceConfig.swift +++ b/FirebaseAI/Tests/TestApp/Tests/Utilities/InstanceConfig.swift @@ -20,12 +20,6 @@ import Testing @testable import struct FirebaseAI.APIConfig struct InstanceConfig: Equatable, Encodable { - static let vertexAI_v1 = InstanceConfig( - apiConfig: APIConfig(service: .vertexAI(endpoint: .firebaseProxyProd), version: .v1) - ) - static let vertexAI_v1_staging = InstanceConfig( - apiConfig: APIConfig(service: .vertexAI(endpoint: .firebaseProxyStaging), version: .v1) - ) static let vertexAI_v1beta = InstanceConfig( apiConfig: APIConfig(service: .vertexAI(endpoint: .firebaseProxyProd), version: .v1beta) ) @@ -38,33 +32,19 @@ struct InstanceConfig: Equatable, Encodable { static let googleAI_v1beta_staging = InstanceConfig( apiConfig: APIConfig(service: .googleAI(endpoint: .firebaseProxyStaging), version: .v1beta) ) - static let googleAI_v1_freeTier_bypassProxy = InstanceConfig( - appName: FirebaseAppNames.spark, - apiConfig: APIConfig(service: .googleAI(endpoint: .googleAIBypassProxy), version: .v1) - ) static let googleAI_v1beta_freeTier_bypassProxy = InstanceConfig( appName: FirebaseAppNames.spark, apiConfig: APIConfig(service: .googleAI(endpoint: .googleAIBypassProxy), version: .v1beta) ) static let allConfigs = [ - vertexAI_v1, - vertexAI_v1_staging, vertexAI_v1beta, vertexAI_v1beta_staging, googleAI_v1beta, googleAI_v1beta_staging, - googleAI_v1_freeTier_bypassProxy, googleAI_v1beta_freeTier_bypassProxy, ] - static let allConfigsExceptGoogleAI_v1 = allConfigs.filter { - $0 != googleAI_v1_freeTier_bypassProxy - } - static let vertexAI_v1_appCheckNotConfigured = InstanceConfig( - appName: FirebaseAppNames.appCheckNotConfigured, - apiConfig: APIConfig(service: .vertexAI(endpoint: .firebaseProxyProd), version: .v1) - ) static let vertexAI_v1beta_appCheckNotConfigured = InstanceConfig( appName: FirebaseAppNames.appCheckNotConfigured, apiConfig: APIConfig(service: .vertexAI(endpoint: .firebaseProxyProd), version: .v1beta) @@ -75,7 +55,6 @@ struct InstanceConfig: Equatable, Encodable { ) static let appCheckNotConfiguredConfigs = [ - vertexAI_v1_appCheckNotConfigured, vertexAI_v1beta_appCheckNotConfigured, googleAI_v1beta_appCheckNotConfigured, ] From 70cd2ffd6325a407d6365f26af029289de78166f Mon Sep 17 00:00:00 2001 From: Paul Beusterien Date: Thu, 12 Jun 2025 07:09:02 -0700 Subject: [PATCH 071/113] Add AI Logic product to FEATURE_REQUEST.yml (#14969) --- .github/ISSUE_TEMPLATE/FEATURE_REQUEST.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/ISSUE_TEMPLATE/FEATURE_REQUEST.yml b/.github/ISSUE_TEMPLATE/FEATURE_REQUEST.yml index d684c25d5bd..ecb68dde895 100644 --- a/.github/ISSUE_TEMPLATE/FEATURE_REQUEST.yml +++ b/.github/ISSUE_TEMPLATE/FEATURE_REQUEST.yml @@ -48,6 +48,7 @@ body: multiple: true options: - AB Testing + - AI Logic - Analytics - App Check - App Distribution @@ -65,6 +66,5 @@ body: - Performance - Remote Config - Storage - - Vertex AI validations: required: true From 718df0223b1811dcf30489818ec45e955cf3b1fe Mon Sep 17 00:00:00 2001 From: Seyed Mojtaba Hosseini Zeidabadi Date: Thu, 12 Jun 2025 17:46:11 +0330 Subject: [PATCH 072/113] docs: fix `auxiliary` in firebaseFunctions sources (#14964) --- FirebaseFunctions/Sources/HTTPSCallable.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/FirebaseFunctions/Sources/HTTPSCallable.swift b/FirebaseFunctions/Sources/HTTPSCallable.swift index ab1c02378e8..c7ecdfa0814 100644 --- a/FirebaseFunctions/Sources/HTTPSCallable.swift +++ b/FirebaseFunctions/Sources/HTTPSCallable.swift @@ -35,7 +35,7 @@ open class HTTPSCallable: NSObject, @unchecked Sendable { // MARK: - Private Properties /// Until this class can be marked *checked* `Sendable`, it's implementation - /// is delegated to an auxialiary class that is checked Sendable. + /// is delegated to an auxiliary class that is checked Sendable. private let sendableCallable: SendableHTTPSCallable // MARK: - Public Properties From 334c2b827511a0f8a1f9db6244516fe370c6fabb Mon Sep 17 00:00:00 2001 From: Seyed Mojtaba Hosseini Zeidabadi Date: Thu, 12 Jun 2025 17:46:27 +0330 Subject: [PATCH 073/113] docs: fix `NSDictionary` in firebaseFunctions internal sources (#14965) --- FirebaseFunctions/Sources/Internal/FunctionsSerializer.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/FirebaseFunctions/Sources/Internal/FunctionsSerializer.swift b/FirebaseFunctions/Sources/Internal/FunctionsSerializer.swift index 6220f031252..8fb0ba4cc61 100644 --- a/FirebaseFunctions/Sources/Internal/FunctionsSerializer.swift +++ b/FirebaseFunctions/Sources/Internal/FunctionsSerializer.swift @@ -29,7 +29,7 @@ final class FunctionsSerializer: Sendable { // - NSNull (note: `nil` collection values from a Swift caller will be treated as NSNull) // - NSNumber // - NSString - // - NSDicionary + // - NSDictionary // - NSArray func encode(_ object: Any) throws -> Any { if object is NSNull { @@ -58,7 +58,7 @@ final class FunctionsSerializer: Sendable { // - NSNull (note: `nil` collection values from a Swift caller will be treated as NSNull) // - NSNumber // - NSString - // - NSDicionary + // - NSDictionary // - NSArray func decode(_ object: Any) throws -> Any { // Return these types as is. PORTING NOTE: Moved from the bottom of the func for readability. From d62c7a2a22d2c37b749cd9dbc643875c5b394970 Mon Sep 17 00:00:00 2001 From: Seyed Mojtaba Hosseini Zeidabadi Date: Thu, 12 Jun 2025 18:25:25 +0330 Subject: [PATCH 074/113] fix: a typo in CanSchedule`Operations`WithRespectsToShutdownState (#14966) --- Firestore/core/test/unit/util/async_queue_test.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Firestore/core/test/unit/util/async_queue_test.cc b/Firestore/core/test/unit/util/async_queue_test.cc index 40a727b7f84..6b457a48a60 100644 --- a/Firestore/core/test/unit/util/async_queue_test.cc +++ b/Firestore/core/test/unit/util/async_queue_test.cc @@ -209,7 +209,7 @@ TEST_P(AsyncQueueTest, CanManuallyDrainSpecificDelayedOperationsForTesting) { timer1.Cancel(); } -TEST_P(AsyncQueueTest, CanScheduleOprationsWithRespectsToShutdownState) { +TEST_P(AsyncQueueTest, CanScheduleOperationsWithRespectsToShutdownState) { Expectation ran; std::string steps; From 782689c85029460183b17cb8245f277db9b330d1 Mon Sep 17 00:00:00 2001 From: Nick Cooke <36927374+ncooke3@users.noreply.github.com> Date: Thu, 12 Jun 2025 16:13:06 -0400 Subject: [PATCH 075/113] [Infra] Remove C99 language standard settings (#14970) Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com> --- FirebaseABTesting.podspec | 1 - FirebaseAppCheck.podspec | 1 - FirebaseAppDistribution.podspec | 1 - FirebaseAuth.podspec | 1 - FirebaseCore.podspec | 1 - FirebaseCore/CHANGELOG.md | 3 +++ FirebaseCrashlytics.podspec | 4 ---- FirebaseDatabase.podspec | 1 - FirebaseDynamicLinks.podspec | 1 - FirebaseFirestoreInternal.podspec | 1 - FirebaseFirestoreTestingSupport.podspec | 1 - FirebaseInstallations.podspec | 1 - FirebaseMLModelDownloader.podspec | 1 - FirebaseMessaging.podspec | 1 - FirebasePerformance.podspec | 1 - FirebaseRemoteConfig.podspec | 1 - FirebaseSessions.podspec | 1 - Package.swift | 1 - 18 files changed, 3 insertions(+), 20 deletions(-) diff --git a/FirebaseABTesting.podspec b/FirebaseABTesting.podspec index 5750efc2fbc..82ec4457133 100644 --- a/FirebaseABTesting.podspec +++ b/FirebaseABTesting.podspec @@ -49,7 +49,6 @@ Firebase Cloud Messaging and Firebase Remote Config in your app. s.requires_arc = base_dir + '*.m' s.public_header_files = base_dir + 'Public/FirebaseABTesting/*.h' s.pod_target_xcconfig = { - 'GCC_C_LANGUAGE_STANDARD' => 'c99', 'HEADER_SEARCH_PATHS' => '"${PODS_TARGET_SRCROOT}"' } s.dependency 'FirebaseCore', '~> 11.15.0' diff --git a/FirebaseAppCheck.podspec b/FirebaseAppCheck.podspec index a12e8bd7d99..417e5d63576 100644 --- a/FirebaseAppCheck.podspec +++ b/FirebaseAppCheck.podspec @@ -51,7 +51,6 @@ Pod::Spec.new do |s| s.dependency 'GoogleUtilities/UserDefaults', '~> 8.1' s.pod_target_xcconfig = { - 'GCC_C_LANGUAGE_STANDARD' => 'c99', 'HEADER_SEARCH_PATHS' => '"${PODS_TARGET_SRCROOT}"' } diff --git a/FirebaseAppDistribution.podspec b/FirebaseAppDistribution.podspec index 700028f9a4a..42214d76505 100644 --- a/FirebaseAppDistribution.podspec +++ b/FirebaseAppDistribution.podspec @@ -36,7 +36,6 @@ iOS SDK for App Distribution for Firebase. s.dependency 'FirebaseInstallations', '~> 11.0' s.pod_target_xcconfig = { - 'GCC_C_LANGUAGE_STANDARD' => 'c99', 'HEADER_SEARCH_PATHS' => '"${PODS_TARGET_SRCROOT}"' } diff --git a/FirebaseAuth.podspec b/FirebaseAuth.podspec index e11eaf47c0e..5ca2eb61f2a 100644 --- a/FirebaseAuth.podspec +++ b/FirebaseAuth.podspec @@ -49,7 +49,6 @@ supports email and password accounts, as well as several 3rd party authenticatio 'FirebaseAuth/CHANGELOG.md' ] s.pod_target_xcconfig = { - 'GCC_C_LANGUAGE_STANDARD' => 'c99', # The second path is to find FirebaseAuth-Swift.h from a pod gen project 'HEADER_SEARCH_PATHS' => '"${PODS_TARGET_SRCROOT}" "${OBJECT_FILE_DIR_normal}/${NATIVE_ARCH_ACTUAL}"', 'OTHER_SWIFT_FLAGS' => "$(inherited) #{ENV.key?('FIREBASE_CI') ? '-D FIREBASE_CI -warnings-as-errors' : ''}" diff --git a/FirebaseCore.podspec b/FirebaseCore.podspec index 63a0a5b27fa..12180f591b8 100644 --- a/FirebaseCore.podspec +++ b/FirebaseCore.podspec @@ -56,7 +56,6 @@ Firebase Core includes FIRApp and FIROptions which provide central configuration s.dependency 'FirebaseCoreInternal', '~> 11.15.0' s.pod_target_xcconfig = { - 'GCC_C_LANGUAGE_STANDARD' => 'c99', 'GCC_PREPROCESSOR_DEFINITIONS' => 'Firebase_VERSION=' + s.version.to_s, 'HEADER_SEARCH_PATHS' => '"${PODS_TARGET_SRCROOT}"', 'OTHER_CFLAGS' => '-fno-autolink' diff --git a/FirebaseCore/CHANGELOG.md b/FirebaseCore/CHANGELOG.md index 03fd4f701a4..33bf5733e7b 100644 --- a/FirebaseCore/CHANGELOG.md +++ b/FirebaseCore/CHANGELOG.md @@ -1,3 +1,6 @@ +# Unreleased +- [fixed] Remove c99 as the required C language standard. (#14950) + # Firebase 11.12.0 - [changed] Firebase now requires at least Xcode 16.2. See https://developer.apple.com/news/?id=9s0rgdy9 for more info. diff --git a/FirebaseCrashlytics.podspec b/FirebaseCrashlytics.podspec index 6955088b69e..3ebb6837ffa 100644 --- a/FirebaseCrashlytics.podspec +++ b/FirebaseCrashlytics.podspec @@ -75,7 +75,6 @@ Pod::Spec.new do |s| s.watchos.frameworks = 'Security' s.ios.pod_target_xcconfig = { - 'GCC_C_LANGUAGE_STANDARD' => 'c99', 'GCC_PREPROCESSOR_DEFINITIONS' => 'CLS_SDK_NAME="Crashlytics iOS SDK" ' + # For nanopb: @@ -84,7 +83,6 @@ Pod::Spec.new do |s| } s.osx.pod_target_xcconfig = { - 'GCC_C_LANGUAGE_STANDARD' => 'c99', 'GCC_PREPROCESSOR_DEFINITIONS' => 'CLS_SDK_NAME="Crashlytics Mac SDK" ' + # For nanopb: @@ -93,7 +91,6 @@ Pod::Spec.new do |s| } s.tvos.pod_target_xcconfig = { - 'GCC_C_LANGUAGE_STANDARD' => 'c99', 'GCC_PREPROCESSOR_DEFINITIONS' => 'CLS_SDK_NAME="Crashlytics tvOS SDK" ' + # For nanopb: @@ -102,7 +99,6 @@ Pod::Spec.new do |s| } s.watchos.pod_target_xcconfig = { - 'GCC_C_LANGUAGE_STANDARD' => 'c99', 'GCC_PREPROCESSOR_DEFINITIONS' => 'CLS_SDK_NAME="Crashlytics watchOS SDK" ' + # For nanopb: diff --git a/FirebaseDatabase.podspec b/FirebaseDatabase.podspec index 128a19ba904..09768d48252 100644 --- a/FirebaseDatabase.podspec +++ b/FirebaseDatabase.podspec @@ -53,7 +53,6 @@ Simplify your iOS development, grow your user base, and monetize more effectivel s.dependency 'FirebaseSharedSwift', '~> 11.0' s.dependency 'GoogleUtilities/UserDefaults', '~> 8.1' s.pod_target_xcconfig = { - 'GCC_C_LANGUAGE_STANDARD' => 'c99', 'HEADER_SEARCH_PATHS' => '"${PODS_TARGET_SRCROOT}"' } diff --git a/FirebaseDynamicLinks.podspec b/FirebaseDynamicLinks.podspec index 13d0a340d4d..5ad9a08caa3 100644 --- a/FirebaseDynamicLinks.podspec +++ b/FirebaseDynamicLinks.podspec @@ -40,7 +40,6 @@ Firebase Dynamic Links are deep links that enhance user experience and increase s.dependency 'FirebaseCore', '~> 11.15.0' s.pod_target_xcconfig = { - 'GCC_C_LANGUAGE_STANDARD' => 'c99', 'GCC_PREPROCESSOR_DEFINITIONS' => 'FIRDynamicLinks3P GIN_SCION_LOGGING', 'HEADER_SEARCH_PATHS' => '"${PODS_TARGET_SRCROOT}"' } diff --git a/FirebaseFirestoreInternal.podspec b/FirebaseFirestoreInternal.podspec index 0f71bd8dbe0..ef81b8da45b 100644 --- a/FirebaseFirestoreInternal.podspec +++ b/FirebaseFirestoreInternal.podspec @@ -118,7 +118,6 @@ Google Cloud Firestore is a NoSQL document database built for automatic scaling, s.pod_target_xcconfig = { 'CLANG_CXX_LANGUAGE_STANDARD' => 'c++14', 'CLANG_CXX_LIBRARY' => 'libc++', - 'GCC_C_LANGUAGE_STANDARD' => 'c99', 'GCC_PREPROCESSOR_DEFINITIONS' => "FIRFirestore_VERSION=#{s.version} " + # The nanopb pod sets these defs, so we must too. (We *do* require 16bit diff --git a/FirebaseFirestoreTestingSupport.podspec b/FirebaseFirestoreTestingSupport.podspec index a28ab450c3f..97ab0f834a6 100644 --- a/FirebaseFirestoreTestingSupport.podspec +++ b/FirebaseFirestoreTestingSupport.podspec @@ -45,7 +45,6 @@ Pod::Spec.new do |s| s.dependency 'FirebaseFirestore', '~> 11.0' s.pod_target_xcconfig = { - 'GCC_C_LANGUAGE_STANDARD' => 'c99', 'OTHER_CFLAGS' => '-fno-autolink', 'HEADER_SEARCH_PATHS' => '"${PODS_TARGET_SRCROOT}" ' diff --git a/FirebaseInstallations.podspec b/FirebaseInstallations.podspec index 0adffd04b85..45c40ca732d 100644 --- a/FirebaseInstallations.podspec +++ b/FirebaseInstallations.podspec @@ -52,7 +52,6 @@ Pod::Spec.new do |s| preprocessor_definitions = '' s.pod_target_xcconfig = { - 'GCC_C_LANGUAGE_STANDARD' => 'c99', 'GCC_PREPROCESSOR_DEFINITIONS' => preprocessor_definitions, 'HEADER_SEARCH_PATHS' => '"${PODS_TARGET_SRCROOT}"' } diff --git a/FirebaseMLModelDownloader.podspec b/FirebaseMLModelDownloader.podspec index 004a74143be..2590eead306 100644 --- a/FirebaseMLModelDownloader.podspec +++ b/FirebaseMLModelDownloader.podspec @@ -44,7 +44,6 @@ Pod::Spec.new do |s| s.dependency 'SwiftProtobuf', '~> 1.19' s.pod_target_xcconfig = { - 'GCC_C_LANGUAGE_STANDARD' => 'c99', 'GCC_PREPROCESSOR_DEFINITIONS' => 'FIRMLModelDownloader_VERSION=' + s.version.to_s, 'OTHER_CFLAGS' => '-fno-autolink', } diff --git a/FirebaseMessaging.podspec b/FirebaseMessaging.podspec index 9e66e74b205..8cf729a8fca 100644 --- a/FirebaseMessaging.podspec +++ b/FirebaseMessaging.podspec @@ -50,7 +50,6 @@ device, and it is completely free. } s.library = 'sqlite3' s.pod_target_xcconfig = { - 'GCC_C_LANGUAGE_STANDARD' => 'c99', 'GCC_PREPROCESSOR_DEFINITIONS' => # for nanopb: 'PB_FIELD_32BIT=1 PB_NO_PACKED_STRUCTS=1 PB_ENABLE_MALLOC=1', diff --git a/FirebasePerformance.podspec b/FirebasePerformance.podspec index a95ad9fbd2f..d2124aa25c3 100644 --- a/FirebasePerformance.podspec +++ b/FirebasePerformance.podspec @@ -50,7 +50,6 @@ Firebase Performance library to measure performance of Mobile and Web Apps. end s.pod_target_xcconfig = { - 'GCC_C_LANGUAGE_STANDARD' => 'c99', 'GCC_PREPROCESSOR_DEFINITIONS' => preprocessor_definitions, # Unit tests do library imports using repo-root relative paths. 'HEADER_SEARCH_PATHS' => '"${PODS_TARGET_SRCROOT}"', diff --git a/FirebaseRemoteConfig.podspec b/FirebaseRemoteConfig.podspec index 3d90a14b950..ea7760ffc21 100644 --- a/FirebaseRemoteConfig.podspec +++ b/FirebaseRemoteConfig.podspec @@ -47,7 +47,6 @@ app update. "#{s.module_name}_Privacy" => 'FirebaseRemoteConfig/Swift/Resources/PrivacyInfo.xcprivacy' } s.pod_target_xcconfig = { - 'GCC_C_LANGUAGE_STANDARD' => 'c99', 'HEADER_SEARCH_PATHS' => '"${PODS_TARGET_SRCROOT}"' } s.dependency 'FirebaseABTesting', '~> 11.0' diff --git a/FirebaseSessions.podspec b/FirebaseSessions.podspec index 8c92c6b6172..9bb2e6988da 100644 --- a/FirebaseSessions.podspec +++ b/FirebaseSessions.podspec @@ -49,7 +49,6 @@ Pod::Spec.new do |s| s.dependency 'PromisesSwift', '~> 2.1' s.pod_target_xcconfig = { - 'GCC_C_LANGUAGE_STANDARD' => 'c99', 'HEADER_SEARCH_PATHS' => '"${PODS_TARGET_SRCROOT}"', 'GCC_PREPROCESSOR_DEFINITIONS' => # For nanopb: diff --git a/Package.swift b/Package.swift index 1a46f5a94ab..f82fa0e8222 100644 --- a/Package.swift +++ b/Package.swift @@ -1430,7 +1430,6 @@ let package = Package( ] ), ] + firestoreTargets(), - cLanguageStandard: .c99, cxxLanguageStandard: CXXLanguageStandard.gnucxx14 ) From 5e1ece440ffbe487d985f42d0bedc457e785fd6b Mon Sep 17 00:00:00 2001 From: Nick Cooke <36927374+ncooke3@users.noreply.github.com> Date: Fri, 13 Jun 2025 11:31:29 -0400 Subject: [PATCH 076/113] [Infra] Update FEATURE_REQUEST.yml (#14973) --- .github/ISSUE_TEMPLATE/FEATURE_REQUEST.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/ISSUE_TEMPLATE/FEATURE_REQUEST.yml b/.github/ISSUE_TEMPLATE/FEATURE_REQUEST.yml index ecb68dde895..61b4fe2ebd3 100644 --- a/.github/ISSUE_TEMPLATE/FEATURE_REQUEST.yml +++ b/.github/ISSUE_TEMPLATE/FEATURE_REQUEST.yml @@ -1,5 +1,5 @@ name: ➕ Feature Request -description: File a file request if you have a suggestion for a new feature. +description: File a feature request if you have a suggestion for a new feature. title: "[FR]: " labels: ["type: feature request"] body: From 06042b65527d5498dbb6f9da91e5b1fd8bfca8b1 Mon Sep 17 00:00:00 2001 From: Paul Beusterien Date: Fri, 13 Jun 2025 08:43:20 -0700 Subject: [PATCH 077/113] Remove quickstart tests from dynamiclinks.yml (#14974) --- .github/workflows/dynamiclinks.yml | 67 ------------------------------ 1 file changed, 67 deletions(-) diff --git a/.github/workflows/dynamiclinks.yml b/.github/workflows/dynamiclinks.yml index b6c2ff19c0b..919027e7e20 100644 --- a/.github/workflows/dynamiclinks.yml +++ b/.github/workflows/dynamiclinks.yml @@ -59,70 +59,3 @@ jobs: run: sudo xcode-select -s /Applications/Xcode_16.2.app/Contents/Developer - name: PodLibLint Storage Cron run: scripts/third_party/travis/retry.sh scripts/pod_lib_lint.rb FirebaseDynamicLinks.podspec --platforms=ios ${{ matrix.flags }} --allow-warnings - - quickstart: - # Don't run on private repo unless it is a PR. - if: (github.repository == 'Firebase/firebase-ios-sdk' && github.event_name == 'schedule') || github.event_name == 'pull_request' - - env: - plist_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} - signin_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} - runs-on: macos-15 - steps: - - uses: actions/checkout@v4 - - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1 - - name: Xcode - run: sudo xcode-select -s /Applications/Xcode_16.2.app/Contents/Developer - - name: Setup quickstart - run: scripts/setup_quickstart.sh DynamicLinks - - name: Install Secret GoogleService-Info.plist - run: scripts/decrypt_gha_secret.sh scripts/gha-encrypted/qs-dynamiclinks.plist.gpg \ - quickstart-ios/dynamiclinks/GoogleService-Info.plist "$plist_secret" - - name: Update Environment Variable For DynamicLinks - run: | - sed -i '' 's#DYNAMIC_LINK_DOMAIN#https://qpf6m.app.goo.gl#' quickstart-ios/dynamiclinks/DynamicLinksExample/DynamicLinksExample.entitlements - sed -i '' 's#YOUR_DOMAIN_URI_PREFIX";#https://qpf6m.app.goo.gl";#' quickstart-ios/dynamiclinks/DynamicLinksExample/ViewController.m - sed -i '' 's#YOUR_DOMAIN_URI_PREFIX";#https://qpf6m.app.goo.gl";#' quickstart-ios/dynamiclinks/DynamicLinksExampleSwift/ViewController.swift - - name: Test objc quickstart - run: ([ -z $plist_secret ] || scripts/third_party/travis/retry.sh scripts/test_quickstart.sh DynamicLinks false) - - name: Test swift quickstart - if: ${{ always() }} - run: ([ -z $plist_secret ] || scripts/third_party/travis/retry.sh scripts/test_quickstart.sh DynamicLinks false swift) - - quickstart-ftl-cron-only: - # Don't run on private repo. - if: github.repository == 'Firebase/firebase-ios-sdk' && github.event_name == 'schedule' - - env: - plist_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} - signin_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} - runs-on: macos-15 - steps: - - uses: actions/checkout@v4 - - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1 - - uses: actions/setup-python@v5 - with: - python-version: '3.11' - - name: Xcode - run: sudo xcode-select -s /Applications/Xcode_16.2.app/Contents/Developer - - name: Setup quickstart - run: scripts/setup_quickstart.sh DynamicLinks - - name: Install Secret GoogleService-Info.plist - run: scripts/decrypt_gha_secret.sh scripts/gha-encrypted/qs-dynamiclinks.plist.gpg \ - quickstart-ios/dynamiclinks/GoogleService-Info.plist "$plist_secret" - - name: Update Environment Variable For DynamicLinks - run: | - sed -i '' 's#DYNAMIC_LINK_DOMAIN#https://qpf6m.app.goo.gl#' quickstart-ios/dynamiclinks/DynamicLinksExample/DynamicLinksExample.entitlements - sed -i '' 's#YOUR_DOMAIN_URI_PREFIX";#https://qpf6m.app.goo.gl";#' quickstart-ios/dynamiclinks/DynamicLinksExample/ViewController.m - sed -i '' 's#YOUR_DOMAIN_URI_PREFIX";#https://qpf6m.app.goo.gl";#' quickstart-ios/dynamiclinks/DynamicLinksExampleSwift/ViewController.swift - # - name: Build objc quickstart - # run: ([ -z $plist_secret ] || scripts/third_party/travis/retry.sh scripts/test_quickstart_ftl.sh DynamicLinks) - - name: Build swift quickstart - if: ${{ always() }} - run: ([ -z $plist_secret ] || scripts/third_party/travis/retry.sh scripts/test_quickstart_ftl.sh DynamicLinks swift) - - id: ftl_test - uses: FirebaseExtended/github-actions/firebase-test-lab@v1.4 - with: - credentials_json: ${{ secrets.FIREBASE_SERVICE_ACCOUNT_CREDENTIALS }} - testapp_dir: quickstart-ios/build-for-testing - test_type: "xctest" From cf262dae029b4c10a1961390e83d3b0f27b30d63 Mon Sep 17 00:00:00 2001 From: Nick Cooke <36927374+ncooke3@users.noreply.github.com> Date: Fri, 13 Jun 2025 11:45:03 -0400 Subject: [PATCH 078/113] [Infra] Delete scripts/gha-encrypted/qs-dynamiclinks.plist.gpg (#14976) --- scripts/gha-encrypted/qs-dynamiclinks.plist.gpg | Bin 680 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 scripts/gha-encrypted/qs-dynamiclinks.plist.gpg diff --git a/scripts/gha-encrypted/qs-dynamiclinks.plist.gpg b/scripts/gha-encrypted/qs-dynamiclinks.plist.gpg deleted file mode 100644 index a34c06c5c47d0c4f8fcb9b4176575980f3fb8958..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 680 zcmV;Z0$2Tv4Fm}T2tDzaPZ`6SwExoS0Z6Ps(=Sa4fFv8IQU=|TdIE1|c1>uC&F1W2 z<+HMiS=3NMpi8E{2C+VVS{qPxVd{J?3X=;w>`)Fxy(z0R8&F^Aw6EtnY=wlVEos3Q z<-bD7@m#!pLQQ9XI*Hpa=bl_RN`|~sk>uI7t)^AB^qowR;DiS6co6RQFOAMJ4}CPN zzBK|!+#Kg=KTS?u8fh$-F~x50CW4-*=?Yi}s0}sVi-t4{QI(b|5Gr@({I?~YVd_{| zGSWy=)l$>gZ%OjYarK{3tik+u8_w;6>heK5ez&!iLFe0}KohDG`eu;ILrx?wtBTU$ z#M{p*Yd-o!YS&Ie;Dm#cMbz_`nrzV=-xKWA{{s$nVI{J~_cs9jUDzKg?RK{3n019F zdOHil38kxN#;h)Ta&~6H5{nM=wg;Wy)fScT;fTlrU+ZL0Nc6`jm4uDzg?lM^Tp~X| zK2W?!p&`uV4CLU{ETCZ7%*VUyZ#ySZ%dfyx)|lyQ`G4A0>c5td?9Gj9Dc`HJ3( z4?CXe5bQ5w7sbTcrqOaX6l%}*4&K$> From 9b7b370bf09fad62baacd0afff82a0811bec0685 Mon Sep 17 00:00:00 2001 From: Nick Cooke <36927374+ncooke3@users.noreply.github.com> Date: Fri, 13 Jun 2025 11:53:57 -0400 Subject: [PATCH 079/113] [Infra] Remove FDL qs from [pre]release.yml (#14977) --- .github/workflows/prerelease.yml | 43 ----------------------- .github/workflows/release.yml | 43 ----------------------- .github/workflows/zip.yml | 59 -------------------------------- 3 files changed, 145 deletions(-) diff --git a/.github/workflows/prerelease.yml b/.github/workflows/prerelease.yml index 1ba55e09c1c..421561065eb 100644 --- a/.github/workflows/prerelease.yml +++ b/.github/workflows/prerelease.yml @@ -363,49 +363,6 @@ jobs: name: quickstart_artifacts_database path: quickstart-ios/ - dynamiclinks_quickstart: - # Don't run on private repo unless it is a PR. - if: (github.repository == 'Firebase/firebase-ios-sdk' && github.event_name == 'schedule') || github.event_name == 'workflow_dispatch' - needs: buildup_SpecsTesting_repo - env: - plist_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} - signin_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} - bot_token_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} - testing_repo_dir: "/tmp/test/" - testing_repo: "firebase-ios-sdk" - runs-on: macos-15 - steps: - - uses: actions/checkout@v4 - - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1 - - name: Get token - run: scripts/decrypt_gha_secret.sh scripts/gha-encrypted/prerelease-testing-token.txt.gpg \ - bot-access.txt "$bot_token_secret" - - name: Setup testing repo and quickstart - run: | - botaccess=`cat bot-access.txt` - BOT_TOKEN="${botaccess}" scripts/setup_quickstart.sh dynamiclinks prerelease_testing - - name: Install Secret GoogleService-Info.plist - run: scripts/decrypt_gha_secret.sh scripts/gha-encrypted/qs-dynamiclinks.plist.gpg \ - quickstart-ios/dynamiclinks/GoogleService-Info.plist "$plist_secret" - - name: Update Environment Variable For DynamicLinks - run: | - sed -i '' 's#DYNAMIC_LINK_DOMAIN#https://qpf6m.app.goo.gl#' quickstart-ios/dynamiclinks/DynamicLinksExample/DynamicLinksExample.entitlements - sed -i '' 's#YOUR_DOMAIN_URI_PREFIX";#https://qpf6m.app.goo.gl";#' quickstart-ios/dynamiclinks/DynamicLinksExample/ViewController.m - sed -i '' 's#YOUR_DOMAIN_URI_PREFIX";#https://qpf6m.app.goo.gl";#' quickstart-ios/dynamiclinks/DynamicLinksExampleSwift/ViewController.swift - - name: Test objc quickstart - run: ([ -z $plist_secret ] || scripts/third_party/travis/retry.sh scripts/test_quickstart.sh DynamicLinks false) - - name: Test swift quickstart - if: ${{ always() }} - run: ([ -z $plist_secret ] || scripts/third_party/travis/retry.sh scripts/test_quickstart.sh DynamicLinks false swift) - - name: Remove data before upload - if: ${{ failure() }} - run: scripts/remove_data.sh dynamiclinks - - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: quickstart_artifacts_dynamiclinks - path: quickstart-ios/ - firestore_quickstart: # Don't run on private repo unless it is a PR. if: (github.repository == 'Firebase/firebase-ios-sdk' && github.event_name == 'schedule') || github.event_name == 'workflow_dispatch' diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index d61fd0a814f..009c9d7a7af 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -308,49 +308,6 @@ jobs: name: quickstart_artifacts_database path: quickstart-ios/ - dynamiclinks_quickstart: - # Don't run on private repo unless it is a PR. - if: (github.repository == 'Firebase/firebase-ios-sdk' && github.event_name == 'schedule') || github.event_name == 'pull_request' || github.event_name == 'workflow_dispatch' - needs: buildup_SpecsReleasing_repo - env: - plist_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} - signin_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} - bot_token_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} - testing_repo_dir: "/tmp/test/" - testing_repo: "firebase-ios-sdk" - runs-on: macos-14 - steps: - - uses: actions/checkout@v4 - - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1 - - name: Get token - run: scripts/decrypt_gha_secret.sh scripts/gha-encrypted/release-testing-token.txt.gpg \ - bot-access.txt "$bot_token_secret" - - name: Setup testing repo and quickstart - run: | - botaccess=`cat bot-access.txt` - BOT_TOKEN="${botaccess}" scripts/setup_quickstart.sh dynamiclinks nightly_release_testing - - name: Install Secret GoogleService-Info.plist - run: scripts/decrypt_gha_secret.sh scripts/gha-encrypted/qs-dynamiclinks.plist.gpg \ - quickstart-ios/dynamiclinks/GoogleService-Info.plist "$plist_secret" - - name: Update Environment Variable For DynamicLinks - run: | - sed -i '' 's#DYNAMIC_LINK_DOMAIN#https://qpf6m.app.goo.gl#' quickstart-ios/dynamiclinks/DynamicLinksExample/DynamicLinksExample.entitlements - sed -i '' 's#YOUR_DOMAIN_URI_PREFIX";#https://qpf6m.app.goo.gl";#' quickstart-ios/dynamiclinks/DynamicLinksExample/ViewController.m - sed -i '' 's#YOUR_DOMAIN_URI_PREFIX";#https://qpf6m.app.goo.gl";#' quickstart-ios/dynamiclinks/DynamicLinksExampleSwift/ViewController.swift - - name: Test objc quickstart - run: ([ -z $plist_secret ] || scripts/third_party/travis/retry.sh scripts/test_quickstart.sh DynamicLinks true) - - name: Test swift quickstart - if: ${{ always() }} - run: ([ -z $plist_secret ] || scripts/third_party/travis/retry.sh scripts/test_quickstart.sh DynamicLinks true swift) - - name: Remove data before upload - if: ${{ failure() }} - run: scripts/remove_data.sh dynamiclinks - - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: quickstart_artifacts_dynamiclinks - path: quickstart-ios/ - firestore_quickstart: # Don't run on private repo unless it is a PR. if: (github.repository == 'Firebase/firebase-ios-sdk' && github.event_name == 'schedule') || github.event_name == 'pull_request' || github.event_name == 'workflow_dispatch' diff --git a/.github/workflows/zip.yml b/.github/workflows/zip.yml index d5b23ce50da..2b300b11e86 100644 --- a/.github/workflows/zip.yml +++ b/.github/workflows/zip.yml @@ -391,65 +391,6 @@ jobs: name: quickstart_artifacts database path: quickstart-ios/ - quickstart_framework_dynamiclinks: - # Don't run on private repo. - if: (github.repository == 'Firebase/firebase-ios-sdk' && github.event_name == 'schedule') || github.event_name == 'pull_request' || github.event_name == 'workflow_dispatch' - needs: package-head - env: - plist_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} - signin_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} - SDK: "DynamicLinks" - strategy: - matrix: - artifact: [Firebase-actions-dir, Firebase-actions-dir-dynamic] - build-env: - - os: macos-15 - xcode: Xcode_16.2 - # - os: macos-15 - # xcode: Xcode_16.3 - runs-on: ${{ matrix.build-env.os }} - steps: - - uses: actions/checkout@v4 - - name: Get framework dir - uses: actions/download-artifact@v4.1.7 - with: - name: ${{ matrix.artifact }} - - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1 - - name: Setup Bundler - run: ./scripts/setup_bundler.sh - - name: Move frameworks - run: | - mkdir -p "${HOME}"/ios_frameworks/ - find "${GITHUB_WORKSPACE}" -name "Firebase*latest.zip" -exec unzip -d "${HOME}"/ios_frameworks/ {} + - - name: Setup Objc Quickstart - run: SAMPLE="$SDK" TARGET="${SDK}Example" scripts/setup_quickstart_framework.sh \ - "${HOME}"/ios_frameworks/Firebase/FirebaseDynamicLinks/* \ - "${HOME}"/ios_frameworks/Firebase/FirebaseAnalytics/* - - name: Xcode - run: sudo xcode-select -s /Applications/${{ matrix.build-env.xcode }}.app/Contents/Developer - - name: Setup Swift Quickstart - run: SAMPLE="$SDK" TARGET="${SDK}ExampleSwift" scripts/setup_quickstart_framework.sh - - name: Update Environment Variable For DynamicLinks - run: | - sed -i '' 's#DYNAMIC_LINK_DOMAIN#https://qpf6m.app.goo.gl#' quickstart-ios/dynamiclinks/DynamicLinksExample/DynamicLinksExample.entitlements - sed -i '' 's#YOUR_DOMAIN_URI_PREFIX";#https://qpf6m.app.goo.gl";#' quickstart-ios/dynamiclinks/DynamicLinksExample/ViewController.m - sed -i '' 's#YOUR_DOMAIN_URI_PREFIX";#https://qpf6m.app.goo.gl";#' quickstart-ios/dynamiclinks/DynamicLinksExampleSwift/ViewController.swift - - name: Install Secret GoogleService-Info.plist - run: scripts/decrypt_gha_secret.sh scripts/gha-encrypted/qs-dynamiclinks.plist.gpg \ - quickstart-ios/dynamiclinks/GoogleService-Info.plist "$plist_secret" - - name: Test Objc Quickstart - run: ([ -z $plist_secret ] || scripts/third_party/travis/retry.sh scripts/test_quickstart_framework.sh "${SDK}") - - name: Test Swift Quickstart - run: ([ -z $plist_secret ] || scripts/third_party/travis/retry.sh scripts/test_quickstart_framework.sh "${SDK}" swift) - - name: Remove data before upload - if: ${{ failure() }} - run: scripts/remove_data.sh dynamiclinks - - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: quickstart_artifacts_dynamiclinks - path: quickstart-ios/ - quickstart_framework_firestore: # Don't run on private repo. if: (github.repository == 'Firebase/firebase-ios-sdk' && github.event_name == 'schedule') || github.event_name == 'pull_request' || github.event_name == 'workflow_dispatch' From b54e68eda1f1b9c39c928bf7fe2864e688aaf7fb Mon Sep 17 00:00:00 2001 From: SeanChinJunKai <82928860+SeanChinJunKai@users.noreply.github.com> Date: Sat, 14 Jun 2025 01:25:45 +0800 Subject: [PATCH 080/113] Add title parameter to all static functions in Schema class (#14971) --- FirebaseAI/Sources/Types/Public/Schema.swift | 40 +++++++++++++------ FirebaseAI/Tests/Unit/Types/SchemaTests.swift | 34 ++++++++++++++-- 2 files changed, 59 insertions(+), 15 deletions(-) diff --git a/FirebaseAI/Sources/Types/Public/Schema.swift b/FirebaseAI/Sources/Types/Public/Schema.swift index f5a378a4c11..b8b2ba6c16e 100644 --- a/FirebaseAI/Sources/Types/Public/Schema.swift +++ b/FirebaseAI/Sources/Types/Public/Schema.swift @@ -167,6 +167,7 @@ public final class Schema: Sendable { /// - Parameters: /// - description: An optional description of what the string should contain or represent; may /// use Markdown format. + /// - title: An optional human-readable name/summary for the schema. /// - nullable: If `true`, instructs the model that it *may* generate `null` instead of a /// string; defaults to `false`, enforcing that a string value is generated. /// - format: An optional modifier describing the expected format of the string. Currently no @@ -174,12 +175,13 @@ public final class Schema: Sendable { /// ``StringFormat/custom(_:)``, for example `.custom("email")` or `.custom("byte")`; these /// provide additional hints for how the model should respond but are not guaranteed to be /// adhered to. - public static func string(description: String? = nil, nullable: Bool = false, - format: StringFormat? = nil) -> Schema { + public static func string(description: String? = nil, title: String? = nil, + nullable: Bool = false, format: StringFormat? = nil) -> Schema { return self.init( type: .string, format: format?.rawValue, description: description, + title: title, nullable: nullable ) } @@ -202,15 +204,17 @@ public final class Schema: Sendable { /// - values: The list of string values that may be generated by the model. /// - description: An optional description of what the `values` contain or represent; may use /// Markdown format. + /// - title: An optional human-readable name/summary for the schema. /// - nullable: If `true`, instructs the model that it *may* generate `null` instead of one of /// the strings specified in `values`; defaults to `false`, enforcing that one of the string /// values is generated. public static func enumeration(values: [String], description: String? = nil, - nullable: Bool = false) -> Schema { + title: String? = nil, nullable: Bool = false) -> Schema { return self.init( type: .string, format: "enum", description: description, + title: title, nullable: nullable, enumValues: values ) @@ -229,18 +233,20 @@ public final class Schema: Sendable { /// - Parameters: /// - description: An optional description of what the number should contain or represent; may /// use Markdown format. + /// - title: An optional human-readable name/summary for the schema. /// - nullable: If `true`, instructs the model that it may generate `null` instead of a number; /// defaults to `false`, enforcing that a number is generated. /// - minimum: If specified, instructs the model that the value should be greater than or /// equal to the specified minimum. /// - maximum: If specified, instructs the model that the value should be less than or equal /// to the specified maximum. - public static func float(description: String? = nil, nullable: Bool = false, + public static func float(description: String? = nil, title: String? = nil, nullable: Bool = false, minimum: Float? = nil, maximum: Float? = nil) -> Schema { return self.init( type: .number, format: "float", description: description, + title: title, nullable: nullable, minimum: minimum.map { Double($0) }, maximum: maximum.map { Double($0) } @@ -255,17 +261,20 @@ public final class Schema: Sendable { /// - Parameters: /// - description: An optional description of what the number should contain or represent; may /// use Markdown format. + /// - title: An optional human-readable name/summary for the schema. /// - nullable: If `true`, instructs the model that it may return `null` instead of a number; /// defaults to `false`, enforcing that a number is returned. /// - minimum: If specified, instructs the model that the value should be greater than or /// equal to the specified minimum. /// - maximum: If specified, instructs the model that the value should be less than or equal /// to the specified maximum. - public static func double(description: String? = nil, nullable: Bool = false, + public static func double(description: String? = nil, title: String? = nil, + nullable: Bool = false, minimum: Double? = nil, maximum: Double? = nil) -> Schema { return self.init( type: .number, description: description, + title: title, nullable: nullable, minimum: minimum, maximum: maximum @@ -287,6 +296,7 @@ public final class Schema: Sendable { /// - Parameters: /// - description: An optional description of what the integer should contain or represent; may /// use Markdown format. + /// - title: An optional human-readable name/summary for the schema. /// - nullable: If `true`, instructs the model that it may return `null` instead of an integer; /// defaults to `false`, enforcing that an integer is returned. /// - format: An optional modifier describing the expected format of the integer. Currently the @@ -296,13 +306,14 @@ public final class Schema: Sendable { /// equal to the specified minimum. /// - maximum: If specified, instructs the model that the value should be less than or equal /// to the specified maximum. - public static func integer(description: String? = nil, nullable: Bool = false, - format: IntegerFormat? = nil, + public static func integer(description: String? = nil, title: String? = nil, + nullable: Bool = false, format: IntegerFormat? = nil, minimum: Int? = nil, maximum: Int? = nil) -> Schema { return self.init( type: .integer, format: format?.rawValue, description: description, + title: title, nullable: nullable.self, minimum: minimum.map { Double($0) }, maximum: maximum.map { Double($0) } @@ -317,10 +328,12 @@ public final class Schema: Sendable { /// - Parameters: /// - description: An optional description of what the boolean should contain or represent; may /// use Markdown format. + /// - title: An optional human-readable name/summary for the schema. /// - nullable: If `true`, instructs the model that it may return `null` instead of a boolean; /// defaults to `false`, enforcing that a boolean is returned. - public static func boolean(description: String? = nil, nullable: Bool = false) -> Schema { - return self.init(type: .boolean, description: description, nullable: nullable) + public static func boolean(description: String? = nil, title: String? = nil, + nullable: Bool = false) -> Schema { + return self.init(type: .boolean, description: description, title: title, nullable: nullable) } /// Returns a `Schema` representing an array. @@ -334,17 +347,20 @@ public final class Schema: Sendable { /// - items: The `Schema` of the elements that the array will hold. /// - description: An optional description of what the array should contain or represent; may /// use Markdown format. + /// - title: An optional human-readable name/summary for the schema. /// - nullable: If `true`, instructs the model that it may return `null` instead of an array; /// defaults to `false`, enforcing that an array is returned. /// - minItems: Instructs the model to produce at least the specified minimum number of elements /// in the array; defaults to `nil`, meaning any number. /// - maxItems: Instructs the model to produce at most the specified maximum number of elements /// in the array. - public static func array(items: Schema, description: String? = nil, nullable: Bool = false, - minItems: Int? = nil, maxItems: Int? = nil) -> Schema { + public static func array(items: Schema, description: String? = nil, title: String? = nil, + nullable: Bool = false, minItems: Int? = nil, + maxItems: Int? = nil) -> Schema { return self.init( type: .array, description: description, + title: title, nullable: nullable, items: items, minItems: minItems, @@ -384,7 +400,7 @@ public final class Schema: Sendable { /// generated JSON string. See ``propertyOrdering`` for details. /// - description: An optional description of what the object should contain or represent; may /// use Markdown format. - /// - title: An optional human-readable name/summary for the object schema. + /// - title: An optional human-readable name/summary for the schema. /// - nullable: If `true`, instructs the model that it may return `null` instead of an object; /// defaults to `false`, enforcing that an object is returned. public static func object(properties: [String: Schema], optionalProperties: [String] = [], diff --git a/FirebaseAI/Tests/Unit/Types/SchemaTests.swift b/FirebaseAI/Tests/Unit/Types/SchemaTests.swift index e6eb839a39a..bd8d595dd24 100644 --- a/FirebaseAI/Tests/Unit/Types/SchemaTests.swift +++ b/FirebaseAI/Tests/Unit/Types/SchemaTests.swift @@ -43,8 +43,14 @@ final class SchemaTests: XCTestCase { func testEncodeSchema_string_allOptions() throws { let description = "Timestamp of the event." + let title = "Event Timestamp" let format = Schema.StringFormat.custom("date-time") - let schema = Schema.string(description: description, nullable: true, format: format) + let schema = Schema.string( + description: description, + title: title, + nullable: true, + format: format + ) let jsonData = try encoder.encode(schema) @@ -54,6 +60,7 @@ final class SchemaTests: XCTestCase { "description" : "\(description)", "format" : "date-time", "nullable" : true, + "title": "\(title)", "type" : "STRING" } """) @@ -85,7 +92,13 @@ final class SchemaTests: XCTestCase { func testEncodeSchema_enumeration_allOptions() throws { let values = ["NORTH", "SOUTH", "EAST", "WEST"] let description = "Compass directions." - let schema = Schema.enumeration(values: values, description: description, nullable: true) + let title = "Directions" + let schema = Schema.enumeration( + values: values, + description: description, + title: title, + nullable: true + ) let jsonData = try encoder.encode(schema) @@ -101,6 +114,7 @@ final class SchemaTests: XCTestCase { ], "format" : "enum", "nullable" : true, + "title": "\(title)", "type" : "STRING" } """) @@ -125,10 +139,12 @@ final class SchemaTests: XCTestCase { func testEncodeSchema_float_allOptions() throws { let description = "Temperature in Celsius." + let title = "Temperature (°C)" let minimum: Float = -40.25 let maximum: Float = 50.5 let schema = Schema.float( description: description, + title: title, nullable: true, minimum: minimum, maximum: maximum @@ -144,6 +160,7 @@ final class SchemaTests: XCTestCase { "maximum" : \(maximum), "minimum" : \(minimum), "nullable" : true, + "title": "\(title)", "type" : "NUMBER" } """) @@ -167,10 +184,12 @@ final class SchemaTests: XCTestCase { func testEncodeSchema_double_allOptions() throws { let description = "Account balance." + let title = "Balance" let minimum = 0.01 let maximum = 1_000_000.99 let schema = Schema.double( description: description, + title: title, nullable: true, minimum: minimum, maximum: maximum @@ -185,6 +204,7 @@ final class SchemaTests: XCTestCase { "maximum" : \(maximum), "minimum" : \(minimum), "nullable" : true, + "title": "\(title)", "type" : "NUMBER" } """) @@ -208,11 +228,13 @@ final class SchemaTests: XCTestCase { func testEncodeSchema_integer_allOptions() throws { let description = "User age." + let title = "Age" let minimum = 0 let maximum = 120 let format = Schema.IntegerFormat.int32 let schema = Schema.integer( description: description, + title: title, nullable: true, format: format, minimum: minimum, @@ -229,6 +251,7 @@ final class SchemaTests: XCTestCase { "maximum" : \(maximum), "minimum" : \(minimum), "nullable" : true, + "title": "\(title)", "type" : "INTEGER" } """) @@ -252,7 +275,8 @@ final class SchemaTests: XCTestCase { func testEncodeSchema_boolean_allOptions() throws { let description = "Is the user an administrator?" - let schema = Schema.boolean(description: description, nullable: true) + let title = "Administrator Check" + let schema = Schema.boolean(description: description, title: title, nullable: true) let jsonData = try encoder.encode(schema) @@ -261,6 +285,7 @@ final class SchemaTests: XCTestCase { { "description" : "\(description)", "nullable" : true, + "title": "\(title)", "type" : "BOOLEAN" } """) @@ -290,11 +315,13 @@ final class SchemaTests: XCTestCase { func testEncodeSchema_array_allOptions() throws { let itemsSchema = Schema.integer(format: .int64) let description = "List of product IDs." + let title = "Product IDs" let minItems = 1 let maxItems = 10 let schema = Schema.array( items: itemsSchema, description: description, + title: title, nullable: true, minItems: minItems, maxItems: maxItems @@ -314,6 +341,7 @@ final class SchemaTests: XCTestCase { "maxItems" : \(maxItems), "minItems" : \(minItems), "nullable" : true, + "title": "\(title)", "type" : "ARRAY" } """) From 343bda64d0c4c8bea16b446d330fad23f6884f25 Mon Sep 17 00:00:00 2001 From: Andrew Heard Date: Fri, 13 Jun 2025 16:30:58 -0400 Subject: [PATCH 081/113] [Firebase AI] Fix JSON formatting issue in `Schema` unit tests (#14980) --- FirebaseAI/CHANGELOG.md | 2 ++ FirebaseAI/Tests/Unit/Types/SchemaTests.swift | 14 +++++++------- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/FirebaseAI/CHANGELOG.md b/FirebaseAI/CHANGELOG.md index 9b1ba5c782b..6329e05419a 100644 --- a/FirebaseAI/CHANGELOG.md +++ b/FirebaseAI/CHANGELOG.md @@ -1,5 +1,7 @@ # Unreleased - [fixed] Fixed `Sendable` warnings introduced in the Xcode 26 beta. (#14947) +- [added] Added support for setting `title` in string, number and array `Schema` + types. (#14971) # 11.13.0 - [feature] Initial release of the Firebase AI Logic SDK (`FirebaseAI`). This diff --git a/FirebaseAI/Tests/Unit/Types/SchemaTests.swift b/FirebaseAI/Tests/Unit/Types/SchemaTests.swift index bd8d595dd24..4f911b31bd7 100644 --- a/FirebaseAI/Tests/Unit/Types/SchemaTests.swift +++ b/FirebaseAI/Tests/Unit/Types/SchemaTests.swift @@ -60,7 +60,7 @@ final class SchemaTests: XCTestCase { "description" : "\(description)", "format" : "date-time", "nullable" : true, - "title": "\(title)", + "title" : "\(title)", "type" : "STRING" } """) @@ -114,7 +114,7 @@ final class SchemaTests: XCTestCase { ], "format" : "enum", "nullable" : true, - "title": "\(title)", + "title" : "\(title)", "type" : "STRING" } """) @@ -160,7 +160,7 @@ final class SchemaTests: XCTestCase { "maximum" : \(maximum), "minimum" : \(minimum), "nullable" : true, - "title": "\(title)", + "title" : "\(title)", "type" : "NUMBER" } """) @@ -204,7 +204,7 @@ final class SchemaTests: XCTestCase { "maximum" : \(maximum), "minimum" : \(minimum), "nullable" : true, - "title": "\(title)", + "title" : "\(title)", "type" : "NUMBER" } """) @@ -251,7 +251,7 @@ final class SchemaTests: XCTestCase { "maximum" : \(maximum), "minimum" : \(minimum), "nullable" : true, - "title": "\(title)", + "title" : "\(title)", "type" : "INTEGER" } """) @@ -285,7 +285,7 @@ final class SchemaTests: XCTestCase { { "description" : "\(description)", "nullable" : true, - "title": "\(title)", + "title" : "\(title)", "type" : "BOOLEAN" } """) @@ -341,7 +341,7 @@ final class SchemaTests: XCTestCase { "maxItems" : \(maxItems), "minItems" : \(minItems), "nullable" : true, - "title": "\(title)", + "title" : "\(title)", "type" : "ARRAY" } """) From 56b4128c63c6c4c0d4cceabc1f04a10eee8e4d35 Mon Sep 17 00:00:00 2001 From: Andrew Heard Date: Mon, 16 Jun 2025 14:23:40 -0400 Subject: [PATCH 082/113] [Firebase AI] Add support for configuring a thinking budget (#14909) --- FirebaseAI/CHANGELOG.md | 2 + .../Sources/GenerateContentResponse.swift | 12 ++++ FirebaseAI/Sources/GenerationConfig.swift | 10 ++- .../Sources/Types/Public/ThinkingConfig.swift | 51 +++++++++++++++ .../Tests/TestApp/Sources/Constants.swift | 2 + .../GenerateContentIntegrationTests.swift | 64 +++++++++++++++++++ .../Tests/Utilities/InstanceConfig.swift | 4 ++ 7 files changed, 144 insertions(+), 1 deletion(-) create mode 100644 FirebaseAI/Sources/Types/Public/ThinkingConfig.swift diff --git a/FirebaseAI/CHANGELOG.md b/FirebaseAI/CHANGELOG.md index 6329e05419a..1d2b651e78c 100644 --- a/FirebaseAI/CHANGELOG.md +++ b/FirebaseAI/CHANGELOG.md @@ -2,6 +2,8 @@ - [fixed] Fixed `Sendable` warnings introduced in the Xcode 26 beta. (#14947) - [added] Added support for setting `title` in string, number and array `Schema` types. (#14971) +- [added] Added support for configuring the "thinking" budget when using Gemini + 2.5 series models. (#14909) # 11.13.0 - [feature] Initial release of the Firebase AI Logic SDK (`FirebaseAI`). This diff --git a/FirebaseAI/Sources/GenerateContentResponse.swift b/FirebaseAI/Sources/GenerateContentResponse.swift index 6d4ba6932ec..cb212e5a616 100644 --- a/FirebaseAI/Sources/GenerateContentResponse.swift +++ b/FirebaseAI/Sources/GenerateContentResponse.swift @@ -26,6 +26,16 @@ public struct GenerateContentResponse: Sendable { /// The total number of tokens across the generated response candidates. public let candidatesTokenCount: Int + /// The number of tokens used by the model's internal "thinking" process. + /// + /// For models that support thinking (like Gemini 2.5 Pro and Flash), this represents the actual + /// number of tokens consumed for reasoning before the model generated a response. For models + /// that do not support thinking, this value will be `0`. + /// + /// When thinking is used, this count will be less than or equal to the `thinkingBudget` set in + /// the ``ThinkingConfig``. + public let thoughtsTokenCount: Int + /// The total number of tokens in both the request and response. public let totalTokenCount: Int @@ -330,6 +340,7 @@ extension GenerateContentResponse.UsageMetadata: Decodable { enum CodingKeys: CodingKey { case promptTokenCount case candidatesTokenCount + case thoughtsTokenCount case totalTokenCount case promptTokensDetails case candidatesTokensDetails @@ -340,6 +351,7 @@ extension GenerateContentResponse.UsageMetadata: Decodable { promptTokenCount = try container.decodeIfPresent(Int.self, forKey: .promptTokenCount) ?? 0 candidatesTokenCount = try container.decodeIfPresent(Int.self, forKey: .candidatesTokenCount) ?? 0 + thoughtsTokenCount = try container.decodeIfPresent(Int.self, forKey: .thoughtsTokenCount) ?? 0 totalTokenCount = try container.decodeIfPresent(Int.self, forKey: .totalTokenCount) ?? 0 promptTokensDetails = try container.decodeIfPresent([ModalityTokenCount].self, forKey: .promptTokensDetails) ?? [] diff --git a/FirebaseAI/Sources/GenerationConfig.swift b/FirebaseAI/Sources/GenerationConfig.swift index 3daebbae692..27c4310f12d 100644 --- a/FirebaseAI/Sources/GenerationConfig.swift +++ b/FirebaseAI/Sources/GenerationConfig.swift @@ -51,6 +51,9 @@ public struct GenerationConfig: Sendable { /// Supported modalities of the response. let responseModalities: [ResponseModality]? + /// Configuration for controlling the "thinking" behavior of compatible Gemini models. + let thinkingConfig: ThinkingConfig? + /// Creates a new `GenerationConfig` value. /// /// See the @@ -152,11 +155,14 @@ public struct GenerationConfig: Sendable { /// > Warning: Specifying response modalities is a **Public Preview** feature, which means /// > that it is not subject to any SLA or deprecation policy and could change in /// > backwards-incompatible ways. + /// - thinkingConfig: Configuration for controlling the "thinking" behavior of compatible Gemini + /// models; see ``ThinkingConfig`` for more details. public init(temperature: Float? = nil, topP: Float? = nil, topK: Int? = nil, candidateCount: Int? = nil, maxOutputTokens: Int? = nil, presencePenalty: Float? = nil, frequencyPenalty: Float? = nil, stopSequences: [String]? = nil, responseMIMEType: String? = nil, - responseSchema: Schema? = nil, responseModalities: [ResponseModality]? = nil) { + responseSchema: Schema? = nil, responseModalities: [ResponseModality]? = nil, + thinkingConfig: ThinkingConfig? = nil) { // Explicit init because otherwise if we re-arrange the above variables it changes the API // surface. self.temperature = temperature @@ -170,6 +176,7 @@ public struct GenerationConfig: Sendable { self.responseMIMEType = responseMIMEType self.responseSchema = responseSchema self.responseModalities = responseModalities + self.thinkingConfig = thinkingConfig } } @@ -189,5 +196,6 @@ extension GenerationConfig: Encodable { case responseMIMEType = "responseMimeType" case responseSchema case responseModalities + case thinkingConfig } } diff --git a/FirebaseAI/Sources/Types/Public/ThinkingConfig.swift b/FirebaseAI/Sources/Types/Public/ThinkingConfig.swift new file mode 100644 index 00000000000..c0e8f31465b --- /dev/null +++ b/FirebaseAI/Sources/Types/Public/ThinkingConfig.swift @@ -0,0 +1,51 @@ +// Copyright 2025 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. + +/// Configuration for controlling the "thinking" behavior of compatible Gemini models. +/// +/// Certain models, like Gemini 2.5 Flash and Pro, utilize a thinking process before generating a +/// response. This allows them to reason through complex problems and plan a more coherent and +/// accurate answer. +public struct ThinkingConfig: Sendable { + /// The thinking budget in tokens. + /// + /// This parameter sets an upper limit on the number of tokens the model can use for its internal + /// "thinking" process. A higher budget may result in better quality responses for complex tasks + /// but can also increase latency and cost. + /// + /// If you don't specify a budget (`nil`), the model will automatically determine the appropriate + /// amount of thinking based on the complexity of the prompt. + /// + /// **Model-Specific Behavior:** + /// - **Gemini 2.5 Flash:** The budget can range from `0` to `24576`. Setting the budget to `0` + /// disables the thinking process, which prioritizes the lowest latency and cost. + /// - **Gemini 2.5 Pro:** The budget must be an integer between `128` and `32768`. Thinking cannot + /// be disabled for this model. + /// + /// An error will be thrown if you set a thinking budget for a model that does not support this + /// feature or if the specified budget is not within the model's supported range. + let thinkingBudget: Int? + + /// Initializes a new `ThinkingConfig`. + /// + /// - Parameters: + /// - thinkingBudget: The maximum number of tokens to be used for the model's thinking process. + public init(thinkingBudget: Int? = nil) { + self.thinkingBudget = thinkingBudget + } +} + +// MARK: - Codable Conformances + +extension ThinkingConfig: Encodable {} diff --git a/FirebaseAI/Tests/TestApp/Sources/Constants.swift b/FirebaseAI/Tests/TestApp/Sources/Constants.swift index 1010b27cee3..71305646ab3 100644 --- a/FirebaseAI/Tests/TestApp/Sources/Constants.swift +++ b/FirebaseAI/Tests/TestApp/Sources/Constants.swift @@ -24,5 +24,7 @@ public enum ModelNames { public static let gemini2Flash = "gemini-2.0-flash-001" public static let gemini2FlashLite = "gemini-2.0-flash-lite-001" public static let gemini2FlashExperimental = "gemini-2.0-flash-exp" + public static let gemini2_5_FlashPreview = "gemini-2.5-flash-preview-05-20" + public static let gemini2_5_ProPreview = "gemini-2.5-pro-preview-06-05" public static let gemma3_4B = "gemma-3-4b-it" } diff --git a/FirebaseAI/Tests/TestApp/Tests/Integration/GenerateContentIntegrationTests.swift b/FirebaseAI/Tests/TestApp/Tests/Integration/GenerateContentIntegrationTests.swift index 8513ddfa484..962645d7ee3 100644 --- a/FirebaseAI/Tests/TestApp/Tests/Integration/GenerateContentIntegrationTests.swift +++ b/FirebaseAI/Tests/TestApp/Tests/Integration/GenerateContentIntegrationTests.swift @@ -76,6 +76,7 @@ struct GenerateContentIntegrationTests { let promptTokensDetails = try #require(usageMetadata.promptTokensDetails.first) #expect(promptTokensDetails.modality == .text) #expect(promptTokensDetails.tokenCount == usageMetadata.promptTokenCount) + #expect(usageMetadata.thoughtsTokenCount == 0) // The fields `candidatesTokenCount` and `candidatesTokensDetails` are not included when using // Gemma models. if modelName.hasPrefix("gemma") { @@ -119,6 +120,7 @@ struct GenerateContentIntegrationTests { let usageMetadata = try #require(response.usageMetadata) #expect(usageMetadata.promptTokenCount.isEqual(to: 15, accuracy: tokenCountAccuracy)) #expect(usageMetadata.candidatesTokenCount.isEqual(to: 1, accuracy: tokenCountAccuracy)) + #expect(usageMetadata.thoughtsTokenCount == 0) #expect(usageMetadata.totalTokenCount == usageMetadata.promptTokenCount + usageMetadata.candidatesTokenCount) #expect(usageMetadata.promptTokensDetails.count == 1) @@ -131,6 +133,68 @@ struct GenerateContentIntegrationTests { #expect(candidatesTokensDetails.tokenCount == usageMetadata.candidatesTokenCount) } + @Test(arguments: [ + (InstanceConfig.vertexAI_v1beta, ModelNames.gemini2_5_FlashPreview, 0), + (InstanceConfig.vertexAI_v1beta, ModelNames.gemini2_5_FlashPreview, 24576), + // TODO: Add Vertex AI Gemini 2.5 Pro tests when available. + // (InstanceConfig.vertexAI_v1beta, ModelNames.gemini2_5_ProPreview, 128), + // (InstanceConfig.vertexAI_v1beta, ModelNames.gemini2_5_ProPreview, 32768), + (InstanceConfig.googleAI_v1beta, ModelNames.gemini2_5_FlashPreview, 0), + (InstanceConfig.googleAI_v1beta, ModelNames.gemini2_5_FlashPreview, 24576), + (InstanceConfig.googleAI_v1beta, ModelNames.gemini2_5_ProPreview, 128), + (InstanceConfig.googleAI_v1beta, ModelNames.gemini2_5_ProPreview, 32768), + (InstanceConfig.googleAI_v1beta_freeTier, ModelNames.gemini2_5_FlashPreview, 0), + (InstanceConfig.googleAI_v1beta_freeTier, ModelNames.gemini2_5_FlashPreview, 24576), + ]) + func generateContentThinking(_ config: InstanceConfig, modelName: String, + thinkingBudget: Int) async throws { + let model = FirebaseAI.componentInstance(config).generativeModel( + modelName: modelName, + generationConfig: GenerationConfig( + temperature: 0.0, + topP: 0.0, + topK: 1, + thinkingConfig: ThinkingConfig(thinkingBudget: thinkingBudget) + ), + safetySettings: safetySettings + ) + let prompt = "Where is Google headquarters located? Answer with the city name only." + + let response = try await model.generateContent(prompt) + + let text = try #require(response.text).trimmingCharacters(in: .whitespacesAndNewlines) + #expect(text == "Mountain View") + + let usageMetadata = try #require(response.usageMetadata) + #expect(usageMetadata.promptTokenCount.isEqual(to: 13, accuracy: tokenCountAccuracy)) + #expect(usageMetadata.promptTokensDetails.count == 1) + let promptTokensDetails = try #require(usageMetadata.promptTokensDetails.first) + #expect(promptTokensDetails.modality == .text) + #expect(promptTokensDetails.tokenCount == usageMetadata.promptTokenCount) + if thinkingBudget == 0 { + #expect(usageMetadata.thoughtsTokenCount == 0) + } else { + #expect(usageMetadata.thoughtsTokenCount <= thinkingBudget) + } + #expect(usageMetadata.candidatesTokenCount.isEqual(to: 3, accuracy: tokenCountAccuracy)) + // The `candidatesTokensDetails` field is erroneously omitted when using the Google AI (Gemini + // Developer API) backend. + if case .googleAI = config.apiConfig.service { + #expect(usageMetadata.candidatesTokensDetails.isEmpty) + } else { + #expect(usageMetadata.candidatesTokensDetails.count == 1) + let candidatesTokensDetails = try #require(usageMetadata.candidatesTokensDetails.first) + #expect(candidatesTokensDetails.modality == .text) + #expect(candidatesTokensDetails.tokenCount == usageMetadata.candidatesTokenCount) + } + #expect(usageMetadata.totalTokenCount > 0) + #expect(usageMetadata.totalTokenCount == ( + usageMetadata.promptTokenCount + + usageMetadata.thoughtsTokenCount + + usageMetadata.candidatesTokenCount + )) + } + @Test(arguments: [ InstanceConfig.vertexAI_v1beta, InstanceConfig.googleAI_v1beta, diff --git a/FirebaseAI/Tests/TestApp/Tests/Utilities/InstanceConfig.swift b/FirebaseAI/Tests/TestApp/Tests/Utilities/InstanceConfig.swift index 82f345d99fc..fbea0796f26 100644 --- a/FirebaseAI/Tests/TestApp/Tests/Utilities/InstanceConfig.swift +++ b/FirebaseAI/Tests/TestApp/Tests/Utilities/InstanceConfig.swift @@ -32,6 +32,10 @@ struct InstanceConfig: Equatable, Encodable { static let googleAI_v1beta_staging = InstanceConfig( apiConfig: APIConfig(service: .googleAI(endpoint: .firebaseProxyStaging), version: .v1beta) ) + static let googleAI_v1beta_freeTier = InstanceConfig( + appName: FirebaseAppNames.spark, + apiConfig: APIConfig(service: .googleAI(endpoint: .firebaseProxyProd), version: .v1beta) + ) static let googleAI_v1beta_freeTier_bypassProxy = InstanceConfig( appName: FirebaseAppNames.spark, apiConfig: APIConfig(service: .googleAI(endpoint: .googleAIBypassProxy), version: .v1beta) From 3b76a1b8b622f7229614f06f596b6069c34dddee Mon Sep 17 00:00:00 2001 From: Andrew Heard Date: Mon, 16 Jun 2025 19:41:26 -0400 Subject: [PATCH 083/113] [Firebase AI] Add integration tests for `global` endpoint (#14991) --- .../Integration/GenerateContentIntegrationTests.swift | 7 ++++--- .../Tests/TestApp/Tests/Utilities/InstanceConfig.swift | 5 +++++ 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/FirebaseAI/Tests/TestApp/Tests/Integration/GenerateContentIntegrationTests.swift b/FirebaseAI/Tests/TestApp/Tests/Integration/GenerateContentIntegrationTests.swift index 962645d7ee3..17854c3ab22 100644 --- a/FirebaseAI/Tests/TestApp/Tests/Integration/GenerateContentIntegrationTests.swift +++ b/FirebaseAI/Tests/TestApp/Tests/Integration/GenerateContentIntegrationTests.swift @@ -49,6 +49,7 @@ struct GenerateContentIntegrationTests { @Test(arguments: [ (InstanceConfig.vertexAI_v1beta, ModelNames.gemini2FlashLite), + (InstanceConfig.vertexAI_v1beta_global, ModelNames.gemini2FlashLite), (InstanceConfig.vertexAI_v1beta_staging, ModelNames.gemini2FlashLite), (InstanceConfig.googleAI_v1beta, ModelNames.gemini2FlashLite), (InstanceConfig.googleAI_v1beta, ModelNames.gemma3_4B), @@ -136,9 +137,8 @@ struct GenerateContentIntegrationTests { @Test(arguments: [ (InstanceConfig.vertexAI_v1beta, ModelNames.gemini2_5_FlashPreview, 0), (InstanceConfig.vertexAI_v1beta, ModelNames.gemini2_5_FlashPreview, 24576), - // TODO: Add Vertex AI Gemini 2.5 Pro tests when available. - // (InstanceConfig.vertexAI_v1beta, ModelNames.gemini2_5_ProPreview, 128), - // (InstanceConfig.vertexAI_v1beta, ModelNames.gemini2_5_ProPreview, 32768), + (InstanceConfig.vertexAI_v1beta_global, ModelNames.gemini2_5_ProPreview, 128), + (InstanceConfig.vertexAI_v1beta_global, ModelNames.gemini2_5_ProPreview, 32768), (InstanceConfig.googleAI_v1beta, ModelNames.gemini2_5_FlashPreview, 0), (InstanceConfig.googleAI_v1beta, ModelNames.gemini2_5_FlashPreview, 24576), (InstanceConfig.googleAI_v1beta, ModelNames.gemini2_5_ProPreview, 128), @@ -250,6 +250,7 @@ struct GenerateContentIntegrationTests { @Test(arguments: [ (InstanceConfig.vertexAI_v1beta, ModelNames.gemini2FlashLite), + (InstanceConfig.vertexAI_v1beta_global, ModelNames.gemini2FlashLite), (InstanceConfig.vertexAI_v1beta_staging, ModelNames.gemini2FlashLite), (InstanceConfig.googleAI_v1beta, ModelNames.gemini2FlashLite), (InstanceConfig.googleAI_v1beta, ModelNames.gemma3_4B), diff --git a/FirebaseAI/Tests/TestApp/Tests/Utilities/InstanceConfig.swift b/FirebaseAI/Tests/TestApp/Tests/Utilities/InstanceConfig.swift index fbea0796f26..21554d28250 100644 --- a/FirebaseAI/Tests/TestApp/Tests/Utilities/InstanceConfig.swift +++ b/FirebaseAI/Tests/TestApp/Tests/Utilities/InstanceConfig.swift @@ -23,6 +23,10 @@ struct InstanceConfig: Equatable, Encodable { static let vertexAI_v1beta = InstanceConfig( apiConfig: APIConfig(service: .vertexAI(endpoint: .firebaseProxyProd), version: .v1beta) ) + static let vertexAI_v1beta_global = InstanceConfig( + location: "global", + apiConfig: APIConfig(service: .vertexAI(endpoint: .firebaseProxyProd), version: .v1beta) + ) static let vertexAI_v1beta_staging = InstanceConfig( apiConfig: APIConfig(service: .vertexAI(endpoint: .firebaseProxyStaging), version: .v1beta) ) @@ -43,6 +47,7 @@ struct InstanceConfig: Equatable, Encodable { static let allConfigs = [ vertexAI_v1beta, + vertexAI_v1beta_global, vertexAI_v1beta_staging, googleAI_v1beta, googleAI_v1beta_staging, From 1c567262e55bcc0dc714c8764216fb0e99aee0aa Mon Sep 17 00:00:00 2001 From: Paul Beusterien Date: Tue, 17 Jun 2025 07:34:00 -0700 Subject: [PATCH 084/113] Changelog 11.15.0 (#14994) --- FirebaseAI/CHANGELOG.md | 2 +- FirebaseCore/CHANGELOG.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/FirebaseAI/CHANGELOG.md b/FirebaseAI/CHANGELOG.md index 1d2b651e78c..2527a2bae56 100644 --- a/FirebaseAI/CHANGELOG.md +++ b/FirebaseAI/CHANGELOG.md @@ -1,4 +1,4 @@ -# Unreleased +# 11.15.0 - [fixed] Fixed `Sendable` warnings introduced in the Xcode 26 beta. (#14947) - [added] Added support for setting `title` in string, number and array `Schema` types. (#14971) diff --git a/FirebaseCore/CHANGELOG.md b/FirebaseCore/CHANGELOG.md index 33bf5733e7b..200a2c2e01b 100644 --- a/FirebaseCore/CHANGELOG.md +++ b/FirebaseCore/CHANGELOG.md @@ -1,4 +1,4 @@ -# Unreleased +# Firebase 11.15.0 - [fixed] Remove c99 as the required C language standard. (#14950) # Firebase 11.12.0 From cf99a3cc42e81e6697f88a600510d1592f117046 Mon Sep 17 00:00:00 2001 From: Nick Cooke <36927374+ncooke3@users.noreply.github.com> Date: Tue, 17 Jun 2025 18:11:03 -0400 Subject: [PATCH 085/113] [Auth] Address Xcode 26 warnings in Auth (#14996) --- FirebaseAuth/CHANGELOG.md | 3 + FirebaseAuth/Sources/Swift/Auth/Auth.swift | 79 ++++++++++--------- .../Unit/Fakes/FakeBackendRPCIssuer.swift | 6 +- 3 files changed, 48 insertions(+), 40 deletions(-) diff --git a/FirebaseAuth/CHANGELOG.md b/FirebaseAuth/CHANGELOG.md index 01e82591381..b9278b58399 100644 --- a/FirebaseAuth/CHANGELOG.md +++ b/FirebaseAuth/CHANGELOG.md @@ -1,3 +1,6 @@ +# 11.15.0 +- [fixed] Fixed `Sendable` warnings introduced in the Xcode 26 beta. (#14996) + # 11.14.0 - [fixed] Synchronize internal `AuthKeychainServices` class to prevent crashes from concurrent access. (#14835) diff --git a/FirebaseAuth/Sources/Swift/Auth/Auth.swift b/FirebaseAuth/Sources/Swift/Auth/Auth.swift index 1f89d5ddfe4..3cfb87f41cc 100644 --- a/FirebaseAuth/Sources/Swift/Auth/Auth.swift +++ b/FirebaseAuth/Sources/Swift/Auth/Auth.swift @@ -863,29 +863,41 @@ extension Auth: AuthInterop { displayName: nil, idToken: nil, requestConfiguration: self.requestConfiguration) - #if os(iOS) - self.wrapInjectRecaptcha(request: request, - action: AuthRecaptchaAction.signUpPassword) { response, error in - if let error { + Task { + do { + let response = try await self.injectRecaptcha( + request: request, + action: AuthRecaptchaAction.signUpPassword + ) + self.internalCreateUserWithEmail( + request: request, + inResponse: response, + decoratedCallback: decoratedCallback + ) + } catch { DispatchQueue.main.async { decoratedCallback(.failure(error)) } return } - self.internalCreateUserWithEmail(request: request, inResponse: response, - decoratedCallback: decoratedCallback) } #else - self.internalCreateUserWithEmail(request: request, decoratedCallback: decoratedCallback) + self.internalCreateUserWithEmail( + request: request, + decoratedCallback: decoratedCallback + ) #endif } } - func internalCreateUserWithEmail(request: SignUpNewUserRequest, - inResponse: SignUpNewUserResponse? = nil, - decoratedCallback: @escaping (Result) - -> Void) { + private func internalCreateUserWithEmail(request: SignUpNewUserRequest, + inResponse: SignUpNewUserResponse? = nil, + decoratedCallback: @escaping (Result< + AuthDataResult, + Error + >) + -> Void) { Task { do { var response: SignUpNewUserResponse @@ -1161,12 +1173,15 @@ extension Auth: AuthInterop { requestConfiguration: self.requestConfiguration ) #if os(iOS) - self.wrapInjectRecaptcha(request: request, - action: AuthRecaptchaAction.getOobCode) { result, error in - if let completion { - DispatchQueue.main.async { - completion(error) - } + Task { + do { + _ = try await self.injectRecaptcha( + request: request, + action: AuthRecaptchaAction.getOobCode + ) + Auth.wrapMainAsync(completion, nil) + } catch { + Auth.wrapMainAsync(completion, error) } } #else @@ -1234,12 +1249,15 @@ extension Auth: AuthInterop { requestConfiguration: self.requestConfiguration ) #if os(iOS) - self.wrapInjectRecaptcha(request: request, - action: AuthRecaptchaAction.getOobCode) { result, error in - if let completion { - DispatchQueue.main.async { - completion(error) - } + Task { + do { + _ = try await self.injectRecaptcha( + request: request, + action: AuthRecaptchaAction.getOobCode + ) + Auth.wrapMainAsync(completion, nil) + } catch { + Auth.wrapMainAsync(completion, error) } } #else @@ -2289,21 +2307,6 @@ extension Auth: AuthInterop { } #if os(iOS) - private func wrapInjectRecaptcha(request: T, - action: AuthRecaptchaAction, - _ callback: @escaping ( - (T.Response?, Error?) -> Void - )) { - Task { - do { - let response = try await injectRecaptcha(request: request, action: action) - callback(response, nil) - } catch { - callback(nil, error) - } - } - } - func injectRecaptcha(request: T, action: AuthRecaptchaAction) async throws -> T .Response { diff --git a/FirebaseAuth/Tests/Unit/Fakes/FakeBackendRPCIssuer.swift b/FirebaseAuth/Tests/Unit/Fakes/FakeBackendRPCIssuer.swift index ec931c0c859..a3e7d12db48 100644 --- a/FirebaseAuth/Tests/Unit/Fakes/FakeBackendRPCIssuer.swift +++ b/FirebaseAuth/Tests/Unit/Fakes/FakeBackendRPCIssuer.swift @@ -153,13 +153,15 @@ final class FakeBackendRPCIssuer: AuthBackendRPCIssuerProtocol, @unchecked Senda requestData = body // Use the real implementation so that the complete request can // be verified during testing. + let requestURL = request.requestURL() + let requestConfiguration = request.requestConfiguration() completeRequest = Task { await AuthBackend .request( - for: request.requestURL(), + for: requestURL, httpMethod: requestData == nil ? "GET" : "POST", contentType: contentType, - requestConfiguration: request.requestConfiguration() + requestConfiguration: requestConfiguration ) } decodedRequest = try? JSONSerialization.jsonObject(with: body) as? [String: Any] From fa3529aa3f88e1012ea0236d54acfe26f37d36aa Mon Sep 17 00:00:00 2001 From: htcgh Date: Tue, 17 Jun 2025 15:50:14 -0700 Subject: [PATCH 086/113] Analytics 11.15.0 (#14999) --- FirebaseAnalytics.podspec | 2 +- GoogleAppMeasurement.podspec | 4 ++-- GoogleAppMeasurementOnDeviceConversion.podspec | 2 +- Package.swift | 6 +++--- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/FirebaseAnalytics.podspec b/FirebaseAnalytics.podspec index a4569b8588f..c3d5abf2ad5 100644 --- a/FirebaseAnalytics.podspec +++ b/FirebaseAnalytics.podspec @@ -13,7 +13,7 @@ Pod::Spec.new do |s| s.authors = 'Google, Inc.' s.source = { - :http => 'https://dl.google.com/firebase/ios/analytics/928ced72694a6548/FirebaseAnalytics-11.14.0.tar.gz' + :http => 'https://dl.google.com/firebase/ios/analytics/76d70f97e309a17e/FirebaseAnalytics-11.15.0.tar.gz' } s.cocoapods_version = '>= 1.12.0' diff --git a/GoogleAppMeasurement.podspec b/GoogleAppMeasurement.podspec index 437923cd679..bbfca9bbefc 100644 --- a/GoogleAppMeasurement.podspec +++ b/GoogleAppMeasurement.podspec @@ -16,7 +16,7 @@ Pod::Spec.new do |s| s.authors = 'Google, Inc.' s.source = { - :http => 'https://dl.google.com/firebase/ios/analytics/947bee486051ffca/GoogleAppMeasurement-11.14.0.tar.gz' + :http => 'https://dl.google.com/firebase/ios/analytics/922d99823e10f4a0/GoogleAppMeasurement-11.15.0.tar.gz' } s.cocoapods_version = '>= 1.12.0' @@ -39,7 +39,7 @@ Pod::Spec.new do |s| s.subspec 'Default' do |ss| ss.dependency 'GoogleAppMeasurement/Core', '11.15.0' ss.dependency 'GoogleAppMeasurement/IdentitySupport', '11.15.0' - ss.ios.dependency 'GoogleAdsOnDeviceConversion', '2.0.0' + ss.ios.dependency 'GoogleAdsOnDeviceConversion', '2.1.0' end s.subspec 'Core' do |ss| diff --git a/GoogleAppMeasurementOnDeviceConversion.podspec b/GoogleAppMeasurementOnDeviceConversion.podspec index 368e0618644..fb9b864a069 100644 --- a/GoogleAppMeasurementOnDeviceConversion.podspec +++ b/GoogleAppMeasurementOnDeviceConversion.podspec @@ -17,7 +17,7 @@ Pod::Spec.new do |s| s.authors = 'Google, Inc.' s.source = { - :http => 'https://dl.google.com/firebase/ios/analytics/af5df76743613a77/GoogleAppMeasurementOnDeviceConversion-11.14.0.tar.gz' + :http => 'https://dl.google.com/firebase/ios/analytics/de0ea660a77ecdb8/GoogleAppMeasurementOnDeviceConversion-11.15.0.tar.gz' } s.cocoapods_version = '>= 1.12.0' diff --git a/Package.swift b/Package.swift index f82fa0e8222..2627e79daca 100644 --- a/Package.swift +++ b/Package.swift @@ -375,8 +375,8 @@ let package = Package( ), .binaryTarget( name: "FirebaseAnalytics", - url: "https://dl.google.com/firebase/ios/swiftpm/11.14.0/FirebaseAnalytics.zip", - checksum: "b86d668ff8b5e0df396d1a5711632b542247e03c8dda8ab4722185090d47300c" + url: "https://dl.google.com/firebase/ios/swiftpm/11.15.0/FirebaseAnalytics.zip", + checksum: "b535a4eb74ddb2786b0e65bbd14e08d11a925c525f9d3e73c1e4fa37963e6b85" ), .testTarget( name: "AnalyticsSwiftUnit", @@ -1444,7 +1444,7 @@ func googleAppMeasurementDependency() -> Package.Dependency { return .package(url: appMeasurementURL, branch: "main") } - return .package(url: appMeasurementURL, exact: "11.14.0") + return .package(url: appMeasurementURL, exact: "11.15.0") } func abseilDependency() -> Package.Dependency { From 38790946ab23ef6e7fcc35adde39fc0f1ba352b2 Mon Sep 17 00:00:00 2001 From: Andrew Heard Date: Tue, 17 Jun 2025 19:09:32 -0400 Subject: [PATCH 087/113] [Firebase AI] Deprecate `CountTokensResponse.totalBillableCharacters` (#14998) --- FirebaseAI/CHANGELOG.md | 3 +++ .../Requests/CountTokensRequest.swift | 21 ++++++++++++++++--- .../CountTokensIntegrationTests.swift | 12 +++++------ .../Tests/Integration/IntegrationTests.swift | 14 +++++++------ .../Unit/GenerativeModelVertexAITests.swift | 8 +++---- 5 files changed, 39 insertions(+), 19 deletions(-) diff --git a/FirebaseAI/CHANGELOG.md b/FirebaseAI/CHANGELOG.md index 2527a2bae56..ff5db6078e7 100644 --- a/FirebaseAI/CHANGELOG.md +++ b/FirebaseAI/CHANGELOG.md @@ -4,6 +4,9 @@ types. (#14971) - [added] Added support for configuring the "thinking" budget when using Gemini 2.5 series models. (#14909) +- [changed] Deprecated `CountTokensResponse.totalBillableCharacters`; use + `totalTokens` instead. Gemini 2.0 series models and newer are always billed by + token count. (#14934) # 11.13.0 - [feature] Initial release of the Firebase AI Logic SDK (`FirebaseAI`). This diff --git a/FirebaseAI/Sources/Types/Internal/Requests/CountTokensRequest.swift b/FirebaseAI/Sources/Types/Internal/Requests/CountTokensRequest.swift index ba3c082f297..3247fd5ebb5 100644 --- a/FirebaseAI/Sources/Types/Internal/Requests/CountTokensRequest.swift +++ b/FirebaseAI/Sources/Types/Internal/Requests/CountTokensRequest.swift @@ -39,6 +39,14 @@ extension CountTokensRequest: GenerativeAIRequest { /// The model's response to a count tokens request. @available(iOS 15.0, macOS 12.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) public struct CountTokensResponse: Sendable { + /// Container for deprecated properties or methods. + /// + /// This workaround allows deprecated fields to be referenced internally (for example in the + /// `init(from:)` constructor) without introducing compiler warnings. + struct Deprecated { + let totalBillableCharacters: Int? + } + /// The total number of tokens in the input given to the model as a prompt. public let totalTokens: Int @@ -46,10 +54,16 @@ public struct CountTokensResponse: Sendable { /// /// > Important: This does not include billable image, video or other non-text input. See /// [Vertex AI pricing](https://firebase.google.com/docs/vertex-ai/pricing) for details. - public let totalBillableCharacters: Int? + @available(*, deprecated, message: """ + Use `totalTokens` instead; Gemini 2.0 series models and newer are always billed by token count. + """) + public var totalBillableCharacters: Int? { deprecated.totalBillableCharacters } /// The breakdown, by modality, of how many tokens are consumed by the prompt. public let promptTokensDetails: [ModalityTokenCount] + + /// Deprecated properties or methods. + let deprecated: Deprecated } // MARK: - Codable Conformances @@ -105,9 +119,10 @@ extension CountTokensResponse: Decodable { public init(from decoder: any Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) totalTokens = try container.decodeIfPresent(Int.self, forKey: .totalTokens) ?? 0 - totalBillableCharacters = - try container.decodeIfPresent(Int.self, forKey: .totalBillableCharacters) promptTokensDetails = try container.decodeIfPresent([ModalityTokenCount].self, forKey: .promptTokensDetails) ?? [] + let totalBillableCharacters = + try container.decodeIfPresent(Int.self, forKey: .totalBillableCharacters) + deprecated = CountTokensResponse.Deprecated(totalBillableCharacters: totalBillableCharacters) } } diff --git a/FirebaseAI/Tests/TestApp/Tests/Integration/CountTokensIntegrationTests.swift b/FirebaseAI/Tests/TestApp/Tests/Integration/CountTokensIntegrationTests.swift index 4c7c1a49a86..3851fe527fa 100644 --- a/FirebaseAI/Tests/TestApp/Tests/Integration/CountTokensIntegrationTests.swift +++ b/FirebaseAI/Tests/TestApp/Tests/Integration/CountTokensIntegrationTests.swift @@ -59,9 +59,9 @@ struct CountTokensIntegrationTests { #expect(response.totalTokens == 6) switch config.apiConfig.service { case .vertexAI: - #expect(response.totalBillableCharacters == 16) + #expect(response.deprecated.totalBillableCharacters == 16) case .googleAI: - #expect(response.totalBillableCharacters == nil) + #expect(response.deprecated.totalBillableCharacters == nil) } #expect(response.promptTokensDetails.count == 1) let promptTokensDetails = try #require(response.promptTokensDetails.first) @@ -83,9 +83,9 @@ struct CountTokensIntegrationTests { #expect(response.totalTokens == 14) switch config.apiConfig.service { case .vertexAI: - #expect(response.totalBillableCharacters == 61) + #expect(response.deprecated.totalBillableCharacters == 61) case .googleAI: - #expect(response.totalBillableCharacters == nil) + #expect(response.deprecated.totalBillableCharacters == nil) } #expect(response.promptTokensDetails.count == 1) let promptTokensDetails = try #require(response.promptTokensDetails.first) @@ -115,12 +115,12 @@ struct CountTokensIntegrationTests { switch config.apiConfig.service { case .vertexAI: #expect(response.totalTokens == 65) - #expect(response.totalBillableCharacters == 170) + #expect(response.deprecated.totalBillableCharacters == 170) case .googleAI: // The Developer API erroneously ignores the `responseSchema` when counting tokens, resulting // in a lower total count than Vertex AI. #expect(response.totalTokens == 34) - #expect(response.totalBillableCharacters == nil) + #expect(response.deprecated.totalBillableCharacters == nil) } #expect(response.promptTokensDetails.count == 1) let promptTokensDetails = try #require(response.promptTokensDetails.first) diff --git a/FirebaseAI/Tests/TestApp/Tests/Integration/IntegrationTests.swift b/FirebaseAI/Tests/TestApp/Tests/Integration/IntegrationTests.swift index e870a52d7a6..7ec14f8fef1 100644 --- a/FirebaseAI/Tests/TestApp/Tests/Integration/IntegrationTests.swift +++ b/FirebaseAI/Tests/TestApp/Tests/Integration/IntegrationTests.swift @@ -19,6 +19,8 @@ import FirebaseCore import FirebaseStorage import XCTest +@testable import struct FirebaseAI.CountTokensRequest + // TODO(#14405): Migrate to Swift Testing and parameterize tests. final class IntegrationTests: XCTestCase { // Set temperature, topP and topK to lowest allowed values to make responses more deterministic. @@ -83,7 +85,7 @@ final class IntegrationTests: XCTestCase { let response = try await model.countTokens(prompt) XCTAssertEqual(response.totalTokens, 14) - XCTAssertEqual(response.totalBillableCharacters, 51) + XCTAssertEqual(response.deprecated.totalBillableCharacters, 51) XCTAssertEqual(response.promptTokensDetails.count, 1) let promptTokensDetails = try XCTUnwrap(response.promptTokensDetails.first) XCTAssertEqual(promptTokensDetails.modality, .text) @@ -100,7 +102,7 @@ final class IntegrationTests: XCTestCase { let response = try await model.countTokens(image) XCTAssertEqual(response.totalTokens, 266) - XCTAssertEqual(response.totalBillableCharacters, 35) + XCTAssertEqual(response.deprecated.totalBillableCharacters, 35) XCTAssertEqual(response.promptTokensDetails.count, 2) // Image prompt + system instruction let textPromptTokensDetails = try XCTUnwrap(response.promptTokensDetails.first { $0.modality == .text @@ -120,7 +122,7 @@ final class IntegrationTests: XCTestCase { let response = try await model.countTokens(fileData) XCTAssertEqual(response.totalTokens, 266) - XCTAssertEqual(response.totalBillableCharacters, 35) + XCTAssertEqual(response.deprecated.totalBillableCharacters, 35) XCTAssertEqual(response.promptTokensDetails.count, 2) // Image prompt + system instruction let textPromptTokensDetails = try XCTUnwrap(response.promptTokensDetails.first { $0.modality == .text @@ -139,7 +141,7 @@ final class IntegrationTests: XCTestCase { let response = try await model.countTokens(fileData) XCTAssertEqual(response.totalTokens, 266) - XCTAssertEqual(response.totalBillableCharacters, 35) + XCTAssertEqual(response.deprecated.totalBillableCharacters, 35) } func testCountTokens_image_fileData_requiresUserAuth_userSignedIn() async throws { @@ -150,7 +152,7 @@ final class IntegrationTests: XCTestCase { let response = try await model.countTokens(fileData) XCTAssertEqual(response.totalTokens, 266) - XCTAssertEqual(response.totalBillableCharacters, 35) + XCTAssertEqual(response.deprecated.totalBillableCharacters, 35) } func testCountTokens_image_fileData_requiresUserAuth_wrongUser_permissionDenied() async throws { @@ -191,7 +193,7 @@ final class IntegrationTests: XCTestCase { ]) XCTAssertGreaterThan(response.totalTokens, 0) - XCTAssertEqual(response.totalBillableCharacters, 71) + XCTAssertEqual(response.deprecated.totalBillableCharacters, 71) XCTAssertEqual(response.promptTokensDetails.count, 1) let promptTokensDetails = try XCTUnwrap(response.promptTokensDetails.first) XCTAssertEqual(promptTokensDetails.modality, .text) diff --git a/FirebaseAI/Tests/Unit/GenerativeModelVertexAITests.swift b/FirebaseAI/Tests/Unit/GenerativeModelVertexAITests.swift index f1092a4c4f6..75a15376636 100644 --- a/FirebaseAI/Tests/Unit/GenerativeModelVertexAITests.swift +++ b/FirebaseAI/Tests/Unit/GenerativeModelVertexAITests.swift @@ -1517,7 +1517,7 @@ final class GenerativeModelVertexAITests: XCTestCase { let response = try await model.countTokens("Why is the sky blue?") XCTAssertEqual(response.totalTokens, 6) - XCTAssertEqual(response.totalBillableCharacters, 16) + XCTAssertEqual(response.deprecated.totalBillableCharacters, 16) } func testCountTokens_succeeds_detailed() async throws { @@ -1530,7 +1530,7 @@ final class GenerativeModelVertexAITests: XCTestCase { let response = try await model.countTokens("Why is the sky blue?") XCTAssertEqual(response.totalTokens, 1837) - XCTAssertEqual(response.totalBillableCharacters, 117) + XCTAssertEqual(response.deprecated.totalBillableCharacters, 117) XCTAssertEqual(response.promptTokensDetails.count, 2) XCTAssertEqual(response.promptTokensDetails[0].modality, .image) XCTAssertEqual(response.promptTokensDetails[0].tokenCount, 1806) @@ -1577,7 +1577,7 @@ final class GenerativeModelVertexAITests: XCTestCase { let response = try await model.countTokens("Why is the sky blue?") XCTAssertEqual(response.totalTokens, 6) - XCTAssertEqual(response.totalBillableCharacters, 16) + XCTAssertEqual(response.deprecated.totalBillableCharacters, 16) } func testCountTokens_succeeds_noBillableCharacters() async throws { @@ -1590,7 +1590,7 @@ final class GenerativeModelVertexAITests: XCTestCase { let response = try await model.countTokens(InlineDataPart(data: Data(), mimeType: "image/jpeg")) XCTAssertEqual(response.totalTokens, 258) - XCTAssertNil(response.totalBillableCharacters) + XCTAssertNil(response.deprecated.totalBillableCharacters) } func testCountTokens_modelNotFound() async throws { From 676a24df304b5b6f1702eb8eea43ac8b2f21f8be Mon Sep 17 00:00:00 2001 From: Nick Cooke <36927374+ncooke3@users.noreply.github.com> Date: Tue, 17 Jun 2025 22:43:50 -0400 Subject: [PATCH 088/113] [Infra] Remove Firebase Dynamic Links from the InAppMessaging sample applications. (#15000) Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com> --- .../InAppMessaging-Example-iOS/AppDelegate.m | 50 --- .../GoogleService-Info.plist | 28 -- .../fiam-external-ios-testing-app/Podfile | 18 - .../project.pbxproj | 423 ------------------ .../AppDelegate.h | 21 - .../AppDelegate.m | 70 --- .../AppIcon.appiconset/Contents.json | 93 ---- .../Base.lproj/LaunchScreen.storyboard | 31 -- .../Base.lproj/Main.storyboard | 51 --- .../fiam-external-ios-testing-app/Info.plist | 60 --- .../ViewController.h | 19 - .../ViewController.m | 39 -- .../fiam-external-ios-testing-app/main.m | 24 - .../Integration/FunctionalTestApp/Podfile | 1 - 14 files changed, 928 deletions(-) delete mode 100644 FirebaseInAppMessaging/Tests/Integration/FunctionalTestApp/ExternalAppExample/fiam-external-ios-testing-app/GoogleService-Info.plist delete mode 100644 FirebaseInAppMessaging/Tests/Integration/FunctionalTestApp/ExternalAppExample/fiam-external-ios-testing-app/Podfile delete mode 100644 FirebaseInAppMessaging/Tests/Integration/FunctionalTestApp/ExternalAppExample/fiam-external-ios-testing-app/fiam-external-ios-testing-app.xcodeproj/project.pbxproj delete mode 100644 FirebaseInAppMessaging/Tests/Integration/FunctionalTestApp/ExternalAppExample/fiam-external-ios-testing-app/fiam-external-ios-testing-app/AppDelegate.h delete mode 100644 FirebaseInAppMessaging/Tests/Integration/FunctionalTestApp/ExternalAppExample/fiam-external-ios-testing-app/fiam-external-ios-testing-app/AppDelegate.m delete mode 100644 FirebaseInAppMessaging/Tests/Integration/FunctionalTestApp/ExternalAppExample/fiam-external-ios-testing-app/fiam-external-ios-testing-app/Assets.xcassets/AppIcon.appiconset/Contents.json delete mode 100644 FirebaseInAppMessaging/Tests/Integration/FunctionalTestApp/ExternalAppExample/fiam-external-ios-testing-app/fiam-external-ios-testing-app/Base.lproj/LaunchScreen.storyboard delete mode 100644 FirebaseInAppMessaging/Tests/Integration/FunctionalTestApp/ExternalAppExample/fiam-external-ios-testing-app/fiam-external-ios-testing-app/Base.lproj/Main.storyboard delete mode 100644 FirebaseInAppMessaging/Tests/Integration/FunctionalTestApp/ExternalAppExample/fiam-external-ios-testing-app/fiam-external-ios-testing-app/Info.plist delete mode 100644 FirebaseInAppMessaging/Tests/Integration/FunctionalTestApp/ExternalAppExample/fiam-external-ios-testing-app/fiam-external-ios-testing-app/ViewController.h delete mode 100644 FirebaseInAppMessaging/Tests/Integration/FunctionalTestApp/ExternalAppExample/fiam-external-ios-testing-app/fiam-external-ios-testing-app/ViewController.m delete mode 100644 FirebaseInAppMessaging/Tests/Integration/FunctionalTestApp/ExternalAppExample/fiam-external-ios-testing-app/fiam-external-ios-testing-app/main.m diff --git a/FirebaseInAppMessaging/Tests/Integration/FunctionalTestApp/App/InAppMessaging-Example-iOS/AppDelegate.m b/FirebaseInAppMessaging/Tests/Integration/FunctionalTestApp/App/InAppMessaging-Example-iOS/AppDelegate.m index 85317849f83..cf8c48b8801 100644 --- a/FirebaseInAppMessaging/Tests/Integration/FunctionalTestApp/App/InAppMessaging-Example-iOS/AppDelegate.m +++ b/FirebaseInAppMessaging/Tests/Integration/FunctionalTestApp/App/InAppMessaging-Example-iOS/AppDelegate.m @@ -21,7 +21,6 @@ #import #import -#import @interface FIRInAppMessaging (Testing) + (void)disableAutoBootstrapWithFIRApp; @@ -65,53 +64,4 @@ - (BOOL)application:(UIApplication *)application return YES; } -- (BOOL)application:(UIApplication *)application - continueUserActivity:(NSUserActivity *)userActivity - restorationHandler:(void (^)(NSArray> *))restorationHandler { - NSLog(@"handle page url %@", userActivity.webpageURL); - BOOL handled = [[FIRDynamicLinks dynamicLinks] - handleUniversalLink:userActivity.webpageURL - completion:^(FIRDynamicLink *_Nullable dynamicLink, NSError *_Nullable error) { - if (dynamicLink) { - NSLog(@"dynamic link recognized with url as %@", dynamicLink.url.absoluteString); - [self showDeepLink:dynamicLink.url.absoluteString forUrlType:@"universal link"]; - } else { - NSLog(@"error happened %@", error); - } - }]; - return handled; -} - -- (void)showDeepLink:(NSString *)url forUrlType:(NSString *)urlType { - NSString *message = [NSString stringWithFormat:@"App wants to open a %@ : %@", urlType, url]; - UIAlertController *alert = - [UIAlertController alertControllerWithTitle:@"Deep link recognized" - message:message - preferredStyle:UIAlertControllerStyleAlert]; - - UIAlertAction *defaultAction = [UIAlertAction actionWithTitle:@"OK" - style:UIAlertActionStyleDefault - handler:^(UIAlertAction *action){ - }]; - - [alert addAction:defaultAction]; - [UIApplication.sharedApplication.keyWindow.rootViewController presentViewController:alert - animated:YES - completion:nil]; -} - -- (BOOL)application:(UIApplication *)app - openURL:(NSURL *)url - options:(NSDictionary *)options { - return [self application:app openURL:url sourceApplication:@"source app" annotation:@{}]; -} - -- (BOOL)application:(UIApplication *)application - openURL:(NSURL *)url - sourceApplication:(NSString *)sourceApplication - annotation:(id)annotation { - NSLog(@"handle link with custom scheme: %@", url.absoluteString); - [self showDeepLink:url.absoluteString forUrlType:@"custom scheme url"]; - return YES; -} @end diff --git a/FirebaseInAppMessaging/Tests/Integration/FunctionalTestApp/ExternalAppExample/fiam-external-ios-testing-app/GoogleService-Info.plist b/FirebaseInAppMessaging/Tests/Integration/FunctionalTestApp/ExternalAppExample/fiam-external-ios-testing-app/GoogleService-Info.plist deleted file mode 100644 index cb4d6f4ac0f..00000000000 --- a/FirebaseInAppMessaging/Tests/Integration/FunctionalTestApp/ExternalAppExample/fiam-external-ios-testing-app/GoogleService-Info.plist +++ /dev/null @@ -1,28 +0,0 @@ - - - - - API_KEY - correct_api_key - TRACKING_ID - correct_tracking_id - CLIENT_ID - correct_client_id - REVERSED_CLIENT_ID - correct_reversed_client_id - GOOGLE_APP_ID - 1:123:ios:123abc - GCM_SENDER_ID - correct_gcm_sender_id - PLIST_VERSION - 1 - BUNDLE_ID - com.google.FirebaseSDKTests - PROJECT_ID - abc-xyz-123 - DATABASE_URL - https://abc-xyz-123.firebaseio.com - STORAGE_BUCKET - project-id-123.storage.firebase.com - - diff --git a/FirebaseInAppMessaging/Tests/Integration/FunctionalTestApp/ExternalAppExample/fiam-external-ios-testing-app/Podfile b/FirebaseInAppMessaging/Tests/Integration/FunctionalTestApp/ExternalAppExample/fiam-external-ios-testing-app/Podfile deleted file mode 100644 index dafdb96088f..00000000000 --- a/FirebaseInAppMessaging/Tests/Integration/FunctionalTestApp/ExternalAppExample/fiam-external-ios-testing-app/Podfile +++ /dev/null @@ -1,18 +0,0 @@ -# Uncomment the next line to define a global platform for your project -platform :ios, '11.0' - -# uncomment the follow two lines if you are trying to test internal releases -#source 'sso://cpdc-internal/spec.git' -#source 'https://github.com/CocoaPods/Specs.git' - -use_frameworks! - -target 'fiam-external-ios-testing-app' do - # Uncomment the next line if you're using Swift or would like to use dynamic frameworks - # use_frameworks! - - # Pods for fiam-external-ios-testing-app - pod 'Firebase/Core' - pod 'Firebase/InAppMessaging' - pod 'Firebase/DynamicLinks' -end diff --git a/FirebaseInAppMessaging/Tests/Integration/FunctionalTestApp/ExternalAppExample/fiam-external-ios-testing-app/fiam-external-ios-testing-app.xcodeproj/project.pbxproj b/FirebaseInAppMessaging/Tests/Integration/FunctionalTestApp/ExternalAppExample/fiam-external-ios-testing-app/fiam-external-ios-testing-app.xcodeproj/project.pbxproj deleted file mode 100644 index 8ff5249f0e2..00000000000 --- a/FirebaseInAppMessaging/Tests/Integration/FunctionalTestApp/ExternalAppExample/fiam-external-ios-testing-app/fiam-external-ios-testing-app.xcodeproj/project.pbxproj +++ /dev/null @@ -1,423 +0,0 @@ -// !$*UTF8*$! -{ - archiveVersion = 1; - classes = { - }; - objectVersion = 48; - objects = { - -/* Begin PBXBuildFile section */ - 7D31D8493943DCD77743922A /* Pods_fiam_external_ios_testing_app.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 12F51E141FEC71BA1CE57DC4 /* Pods_fiam_external_ios_testing_app.framework */; }; - AD7649C71FE1B0A800378AE0 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = AD7649C61FE1B0A800378AE0 /* AppDelegate.m */; }; - AD7649CA1FE1B0A800378AE0 /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = AD7649C91FE1B0A800378AE0 /* ViewController.m */; }; - AD7649CD1FE1B0A800378AE0 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = AD7649CB1FE1B0A800378AE0 /* Main.storyboard */; }; - AD7649CF1FE1B0A800378AE0 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = AD7649CE1FE1B0A800378AE0 /* Assets.xcassets */; }; - AD7649D21FE1B0A800378AE0 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = AD7649D01FE1B0A800378AE0 /* LaunchScreen.storyboard */; }; - AD7649D51FE1B0A800378AE0 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = AD7649D41FE1B0A800378AE0 /* main.m */; }; - AD7649DC1FE1B57A00378AE0 /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = AD7649DB1FE1B57A00378AE0 /* GoogleService-Info.plist */; }; -/* End PBXBuildFile section */ - -/* Begin PBXFileReference section */ - 12F51E141FEC71BA1CE57DC4 /* Pods_fiam_external_ios_testing_app.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_fiam_external_ios_testing_app.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 61D649CA05E938083C88FC6D /* Pods-fiam-external-ios-testing-app.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-fiam-external-ios-testing-app.debug.xcconfig"; path = "Pods/Target Support Files/Pods-fiam-external-ios-testing-app/Pods-fiam-external-ios-testing-app.debug.xcconfig"; sourceTree = ""; }; - AD7649C21FE1B0A800378AE0 /* fiam-external-ios-testing-app.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "fiam-external-ios-testing-app.app"; sourceTree = BUILT_PRODUCTS_DIR; }; - AD7649C51FE1B0A800378AE0 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; - AD7649C61FE1B0A800378AE0 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; - AD7649C81FE1B0A800378AE0 /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = ""; }; - AD7649C91FE1B0A800378AE0 /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = ""; }; - AD7649CC1FE1B0A800378AE0 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; - AD7649CE1FE1B0A800378AE0 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; - AD7649D11FE1B0A800378AE0 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; - AD7649D31FE1B0A800378AE0 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - AD7649D41FE1B0A800378AE0 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; - AD7649DB1FE1B57A00378AE0 /* GoogleService-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "GoogleService-Info.plist"; sourceTree = SOURCE_ROOT; }; - EE0B5FD5B23F372E4894C799 /* Pods-fiam-external-ios-testing-app.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-fiam-external-ios-testing-app.release.xcconfig"; path = "Pods/Target Support Files/Pods-fiam-external-ios-testing-app/Pods-fiam-external-ios-testing-app.release.xcconfig"; sourceTree = ""; }; -/* End PBXFileReference section */ - -/* Begin PBXFrameworksBuildPhase section */ - AD7649BF1FE1B0A800378AE0 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 7D31D8493943DCD77743922A /* Pods_fiam_external_ios_testing_app.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXFrameworksBuildPhase section */ - -/* Begin PBXGroup section */ - 2F924E232047E700385C2AFA /* Frameworks */ = { - isa = PBXGroup; - children = ( - 12F51E141FEC71BA1CE57DC4 /* Pods_fiam_external_ios_testing_app.framework */, - ); - name = Frameworks; - sourceTree = ""; - }; - 4DC924B9E0562D822E3E68F3 /* Pods */ = { - isa = PBXGroup; - children = ( - 61D649CA05E938083C88FC6D /* Pods-fiam-external-ios-testing-app.debug.xcconfig */, - EE0B5FD5B23F372E4894C799 /* Pods-fiam-external-ios-testing-app.release.xcconfig */, - ); - name = Pods; - sourceTree = ""; - }; - AD7649B91FE1B0A800378AE0 = { - isa = PBXGroup; - children = ( - AD7649C41FE1B0A800378AE0 /* fiam-external-ios-testing-app */, - AD7649C31FE1B0A800378AE0 /* Products */, - 4DC924B9E0562D822E3E68F3 /* Pods */, - 2F924E232047E700385C2AFA /* Frameworks */, - ); - sourceTree = ""; - }; - AD7649C31FE1B0A800378AE0 /* Products */ = { - isa = PBXGroup; - children = ( - AD7649C21FE1B0A800378AE0 /* fiam-external-ios-testing-app.app */, - ); - name = Products; - sourceTree = ""; - }; - AD7649C41FE1B0A800378AE0 /* fiam-external-ios-testing-app */ = { - isa = PBXGroup; - children = ( - AD7649DB1FE1B57A00378AE0 /* GoogleService-Info.plist */, - AD7649C51FE1B0A800378AE0 /* AppDelegate.h */, - AD7649C61FE1B0A800378AE0 /* AppDelegate.m */, - AD7649C81FE1B0A800378AE0 /* ViewController.h */, - AD7649C91FE1B0A800378AE0 /* ViewController.m */, - AD7649CB1FE1B0A800378AE0 /* Main.storyboard */, - AD7649CE1FE1B0A800378AE0 /* Assets.xcassets */, - AD7649D01FE1B0A800378AE0 /* LaunchScreen.storyboard */, - AD7649D31FE1B0A800378AE0 /* Info.plist */, - AD7649D41FE1B0A800378AE0 /* main.m */, - ); - path = "fiam-external-ios-testing-app"; - sourceTree = ""; - }; -/* End PBXGroup section */ - -/* Begin PBXNativeTarget section */ - AD7649C11FE1B0A800378AE0 /* fiam-external-ios-testing-app */ = { - isa = PBXNativeTarget; - buildConfigurationList = AD7649D81FE1B0A800378AE0 /* Build configuration list for PBXNativeTarget "fiam-external-ios-testing-app" */; - buildPhases = ( - 89F39EB5CA1632B8B86E938F /* [CP] Check Pods Manifest.lock */, - AD7649BE1FE1B0A800378AE0 /* Sources */, - AD7649BF1FE1B0A800378AE0 /* Frameworks */, - AD7649C01FE1B0A800378AE0 /* Resources */, - AF2C898A9A08823BD10E1650 /* [CP] Embed Pods Frameworks */, - 638CE7E9369C7DEB067D82E7 /* [CP] Copy Pods Resources */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = "fiam-external-ios-testing-app"; - productName = "fiam-external-ios-testing-app"; - productReference = AD7649C21FE1B0A800378AE0 /* fiam-external-ios-testing-app.app */; - productType = "com.apple.product-type.application"; - }; -/* End PBXNativeTarget section */ - -/* Begin PBXProject section */ - AD7649BA1FE1B0A800378AE0 /* Project object */ = { - isa = PBXProject; - attributes = { - LastUpgradeCheck = 0910; - ORGANIZATIONNAME = "Yong Mao"; - TargetAttributes = { - AD7649C11FE1B0A800378AE0 = { - CreatedOnToolsVersion = 9.1; - ProvisioningStyle = Automatic; - }; - }; - }; - buildConfigurationList = AD7649BD1FE1B0A800378AE0 /* Build configuration list for PBXProject "fiam-external-ios-testing-app" */; - compatibilityVersion = "Xcode 8.0"; - developmentRegion = en; - hasScannedForEncodings = 0; - knownRegions = ( - en, - Base, - ); - mainGroup = AD7649B91FE1B0A800378AE0; - productRefGroup = AD7649C31FE1B0A800378AE0 /* Products */; - projectDirPath = ""; - projectRoot = ""; - targets = ( - AD7649C11FE1B0A800378AE0 /* fiam-external-ios-testing-app */, - ); - }; -/* End PBXProject section */ - -/* Begin PBXResourcesBuildPhase section */ - AD7649C01FE1B0A800378AE0 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - AD7649D21FE1B0A800378AE0 /* LaunchScreen.storyboard in Resources */, - AD7649DC1FE1B57A00378AE0 /* GoogleService-Info.plist in Resources */, - AD7649CF1FE1B0A800378AE0 /* Assets.xcassets in Resources */, - AD7649CD1FE1B0A800378AE0 /* Main.storyboard in Resources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXResourcesBuildPhase section */ - -/* Begin PBXShellScriptBuildPhase section */ - 638CE7E9369C7DEB067D82E7 /* [CP] Copy Pods Resources */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - "${SRCROOT}/Pods/Target Support Files/Pods-fiam-external-ios-testing-app/Pods-fiam-external-ios-testing-app-resources.sh", - "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseInAppMessagingDisplay/InAppMessagingDisplayResources.bundle", - ); - name = "[CP] Copy Pods Resources"; - outputPaths = ( - "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/InAppMessagingDisplayResources.bundle", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-fiam-external-ios-testing-app/Pods-fiam-external-ios-testing-app-resources.sh\"\n"; - showEnvVarsInLog = 0; - }; - 89F39EB5CA1632B8B86E938F /* [CP] Check Pods Manifest.lock */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - "${PODS_PODFILE_DIR_PATH}/Podfile.lock", - "${PODS_ROOT}/Manifest.lock", - ); - name = "[CP] Check Pods Manifest.lock"; - outputPaths = ( - "$(DERIVED_FILE_DIR)/Pods-fiam-external-ios-testing-app-checkManifestLockResult.txt", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; - showEnvVarsInLog = 0; - }; - AF2C898A9A08823BD10E1650 /* [CP] Embed Pods Frameworks */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - "${SRCROOT}/Pods/Target Support Files/Pods-fiam-external-ios-testing-app/Pods-fiam-external-ios-testing-app-frameworks.sh", - "${BUILT_PRODUCTS_DIR}/GoogleUtilities/GoogleUtilities.framework", - "${BUILT_PRODUCTS_DIR}/nanopb/nanopb.framework", - ); - name = "[CP] Embed Pods Frameworks"; - outputPaths = ( - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/GoogleUtilities.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/nanopb.framework", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-fiam-external-ios-testing-app/Pods-fiam-external-ios-testing-app-frameworks.sh\"\n"; - showEnvVarsInLog = 0; - }; -/* End PBXShellScriptBuildPhase section */ - -/* Begin PBXSourcesBuildPhase section */ - AD7649BE1FE1B0A800378AE0 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - AD7649CA1FE1B0A800378AE0 /* ViewController.m in Sources */, - AD7649D51FE1B0A800378AE0 /* main.m in Sources */, - AD7649C71FE1B0A800378AE0 /* AppDelegate.m in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXSourcesBuildPhase section */ - -/* Begin PBXVariantGroup section */ - AD7649CB1FE1B0A800378AE0 /* Main.storyboard */ = { - isa = PBXVariantGroup; - children = ( - AD7649CC1FE1B0A800378AE0 /* Base */, - ); - name = Main.storyboard; - sourceTree = ""; - }; - AD7649D01FE1B0A800378AE0 /* LaunchScreen.storyboard */ = { - isa = PBXVariantGroup; - children = ( - AD7649D11FE1B0A800378AE0 /* Base */, - ); - name = LaunchScreen.storyboard; - sourceTree = ""; - }; -/* End PBXVariantGroup section */ - -/* Begin XCBuildConfiguration section */ - AD7649D61FE1B0A800378AE0 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_NONNULL = YES; - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - CODE_SIGN_IDENTITY = "iPhone Developer"; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = dwarf; - ENABLE_STRICT_OBJC_MSGSEND = YES; - ENABLE_TESTABILITY = YES; - GCC_C_LANGUAGE_STANDARD = gnu11; - GCC_DYNAMIC_NO_PIC = NO; - GCC_NO_COMMON_BLOCKS = YES; - GCC_OPTIMIZATION_LEVEL = 0; - GCC_PREPROCESSOR_DEFINITIONS = ( - "DEBUG=1", - "$(inherited)", - ); - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 11.1; - MTL_ENABLE_DEBUG_INFO = YES; - ONLY_ACTIVE_ARCH = YES; - SDKROOT = iphoneos; - }; - name = Debug; - }; - AD7649D71FE1B0A800378AE0 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_NONNULL = YES; - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - CODE_SIGN_IDENTITY = "iPhone Developer"; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - ENABLE_NS_ASSERTIONS = NO; - ENABLE_STRICT_OBJC_MSGSEND = YES; - GCC_C_LANGUAGE_STANDARD = gnu11; - GCC_NO_COMMON_BLOCKS = YES; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 11.1; - MTL_ENABLE_DEBUG_INFO = NO; - SDKROOT = iphoneos; - VALIDATE_PRODUCT = YES; - }; - name = Release; - }; - AD7649D91FE1B0A800378AE0 /* Debug */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 61D649CA05E938083C88FC6D /* Pods-fiam-external-ios-testing-app.debug.xcconfig */; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CODE_SIGN_STYLE = Automatic; - DEVELOPMENT_TEAM = EQHXZ8M8AV; - INFOPLIST_FILE = "fiam-external-ios-testing-app/Info.plist"; - IPHONEOS_DEPLOYMENT_TARGET = 11.0; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = "com.google.fiam-external-ios-testing"; - PRODUCT_NAME = "$(TARGET_NAME)"; - TARGETED_DEVICE_FAMILY = "1,2"; - }; - name = Debug; - }; - AD7649DA1FE1B0A800378AE0 /* Release */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = EE0B5FD5B23F372E4894C799 /* Pods-fiam-external-ios-testing-app.release.xcconfig */; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CODE_SIGN_STYLE = Automatic; - DEVELOPMENT_TEAM = EQHXZ8M8AV; - INFOPLIST_FILE = "fiam-external-ios-testing-app/Info.plist"; - IPHONEOS_DEPLOYMENT_TARGET = 11.0; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = "com.google.fiam-external-ios-testing"; - PRODUCT_NAME = "$(TARGET_NAME)"; - TARGETED_DEVICE_FAMILY = "1,2"; - }; - name = Release; - }; -/* End XCBuildConfiguration section */ - -/* Begin XCConfigurationList section */ - AD7649BD1FE1B0A800378AE0 /* Build configuration list for PBXProject "fiam-external-ios-testing-app" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - AD7649D61FE1B0A800378AE0 /* Debug */, - AD7649D71FE1B0A800378AE0 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - AD7649D81FE1B0A800378AE0 /* Build configuration list for PBXNativeTarget "fiam-external-ios-testing-app" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - AD7649D91FE1B0A800378AE0 /* Debug */, - AD7649DA1FE1B0A800378AE0 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; -/* End XCConfigurationList section */ - }; - rootObject = AD7649BA1FE1B0A800378AE0 /* Project object */; -} diff --git a/FirebaseInAppMessaging/Tests/Integration/FunctionalTestApp/ExternalAppExample/fiam-external-ios-testing-app/fiam-external-ios-testing-app/AppDelegate.h b/FirebaseInAppMessaging/Tests/Integration/FunctionalTestApp/ExternalAppExample/fiam-external-ios-testing-app/fiam-external-ios-testing-app/AppDelegate.h deleted file mode 100644 index 013891c90b6..00000000000 --- a/FirebaseInAppMessaging/Tests/Integration/FunctionalTestApp/ExternalAppExample/fiam-external-ios-testing-app/fiam-external-ios-testing-app/AppDelegate.h +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright 2017 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 - -@interface AppDelegate : UIResponder - -@property(strong, nonatomic) UIWindow *window; - -@end diff --git a/FirebaseInAppMessaging/Tests/Integration/FunctionalTestApp/ExternalAppExample/fiam-external-ios-testing-app/fiam-external-ios-testing-app/AppDelegate.m b/FirebaseInAppMessaging/Tests/Integration/FunctionalTestApp/ExternalAppExample/fiam-external-ios-testing-app/fiam-external-ios-testing-app/AppDelegate.m deleted file mode 100644 index dfd8cd7b450..00000000000 --- a/FirebaseInAppMessaging/Tests/Integration/FunctionalTestApp/ExternalAppExample/fiam-external-ios-testing-app/fiam-external-ios-testing-app/AppDelegate.m +++ /dev/null @@ -1,70 +0,0 @@ -// Copyright 2017 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 "AppDelegate.h" - -#import - -@interface AppDelegate () - -@end - -@implementation AppDelegate - -- (BOOL)application:(UIApplication *)application - didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { - // Override point for customization after application launch. - // uncomment the following line for disabling the auto startup - // of the sdk - // [FIRInAppMessaging inAppMessaging].automaticDataCollectionEnabled = @NO; - - [FIROptions defaultOptions].deepLinkURLScheme = @"com.google.InAppMessagingExampleiOS"; - [FIRApp configure]; - return YES; -} - -- (BOOL)application:(UIApplication *)app - openURL:(NSURL *)url - options:(NSDictionary *)options { - NSLog(@"called here 1"); - return [self application:app - openURL:url - sourceApplication:options[UIApplicationOpenURLOptionsSourceApplicationKey] - annotation:options[UIApplicationOpenURLOptionsAnnotationKey]]; -} - -- (BOOL)application:(UIApplication *)application - openURL:(NSURL *)url - sourceApplication:(NSString *)sourceApplication - annotation:(id)annotation { - FIRDynamicLink *dynamicLink = [[FIRDynamicLinks dynamicLinks] dynamicLinkFromCustomSchemeURL:url]; - - NSLog(@"called here with %@", dynamicLink); - if (dynamicLink) { - if (dynamicLink.url) { - // Handle the deep link. For example, show the deep-linked content, - // apply a promotional offer to the user's account or show customized onboarding view. - // ... - - } else { - // Dynamic link has empty deep link. This situation will happens if - // Firebase Dynamic Links iOS SDK tried to retrieve pending dynamic link, - // but pending link is not available for this device/App combination. - // At this point you may display default onboarding view. - } - return YES; - } - return NO; -} -@end diff --git a/FirebaseInAppMessaging/Tests/Integration/FunctionalTestApp/ExternalAppExample/fiam-external-ios-testing-app/fiam-external-ios-testing-app/Assets.xcassets/AppIcon.appiconset/Contents.json b/FirebaseInAppMessaging/Tests/Integration/FunctionalTestApp/ExternalAppExample/fiam-external-ios-testing-app/fiam-external-ios-testing-app/Assets.xcassets/AppIcon.appiconset/Contents.json deleted file mode 100644 index 1d060ed2882..00000000000 --- a/FirebaseInAppMessaging/Tests/Integration/FunctionalTestApp/ExternalAppExample/fiam-external-ios-testing-app/fiam-external-ios-testing-app/Assets.xcassets/AppIcon.appiconset/Contents.json +++ /dev/null @@ -1,93 +0,0 @@ -{ - "images" : [ - { - "idiom" : "iphone", - "size" : "20x20", - "scale" : "2x" - }, - { - "idiom" : "iphone", - "size" : "20x20", - "scale" : "3x" - }, - { - "idiom" : "iphone", - "size" : "29x29", - "scale" : "2x" - }, - { - "idiom" : "iphone", - "size" : "29x29", - "scale" : "3x" - }, - { - "idiom" : "iphone", - "size" : "40x40", - "scale" : "2x" - }, - { - "idiom" : "iphone", - "size" : "40x40", - "scale" : "3x" - }, - { - "idiom" : "iphone", - "size" : "60x60", - "scale" : "2x" - }, - { - "idiom" : "iphone", - "size" : "60x60", - "scale" : "3x" - }, - { - "idiom" : "ipad", - "size" : "20x20", - "scale" : "1x" - }, - { - "idiom" : "ipad", - "size" : "20x20", - "scale" : "2x" - }, - { - "idiom" : "ipad", - "size" : "29x29", - "scale" : "1x" - }, - { - "idiom" : "ipad", - "size" : "29x29", - "scale" : "2x" - }, - { - "idiom" : "ipad", - "size" : "40x40", - "scale" : "1x" - }, - { - "idiom" : "ipad", - "size" : "40x40", - "scale" : "2x" - }, - { - "idiom" : "ipad", - "size" : "76x76", - "scale" : "1x" - }, - { - "idiom" : "ipad", - "size" : "76x76", - "scale" : "2x" - }, - { - "idiom" : "ipad", - "size" : "83.5x83.5", - "scale" : "2x" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - } -} \ No newline at end of file diff --git a/FirebaseInAppMessaging/Tests/Integration/FunctionalTestApp/ExternalAppExample/fiam-external-ios-testing-app/fiam-external-ios-testing-app/Base.lproj/LaunchScreen.storyboard b/FirebaseInAppMessaging/Tests/Integration/FunctionalTestApp/ExternalAppExample/fiam-external-ios-testing-app/fiam-external-ios-testing-app/Base.lproj/LaunchScreen.storyboard deleted file mode 100644 index acde84d5a56..00000000000 --- a/FirebaseInAppMessaging/Tests/Integration/FunctionalTestApp/ExternalAppExample/fiam-external-ios-testing-app/fiam-external-ios-testing-app/Base.lproj/LaunchScreen.storyboard +++ /dev/null @@ -1,31 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/FirebaseInAppMessaging/Tests/Integration/FunctionalTestApp/ExternalAppExample/fiam-external-ios-testing-app/fiam-external-ios-testing-app/Base.lproj/Main.storyboard b/FirebaseInAppMessaging/Tests/Integration/FunctionalTestApp/ExternalAppExample/fiam-external-ios-testing-app/fiam-external-ios-testing-app/Base.lproj/Main.storyboard deleted file mode 100644 index 67cb7ed4c58..00000000000 --- a/FirebaseInAppMessaging/Tests/Integration/FunctionalTestApp/ExternalAppExample/fiam-external-ios-testing-app/fiam-external-ios-testing-app/Base.lproj/Main.storyboard +++ /dev/null @@ -1,51 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/FirebaseInAppMessaging/Tests/Integration/FunctionalTestApp/ExternalAppExample/fiam-external-ios-testing-app/fiam-external-ios-testing-app/Info.plist b/FirebaseInAppMessaging/Tests/Integration/FunctionalTestApp/ExternalAppExample/fiam-external-ios-testing-app/fiam-external-ios-testing-app/Info.plist deleted file mode 100644 index 15f461a4e6a..00000000000 --- a/FirebaseInAppMessaging/Tests/Integration/FunctionalTestApp/ExternalAppExample/fiam-external-ios-testing-app/fiam-external-ios-testing-app/Info.plist +++ /dev/null @@ -1,60 +0,0 @@ - - - - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleDisplayName - fiam-external-ios-testing - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - APPL - CFBundleShortVersionString - 1.0 - CFBundleURLTypes - - - CFBundleTypeRole - Editor - CFBundleURLName - my-url - CFBundleURLSchemes - - com.google.InAppMessagingExampleiOS - - - - CFBundleVersion - 1 - LSRequiresIPhoneOS - - UILaunchStoryboardName - LaunchScreen - UIMainStoryboardFile - Main - UIRequiredDeviceCapabilities - - armv7 - - UISupportedInterfaceOrientations - - UIInterfaceOrientationPortrait - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - UISupportedInterfaceOrientations~ipad - - UIInterfaceOrientationPortrait - UIInterfaceOrientationPortraitUpsideDown - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - - diff --git a/FirebaseInAppMessaging/Tests/Integration/FunctionalTestApp/ExternalAppExample/fiam-external-ios-testing-app/fiam-external-ios-testing-app/ViewController.h b/FirebaseInAppMessaging/Tests/Integration/FunctionalTestApp/ExternalAppExample/fiam-external-ios-testing-app/fiam-external-ios-testing-app/ViewController.h deleted file mode 100644 index b6115b80707..00000000000 --- a/FirebaseInAppMessaging/Tests/Integration/FunctionalTestApp/ExternalAppExample/fiam-external-ios-testing-app/fiam-external-ios-testing-app/ViewController.h +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright 2017 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 - -@interface ViewController : UIViewController - -@end diff --git a/FirebaseInAppMessaging/Tests/Integration/FunctionalTestApp/ExternalAppExample/fiam-external-ios-testing-app/fiam-external-ios-testing-app/ViewController.m b/FirebaseInAppMessaging/Tests/Integration/FunctionalTestApp/ExternalAppExample/fiam-external-ios-testing-app/fiam-external-ios-testing-app/ViewController.m deleted file mode 100644 index 44335d8292b..00000000000 --- a/FirebaseInAppMessaging/Tests/Integration/FunctionalTestApp/ExternalAppExample/fiam-external-ios-testing-app/fiam-external-ios-testing-app/ViewController.m +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright 2017 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 "ViewController.h" - -#import - -@interface ViewController () -@property(weak, nonatomic) IBOutlet UITextField *urlText; - -@end - -@implementation ViewController -- (IBAction)triggerEvent:(id)sender { - [FIRAnalytics logEventWithName:self.urlText.text parameters:@{}]; -} - -- (void)viewDidLoad { - [super viewDidLoad]; - // Do any additional setup after loading the view, typically from a nib. -} - -- (void)didReceiveMemoryWarning { - [super didReceiveMemoryWarning]; - // Dispose of any resources that can be recreated. -} - -@end diff --git a/FirebaseInAppMessaging/Tests/Integration/FunctionalTestApp/ExternalAppExample/fiam-external-ios-testing-app/fiam-external-ios-testing-app/main.m b/FirebaseInAppMessaging/Tests/Integration/FunctionalTestApp/ExternalAppExample/fiam-external-ios-testing-app/fiam-external-ios-testing-app/main.m deleted file mode 100644 index 3b3b323ef02..00000000000 --- a/FirebaseInAppMessaging/Tests/Integration/FunctionalTestApp/ExternalAppExample/fiam-external-ios-testing-app/fiam-external-ios-testing-app/main.m +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright 2017 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 -#import "AppDelegate.h" - -int main(int argc, char* argv[]) { - @autoreleasepool { - return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); - } -} diff --git a/FirebaseInAppMessaging/Tests/Integration/FunctionalTestApp/Podfile b/FirebaseInAppMessaging/Tests/Integration/FunctionalTestApp/Podfile index 50db2923845..8d78252504b 100644 --- a/FirebaseInAppMessaging/Tests/Integration/FunctionalTestApp/Podfile +++ b/FirebaseInAppMessaging/Tests/Integration/FunctionalTestApp/Podfile @@ -13,6 +13,5 @@ target 'InAppMessaging_Example_iOS' do platform :ios, '13.0' pod 'FirebaseInAppMessaging', :path => '../../../..' - pod 'FirebaseDynamicLinks', :path => '../../../..' end From 01a7794e082013717839ddead71b62adc39993ed Mon Sep 17 00:00:00 2001 From: Nick Cooke <36927374+ncooke3@users.noreply.github.com> Date: Tue, 17 Jun 2025 23:25:27 -0400 Subject: [PATCH 089/113] [Core] Deprecate '-[FIROptions deepLinkURLScheme]' API (#15001) --- FirebaseCore/Sources/FIROptions.m | 8 ++++---- FirebaseCore/Sources/Public/FirebaseCore/FIROptions.h | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/FirebaseCore/Sources/FIROptions.m b/FirebaseCore/Sources/FIROptions.m index bfaeff1620e..16fdb6f41bc 100644 --- a/FirebaseCore/Sources/FIROptions.m +++ b/FirebaseCore/Sources/FIROptions.m @@ -160,7 +160,7 @@ - (id)copyWithZone:(NSZone *)zone { FIROptions *newOptions = [(FIROptions *)[[self class] allocWithZone:zone] initInternalWithOptionsDictionary:self.optionsDictionary]; if (newOptions) { - newOptions.deepLinkURLScheme = self.deepLinkURLScheme; + newOptions->_deepLinkURLScheme = self->_deepLinkURLScheme; newOptions.appGroupID = self.appGroupID; newOptions.editingLocked = self.isEditingLocked; newOptions.usingOptionsFromDefaultPlist = self.usingOptionsFromDefaultPlist; @@ -357,8 +357,8 @@ - (BOOL)isEqualToOptions:(FIROptions *)options { // Validate extra properties not contained in the dictionary. Only validate it if one of the // objects has the property set. - if ((options.deepLinkURLScheme != nil || self.deepLinkURLScheme != nil) && - ![options.deepLinkURLScheme isEqualToString:self.deepLinkURLScheme]) { + if ((options->_deepLinkURLScheme != nil || self->_deepLinkURLScheme != nil) && + ![options->_deepLinkURLScheme isEqualToString:self->_deepLinkURLScheme]) { return NO; } @@ -384,7 +384,7 @@ - (NSUInteger)hash { // Note: `self.analyticsOptionsDictionary` was left out here since it solely relies on the // contents of the main bundle's `Info.plist`. We should avoid reading that file and the contents // should be identical. - return self.optionsDictionary.hash ^ self.deepLinkURLScheme.hash ^ self.appGroupID.hash; + return self.optionsDictionary.hash ^ self->_deepLinkURLScheme.hash ^ self.appGroupID.hash; } #pragma mark - Internal instance methods diff --git a/FirebaseCore/Sources/Public/FirebaseCore/FIROptions.h b/FirebaseCore/Sources/Public/FirebaseCore/FIROptions.h index 14e60fcde33..db1570a083c 100644 --- a/FirebaseCore/Sources/Public/FirebaseCore/FIROptions.h +++ b/FirebaseCore/Sources/Public/FirebaseCore/FIROptions.h @@ -83,7 +83,7 @@ NS_SWIFT_NAME(FirebaseOptions) /** * The URL scheme used to set up Durable Deep Link service. */ -@property(nonatomic, copy, nullable) NSString *deepLinkURLScheme; +@property(nonatomic, copy, nullable) NSString *deepLinkURLScheme DEPRECATED_ATTRIBUTE; /** * The Google Cloud Storage bucket name, e.g. @"abc-xyz-123.storage.firebase.com". From 0d4728b0108697ac512954ae4c7c7e86c3c8261e Mon Sep 17 00:00:00 2001 From: Nick Cooke <36927374+ncooke3@users.noreply.github.com> Date: Tue, 17 Jun 2025 23:35:20 -0400 Subject: [PATCH 090/113] [Infra] Update CHANGELOG.md for `Options.deepLinkURLScheme` deprecation (#15002) --- FirebaseCore/CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/FirebaseCore/CHANGELOG.md b/FirebaseCore/CHANGELOG.md index 200a2c2e01b..a63dc94fc7d 100644 --- a/FirebaseCore/CHANGELOG.md +++ b/FirebaseCore/CHANGELOG.md @@ -1,5 +1,9 @@ # Firebase 11.15.0 - [fixed] Remove c99 as the required C language standard. (#14950) +- [deprecated] Deprecated the `Options.deepLinkURLScheme` property. This + property will be removed in a future release. This is related to the + overall Firebase Dynamic Links deprecation. For more details, see + the [Dynamic Links deprecation FAQ](https://firebase.google.com/support/dynamic-links-faq). # Firebase 11.12.0 - [changed] Firebase now requires at least Xcode 16.2. See From a00029bb70a7dbf7cfa25fe091972a9ca9984025 Mon Sep 17 00:00:00 2001 From: Nick Cooke <36927374+ncooke3@users.noreply.github.com> Date: Wed, 18 Jun 2025 10:17:48 -0400 Subject: [PATCH 091/113] [Core] Remove testing usage of Options.deepLinkURLScheme (#15004) --- .../Tests/SwiftUnit/CoreAPITests.swift | 4 -- .../Tests/SwiftUnit/FirebaseAppTests.swift | 5 --- .../SwiftUnit/FirebaseOptionsTests.swift | 12 ------ .../SwiftTestingUtilities/Constants.swift | 1 - FirebaseCore/Tests/Unit/FIRAppTest.m | 2 - FirebaseCore/Tests/Unit/FIROptionsTest.m | 41 ------------------- 6 files changed, 65 deletions(-) diff --git a/FirebaseCore/Tests/SwiftUnit/CoreAPITests.swift b/FirebaseCore/Tests/SwiftUnit/CoreAPITests.swift index 8a0e1445263..8ac8e5960be 100644 --- a/FirebaseCore/Tests/SwiftUnit/CoreAPITests.swift +++ b/FirebaseCore/Tests/SwiftUnit/CoreAPITests.swift @@ -129,10 +129,6 @@ final class CoreAPITests { // ... } - if let _ /* deepLinkURLScheme */ = options.deepLinkURLScheme { - // ... - } - if let _ /* storageBucket */ = options.storageBucket { // ... } diff --git a/FirebaseCore/Tests/SwiftUnit/FirebaseAppTests.swift b/FirebaseCore/Tests/SwiftUnit/FirebaseAppTests.swift index c6f82725675..3c301c92edd 100644 --- a/FirebaseCore/Tests/SwiftUnit/FirebaseAppTests.swift +++ b/FirebaseCore/Tests/SwiftUnit/FirebaseAppTests.swift @@ -144,7 +144,6 @@ class FirebaseAppTests: XCTestCase { func testConfigureMultipleApps() throws { let options1 = FirebaseOptions(googleAppID: Constants.Options.googleAppID, gcmSenderID: Constants.Options.gcmSenderID) - options1.deepLinkURLScheme = Constants.Options.deepLinkURLScheme expectAppConfigurationNotification(appName: Constants.testAppName1, isDefaultApp: false) @@ -154,7 +153,6 @@ class FirebaseAppTests: XCTestCase { XCTAssertEqual(app1.name, Constants.testAppName1) XCTAssertEqual(app1.options.googleAppID, Constants.Options.googleAppID) XCTAssertEqual(app1.options.gcmSenderID, Constants.Options.gcmSenderID) - XCTAssertEqual(app1.options.deepLinkURLScheme, Constants.Options.deepLinkURLScheme) XCTAssertTrue(FirebaseApp.allApps?.count == 1) // Configure a different app with valid customized options. @@ -288,8 +286,6 @@ class FirebaseAppTests: XCTestCase { let options = FirebaseOptions(googleAppID: Constants.Options.googleAppID, gcmSenderID: Constants.Options.gcmSenderID) - let superSecretURLScheme = "com.supersecret.googledeeplinkurl" - options.deepLinkURLScheme = superSecretURLScheme FirebaseApp.configure(name: Constants.testAppName1, options: options) let app = try XCTUnwrap( @@ -299,7 +295,6 @@ class FirebaseAppTests: XCTestCase { XCTAssertEqual(app.name, Constants.testAppName1) XCTAssertEqual(app.options.googleAppID, Constants.Options.googleAppID) XCTAssertEqual(app.options.gcmSenderID, Constants.Options.gcmSenderID) - XCTAssertEqual(app.options.deepLinkURLScheme, superSecretURLScheme) } func testFirebaseDataCollectionDefaultEnabled() throws { diff --git a/FirebaseCore/Tests/SwiftUnit/FirebaseOptionsTests.swift b/FirebaseCore/Tests/SwiftUnit/FirebaseOptionsTests.swift index 1de4a86d090..0fa369a8c36 100644 --- a/FirebaseCore/Tests/SwiftUnit/FirebaseOptionsTests.swift +++ b/FirebaseCore/Tests/SwiftUnit/FirebaseOptionsTests.swift @@ -91,10 +91,6 @@ class FirebaseOptionsTests: XCTestCase { options.googleAppID = newGoogleAppID XCTAssertEqual(options.googleAppID, newGoogleAppID) - XCTAssertNil(options.deepLinkURLScheme) - options.deepLinkURLScheme = Constants.Options.deepLinkURLScheme - XCTAssertEqual(options.deepLinkURLScheme, Constants.Options.deepLinkURLScheme) - XCTAssertNil(options.appGroupID) options.appGroupID = Constants.Options.appGroupID XCTAssertEqual(options.appGroupID, Constants.Options.appGroupID) @@ -110,12 +106,6 @@ class FirebaseOptionsTests: XCTestCase { XCTAssertEqual(options.apiKey, apiKey) apiKey = "000000000" XCTAssertNotEqual(options.apiKey, apiKey) - - var deepLinkURLScheme = "comdeeplinkurl" - options.deepLinkURLScheme = deepLinkURLScheme - XCTAssertEqual(options.deepLinkURLScheme, deepLinkURLScheme) - deepLinkURLScheme = "comlinkurl" - XCTAssertNotEqual(options.deepLinkURLScheme, deepLinkURLScheme) } func testOptionsEquality() throws { @@ -146,7 +136,6 @@ class FirebaseOptionsTests: XCTestCase { XCTAssertEqual(options.projectID, Constants.Options.projectID) XCTAssertEqual(options.googleAppID, Constants.Options.googleAppID) XCTAssertEqual(options.databaseURL, Constants.Options.databaseURL) - XCTAssertNil(options.deepLinkURLScheme) XCTAssertEqual(options.storageBucket, Constants.Options.storageBucket) XCTAssertNil(options.appGroupID) } @@ -156,7 +145,6 @@ class FirebaseOptionsTests: XCTestCase { XCTAssertNil(options.clientID) XCTAssertNil(options.projectID) XCTAssertNil(options.databaseURL) - XCTAssertNil(options.deepLinkURLScheme) XCTAssertNil(options.storageBucket) XCTAssertNil(options.appGroupID) } diff --git a/FirebaseCore/Tests/SwiftUnit/SwiftTestingUtilities/Constants.swift b/FirebaseCore/Tests/SwiftUnit/SwiftTestingUtilities/Constants.swift index cf6e5bf6530..fa9ff52c62f 100644 --- a/FirebaseCore/Tests/SwiftUnit/SwiftTestingUtilities/Constants.swift +++ b/FirebaseCore/Tests/SwiftUnit/SwiftTestingUtilities/Constants.swift @@ -28,7 +28,6 @@ public enum Constants { static let projectID = "abc-xyz-123" static let googleAppID = "1:123:ios:123abc" static let databaseURL = "https://abc-xyz-123.firebaseio.com" - static let deepLinkURLScheme = "comgoogledeeplinkurl" static let storageBucket = "project-id-123.storage.firebase.com" static let appGroupID: String? = nil } diff --git a/FirebaseCore/Tests/Unit/FIRAppTest.m b/FirebaseCore/Tests/Unit/FIRAppTest.m index 0bba5dceba1..6a0bb47035d 100644 --- a/FirebaseCore/Tests/Unit/FIRAppTest.m +++ b/FirebaseCore/Tests/Unit/FIRAppTest.m @@ -222,8 +222,6 @@ - (void)testConfigureWithNameAndOptions { - (void)testConfigureWithMultipleApps { FIROptions *options1 = [[FIROptions alloc] initWithGoogleAppID:kGoogleAppID GCMSenderID:kGCMSenderID]; - options1.deepLinkURLScheme = kDeepLinkURLScheme; - NSDictionary *expectedUserInfo1 = [self expectedUserInfoWithAppName:kFIRTestAppName1 isDefaultApp:NO]; XCTestExpectation *configExpectation1 = diff --git a/FirebaseCore/Tests/Unit/FIROptionsTest.m b/FirebaseCore/Tests/Unit/FIROptionsTest.m index 3f228c83fad..d4898c224ab 100644 --- a/FirebaseCore/Tests/Unit/FIROptionsTest.m +++ b/FirebaseCore/Tests/Unit/FIROptionsTest.m @@ -48,11 +48,7 @@ - (void)testInit { NSDictionary *optionsDictionary = [FIROptions defaultOptionsDictionary]; FIROptions *options = [[FIROptions alloc] initInternalWithOptionsDictionary:optionsDictionary]; [self assertOptionsMatchDefaults:options andProjectID:YES]; - XCTAssertNil(options.deepLinkURLScheme); XCTAssertTrue(options.usingOptionsFromDefaultPlist); - - options.deepLinkURLScheme = kDeepLinkURLScheme; - XCTAssertEqualObjects(options.deepLinkURLScheme, kDeepLinkURLScheme); } - (void)testDefaultOptionsDictionaryWithNilFilePath { @@ -77,11 +73,7 @@ - (void)testDefaultOptions { [FIROptionsMock mockFIROptions]; FIROptions *options = [FIROptions defaultOptions]; [self assertOptionsMatchDefaults:options andProjectID:YES]; - XCTAssertNil(options.deepLinkURLScheme); XCTAssertTrue(options.usingOptionsFromDefaultPlist); - - options.deepLinkURLScheme = kDeepLinkURLScheme; - XCTAssertEqualObjects(options.deepLinkURLScheme, kDeepLinkURLScheme); } #ifndef SWIFT_PACKAGE @@ -124,7 +116,6 @@ - (void)testInitWithContentsOfFile { NSString *filePath = [self validGoogleServicesInfoPlistPath]; FIROptions *options = [[FIROptions alloc] initWithContentsOfFile:filePath]; [self assertOptionsMatchDefaults:options andProjectID:YES]; - XCTAssertNil(options.deepLinkURLScheme); XCTAssertFalse(options.usingOptionsFromDefaultPlist); #pragma clang diagnostic push @@ -145,11 +136,9 @@ - (void)testInitCustomizedOptions { options.bundleID = kBundleID; options.clientID = kClientID; options.databaseURL = kDatabaseURL; - options.deepLinkURLScheme = kDeepLinkURLScheme; options.projectID = kProjectID; options.storageBucket = kStorageBucket; [self assertOptionsMatchDefaults:options andProjectID:YES]; - XCTAssertEqualObjects(options.deepLinkURLScheme, kDeepLinkURLScheme); XCTAssertFalse(options.usingOptionsFromDefaultPlist); } @@ -209,11 +198,6 @@ - (void)testCopyingProperties { [mutableString appendString:@"2"]; XCTAssertEqualObjects(options.databaseURL, @"1"); - mutableString = [[NSMutableString alloc] initWithString:@"1"]; - options.deepLinkURLScheme = mutableString; - [mutableString appendString:@"2"]; - XCTAssertEqualObjects(options.deepLinkURLScheme, @"1"); - mutableString = [[NSMutableString alloc] initWithString:@"1"]; options.storageBucket = mutableString; [mutableString appendString:@"2"]; @@ -225,30 +209,6 @@ - (void)testCopyingProperties { XCTAssertEqualObjects(options.appGroupID, @"1"); } -- (void)testCopyWithZone { - [FIROptionsMock mockFIROptions]; - // default options - FIROptions *options = [FIROptions defaultOptions]; - options.deepLinkURLScheme = kDeepLinkURLScheme; - XCTAssertEqualObjects(options.deepLinkURLScheme, kDeepLinkURLScheme); - - FIROptions *newOptions = [options copy]; - XCTAssertEqualObjects(newOptions.deepLinkURLScheme, kDeepLinkURLScheme); - - [options setDeepLinkURLScheme:kNewDeepLinkURLScheme]; - XCTAssertEqualObjects(options.deepLinkURLScheme, kNewDeepLinkURLScheme); - XCTAssertEqualObjects(newOptions.deepLinkURLScheme, kDeepLinkURLScheme); - - // customized options - FIROptions *customizedOptions = [[FIROptions alloc] initWithGoogleAppID:kGoogleAppID - GCMSenderID:kGCMSenderID]; - customizedOptions.deepLinkURLScheme = kDeepLinkURLScheme; - FIROptions *copyCustomizedOptions = [customizedOptions copy]; - [copyCustomizedOptions setDeepLinkURLScheme:kNewDeepLinkURLScheme]; - XCTAssertEqualObjects(customizedOptions.deepLinkURLScheme, kDeepLinkURLScheme); - XCTAssertEqualObjects(copyCustomizedOptions.deepLinkURLScheme, kNewDeepLinkURLScheme); -} - - (void)testAnalyticsConstants { // The keys are public values and should never change. XCTAssertEqualObjects(kFIRIsMeasurementEnabled, @"IS_MEASUREMENT_ENABLED"); @@ -588,7 +548,6 @@ - (void)testModifyingOptionsThrows { XCTAssertThrows(options.bundleID = @"should_throw"); XCTAssertThrows(options.clientID = @"should_throw"); XCTAssertThrows(options.databaseURL = @"should_throw"); - XCTAssertThrows(options.deepLinkURLScheme = @"should_throw"); XCTAssertThrows(options.GCMSenderID = @"should_throw"); XCTAssertThrows(options.googleAppID = @"should_throw"); XCTAssertThrows(options.projectID = @"should_throw"); From 3027569e062ba5012b54f2b11b572302630fe130 Mon Sep 17 00:00:00 2001 From: Andrew Heard Date: Thu, 19 Jun 2025 08:46:16 -0400 Subject: [PATCH 092/113] [Firebase AI] Update models used in integration tests (#15007) --- .../Tests/TestApp/Sources/Constants.swift | 6 ++--- .../GenerateContentIntegrationTests.swift | 23 ++++++++++--------- 2 files changed, 15 insertions(+), 14 deletions(-) diff --git a/FirebaseAI/Tests/TestApp/Sources/Constants.swift b/FirebaseAI/Tests/TestApp/Sources/Constants.swift index 71305646ab3..ef7d9e7c061 100644 --- a/FirebaseAI/Tests/TestApp/Sources/Constants.swift +++ b/FirebaseAI/Tests/TestApp/Sources/Constants.swift @@ -23,8 +23,8 @@ public enum FirebaseAppNames { public enum ModelNames { public static let gemini2Flash = "gemini-2.0-flash-001" public static let gemini2FlashLite = "gemini-2.0-flash-lite-001" - public static let gemini2FlashExperimental = "gemini-2.0-flash-exp" - public static let gemini2_5_FlashPreview = "gemini-2.5-flash-preview-05-20" - public static let gemini2_5_ProPreview = "gemini-2.5-pro-preview-06-05" + public static let gemini2FlashPreviewImageGeneration = "gemini-2.0-flash-preview-image-generation" + public static let gemini2_5_Flash = "gemini-2.5-flash" + public static let gemini2_5_Pro = "gemini-2.5-pro" public static let gemma3_4B = "gemma-3-4b-it" } diff --git a/FirebaseAI/Tests/TestApp/Tests/Integration/GenerateContentIntegrationTests.swift b/FirebaseAI/Tests/TestApp/Tests/Integration/GenerateContentIntegrationTests.swift index 17854c3ab22..5a63ca41a6d 100644 --- a/FirebaseAI/Tests/TestApp/Tests/Integration/GenerateContentIntegrationTests.swift +++ b/FirebaseAI/Tests/TestApp/Tests/Integration/GenerateContentIntegrationTests.swift @@ -135,16 +135,16 @@ struct GenerateContentIntegrationTests { } @Test(arguments: [ - (InstanceConfig.vertexAI_v1beta, ModelNames.gemini2_5_FlashPreview, 0), - (InstanceConfig.vertexAI_v1beta, ModelNames.gemini2_5_FlashPreview, 24576), - (InstanceConfig.vertexAI_v1beta_global, ModelNames.gemini2_5_ProPreview, 128), - (InstanceConfig.vertexAI_v1beta_global, ModelNames.gemini2_5_ProPreview, 32768), - (InstanceConfig.googleAI_v1beta, ModelNames.gemini2_5_FlashPreview, 0), - (InstanceConfig.googleAI_v1beta, ModelNames.gemini2_5_FlashPreview, 24576), - (InstanceConfig.googleAI_v1beta, ModelNames.gemini2_5_ProPreview, 128), - (InstanceConfig.googleAI_v1beta, ModelNames.gemini2_5_ProPreview, 32768), - (InstanceConfig.googleAI_v1beta_freeTier, ModelNames.gemini2_5_FlashPreview, 0), - (InstanceConfig.googleAI_v1beta_freeTier, ModelNames.gemini2_5_FlashPreview, 24576), + (InstanceConfig.vertexAI_v1beta, ModelNames.gemini2_5_Flash, 0), + (InstanceConfig.vertexAI_v1beta, ModelNames.gemini2_5_Flash, 24576), + (InstanceConfig.vertexAI_v1beta_global, ModelNames.gemini2_5_Pro, 128), + (InstanceConfig.vertexAI_v1beta_global, ModelNames.gemini2_5_Pro, 32768), + (InstanceConfig.googleAI_v1beta, ModelNames.gemini2_5_Flash, 0), + (InstanceConfig.googleAI_v1beta, ModelNames.gemini2_5_Flash, 24576), + (InstanceConfig.googleAI_v1beta, ModelNames.gemini2_5_Pro, 128), + (InstanceConfig.googleAI_v1beta, ModelNames.gemini2_5_Pro, 32768), + (InstanceConfig.googleAI_v1beta_freeTier, ModelNames.gemini2_5_Flash, 0), + (InstanceConfig.googleAI_v1beta_freeTier, ModelNames.gemini2_5_Flash, 24576), ]) func generateContentThinking(_ config: InstanceConfig, modelName: String, thinkingBudget: Int) async throws { @@ -197,6 +197,7 @@ struct GenerateContentIntegrationTests { @Test(arguments: [ InstanceConfig.vertexAI_v1beta, + InstanceConfig.vertexAI_v1beta_global, InstanceConfig.googleAI_v1beta, InstanceConfig.googleAI_v1beta_staging, InstanceConfig.googleAI_v1beta_freeTier_bypassProxy, @@ -209,7 +210,7 @@ struct GenerateContentIntegrationTests { responseModalities: [.text, .image] ) let model = FirebaseAI.componentInstance(config).generativeModel( - modelName: ModelNames.gemini2FlashExperimental, + modelName: ModelNames.gemini2FlashPreviewImageGeneration, generationConfig: generationConfig, safetySettings: safetySettings ) From e05b2382312bf2479e1427898bd44684d775210d Mon Sep 17 00:00:00 2001 From: Nick Cooke <36927374+ncooke3@users.noreply.github.com> Date: Fri, 20 Jun 2025 11:40:46 -0400 Subject: [PATCH 093/113] [Core] Remove Options.deepLinkURLScheme (#15006) --- FirebaseCore/CHANGELOG.md | 5 +++++ FirebaseCore/Sources/FIROptions.m | 13 +------------ .../Sources/Public/FirebaseCore/FIROptions.h | 5 ----- .../App/InAppMessaging-Example-iOS/AppDelegate.m | 1 - SharedTestUtilities/FIROptionsMock.h | 3 --- SharedTestUtilities/FIROptionsMock.m | 3 --- docs/FirebaseOptionsPerProduct.md | 6 +----- 7 files changed, 7 insertions(+), 29 deletions(-) diff --git a/FirebaseCore/CHANGELOG.md b/FirebaseCore/CHANGELOG.md index a63dc94fc7d..96eebc5e656 100644 --- a/FirebaseCore/CHANGELOG.md +++ b/FirebaseCore/CHANGELOG.md @@ -1,3 +1,8 @@ +# Unreleased +- [removed] **Breaking change**: Removed the `Options.deepLinkURLScheme` + property. This API was exclusively used by the Dynamic Links SDK, which + has been removed. + # Firebase 11.15.0 - [fixed] Remove c99 as the required C language standard. (#14950) - [deprecated] Deprecated the `Options.deepLinkURLScheme` property. This diff --git a/FirebaseCore/Sources/FIROptions.m b/FirebaseCore/Sources/FIROptions.m index 16fdb6f41bc..c3b10b06bdb 100644 --- a/FirebaseCore/Sources/FIROptions.m +++ b/FirebaseCore/Sources/FIROptions.m @@ -160,7 +160,6 @@ - (id)copyWithZone:(NSZone *)zone { FIROptions *newOptions = [(FIROptions *)[[self class] allocWithZone:zone] initInternalWithOptionsDictionary:self.optionsDictionary]; if (newOptions) { - newOptions->_deepLinkURLScheme = self->_deepLinkURLScheme; newOptions.appGroupID = self.appGroupID; newOptions.editingLocked = self.isEditingLocked; newOptions.usingOptionsFromDefaultPlist = self.usingOptionsFromDefaultPlist; @@ -315,11 +314,6 @@ - (void)setStorageBucket:(NSString *)storageBucket { _optionsDictionary[kFIRStorageBucket] = [storageBucket copy]; } -- (void)setDeepLinkURLScheme:(NSString *)deepLinkURLScheme { - [self checkEditingLocked]; - _deepLinkURLScheme = [deepLinkURLScheme copy]; -} - - (NSString *)bundleID { return self.optionsDictionary[kFIRBundleID]; } @@ -357,11 +351,6 @@ - (BOOL)isEqualToOptions:(FIROptions *)options { // Validate extra properties not contained in the dictionary. Only validate it if one of the // objects has the property set. - if ((options->_deepLinkURLScheme != nil || self->_deepLinkURLScheme != nil) && - ![options->_deepLinkURLScheme isEqualToString:self->_deepLinkURLScheme]) { - return NO; - } - if ((options.appGroupID != nil || self.appGroupID != nil) && ![options.appGroupID isEqualToString:self.appGroupID]) { return NO; @@ -384,7 +373,7 @@ - (NSUInteger)hash { // Note: `self.analyticsOptionsDictionary` was left out here since it solely relies on the // contents of the main bundle's `Info.plist`. We should avoid reading that file and the contents // should be identical. - return self.optionsDictionary.hash ^ self->_deepLinkURLScheme.hash ^ self.appGroupID.hash; + return self.optionsDictionary.hash ^ self.appGroupID.hash; } #pragma mark - Internal instance methods diff --git a/FirebaseCore/Sources/Public/FirebaseCore/FIROptions.h b/FirebaseCore/Sources/Public/FirebaseCore/FIROptions.h index db1570a083c..4272b8433e2 100644 --- a/FirebaseCore/Sources/Public/FirebaseCore/FIROptions.h +++ b/FirebaseCore/Sources/Public/FirebaseCore/FIROptions.h @@ -80,11 +80,6 @@ NS_SWIFT_NAME(FirebaseOptions) */ @property(nonatomic, copy, nullable) NSString *databaseURL; -/** - * The URL scheme used to set up Durable Deep Link service. - */ -@property(nonatomic, copy, nullable) NSString *deepLinkURLScheme DEPRECATED_ATTRIBUTE; - /** * The Google Cloud Storage bucket name, e.g. @"abc-xyz-123.storage.firebase.com". */ diff --git a/FirebaseInAppMessaging/Tests/Integration/FunctionalTestApp/App/InAppMessaging-Example-iOS/AppDelegate.m b/FirebaseInAppMessaging/Tests/Integration/FunctionalTestApp/App/InAppMessaging-Example-iOS/AppDelegate.m index cf8c48b8801..c154cd03046 100644 --- a/FirebaseInAppMessaging/Tests/Integration/FunctionalTestApp/App/InAppMessaging-Example-iOS/AppDelegate.m +++ b/FirebaseInAppMessaging/Tests/Integration/FunctionalTestApp/App/InAppMessaging-Example-iOS/AppDelegate.m @@ -34,7 +34,6 @@ - (BOOL)application:(UIApplication *)application NSLog(@"application started"); [FIRInAppMessaging disableAutoBootstrapWithFIRApp]; - [FIROptions defaultOptions].deepLinkURLScheme = @"fiam-testing"; [FIRApp configure]; FIRIAMSDKSettings *sdkSetting = [[FIRIAMSDKSettings alloc] init]; diff --git a/SharedTestUtilities/FIROptionsMock.h b/SharedTestUtilities/FIROptionsMock.h index 59707c00434..3a22bc033c1 100644 --- a/SharedTestUtilities/FIROptionsMock.h +++ b/SharedTestUtilities/FIROptionsMock.h @@ -27,9 +27,6 @@ extern NSString *const kGoogleAppID; extern NSString *const kDatabaseURL; extern NSString *const kStorageBucket; -extern NSString *const kDeepLinkURLScheme; -extern NSString *const kNewDeepLinkURLScheme; - extern NSString *const kBundleID; extern NSString *const kProjectID; diff --git a/SharedTestUtilities/FIROptionsMock.m b/SharedTestUtilities/FIROptionsMock.m index d9dc4c246ba..957b1ec1d81 100644 --- a/SharedTestUtilities/FIROptionsMock.m +++ b/SharedTestUtilities/FIROptionsMock.m @@ -25,9 +25,6 @@ NSString *const kDatabaseURL = @"https://abc-xyz-123.firebaseio.com"; NSString *const kStorageBucket = @"project-id-123.storage.firebase.com"; -NSString *const kDeepLinkURLScheme = @"comgoogledeeplinkurl"; -NSString *const kNewDeepLinkURLScheme = @"newdeeplinkurlfortest"; - NSString *const kBundleID = @"com.google.FirebaseSDKTests"; NSString *const kProjectID = @"abc-xyz-123"; diff --git a/docs/FirebaseOptionsPerProduct.md b/docs/FirebaseOptionsPerProduct.md index b4f4be15939..434258e167c 100644 --- a/docs/FirebaseOptionsPerProduct.md +++ b/docs/FirebaseOptionsPerProduct.md @@ -11,7 +11,6 @@ Summarize which Firebase Options fields (and GoogleService-Info.plist attributes | **projectID** | | ✅ | | | | | ✅ | | ✅ | ✅ | | ✅ | | ✅ | ✅ | ✅ | | | **googleAppID** | ✅ | ✅ | | ✅ | | ✅ | ✅ | | | | ✅ | ✅ | ✅ | | ✅ | ✅ | ✅ | | **databaseURL** | | | | | | | ✅ | | | | | | | | | | | -| **deepLinkURLScheme** | | | | | | | | ✅ | | | | | | | | | | | **storageBucket** | | | | | | | | | | | | | | | | | ✅ | @@ -26,7 +25,6 @@ to GoogleService-Info.plist attributes. * *projectID*: The Project ID from the Firebase console * *googleAppID*: The Google App ID that is used to uniquely identify an instance of an app * *databaseURL*: The realtime database root URL -* *deepLinkURLScheme*: The URL scheme used to set up Durable Deep Link service * *storageBucket*: The Google Cloud Storage bucket name ## Questions @@ -36,10 +34,8 @@ to GoogleService-Info.plist attributes. * *gcmSenderID* is the second subfield of *googleAppID*. Can it be eliminated? * *bundleID* seems to have three purposes: Performance SDK uses it. Messaging back end uses it. Core will generate an error message if it doesn't match the actual bundleID. Anything else? -* Why isn't *deepLinkURLScheme* set from the GoogleService-Info.plist field `REVERSED_CLIENT_ID` like - other Firebase Options? The client code is required to explicitly set it. * Is there a better way to manage the fields that are only used by one product? *clientID*, *databaseURL*, - *deepLinkURLScheme*, and *storageBucket*. + and *storageBucket*. ## Unused FirebaseOptions Proposal: Deprecate these in the SDK and stop generating them for GoogleService-Info.plist. From d2e2ed0f8057aaa56762a9a32f04a9a772ea13d3 Mon Sep 17 00:00:00 2001 From: Nick Cooke <36927374+ncooke3@users.noreply.github.com> Date: Fri, 20 Jun 2025 11:53:29 -0400 Subject: [PATCH 094/113] [DynamicLinks] Remove library and corresponding infra (#14978) --- .github/ISSUE_TEMPLATE/FEATURE_REQUEST.yml | 1 - .github/workflows/archiving.yml | 2 +- .github/workflows/dynamiclinks.yml | 61 - .../workflows/health-metrics-presubmit.yml | 26 +- .github/workflows/zip.yml | 2 - Carthage.md | 1 - CoreOnly/NOTICES | 1 - CoreOnly/Sources/Firebase.h | 4 - .../FirebasePodTest/AppDelegate.swift | 1 - CoreOnly/Tests/FirebasePodTest/Podfile | 1 - Dangerfile | 5 - Firebase.podspec | 6 - FirebaseCore/CHANGELOG.md | 2 + FirebaseDynamicLinks.podspec | 60 - FirebaseDynamicLinks/CHANGELOG.md | 4 + FirebaseDynamicLinks/README.md | 40 - .../FDLURLComponents+Private.h | 67 - .../FDLURLComponents/FDLURLComponents.m | 700 ------- .../FIRDynamicLinkComponentsKeyProvider.h | 23 - .../FIRDynamicLinkComponentsKeyProvider.m | 39 - .../Sources/FIRDLDefaultRetrievalProcessV2.h | 41 - .../Sources/FIRDLDefaultRetrievalProcessV2.m | 256 --- .../Sources/FIRDLJavaScriptExecutor.h | 38 - .../Sources/FIRDLJavaScriptExecutor.m | 174 -- .../Sources/FIRDLRetrievalProcessFactory.h | 39 - .../Sources/FIRDLRetrievalProcessFactory.m | 61 - .../Sources/FIRDLRetrievalProcessProtocols.h | 39 - .../FIRDLRetrievalProcessResult+Private.h | 30 - .../Sources/FIRDLRetrievalProcessResult.h | 38 - .../Sources/FIRDLRetrievalProcessResult.m | 65 - .../Sources/FIRDLScionLogging.h | 45 - .../Sources/FIRDLScionLogging.m | 59 - .../Sources/FIRDynamicLink+Private.h | 52 - FirebaseDynamicLinks/Sources/FIRDynamicLink.m | 153 -- .../FIRDynamicLinkNetworking+Private.h | 49 - .../Sources/FIRDynamicLinkNetworking.h | 133 -- .../Sources/FIRDynamicLinkNetworking.m | 369 ---- .../Sources/FIRDynamicLinks+FirstParty.h | 122 -- .../Sources/FIRDynamicLinks+Private.h | 55 - .../Sources/FIRDynamicLinks.m | 805 -------- .../Sources/GINInvocation/GINArgument.h | 52 - .../Sources/GINInvocation/GINArgument.m | 84 - .../Sources/GINInvocation/GINInvocation.h | 71 - .../Sources/GINInvocation/GINInvocation.m | 98 - .../Sources/Logging/FDLLogging.h | 48 - .../Sources/Logging/FDLLogging.m | 73 - .../FirebaseDynamicLinks/FDLURLComponents.h | 560 ------ .../FirebaseDynamicLinks/FIRDynamicLink.h | 90 - .../FirebaseDynamicLinks/FIRDynamicLinks.h | 147 -- .../FIRDynamicLinksCommon.h | 41 - .../FirebaseDynamicLinks.h | 20 - .../Sources/Resources/PrivacyInfo.xcprivacy | 46 - .../Utilities/FDLDeviceHeuristicsHelper.h | 33 - .../Utilities/FDLDeviceHeuristicsHelper.m | 43 - .../Sources/Utilities/FDLUtilities.h | 148 -- .../Sources/Utilities/FDLUtilities.m | 368 ---- .../project.pbxproj | 442 ---- .../FDLBuilderTestAppObjC/AppDelegate.h | 23 - .../FDLBuilderTestAppObjC/AppDelegate.m | 103 - .../AppIcon.appiconset/Contents.json | 98 - .../Assets.xcassets/Contents.json | 6 - .../Base.lproj/LaunchScreen.storyboard | 25 - .../Base.lproj/Main.storyboard | 26 - .../FDLBuilderTestAppObjC.entitlements | 20 - .../Sample/FDLBuilderTestAppObjC/Info.plist | 83 - .../FDLBuilderTestAppObjC/LinkTableViewCell.h | 23 - .../FDLBuilderTestAppObjC/LinkTableViewCell.m | 69 - .../ParamTableViewCell.h | 33 - .../ParamTableViewCell.m | 82 - .../FDLBuilderTestAppObjC/SceneDelegate.h | 23 - .../FDLBuilderTestAppObjC/SceneDelegate.m | 108 - .../FDLBuilderTestAppObjC/ViewController.h | 21 - .../FDLBuilderTestAppObjC/ViewController.m | 399 ---- .../Tests/Sample/FDLBuilderTestAppObjC/main.m | 27 - FirebaseDynamicLinks/Tests/Sample/Podfile | 11 - FirebaseDynamicLinks/Tests/Unit/DL-Info.plist | 56 - .../Tests/Unit/FDLURLComponentsTests.m | 779 ------- .../Tests/Unit/FIRDLScionLoggingTest.m | 182 -- .../Unit/FIRDynamicLinkNetworkingTests.m | 100 - .../Tests/Unit/FIRDynamicLinkTest.m | 79 - .../Tests/Unit/FIRDynamicLinksImportsTest3P.m | 33 - .../Tests/Unit/FIRDynamicLinksTest.m | 1787 ----------------- .../Tests/Unit/UtilitiesTests.m | 198 -- .../ClientApp.xcodeproj/project.pbxproj | 7 - IntegrationTesting/ClientApp/Podfile | 1 - .../Shared/objc-header-import-test.m | 10 +- .../Shared/objc-module-import-test.m | 3 - .../Shared/objcxx-header-import-test.mm | 10 +- .../ClientApp/Shared/swift-import-test.swift | 3 - .../Podfile | 1 - Package.swift | 28 - .../FirebaseManifest/FirebaseManifest.swift | 1 - .../FirebaseDynamicLinksWrap/dummy.m | 18 - .../FirebaseDynamicLinksWrap/include/dummy.h | 15 - SwiftPMTests/objc-import-test/objc-header.m | 2 - SwiftPMTests/objc-import-test/objc-module.m | 1 - SwiftPMTests/swift-test/all-imports.swift | 1 - SymbolCollisionTest/Podfile | 1 - docs/ContinuousIntegration.md | 2 +- scripts/api_diff_report/icore_module.py | 1 - scripts/change_headers.swift | 2 +- scripts/check_imports.swift | 1 - scripts/health_metrics/file_patterns.json | 9 - .../pod_test_code_coverage_report.sh | 2 - 104 files changed, 16 insertions(+), 10530 deletions(-) delete mode 100644 .github/workflows/dynamiclinks.yml delete mode 100644 FirebaseDynamicLinks.podspec delete mode 100644 FirebaseDynamicLinks/README.md delete mode 100644 FirebaseDynamicLinks/Sources/FDLURLComponents/FDLURLComponents+Private.h delete mode 100644 FirebaseDynamicLinks/Sources/FDLURLComponents/FDLURLComponents.m delete mode 100644 FirebaseDynamicLinks/Sources/FDLURLComponents/FIRDynamicLinkComponentsKeyProvider.h delete mode 100644 FirebaseDynamicLinks/Sources/FDLURLComponents/FIRDynamicLinkComponentsKeyProvider.m delete mode 100644 FirebaseDynamicLinks/Sources/FIRDLDefaultRetrievalProcessV2.h delete mode 100644 FirebaseDynamicLinks/Sources/FIRDLDefaultRetrievalProcessV2.m delete mode 100644 FirebaseDynamicLinks/Sources/FIRDLJavaScriptExecutor.h delete mode 100644 FirebaseDynamicLinks/Sources/FIRDLJavaScriptExecutor.m delete mode 100644 FirebaseDynamicLinks/Sources/FIRDLRetrievalProcessFactory.h delete mode 100644 FirebaseDynamicLinks/Sources/FIRDLRetrievalProcessFactory.m delete mode 100644 FirebaseDynamicLinks/Sources/FIRDLRetrievalProcessProtocols.h delete mode 100644 FirebaseDynamicLinks/Sources/FIRDLRetrievalProcessResult+Private.h delete mode 100644 FirebaseDynamicLinks/Sources/FIRDLRetrievalProcessResult.h delete mode 100644 FirebaseDynamicLinks/Sources/FIRDLRetrievalProcessResult.m delete mode 100644 FirebaseDynamicLinks/Sources/FIRDLScionLogging.h delete mode 100644 FirebaseDynamicLinks/Sources/FIRDLScionLogging.m delete mode 100644 FirebaseDynamicLinks/Sources/FIRDynamicLink+Private.h delete mode 100644 FirebaseDynamicLinks/Sources/FIRDynamicLink.m delete mode 100644 FirebaseDynamicLinks/Sources/FIRDynamicLinkNetworking+Private.h delete mode 100644 FirebaseDynamicLinks/Sources/FIRDynamicLinkNetworking.h delete mode 100644 FirebaseDynamicLinks/Sources/FIRDynamicLinkNetworking.m delete mode 100644 FirebaseDynamicLinks/Sources/FIRDynamicLinks+FirstParty.h delete mode 100644 FirebaseDynamicLinks/Sources/FIRDynamicLinks+Private.h delete mode 100644 FirebaseDynamicLinks/Sources/FIRDynamicLinks.m delete mode 100644 FirebaseDynamicLinks/Sources/GINInvocation/GINArgument.h delete mode 100644 FirebaseDynamicLinks/Sources/GINInvocation/GINArgument.m delete mode 100644 FirebaseDynamicLinks/Sources/GINInvocation/GINInvocation.h delete mode 100644 FirebaseDynamicLinks/Sources/GINInvocation/GINInvocation.m delete mode 100644 FirebaseDynamicLinks/Sources/Logging/FDLLogging.h delete mode 100644 FirebaseDynamicLinks/Sources/Logging/FDLLogging.m delete mode 100644 FirebaseDynamicLinks/Sources/Public/FirebaseDynamicLinks/FDLURLComponents.h delete mode 100644 FirebaseDynamicLinks/Sources/Public/FirebaseDynamicLinks/FIRDynamicLink.h delete mode 100644 FirebaseDynamicLinks/Sources/Public/FirebaseDynamicLinks/FIRDynamicLinks.h delete mode 100644 FirebaseDynamicLinks/Sources/Public/FirebaseDynamicLinks/FIRDynamicLinksCommon.h delete mode 100755 FirebaseDynamicLinks/Sources/Public/FirebaseDynamicLinks/FirebaseDynamicLinks.h delete mode 100644 FirebaseDynamicLinks/Sources/Resources/PrivacyInfo.xcprivacy delete mode 100644 FirebaseDynamicLinks/Sources/Utilities/FDLDeviceHeuristicsHelper.h delete mode 100644 FirebaseDynamicLinks/Sources/Utilities/FDLDeviceHeuristicsHelper.m delete mode 100644 FirebaseDynamicLinks/Sources/Utilities/FDLUtilities.h delete mode 100644 FirebaseDynamicLinks/Sources/Utilities/FDLUtilities.m delete mode 100644 FirebaseDynamicLinks/Tests/Sample/FDLBuilderTestAppObjC.xcodeproj/project.pbxproj delete mode 100644 FirebaseDynamicLinks/Tests/Sample/FDLBuilderTestAppObjC/AppDelegate.h delete mode 100644 FirebaseDynamicLinks/Tests/Sample/FDLBuilderTestAppObjC/AppDelegate.m delete mode 100644 FirebaseDynamicLinks/Tests/Sample/FDLBuilderTestAppObjC/Assets.xcassets/AppIcon.appiconset/Contents.json delete mode 100644 FirebaseDynamicLinks/Tests/Sample/FDLBuilderTestAppObjC/Assets.xcassets/Contents.json delete mode 100644 FirebaseDynamicLinks/Tests/Sample/FDLBuilderTestAppObjC/Base.lproj/LaunchScreen.storyboard delete mode 100644 FirebaseDynamicLinks/Tests/Sample/FDLBuilderTestAppObjC/Base.lproj/Main.storyboard delete mode 100644 FirebaseDynamicLinks/Tests/Sample/FDLBuilderTestAppObjC/FDLBuilderTestAppObjC.entitlements delete mode 100644 FirebaseDynamicLinks/Tests/Sample/FDLBuilderTestAppObjC/Info.plist delete mode 100644 FirebaseDynamicLinks/Tests/Sample/FDLBuilderTestAppObjC/LinkTableViewCell.h delete mode 100644 FirebaseDynamicLinks/Tests/Sample/FDLBuilderTestAppObjC/LinkTableViewCell.m delete mode 100644 FirebaseDynamicLinks/Tests/Sample/FDLBuilderTestAppObjC/ParamTableViewCell.h delete mode 100644 FirebaseDynamicLinks/Tests/Sample/FDLBuilderTestAppObjC/ParamTableViewCell.m delete mode 100644 FirebaseDynamicLinks/Tests/Sample/FDLBuilderTestAppObjC/SceneDelegate.h delete mode 100644 FirebaseDynamicLinks/Tests/Sample/FDLBuilderTestAppObjC/SceneDelegate.m delete mode 100644 FirebaseDynamicLinks/Tests/Sample/FDLBuilderTestAppObjC/ViewController.h delete mode 100644 FirebaseDynamicLinks/Tests/Sample/FDLBuilderTestAppObjC/ViewController.m delete mode 100644 FirebaseDynamicLinks/Tests/Sample/FDLBuilderTestAppObjC/main.m delete mode 100644 FirebaseDynamicLinks/Tests/Sample/Podfile delete mode 100644 FirebaseDynamicLinks/Tests/Unit/DL-Info.plist delete mode 100644 FirebaseDynamicLinks/Tests/Unit/FDLURLComponentsTests.m delete mode 100644 FirebaseDynamicLinks/Tests/Unit/FIRDLScionLoggingTest.m delete mode 100644 FirebaseDynamicLinks/Tests/Unit/FIRDynamicLinkNetworkingTests.m delete mode 100644 FirebaseDynamicLinks/Tests/Unit/FIRDynamicLinkTest.m delete mode 100644 FirebaseDynamicLinks/Tests/Unit/FIRDynamicLinksImportsTest3P.m delete mode 100644 FirebaseDynamicLinks/Tests/Unit/FIRDynamicLinksTest.m delete mode 100644 FirebaseDynamicLinks/Tests/Unit/UtilitiesTests.m delete mode 100644 SwiftPM-PlatformExclude/FirebaseDynamicLinksWrap/dummy.m delete mode 100644 SwiftPM-PlatformExclude/FirebaseDynamicLinksWrap/include/dummy.h diff --git a/.github/ISSUE_TEMPLATE/FEATURE_REQUEST.yml b/.github/ISSUE_TEMPLATE/FEATURE_REQUEST.yml index 61b4fe2ebd3..5b1a38a0b07 100644 --- a/.github/ISSUE_TEMPLATE/FEATURE_REQUEST.yml +++ b/.github/ISSUE_TEMPLATE/FEATURE_REQUEST.yml @@ -56,7 +56,6 @@ body: - Crashlytics - Database - Data Connect - - DynamicLinks - Firestore - Functions - In-App Messaging diff --git a/.github/workflows/archiving.yml b/.github/workflows/archiving.yml index 3b609718f89..c70afe14b8e 100644 --- a/.github/workflows/archiving.yml +++ b/.github/workflows/archiving.yml @@ -24,7 +24,7 @@ jobs: strategy: matrix: # These need to be on a single line or else the formatting won't validate. - pod: ["FirebaseAppDistribution", "FirebaseDynamicLinks", "FirebaseInAppMessaging", "FirebasePerformance"] + pod: ["FirebaseAppDistribution", "FirebaseInAppMessaging", "FirebasePerformance"] steps: - uses: actions/checkout@v4 - uses: mikehardy/buildcache-action@c87cea0ccd718971d6cc39e672c4f26815b6c126 diff --git a/.github/workflows/dynamiclinks.yml b/.github/workflows/dynamiclinks.yml deleted file mode 100644 index 919027e7e20..00000000000 --- a/.github/workflows/dynamiclinks.yml +++ /dev/null @@ -1,61 +0,0 @@ -name: dynamiclinks - -permissions: - contents: read - -on: - workflow_dispatch: - pull_request: - paths: - - 'FirebaseDynamicLinks**' - - '.github/workflows/dynamiclinks.yml' - - 'Interop/Analytics/Public/*.h' - - '.github/workflows/common.yml' - - '.github/workflows/common_cocoapods.yml' - - 'Gemfile*' - schedule: - # Run every day at 1am (PST) - cron uses UTC times - - cron: '0 9 * * *' - -concurrency: - group: ${{ github.workflow }}-${{ github.head_ref || github.ref }} - cancel-in-progress: true - -jobs: - spm: - strategy: - matrix: - target: [FirebaseAppCheckUnit, FirebaseAppCheckUnitSwift] - uses: ./.github/workflows/common.yml - with: - target: FirebaseDynamicLinks - buildonly_platforms: iOS - platforms: iOS - - pod_lib_lint: - uses: ./.github/workflows/common_cocoapods.yml - with: - product: FirebaseDynamicLinks - platforms: iOS # Dynamic Links only supports iOS. - allow_warnings: true - - dynamiclinks-cron-only: - # Don't run on private repo. - if: github.event_name == 'schedule' && github.repository == 'Firebase/firebase-ios-sdk' - - runs-on: macos-15 - strategy: - matrix: - flags: [ - '--use-static-frameworks' - ] - needs: pod_lib_lint - steps: - - uses: actions/checkout@v4 - - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1 - - name: Setup Bundler - run: scripts/setup_bundler.sh - - name: Xcode - run: sudo xcode-select -s /Applications/Xcode_16.2.app/Contents/Developer - - name: PodLibLint Storage Cron - run: scripts/third_party/travis/retry.sh scripts/pod_lib_lint.rb FirebaseDynamicLinks.podspec --platforms=ios ${{ matrix.flags }} --allow-warnings diff --git a/.github/workflows/health-metrics-presubmit.yml b/.github/workflows/health-metrics-presubmit.yml index 886cf90f90a..b9bd1a00edc 100644 --- a/.github/workflows/health-metrics-presubmit.yml +++ b/.github/workflows/health-metrics-presubmit.yml @@ -33,7 +33,6 @@ jobs: auth_run_job: ${{ steps.check_files.outputs.auth_run_job }} crashlytics_run_job: ${{ steps.check_files.outputs.crashlytics_run_job }} database_run_job: ${{ steps.check_files.outputs.database_run_job }} - dynamiclinks_run_job: ${{ steps.check_files.outputs.dynamiclinks_run_job }} firestore_run_job: ${{ steps.check_files.outputs.firestore_run_job }} functions_run_job: ${{ steps.check_files.outputs.functions_run_job }} inappmessaging_run_job: ${{ steps.check_files.outputs.inappmessaging_run_job }} @@ -126,29 +125,6 @@ jobs: name: codecoverage path: /Users/runner/*.xcresult - pod-lib-lint-dynamiclinks: - needs: check - # Don't run on private repo unless it is a PR. - if: always() && github.repository == 'Firebase/firebase-ios-sdk' && (needs.check.outputs.dynamiclinks_run_job == 'true'|| github.event.pull_request.merged) - runs-on: macos-14 - strategy: - matrix: - target: [iOS] - steps: - - uses: actions/checkout@v4 - - uses: mikehardy/buildcache-action@c87cea0ccd718971d6cc39e672c4f26815b6c126 - with: - cache_key: ${{ matrix.os }} - - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1 - - name: Setup Bundler - run: scripts/setup_bundler.sh - - name: Build and test - run: ./scripts/health_metrics/pod_test_code_coverage_report.sh --sdk=FirebaseDynamicLinks --platform=${{ matrix.target }} - - uses: actions/upload-artifact@v4 - with: - name: codecoverage - path: /Users/runner/*.xcresult - pod-lib-lint-firestore: needs: check # Don't run on private repo unless it is a PR. @@ -317,7 +293,7 @@ jobs: path: /Users/runner/*.xcresult create_report: - needs: [check, pod-lib-lint-abtesting, pod-lib-lint-auth, pod-lib-lint-database, pod-lib-lint-dynamiclinks, pod-lib-lint-firestore, pod-lib-lint-functions, pod-lib-lint-inappmessaging, pod-lib-lint-messaging, pod-lib-lint-performance, pod-lib-lint-remoteconfig, pod-lib-lint-storage] + needs: [check, pod-lib-lint-abtesting, pod-lib-lint-auth, pod-lib-lint-database, pod-lib-lint-firestore, pod-lib-lint-functions, pod-lib-lint-inappmessaging, pod-lib-lint-messaging, pod-lib-lint-performance, pod-lib-lint-remoteconfig, pod-lib-lint-storage] if: always() runs-on: macos-14 steps: diff --git a/.github/workflows/zip.yml b/.github/workflows/zip.yml index 2b300b11e86..074fc1a26ad 100644 --- a/.github/workflows/zip.yml +++ b/.github/workflows/zip.yml @@ -196,7 +196,6 @@ jobs: - name: Setup Swift Quickstart run: SAMPLE="$SDK" TARGET="${SDK}Example" NON_FIREBASE_SDKS="FBSDKLoginKit FBSDKCoreKit FBSDKCoreKit_Basics FBAEMKit" scripts/setup_quickstart_framework.sh \ "${HOME}"/ios_frameworks/Firebase/NonFirebaseSDKs/* \ - "${HOME}"/ios_frameworks/Firebase/FirebaseDynamicLinks/* \ "${HOME}"/ios_frameworks/Firebase/GoogleSignIn/* \ "${HOME}"/ios_frameworks/Firebase/FirebaseAuth/* \ "${HOME}"/ios_frameworks/Firebase/FirebaseAnalytics/* @@ -508,7 +507,6 @@ jobs: - uses: actions/checkout@v4 - name: Setup quickstart run: SAMPLE="$SDK" TARGET="${SDK}Example" scripts/setup_quickstart_framework.sh \ - "${HOME}"/ios_frameworks/Firebase/FirebaseDynamicLinks/* \ "${HOME}"/ios_frameworks/Firebase/FirebaseInAppMessaging/* \ "${HOME}"/ios_frameworks/Firebase/FirebaseAnalytics/* - name: Xcode diff --git a/Carthage.md b/Carthage.md index d9c8a144c6e..7e8bbfc90a6 100644 --- a/Carthage.md +++ b/Carthage.md @@ -39,7 +39,6 @@ binary "https://dl.google.com/dl/firebase/ios/carthage/FirebaseAppDistributionBi binary "https://dl.google.com/dl/firebase/ios/carthage/FirebaseAuthBinary.json" binary "https://dl.google.com/dl/firebase/ios/carthage/FirebaseCrashlyticsBinary.json" binary "https://dl.google.com/dl/firebase/ios/carthage/FirebaseDatabaseBinary.json" -binary "https://dl.google.com/dl/firebase/ios/carthage/FirebaseDynamicLinksBinary.json" binary "https://dl.google.com/dl/firebase/ios/carthage/FirebaseFirestoreBinary.json" binary "https://dl.google.com/dl/firebase/ios/carthage/FirebaseFunctionsBinary.json" binary "https://dl.google.com/dl/firebase/ios/carthage/FirebaseGoogleSignInBinary.json" diff --git a/CoreOnly/NOTICES b/CoreOnly/NOTICES index 2442b90fb98..01a6bf30bda 100644 --- a/CoreOnly/NOTICES +++ b/CoreOnly/NOTICES @@ -10,7 +10,6 @@ FirebaseAuthInterop FirebaseCore FirebaseCoreExtension FirebaseCoreInternal -FirebaseDynamicLinks FirebaseFunctions FirebaseInAppMessaging FirebaseInstallations diff --git a/CoreOnly/Sources/Firebase.h b/CoreOnly/Sources/Firebase.h index 37d5f9e495c..5262bb4b607 100755 --- a/CoreOnly/Sources/Firebase.h +++ b/CoreOnly/Sources/Firebase.h @@ -49,10 +49,6 @@ #import #endif - #if __has_include() - #import - #endif - #if __has_include() #import #endif diff --git a/CoreOnly/Tests/FirebasePodTest/FirebasePodTest/AppDelegate.swift b/CoreOnly/Tests/FirebasePodTest/FirebasePodTest/AppDelegate.swift index 6470841c297..4ae7852f591 100644 --- a/CoreOnly/Tests/FirebasePodTest/FirebasePodTest/AppDelegate.swift +++ b/CoreOnly/Tests/FirebasePodTest/FirebasePodTest/AppDelegate.swift @@ -25,7 +25,6 @@ class AuthExists: Auth {} // Uncomment next line if ABTesting gets added to Firebase.h. // class ABTestingExists : LifecycleEvents {} class DatabaseExists: Database {} -class DynamicLinksExists: DynamicLinks {} class FirestoreExists: Firestore {} class FunctionsExists: Functions {} class InAppMessagingExists: InAppMessaging {} diff --git a/CoreOnly/Tests/FirebasePodTest/Podfile b/CoreOnly/Tests/FirebasePodTest/Podfile index f96f6219677..238756b7569 100644 --- a/CoreOnly/Tests/FirebasePodTest/Podfile +++ b/CoreOnly/Tests/FirebasePodTest/Podfile @@ -16,7 +16,6 @@ target 'FirebasePodTest' do pod 'FirebaseCore', :path => '../../../' pod 'FirebaseCrashlytics', :path => '../../../' pod 'FirebaseDatabase', :path => '../../../' - pod 'FirebaseDynamicLinks', :path => '../../../' pod 'FirebaseFirestore', :path => '../../../' pod 'FirebaseFirestoreInternal', :path => '../../../' pod 'FirebaseFunctions', :path => '../../../' diff --git a/Dangerfile b/Dangerfile index 1438a1d1010..6e6cb1ce057 100644 --- a/Dangerfile +++ b/Dangerfile @@ -55,7 +55,6 @@ def labelsForModifiedFiles() labels.push("api: core") if @has_core_changes labels.push("api: crashlytics") if @has_crashlytics_changes labels.push("api: database") if @has_database_changes - labels.push("api: dynamiclinks") if @has_dynamiclinks_changes labels.push("api: firebaseai") if @has_firebaseai_changes labels.push("api: firestore") if @has_firestore_changes labels.push("api: functions") if @has_functions_changes @@ -93,7 +92,6 @@ has_license_changes = didModify(["LICENSE"]) "Core", "Crashlytics", "Database", - "DynamicLinks", "FirebaseAI", "Firestore", "Functions", @@ -132,8 +130,6 @@ has_license_changes = didModify(["LICENSE"]) @has_crashlytics_api_changes = hasChangesIn("Crashlytics/Crashlytics/Public/") @has_database_changes = hasChangesIn("FirebaseDatabase") @has_database_api_changes = hasChangesIn("FirebaseDatabase/Sources/Public/") -@has_dynamiclinks_changes = hasChangesIn("FirebaseDynamicLinks") -@has_dynamiclinks_api_changes = hasChangesIn("FirebaseDynamicLinks/Sources/Public/") @has_firebaseai_changes = hasChangesIn([ "FirebaseAI", "FirebaseVertexAI" @@ -168,7 +164,6 @@ has_license_changes = didModify(["LICENSE"]) @has_core_api_changes || @has_crashlytics_api_changes || @has_database_api_changes || - @has_dynamiclinks_api_changes || @has_firestore_api_changes || @has_functions_api_changes || @has_inappmessaging_api_changes || diff --git a/Firebase.podspec b/Firebase.podspec index 2417f0dcb38..007b7ebfe9c 100644 --- a/Firebase.podspec +++ b/Firebase.podspec @@ -138,12 +138,6 @@ Simplify your app development, grow your user base, and monetize more effectivel ss.watchos.deployment_target = '7.0' end - s.subspec 'DynamicLinks' do |ss| - ss.dependency 'Firebase/CoreOnly' - ss.ios.dependency 'FirebaseDynamicLinks', '~> 11.15.0' - ss.ios.deployment_target = '13.0' - end - s.subspec 'Firestore' do |ss| ss.dependency 'Firebase/CoreOnly' ss.dependency 'FirebaseFirestore', '~> 11.15.0' diff --git a/FirebaseCore/CHANGELOG.md b/FirebaseCore/CHANGELOG.md index 96eebc5e656..326642f51f8 100644 --- a/FirebaseCore/CHANGELOG.md +++ b/FirebaseCore/CHANGELOG.md @@ -1,4 +1,6 @@ # Unreleased +- [removed] **Breaking change**: FirebaseDynamicLinks has been removed. See + https://firebase.google.com/support/dynamic-links-faq for more info. - [removed] **Breaking change**: Removed the `Options.deepLinkURLScheme` property. This API was exclusively used by the Dynamic Links SDK, which has been removed. diff --git a/FirebaseDynamicLinks.podspec b/FirebaseDynamicLinks.podspec deleted file mode 100644 index 5ad9a08caa3..00000000000 --- a/FirebaseDynamicLinks.podspec +++ /dev/null @@ -1,60 +0,0 @@ -Pod::Spec.new do |s| - s.name = 'FirebaseDynamicLinks' - s.version = '11.15.0' - s.summary = 'Firebase Dynamic Links' - - s.description = <<-DESC -Firebase Dynamic Links are deep links that enhance user experience and increase engagement by retaining context post-install, across platforms. - DESC - - s.homepage = 'https://firebase.google.com' - s.license = { :type => 'Apache-2.0', :file => 'LICENSE' } - s.authors = 'Google, Inc.' - - s.source = { - :git => 'https://github.com/firebase/firebase-ios-sdk.git', - :tag => 'CocoaPods-' + s.version.to_s - } - s.social_media_url = 'https://twitter.com/Firebase' - s.ios.deployment_target = '13.0' - - s.swift_version = '5.9' - - # See https://firebase.google.com/support/dynamic-links-faq - s.deprecated = true - - s.cocoapods_version = '>= 1.12.0' - s.prefix_header_file = false - - s.source_files = [ - 'FirebaseDynamicLinks/Sources/**/*.[mh]', - 'Interop/Analytics/Public/*.h', - 'FirebaseCore/Extension/*.h', - ] - s.public_header_files = 'FirebaseDynamicLinks/Sources/Public/FirebaseDynamicLinks/*.h' - s.resource_bundles = { - "#{s.module_name}_Privacy" => 'FirebaseDynamicLinks/Sources/Resources/PrivacyInfo.xcprivacy' - } - s.frameworks = 'QuartzCore' - s.weak_framework = 'WebKit' - s.dependency 'FirebaseCore', '~> 11.15.0' - - s.pod_target_xcconfig = { - 'GCC_PREPROCESSOR_DEFINITIONS' => 'FIRDynamicLinks3P GIN_SCION_LOGGING', - 'HEADER_SEARCH_PATHS' => '"${PODS_TARGET_SRCROOT}"' - } - - s.test_spec 'unit' do |unit_tests| - unit_tests.scheme = { :code_coverage => true } - unit_tests.source_files = [ - 'FirebaseDynamicLinks/Tests/Unit/*.[mh]', - ] - unit_tests.requires_app_host = true - unit_tests.resources = 'FirebaseDynamicLinks/Tests/Unit/GoogleService-Info.plist', - # Supply plist for custom domain testing. - 'FirebaseDynamicLinks/Tests/Unit/DL-Info.plist' - unit_tests.dependency 'OCMock' - unit_tests.dependency 'GoogleUtilities/MethodSwizzler', '~> 8.1' - unit_tests.dependency 'GoogleUtilities/SwizzlerTestHelpers', '~> 8.1' - end -end diff --git a/FirebaseDynamicLinks/CHANGELOG.md b/FirebaseDynamicLinks/CHANGELOG.md index 6983b145e35..5734ac9812b 100644 --- a/FirebaseDynamicLinks/CHANGELOG.md +++ b/FirebaseDynamicLinks/CHANGELOG.md @@ -1,3 +1,7 @@ +# 12.0.0 +- [removed] **Breaking change**: FirebaseDynamicLinks has been removed. See + https://firebase.google.com/support/dynamic-links-faq for more info. + # 11.8.0 - [deprecated] The `FirebaseDynamicLinks` CocoaPod is deprecated. For information about timelines and alternatives, see the [Dynamic Links deprecation FAQ](https://firebase.google.com/support/dynamic-links-faq). diff --git a/FirebaseDynamicLinks/README.md b/FirebaseDynamicLinks/README.md deleted file mode 100644 index b921229e91e..00000000000 --- a/FirebaseDynamicLinks/README.md +++ /dev/null @@ -1,40 +0,0 @@ -# Firebase Dynamic Links SDK for iOS - -> [!IMPORTANT] -> 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 Dynamic Links are universal deep links that persist across app installs. -For more info, see the [Firebase website](https://firebase.google.com/products/dynamic-links). - -Please visit [our developer site](https://firebase.google.com/docs/dynamic-links/) for integration -instructions, documentations, support information, and terms of service. - -## Managing the Pasteboard - -Firebase Dynamic Links 4.2.0 and higher use a plist property -`FirebaseDeepLinkPasteboardRetrievalEnabled` that a developer can set to enable/disable the use of -iOS pasteboard by the SDK. - -FDL SDK uses the pasteboard for deep-linking post app install (to enable deferred deep-linking, -where the link is copied on the -[app preview page](https://firebase.google.com/docs/dynamic-links/link-previews#app_preview_pages)) -and app install attribution; otherwise, FDL does not use the pasteboard for anything else. - -Disabling pasteboard access affects the app in the following ways: -* Deferred deep-linking will not work as reliably. At best, your app receives -[weak matches](https://firebase.google.com/docs/reference/unity/namespace/firebase/dynamic-links#linkmatchstrength) -for deep-links. -* App install attribution stats will be less accurate (potentially undercounting app installs). - -Enabling pasteboard access affects the app in the following ways: -* On iOS 14, will show a system alert notifying that your app accessed the content in the -pasteboard. This should happen one-time after installation of the app. -* Deferred deep-linking will work as designed. At best, your app receives a -[perfect match](https://firebase.google.com/docs/reference/unity/namespace/firebase/dynamic-links#linkmatchstrength) -for deep-links. -* SDK will be able to more reliably attribute installation stats for links. - -For more information, check out the -[iOS documentation](https://firebase.google.com/docs/dynamic-links/ios/receive). diff --git a/FirebaseDynamicLinks/Sources/FDLURLComponents/FDLURLComponents+Private.h b/FirebaseDynamicLinks/Sources/FDLURLComponents/FDLURLComponents+Private.h deleted file mode 100644 index f418bfb7e79..00000000000 --- a/FirebaseDynamicLinks/Sources/FDLURLComponents/FDLURLComponents+Private.h +++ /dev/null @@ -1,67 +0,0 @@ -/* - * 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. - */ - -#import "FirebaseDynamicLinks/Sources/Public/FirebaseDynamicLinks/FDLURLComponents.h" - -/** - * Label exceptions from FDL. - */ -FOUNDATION_EXPORT NSString *_Nonnull const kFirebaseDurableDeepLinkErrorDomain; - -NS_ASSUME_NONNULL_BEGIN - -/// Each of the parameter classes used in FIRDynamicLinkURLComponents needs to be able to -/// provide a dictionary representation of itself to be codified into URL query parameters. This -/// protocol defines that behavior. -@protocol FDLDictionaryRepresenting -@required -@property(nonatomic, readonly) NSDictionary *dictionaryRepresentation; -@end - -@interface FIRDynamicLinkGoogleAnalyticsParameters () -@end - -@interface FIRDynamicLinkIOSParameters () -@end - -@interface FIRDynamicLinkItunesConnectAnalyticsParameters () -@end - -@interface FIRDynamicLinkAndroidParameters () -@end - -@interface FIRDynamicLinkSocialMetaTagParameters () -@end - -@interface FIRDynamicLinkNavigationInfoParameters () -@end - -@interface FIRDynamicLinkOtherPlatformParameters () -@end - -@interface FIRDynamicLinkComponents () - -/// Creates and returns a request based on the url and options. Exposed for testing. -+ (NSURLRequest *)shorteningRequestForLongURL:(NSURL *)url - options:(nullable FIRDynamicLinkComponentsOptions *)options; - -/// Sends an HTTP request using NSURLSession. Exposed for testing. -+ (void)sendHTTPRequest:(NSURLRequest *)request - completion:(void (^)(NSData *_Nullable data, NSError *_Nullable error))completion; - -@end - -NS_ASSUME_NONNULL_END diff --git a/FirebaseDynamicLinks/Sources/FDLURLComponents/FDLURLComponents.m b/FirebaseDynamicLinks/Sources/FDLURLComponents/FDLURLComponents.m deleted file mode 100644 index 5a5ea1a3316..00000000000 --- a/FirebaseDynamicLinks/Sources/FDLURLComponents/FDLURLComponents.m +++ /dev/null @@ -1,700 +0,0 @@ -/* - * 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. - */ - -#import -#if TARGET_OS_IOS - -#import - -#import "FirebaseDynamicLinks/Sources/FDLURLComponents/FDLURLComponents+Private.h" -#import "FirebaseDynamicLinks/Sources/FDLURLComponents/FIRDynamicLinkComponentsKeyProvider.h" -#import "FirebaseDynamicLinks/Sources/Public/FirebaseDynamicLinks/FDLURLComponents.h" - -#import "FirebaseDynamicLinks/Sources/Logging/FDLLogging.h" -#import "FirebaseDynamicLinks/Sources/Utilities/FDLUtilities.h" - -// Label exceptions from FDL. -NSString *const kFirebaseDurableDeepLinkErrorDomain = @"com.firebase.durabledeeplink"; - -/// The exact behavior of dict[key] = value is unclear when value is nil. This function safely adds -/// the key-value pair to the dictionary, even when value is nil. -/// This function will treat empty string in the same way as nil. -NS_INLINE void FDLSafelyAddKeyValuePairToDictionary(NSString *key, - NSString *stringValue, - NSMutableDictionary *dictionary) { - if (stringValue != nil && stringValue.length > 0) { - dictionary[key] = stringValue; - } else { - [dictionary removeObjectForKey:key]; - } -} - -@implementation FIRDynamicLinkGoogleAnalyticsParameters { - NSMutableDictionary *_dictionary; -} - -static NSString *const kFDLUTMSourceKey = @"utm_source"; -static NSString *const kFDLUTMMediumKey = @"utm_medium"; -static NSString *const kFDLUTMCampaignKey = @"utm_campaign"; -static NSString *const kFDLUTMTermKey = @"utm_term"; -static NSString *const kFDLUTMContentKey = @"utm_content"; - -+ (instancetype)parameters { - return [[self alloc] init]; -} - -+ (instancetype)parametersWithSource:(NSString *)source - medium:(NSString *)medium - campaign:(NSString *)campaign { - return [[self alloc] initWithSource:source medium:medium campaign:campaign]; -} - -- (instancetype)init { - self = [super init]; - if (self) { - _dictionary = [NSMutableDictionary dictionary]; - } - return self; -} - -- (instancetype)initWithSource:(NSString *)source - medium:(NSString *)medium - campaign:(NSString *)campaign { - self = [self init]; - if (self) { - FDLSafelyAddKeyValuePairToDictionary(kFDLUTMSourceKey, [source copy], _dictionary); - FDLSafelyAddKeyValuePairToDictionary(kFDLUTMMediumKey, [medium copy], _dictionary); - FDLSafelyAddKeyValuePairToDictionary(kFDLUTMCampaignKey, [campaign copy], _dictionary); - } - return self; -} - -- (void)setSource:(NSString *)source { - FDLSafelyAddKeyValuePairToDictionary(kFDLUTMSourceKey, [source copy], _dictionary); -} - -- (NSString *)source { - return _dictionary[kFDLUTMSourceKey]; -} - -- (void)setMedium:(NSString *)medium { - FDLSafelyAddKeyValuePairToDictionary(kFDLUTMMediumKey, [medium copy], _dictionary); -} - -- (NSString *)medium { - return _dictionary[kFDLUTMMediumKey]; -} - -- (void)setCampaign:(NSString *)campaign { - FDLSafelyAddKeyValuePairToDictionary(kFDLUTMCampaignKey, [campaign copy], _dictionary); -} - -- (NSString *)campaign { - return _dictionary[kFDLUTMCampaignKey]; -} - -- (void)setTerm:(NSString *)term { - FDLSafelyAddKeyValuePairToDictionary(kFDLUTMTermKey, [term copy], _dictionary); -} - -- (NSString *)term { - return _dictionary[kFDLUTMTermKey]; -} - -- (void)setContent:(NSString *)content { - FDLSafelyAddKeyValuePairToDictionary(kFDLUTMContentKey, [content copy], _dictionary); -} - -- (NSString *)content { - return _dictionary[kFDLUTMContentKey]; -} - -- (NSDictionary *)dictionaryRepresentation { - return [_dictionary copy]; -} - -@end - -@implementation FIRDynamicLinkIOSParameters { - NSMutableDictionary *_dictionary; -} - -static NSString *const kFDLIOSBundleIdentifierKey = @"ibi"; -static NSString *const kFDLIOSAppStoreIdentifierKey = @"isi"; -static NSString *const kFDLIOSFallbackURLKey = @"ifl"; -static NSString *const kFDLIOSCustomURLSchemeKey = @"ius"; -static NSString *const kFDLIOSMinimumVersionKey = @"imv"; -static NSString *const kFDLIOSIPadBundleIdentifierKey = @"ipbi"; -static NSString *const kFDLIOSIPadFallbackURLKey = @"ipfl"; - -+ (instancetype)parametersWithBundleID:(NSString *)bundleID { - return [[self alloc] initWithBundleID:bundleID]; -} - -- (instancetype)initWithBundleID:(NSString *)bundleID { - self = [super init]; - if (self) { - _dictionary = [NSMutableDictionary dictionary]; - FDLSafelyAddKeyValuePairToDictionary(kFDLIOSBundleIdentifierKey, [bundleID copy], _dictionary); - } - return self; -} - -- (NSString *)bundleID { - return _dictionary[kFDLIOSBundleIdentifierKey]; -} - -- (void)setAppStoreID:(NSString *)appStoreID { - FDLSafelyAddKeyValuePairToDictionary(kFDLIOSAppStoreIdentifierKey, [appStoreID copy], - _dictionary); -} - -- (NSString *)appStoreID { - return _dictionary[kFDLIOSAppStoreIdentifierKey]; -} - -- (void)setFallbackURL:(NSURL *)fallbackURL { - FDLSafelyAddKeyValuePairToDictionary(kFDLIOSFallbackURLKey, fallbackURL.absoluteString, - _dictionary); -} - -- (NSURL *)fallbackURL { - NSString *fallbackURLString = _dictionary[kFDLIOSFallbackURLKey]; - return fallbackURLString != nil ? [NSURL URLWithString:fallbackURLString] : nil; -} - -- (void)setCustomScheme:(NSString *)customScheme { - FDLSafelyAddKeyValuePairToDictionary(kFDLIOSCustomURLSchemeKey, [customScheme copy], _dictionary); -} - -- (NSString *)customScheme { - return _dictionary[kFDLIOSCustomURLSchemeKey]; -} - -- (void)setMinimumAppVersion:(NSString *)minimumAppVersion { - FDLSafelyAddKeyValuePairToDictionary(kFDLIOSMinimumVersionKey, [minimumAppVersion copy], - _dictionary); -} - -- (NSString *)minimumAppVersion { - return _dictionary[kFDLIOSMinimumVersionKey]; -} - -- (void)setIPadBundleID:(NSString *)iPadBundleID { - FDLSafelyAddKeyValuePairToDictionary(kFDLIOSIPadBundleIdentifierKey, [iPadBundleID copy], - _dictionary); -} - -- (NSString *)iPadBundleID { - return _dictionary[kFDLIOSIPadBundleIdentifierKey]; -} - -- (void)setIPadFallbackURL:(NSURL *)iPadFallbackURL { - FDLSafelyAddKeyValuePairToDictionary(kFDLIOSIPadFallbackURLKey, iPadFallbackURL.absoluteString, - _dictionary); -} - -- (NSURL *)iPadFallbackURL { - NSString *fallbackURLString = _dictionary[kFDLIOSIPadFallbackURLKey]; - return fallbackURLString != nil ? [NSURL URLWithString:fallbackURLString] : nil; -} - -- (NSDictionary *)dictionaryRepresentation { - return [_dictionary copy]; -} - -@end - -@implementation FIRDynamicLinkItunesConnectAnalyticsParameters { - NSMutableDictionary *_dictionary; -} - -static NSString *const kFDLITunesConnectAffiliateTokeyKey = @"at"; -static NSString *const kFDLITunesConnectCampaignTokenKey = @"ct"; -static NSString *const kFDLITunesConnectProviderTokenKey = @"pt"; - -+ (instancetype)parameters { - return [[self alloc] init]; -} - -- (instancetype)init { - self = [super init]; - if (self) { - _dictionary = [NSMutableDictionary dictionary]; - } - return self; -} - -- (void)setAffiliateToken:(NSString *)affiliateToken { - FDLSafelyAddKeyValuePairToDictionary(kFDLITunesConnectAffiliateTokeyKey, [affiliateToken copy], - _dictionary); -} - -- (NSString *)affiliateToken { - return _dictionary[kFDLITunesConnectAffiliateTokeyKey]; -} - -- (void)setCampaignToken:(NSString *)campaignToken { - FDLSafelyAddKeyValuePairToDictionary(kFDLITunesConnectCampaignTokenKey, [campaignToken copy], - _dictionary); -} - -- (NSString *)campaignToken { - return _dictionary[kFDLITunesConnectCampaignTokenKey]; -} - -- (void)setProviderToken:(NSString *)providerToken { - FDLSafelyAddKeyValuePairToDictionary(kFDLITunesConnectProviderTokenKey, [providerToken copy], - _dictionary); -} - -- (NSString *)providerToken { - return _dictionary[kFDLITunesConnectProviderTokenKey]; -} - -- (NSDictionary *)dictionaryRepresentation { - return [_dictionary copy]; -} - -@end - -@implementation FIRDynamicLinkAndroidParameters { - NSMutableDictionary *_dictionary; -} - -static NSString *const kFDLAndroidMinimumVersionKey = @"amv"; -static NSString *const kFDLAndroidFallbackURLKey = @"afl"; -static NSString *const kFDLAndroidPackageNameKey = @"apn"; - -+ (instancetype)parametersWithPackageName:(NSString *)packageName { - return [[self alloc] initWithPackageName:packageName]; -} - -- (instancetype)initWithPackageName:(NSString *)packageName { - self = [super init]; - if (self) { - _dictionary = [NSMutableDictionary dictionary]; - FDLSafelyAddKeyValuePairToDictionary(kFDLAndroidPackageNameKey, packageName, _dictionary); - } - return self; -} - -- (NSString *)packageName { - return _dictionary[kFDLAndroidPackageNameKey]; -} - -- (void)setMinimumVersion:(NSInteger)minimumVersion { - _dictionary[kFDLAndroidMinimumVersionKey] = @(minimumVersion).stringValue; -} - -- (NSInteger)minimumVersion { - return _dictionary[kFDLAndroidMinimumVersionKey].integerValue; -} - -- (void)setFallbackURL:(NSURL *)fallbackURL { - FDLSafelyAddKeyValuePairToDictionary(kFDLAndroidFallbackURLKey, fallbackURL.absoluteString, - _dictionary); -} - -- (NSURL *)fallbackURL { - NSString *fallbackURLString = _dictionary[kFDLAndroidFallbackURLKey]; - return fallbackURLString != nil ? [NSURL URLWithString:fallbackURLString] : nil; -} - -- (NSDictionary *)dictionaryRepresentation { - return [_dictionary copy]; -} - -@end - -@implementation FIRDynamicLinkSocialMetaTagParameters { - NSMutableDictionary *_dictionary; -} - -static NSString *const kFDLSocialTitleKey = @"st"; -static NSString *const kFDLSocialDescriptionKey = @"sd"; -static NSString *const kFDLSocialImageURLKey = @"si"; - -+ (instancetype)parameters { - return [[self alloc] init]; -} - -- (instancetype)init { - self = [super init]; - if (self) { - _dictionary = [NSMutableDictionary dictionary]; - } - return self; -} - -- (void)setTitle:(NSString *)title { - FDLSafelyAddKeyValuePairToDictionary(kFDLSocialTitleKey, [title copy], _dictionary); -} - -- (NSString *)title { - return _dictionary[kFDLSocialTitleKey]; -} - -- (void)setDescriptionText:(NSString *)descriptionText { - FDLSafelyAddKeyValuePairToDictionary(kFDLSocialDescriptionKey, [descriptionText copy], - _dictionary); -} - -- (NSString *)descriptionText { - return _dictionary[kFDLSocialDescriptionKey]; -} - -- (void)setImageURL:(NSURL *)imageURL { - FDLSafelyAddKeyValuePairToDictionary(kFDLSocialImageURLKey, imageURL.absoluteString, _dictionary); -} - -- (NSURL *)imageURL { - NSString *imageURLString = _dictionary[kFDLSocialImageURLKey]; - return imageURLString != nil ? [NSURL URLWithString:imageURLString] : nil; -} - -- (NSDictionary *)dictionaryRepresentation { - return [_dictionary copy]; -} - -@end - -@implementation FIRDynamicLinkNavigationInfoParameters { - NSMutableDictionary *_dictionary; -} - -static NSString *const kFDLNavigationInfoForceRedirectKey = @"efr"; - -+ (instancetype)parameters { - return [[self alloc] init]; -} - -- (instancetype)init { - self = [super init]; - if (self) { - _dictionary = [NSMutableDictionary dictionary]; - } - return self; -} - -- (BOOL)isForcedRedirectEnabled { - return [_dictionary[kFDLNavigationInfoForceRedirectKey] boolValue]; -} - -- (void)setForcedRedirectEnabled:(BOOL)forcedRedirectEnabled { - FDLSafelyAddKeyValuePairToDictionary(kFDLNavigationInfoForceRedirectKey, - forcedRedirectEnabled ? @"1" : @"0", _dictionary); -} - -- (NSDictionary *)dictionaryRepresentation { - return [_dictionary copy]; -} - -@end - -@implementation FIRDynamicLinkOtherPlatformParameters { - NSMutableDictionary *_dictionary; -} - -static NSString *const kFDLOtherPlatformParametersFallbackURLKey = @"ofl"; - -+ (instancetype)parameters { - return [[self alloc] init]; -} - -- (instancetype)init { - self = [super init]; - if (self) { - _dictionary = [NSMutableDictionary dictionary]; - } - return self; -} - -- (NSURL *)fallbackUrl { - NSString *fallbackURLString = _dictionary[kFDLOtherPlatformParametersFallbackURLKey]; - return fallbackURLString != nil ? [NSURL URLWithString:fallbackURLString] : nil; -} - -- (void)setFallbackUrl:(NSURL *)fallbackUrl { - FDLSafelyAddKeyValuePairToDictionary(kFDLOtherPlatformParametersFallbackURLKey, - fallbackUrl.absoluteString, _dictionary); -} - -- (NSDictionary *)dictionaryRepresentation { - return [_dictionary copy]; -} - -@end - -@implementation FIRDynamicLinkComponentsOptions - -+ (instancetype)options { - return [[self alloc] init]; -} - -// This is implemented to silence the 'not implemented' warning. -- (instancetype)init { - return [super init]; -} - -@end - -@implementation FIRDynamicLinkComponents - -#pragma mark Deprecated Initializers. -+ (instancetype)componentsWithLink:(NSURL *)link domain:(NSString *)domain { - return [[self alloc] initWithLink:link domain:domain]; -} - -- (instancetype)initWithLink:(NSURL *)link domain:(NSString *)domain { - NSURL *domainURL = [NSURL URLWithString:domain]; - if (domainURL.scheme) { - FDLLog(FDLLogLevelWarning, FDLLogIdentifierSetupWarnHTTPSScheme, - @"You have supplied a domain with a scheme. Please enter a domain name without the " - @"scheme."); - } - NSString *domainURIPrefix = [NSString stringWithFormat:@"https://%@", domain]; - self = [super init]; - if (self) { - _link = link; - _domain = domainURIPrefix; - } - return self; -} - -#pragma mark Initializers. -+ (instancetype)componentsWithLink:(NSURL *)link domainURIPrefix:(NSString *)domainURIPrefix { - return [[self alloc] initWithLink:link domainURIPrefix:domainURIPrefix]; -} - -- (instancetype)initWithLink:(NSURL *)link domainURIPrefix:(NSString *)domainURIPrefix { - self = [super init]; - if (self) { - _link = link; - /// Must be a URL that conforms to RFC 2396. - NSURL *domainURIPrefixURL = [NSURL URLWithString:domainURIPrefix]; - if (!domainURIPrefixURL) { - FDLLog(FDLLogLevelError, FDLLogIdentifierSetupInvalidDomainURIPrefix, - @"Invalid domainURIPrefix. Please input a valid URL."); - return nil; - } - if (![[domainURIPrefixURL.scheme lowercaseString] isEqualToString:@"https"]) { - FDLLog(FDLLogLevelError, FDLLogIdentifierSetupInvalidDomainURIPrefixScheme, - @"Invalid domainURIPrefix scheme. Scheme needs to be https"); - return nil; - } - _domain = [domainURIPrefix copy]; - } - return self; -} - -+ (void)shortenURL:(NSURL *)url - options:(FIRDynamicLinkComponentsOptions *)options - completion:(FIRDynamicLinkShortenerCompletion)completion { - if (![FIRDynamicLinkComponentsKeyProvider APIKey]) { - NSError *error = [NSError - errorWithDomain:kFirebaseDurableDeepLinkErrorDomain - code:0 - userInfo:@{ - NSLocalizedFailureReasonErrorKey : NSLocalizedString( - @"API key is missing.", @"Error reason message when API key is missing"), - }]; - completion(nil, nil, error); - return; - } - NSURLRequest *request = [self shorteningRequestForLongURL:url options:options]; - if (!request) { - NSError *error = [NSError errorWithDomain:kFirebaseDurableDeepLinkErrorDomain - code:0 - userInfo:nil]; - completion(nil, nil, error); - return; - } - [self sendHTTPRequest:request - completion:^(NSData *_Nullable data, NSError *_Nullable error) { - NSURL *shortURL; - NSArray *warnings; - if (data != nil && error == nil) { - NSError *deserializationError; - id JSONObject = [NSJSONSerialization JSONObjectWithData:data - options:0 - error:&deserializationError]; - - if ([JSONObject isKindOfClass:[NSDictionary class]]) { - if ([JSONObject[@"shortLink"] isKindOfClass:[NSString class]]) { - shortURL = [NSURL URLWithString:JSONObject[@"shortLink"]]; - } else { - if ([JSONObject[@"error"] isKindOfClass:[NSDictionary class]]) { - NSMutableDictionary *errorUserInfo = [[NSMutableDictionary alloc] init]; - - NSDictionary *errorDictionary = JSONObject[@"error"]; - if ([errorDictionary[@"message"] isKindOfClass:[NSString class]]) { - errorUserInfo[NSLocalizedFailureReasonErrorKey] = - errorDictionary[@"message"]; - } - if ([errorDictionary[@"status"] isKindOfClass:[NSString class]]) { - errorUserInfo[@"remoteStatus"] = errorDictionary[@"status"]; - } - if (errorDictionary[@"code"] && - [errorDictionary[@"code"] isKindOfClass:[NSNumber class]]) { - errorUserInfo[@"remoteErrorCode"] = errorDictionary[@"code"]; - } - error = [NSError errorWithDomain:kFirebaseDurableDeepLinkErrorDomain - code:0 - userInfo:errorUserInfo]; - } - } - if ([JSONObject[@"warning"] isKindOfClass:[NSArray class]]) { - NSArray *warningsServer = JSONObject[@"warning"]; - NSMutableArray *warningsTmp = - [NSMutableArray arrayWithCapacity:[warningsServer count]]; - for (NSDictionary *warningServer in warningsServer) { - if ([warningServer[@"warningMessage"] isKindOfClass:[NSString class]]) { - [warningsTmp addObject:warningServer[@"warningMessage"]]; - } - } - if ([warningsTmp count] > 0) { - warnings = [warningsTmp copy]; - } - } - } else if (deserializationError) { - error = [NSError - errorWithDomain:kFirebaseDurableDeepLinkErrorDomain - code:0 - userInfo:@{ - NSLocalizedFailureReasonErrorKey : NSLocalizedString( - @"Unrecognized server response", - @"Error reason message when server response can't be parsed"), - NSUnderlyingErrorKey : deserializationError, - }]; - } - } - if (!shortURL && !error) { - // provide generic error message if we have no additional details about failure - error = [NSError errorWithDomain:kFirebaseDurableDeepLinkErrorDomain - code:0 - userInfo:nil]; - } - dispatch_async(dispatch_get_main_queue(), ^{ - completion(shortURL, warnings, error); - }); - }]; -} - -- (void)shortenWithCompletion:(FIRDynamicLinkShortenerCompletion)completion { - NSURL *url = [self url]; - if (!url) { - NSError *error = [NSError errorWithDomain:kFirebaseDurableDeepLinkErrorDomain - code:0 - userInfo:@{ - NSLocalizedFailureReasonErrorKey : NSLocalizedString( - @"Unable to produce long URL", - @"Error reason when long url can't be produced"), - }]; - completion(nil, nil, error); - return; - } - return [FIRDynamicLinkComponents shortenURL:url options:_options completion:completion]; -} - -- (NSURL *)url { - static NSString *const kFDLURLComponentsLinkKey = @"link"; - - NSMutableDictionary *queryDictionary = - [NSMutableDictionary dictionaryWithObject:self.link.absoluteString - forKey:kFDLURLComponentsLinkKey]; - - void (^addEntriesFromDictionaryRepresentingConformerToDictionary)(id) = - ^(id _Nullable dictionaryRepresentingConformer) { - NSDictionary *dictionary = dictionaryRepresentingConformer.dictionaryRepresentation; - if (dictionary.count > 0) { - [queryDictionary addEntriesFromDictionary:dictionary]; - } - }; - - addEntriesFromDictionaryRepresentingConformerToDictionary(_analyticsParameters); - addEntriesFromDictionaryRepresentingConformerToDictionary(_socialMetaTagParameters); - addEntriesFromDictionaryRepresentingConformerToDictionary(_iOSParameters); - addEntriesFromDictionaryRepresentingConformerToDictionary(_iTunesConnectParameters); - addEntriesFromDictionaryRepresentingConformerToDictionary(_androidParameters); - addEntriesFromDictionaryRepresentingConformerToDictionary(_navigationInfoParameters); - addEntriesFromDictionaryRepresentingConformerToDictionary(_otherPlatformParameters); - - NSString *queryString = FIRDLURLQueryStringFromDictionary(queryDictionary); - NSString *urlString = [NSString stringWithFormat:@"%@/%@", _domain, queryString]; - return [NSURL URLWithString:urlString]; -} - -#pragma mark Helper Methods - -+ (void)sendHTTPRequest:(NSURLRequest *)request - completion:(void (^)(NSData *_Nullable data, NSError *_Nullable error))completion { - NSURLSession *session = [NSURLSession sharedSession]; - NSURLSessionDataTask *task = - [session dataTaskWithRequest:request - completionHandler:^(NSData *_Nullable data, NSURLResponse *_Nullable response, - NSError *_Nullable error) { - completion(data, error); - }]; - [task resume]; -} - -+ (NSURLRequest *)shorteningRequestForLongURL:(NSURL *)url - options:(nullable FIRDynamicLinkComponentsOptions *)options { - if (!url) { - return nil; - } - - static NSString *const kFDLURLShortenerAPIHost = @"https://firebasedynamiclinks.googleapis.com"; - static NSString *const kFDLURLShortenerAPIPath = @"/v1/shortLinks"; - static NSString *const kFDLURLShortenerAPIQuery = @"?key="; - - NSString *apiKey = [FIRDynamicLinkComponentsKeyProvider APIKey]; - - NSString *postURLString = - [NSString stringWithFormat:@"%@%@%@%@", kFDLURLShortenerAPIHost, kFDLURLShortenerAPIPath, - kFDLURLShortenerAPIQuery, apiKey]; - NSURL *postURL = [NSURL URLWithString:postURLString]; - - NSMutableDictionary *payloadDictionary = - [NSMutableDictionary dictionaryWithObject:url.absoluteString forKey:@"longDynamicLink"]; - switch (options.pathLength) { - case FIRShortDynamicLinkPathLengthShort: - payloadDictionary[@"suffix"] = @{@"option" : @"SHORT"}; - break; - case FIRShortDynamicLinkPathLengthUnguessable: - payloadDictionary[@"suffix"] = @{@"option" : @"UNGUESSABLE"}; - break; - default: - break; - } - NSData *payload = [NSJSONSerialization dataWithJSONObject:payloadDictionary options:0 error:0]; - - NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:postURL]; - request.HTTPMethod = @"POST"; - request.HTTPBody = payload; - [request setValue:[NSBundle mainBundle].bundleIdentifier - forHTTPHeaderField:@"X-Ios-Bundle-Identifier"]; - NSString *contentType = @"application/json"; - [request setValue:contentType forHTTPHeaderField:@"Accept"]; - [request setValue:contentType forHTTPHeaderField:@"Content-Type"]; - - return [request copy]; -} - -@end - -#endif // TARGET_OS_IOS diff --git a/FirebaseDynamicLinks/Sources/FDLURLComponents/FIRDynamicLinkComponentsKeyProvider.h b/FirebaseDynamicLinks/Sources/FDLURLComponents/FIRDynamicLinkComponentsKeyProvider.h deleted file mode 100644 index a6e11dd9223..00000000000 --- a/FirebaseDynamicLinks/Sources/FDLURLComponents/FIRDynamicLinkComponentsKeyProvider.h +++ /dev/null @@ -1,23 +0,0 @@ -/* - * 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. - */ - -#import - -@interface FIRDynamicLinkComponentsKeyProvider : NSObject - -+ (nullable NSString *)APIKey; - -@end diff --git a/FirebaseDynamicLinks/Sources/FDLURLComponents/FIRDynamicLinkComponentsKeyProvider.m b/FirebaseDynamicLinks/Sources/FDLURLComponents/FIRDynamicLinkComponentsKeyProvider.m deleted file mode 100644 index 24b6c79528c..00000000000 --- a/FirebaseDynamicLinks/Sources/FDLURLComponents/FIRDynamicLinkComponentsKeyProvider.m +++ /dev/null @@ -1,39 +0,0 @@ -/* - * 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. - */ - -#import -#if TARGET_OS_IOS - -#import "FirebaseDynamicLinks/Sources/FDLURLComponents/FIRDynamicLinkComponentsKeyProvider.h" - -#import "FirebaseCore/Extension/FirebaseCoreInternal.h" - -@implementation FIRDynamicLinkComponentsKeyProvider - -+ (nullable NSString *)APIKey { - // If there's no default app, immediately return nil since reading from the default app will cause - // an error to be logged. - if (![FIRApp isDefaultAppConfigured]) { - return nil; - } - - // FDL only supports the default app, use the options from it. - return [FIRApp defaultApp].options.APIKey; -} - -@end - -#endif // TARGET_OS_IOS diff --git a/FirebaseDynamicLinks/Sources/FIRDLDefaultRetrievalProcessV2.h b/FirebaseDynamicLinks/Sources/FIRDLDefaultRetrievalProcessV2.h deleted file mode 100644 index 9d911e29e24..00000000000 --- a/FirebaseDynamicLinks/Sources/FIRDLDefaultRetrievalProcessV2.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - * 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. - */ - -#import "FirebaseDynamicLinks/Sources/FIRDLRetrievalProcessProtocols.h" - -#import - -@class FIRDynamicLinkNetworking; - -NS_ASSUME_NONNULL_BEGIN - -/** - Class to encapsulate logic related to retrieving pending dynamic link. - */ -@interface FIRDLDefaultRetrievalProcessV2 : NSObject - -- (instancetype)initWithNetworkingService:(FIRDynamicLinkNetworking *)networkingService - URLScheme:(NSString *)URLScheme - APIKey:(NSString *)APIKey - FDLSDKVersion:(NSString *)FDLSDKVersion - delegate:(id)delegate - NS_DESIGNATED_INITIALIZER; - -- (instancetype)init NS_UNAVAILABLE; - -@end - -NS_ASSUME_NONNULL_END diff --git a/FirebaseDynamicLinks/Sources/FIRDLDefaultRetrievalProcessV2.m b/FirebaseDynamicLinks/Sources/FIRDLDefaultRetrievalProcessV2.m deleted file mode 100644 index 15224d061c4..00000000000 --- a/FirebaseDynamicLinks/Sources/FIRDLDefaultRetrievalProcessV2.m +++ /dev/null @@ -1,256 +0,0 @@ -/* - * 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. - */ - -#import -#if TARGET_OS_IOS - -#import "FirebaseDynamicLinks/Sources/FIRDLDefaultRetrievalProcessV2.h" - -#import -#import "FirebaseDynamicLinks/Sources/FIRDLJavaScriptExecutor.h" -#import "FirebaseDynamicLinks/Sources/FIRDLRetrievalProcessResult+Private.h" -#import "FirebaseDynamicLinks/Sources/FIRDynamicLink+Private.h" -#import "FirebaseDynamicLinks/Sources/FIRDynamicLinkNetworking.h" -#import "FirebaseDynamicLinks/Sources/Utilities/FDLUtilities.h" - -// Reason for this string to ensure that only FDL links, copied to clipboard by AppPreview Page -// JavaScript code, are recognized and used in copy-unique-match process. If user copied FDL to -// clipboard by himself, that link must not be used in copy-unique-match process. -// This constant must be kept in sync with constant in the server version at -// durabledeeplink/click/ios/click_page.js -static NSString *expectedCopiedLinkStringSuffix = @"_icp=1"; - -NS_ASSUME_NONNULL_BEGIN - -@interface FIRDLDefaultRetrievalProcessV2 () - -@end - -@implementation FIRDLDefaultRetrievalProcessV2 { - FIRDynamicLinkNetworking *_networkingService; - NSString *_URLScheme; - NSString *_APIKey; - NSString *_FDLSDKVersion; - NSString *_clipboardContentAtMatchProcessStart; - FIRDLJavaScriptExecutor *_jsExecutor; - NSString *_localeFromWebView; -} - -@synthesize delegate = _delegate; - -#pragma mark - Initialization - -- (instancetype)initWithNetworkingService:(FIRDynamicLinkNetworking *)networkingService - URLScheme:(NSString *)URLScheme - APIKey:(NSString *)APIKey - FDLSDKVersion:(NSString *)FDLSDKVersion - delegate:(id)delegate { - NSParameterAssert(networkingService); - NSParameterAssert(URLScheme); - NSParameterAssert(APIKey); - if (self = [super init]) { - _networkingService = networkingService; - _URLScheme = [URLScheme copy]; - _APIKey = [APIKey copy]; - _FDLSDKVersion = [FDLSDKVersion copy]; - _delegate = delegate; - } - return self; -} - -#pragma mark - FIRDLRetrievalProcessProtocol - -- (void)retrievePendingDynamicLink { - if (_localeFromWebView) { - [self retrievePendingDynamicLinkInternal]; - } else { - [self fetchLocaleFromWebView]; - } -} - -#pragma mark - FIRDLJavaScriptExecutorDelegate - -- (void)javaScriptExecutor:(FIRDLJavaScriptExecutor *)executor - completedExecutionWithResult:(NSString *)result { - _localeFromWebView = result ?: @""; - _jsExecutor = nil; - [self retrievePendingDynamicLinkInternal]; -} - -- (void)javaScriptExecutor:(FIRDLJavaScriptExecutor *)executor failedWithError:(NSError *)error { - _localeFromWebView = @""; - _jsExecutor = nil; - [self retrievePendingDynamicLinkInternal]; -} - -#pragma mark - Internal methods - -- (void)retrievePendingDynamicLinkInternal { - CGRect mainScreenBounds = [UIScreen mainScreen].bounds; - NSInteger resolutionWidth = mainScreenBounds.size.width; - NSInteger resolutionHeight = mainScreenBounds.size.height; - if ([[[UIDevice currentDevice] model] isEqualToString:@"iPad"] && - UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone) { - // iPhone App running in compatibility mode on iPad - // screen resolution reported by UIDevice/UIScreen will be wrong - resolutionWidth = 0; - resolutionHeight = 0; - } - NSURL *uniqueMatchLinkToCheck = [self uniqueMatchLinkToCheck]; - - __weak __typeof__(self) weakSelf = self; - FIRPostInstallAttributionCompletionHandler completionHandler = - ^(NSDictionary *_Nullable dynamicLinkParameters, NSString *_Nullable matchMessage, - NSError *_Nullable error) { - __typeof__(self) strongSelf = weakSelf; - if (!strongSelf) { - return; - } - - FIRDynamicLink *dynamicLink; - if (dynamicLinkParameters.count) { - dynamicLink = [[FIRDynamicLink alloc] initWithParametersDictionary:dynamicLinkParameters]; - } - FIRDLRetrievalProcessResult *result = - [[FIRDLRetrievalProcessResult alloc] initWithDynamicLink:dynamicLink - error:error - message:matchMessage - matchSource:nil]; - - [strongSelf handleRetrievalProcessWithResult:result]; - if (!error) { - [strongSelf clearUsedUniqueMatchLinkToCheckFromClipboard]; - } - }; - - // Disable deprecated warning for internal methods. -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wdeprecated-declarations" - // If there is not a unique match, we will send an additional request for device heuristics based - // matching. - [_networkingService - retrievePendingDynamicLinkWithIOSVersion:[UIDevice currentDevice].systemVersion - resolutionHeight:resolutionHeight - resolutionWidth:resolutionWidth - locale:FIRDLDeviceLocale() - localeRaw:FIRDLDeviceLocaleRaw() - localeFromWebView:_localeFromWebView - timezone:FIRDLDeviceTimezone() - modelName:FIRDLDeviceModelName() - FDLSDKVersion:_FDLSDKVersion - appInstallationDate:FIRDLAppInstallationDate() - uniqueMatchVisualStyle:FIRDynamicLinkNetworkingUniqueMatchVisualStyleUnknown - retrievalProcessType: - FIRDynamicLinkNetworkingRetrievalProcessTypeImplicitDefault - uniqueMatchLinkToCheck:uniqueMatchLinkToCheck - handler:completionHandler]; -#pragma clang pop -} - -- (void)handleRetrievalProcessWithResult:(FIRDLRetrievalProcessResult *)result { - if (!result) { - // if we did not get any results, construct one - NSString *message = NSLocalizedString(@"Pending dynamic link not found", - @"Message when dynamic link was not found"); - result = [[FIRDLRetrievalProcessResult alloc] initWithDynamicLink:nil - error:nil - message:message - matchSource:nil]; - } - [self.delegate retrievalProcess:self completedWithResult:result]; -} - -- (nullable NSURL *)uniqueMatchLinkToCheck { - _clipboardContentAtMatchProcessStart = nil; - NSString *pasteboardContents = [self retrievePasteboardContents]; - if (!pasteboardContents) { - return nil; - } - NSInteger linkStringMinimumLength = - expectedCopiedLinkStringSuffix.length + /* ? or & */ 1 + /* http:// */ 7; - if ((pasteboardContents.length >= linkStringMinimumLength) && - [pasteboardContents hasSuffix:expectedCopiedLinkStringSuffix] && - [NSURL URLWithString:pasteboardContents]) { - // remove custom suffix and preceding '&' or '?' character from string - NSString *linkStringWithoutSuffix = [pasteboardContents - substringToIndex:pasteboardContents.length - expectedCopiedLinkStringSuffix.length - 1]; - NSURL *URL = [NSURL URLWithString:linkStringWithoutSuffix]; - if (URL) { - // check is link matches short link format - if (FIRDLMatchesShortLinkFormat(URL)) { - _clipboardContentAtMatchProcessStart = pasteboardContents; - return URL; - } - // check is link matches long link format - if (FIRDLCanParseUniversalLinkURL(URL)) { - _clipboardContentAtMatchProcessStart = pasteboardContents; - return URL; - } - } - } - return nil; -} - -- (nullable NSString *)retrievePasteboardContents { - if (![self isPasteboardRetrievalEnabled]) { - // Pasteboard check for dynamic link is disabled by user. - return nil; - } - - if ([[UIPasteboard generalPasteboard] hasURLs]) { - return [UIPasteboard generalPasteboard].string; - } else { - return nil; - } -} - -/** - Property to enable or disable dynamic link retrieval from Pasteboard. - This property is added because of iOS 14 feature where pop up is displayed while accessing - Pasteboard. So if developers don't want their users to see the Pasteboard popup, they can set - "FirebaseDeepLinkPasteboardRetrievalEnabled" to false in their plist. - */ -- (BOOL)isPasteboardRetrievalEnabled { - id retrievalEnabledValue = - [[NSBundle mainBundle] infoDictionary][@"FirebaseDeepLinkPasteboardRetrievalEnabled"]; - if ([retrievalEnabledValue respondsToSelector:@selector(boolValue)]) { - return [retrievalEnabledValue boolValue]; - } - return YES; -} - -- (void)clearUsedUniqueMatchLinkToCheckFromClipboard { - // See discussion in b/65304652 - // We will clear clipboard after we used the unique match link from the clipboard - if (_clipboardContentAtMatchProcessStart.length > 0 && - [_clipboardContentAtMatchProcessStart isEqualToString:_clipboardContentAtMatchProcessStart]) { - [UIPasteboard generalPasteboard].string = @""; - } -} - -- (void)fetchLocaleFromWebView { - if (_jsExecutor) { - return; - } - NSString *jsString = @"window.generateDeviceHeuristics=()=>navigator.language||''"; - _jsExecutor = [[FIRDLJavaScriptExecutor alloc] initWithDelegate:self script:jsString]; -} - -@end - -NS_ASSUME_NONNULL_END - -#endif // TARGET_OS_IOS diff --git a/FirebaseDynamicLinks/Sources/FIRDLJavaScriptExecutor.h b/FirebaseDynamicLinks/Sources/FIRDLJavaScriptExecutor.h deleted file mode 100644 index ea1952156f6..00000000000 --- a/FirebaseDynamicLinks/Sources/FIRDLJavaScriptExecutor.h +++ /dev/null @@ -1,38 +0,0 @@ -/* - * 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. - */ - -#import - -@class FIRDLJavaScriptExecutor; - -NS_ASSUME_NONNULL_BEGIN - -@protocol FIRDLJavaScriptExecutorDelegate - -- (void)javaScriptExecutor:(FIRDLJavaScriptExecutor *)executor - completedExecutionWithResult:(NSString *)result; -- (void)javaScriptExecutor:(FIRDLJavaScriptExecutor *)executor failedWithError:(NSError *)error; - -@end - -@interface FIRDLJavaScriptExecutor : NSObject - -- (instancetype)initWithDelegate:(id)delegate - script:(NSString *)script; - -@end - -NS_ASSUME_NONNULL_END diff --git a/FirebaseDynamicLinks/Sources/FIRDLJavaScriptExecutor.m b/FirebaseDynamicLinks/Sources/FIRDLJavaScriptExecutor.m deleted file mode 100644 index f90113a2438..00000000000 --- a/FirebaseDynamicLinks/Sources/FIRDLJavaScriptExecutor.m +++ /dev/null @@ -1,174 +0,0 @@ -/* - * 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. - */ - -#import -#if TARGET_OS_IOS - -#import - -#import - -#import "FirebaseDynamicLinks/Sources/FIRDLJavaScriptExecutor.h" - -NS_ASSUME_NONNULL_BEGIN - -static NSString *const kJSMethodName = @"generateDeviceHeuristics"; - -/** Creates and returns the FDL JS method name. */ -NSString *FIRDLTypeofDeviceHeuristicsJSMethodNameString(void) { - static NSString *methodName; - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ - methodName = [NSString stringWithFormat:@"typeof(%@)", kJSMethodName]; - }); - return methodName; -} - -/** Creates and returns the FDL JS method definition. */ -NSString *GINDeviceHeuristicsJSMethodString(void) { - static NSString *methodString; - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ - methodString = [NSString stringWithFormat:@"%@()", kJSMethodName]; - }); - return methodString; -} - -@interface FIRDLJavaScriptExecutor () -@end - -@implementation FIRDLJavaScriptExecutor { - __weak id _delegate; - NSString *_script; - - // Web view with which to run JavaScript. - WKWebView *_wkWebView; -} - -- (instancetype)initWithDelegate:(id)delegate - script:(NSString *)script { - NSParameterAssert(delegate); - NSParameterAssert(script); - NSParameterAssert(script.length > 0); - NSAssert([NSThread isMainThread], @"%@ must be used in main thread", - NSStringFromClass([self class])); - if (self = [super init]) { - _delegate = delegate; - _script = [script copy]; - [self start]; - } - return self; -} - -#pragma mark - Internal methods -- (void)start { -// Initializing a `WKWebView` causes a memory allocation error when the process -// is running under Rosetta translation on Apple Silicon. -// The issue only occurs on the simulator in apps targeting below iOS 14. (Issue #7618) -#if TARGET_OS_SIMULATOR - BOOL systemVersionAtLeastiOS14 = [NSProcessInfo.processInfo - isOperatingSystemAtLeastVersion:(NSOperatingSystemVersion){14, 0, 0}]; - // Perform an early exit if the process is running under Rosetta translation and targeting - // under iOS 14. - if (processIsTranslated() && !systemVersionAtLeastiOS14) { - [self handleExecutionError:nil]; - return; - } -#endif - NSString *htmlContent = - [NSString stringWithFormat:@"", _script]; - - _wkWebView = [[WKWebView alloc] init]; - _wkWebView.navigationDelegate = self; - [_wkWebView loadHTMLString:htmlContent baseURL:nil]; -} - -- (void)handleExecutionResult:(NSString *)result { - [self cleanup]; - [_delegate javaScriptExecutor:self completedExecutionWithResult:result]; -} - -- (void)handleExecutionError:(nullable NSError *)error { - [self cleanup]; - if (!error) { - error = [NSError errorWithDomain:@"com.firebase.durabledeeplink" code:-1 userInfo:nil]; - } - [_delegate javaScriptExecutor:self failedWithError:error]; -} - -- (void)cleanup { - _wkWebView.navigationDelegate = nil; - _wkWebView = nil; -} - -#pragma mark - WKNavigationDelegate - -- (void)webView:(WKWebView *)webView - didFinishNavigation:(null_unspecified WKNavigation *)navigation { - __weak __typeof__(self) weakSelf = self; - - // Make sure that the javascript was loaded successfully before calling the method. - [webView evaluateJavaScript:FIRDLTypeofDeviceHeuristicsJSMethodNameString() - completionHandler:^(id _Nullable typeofResult, NSError *_Nullable typeError) { - if (typeError) { - [weakSelf handleExecutionError:typeError]; - return; - } - if ([typeofResult isEqual:@"function"]) { - [webView - evaluateJavaScript:GINDeviceHeuristicsJSMethodString() - completionHandler:^(id _Nullable result, NSError *_Nullable functionError) { - __typeof__(self) strongSelf = weakSelf; - if ([result isKindOfClass:[NSString class]]) { - [strongSelf handleExecutionResult:result]; - } else { - [strongSelf handleExecutionError:nil]; - } - }]; - } else { - [weakSelf handleExecutionError:nil]; - } - }]; -} - -- (void)webView:(WKWebView *)webView - didFailNavigation:(null_unspecified WKNavigation *)navigation - withError:(NSError *)error { - [self handleExecutionError:error]; -} - -// Determine whether a process is running under Rosetta translation. -// Returns 0 for a native process, 1 for a translated process, -// and -1 when an error occurs. -// From: -// https://developer.apple.com/documentation/apple-silicon/about-the-rosetta-translation-environment -#if TARGET_OS_SIMULATOR -static int processIsTranslated(void) { - int ret = 0; - size_t size = sizeof(ret); - if (sysctlbyname("sysctl.proc_translated", &ret, &size, NULL, 0) == -1) { - if (errno == ENOENT) return 0; - return -1; - } - return ret; -} -#endif - -@end - -NS_ASSUME_NONNULL_END - -#endif // TARGET_OS_IOS diff --git a/FirebaseDynamicLinks/Sources/FIRDLRetrievalProcessFactory.h b/FirebaseDynamicLinks/Sources/FIRDLRetrievalProcessFactory.h deleted file mode 100644 index dfe2602694a..00000000000 --- a/FirebaseDynamicLinks/Sources/FIRDLRetrievalProcessFactory.h +++ /dev/null @@ -1,39 +0,0 @@ -/* - * 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. - */ - -#import -#import "FirebaseDynamicLinks/Sources/FIRDLRetrievalProcessProtocols.h" - -@class FIRDynamicLinkNetworking; - -NS_ASSUME_NONNULL_BEGIN - -@interface FIRDLRetrievalProcessFactory : NSObject - -- (instancetype)initWithNetworkingService:(FIRDynamicLinkNetworking *)networkingService - URLScheme:(NSString *)URLScheme - APIKey:(NSString *)APIKey - FDLSDKVersion:(NSString *)FDLSDKVersion - delegate:(id)delegate - NS_DESIGNATED_INITIALIZER; - -- (instancetype)init NS_UNAVAILABLE; - -- (id)automaticRetrievalProcess; - -@end - -NS_ASSUME_NONNULL_END diff --git a/FirebaseDynamicLinks/Sources/FIRDLRetrievalProcessFactory.m b/FirebaseDynamicLinks/Sources/FIRDLRetrievalProcessFactory.m deleted file mode 100644 index 65242212a60..00000000000 --- a/FirebaseDynamicLinks/Sources/FIRDLRetrievalProcessFactory.m +++ /dev/null @@ -1,61 +0,0 @@ -/* - * 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. - */ - -#import -#if TARGET_OS_IOS - -#import "FirebaseDynamicLinks/Sources/FIRDLRetrievalProcessFactory.h" - -#import "FirebaseDynamicLinks/Sources/FIRDLDefaultRetrievalProcessV2.h" - -NS_ASSUME_NONNULL_BEGIN - -@implementation FIRDLRetrievalProcessFactory { - FIRDynamicLinkNetworking *_networkingService; - NSString *_URLScheme; - NSString *_APIKey; - NSString *_FDLSDKVersion; - id _delegate; -} - -- (instancetype)initWithNetworkingService:(FIRDynamicLinkNetworking *)networkingService - URLScheme:(NSString *)URLScheme - APIKey:(NSString *)APIKey - FDLSDKVersion:(NSString *)FDLSDKVersion - delegate:(id)delegate { - if (self = [super init]) { - _networkingService = networkingService; - _URLScheme = URLScheme; - _APIKey = APIKey; - _FDLSDKVersion = FDLSDKVersion; - _delegate = delegate; - } - return self; -} - -- (id)automaticRetrievalProcess { - return [[FIRDLDefaultRetrievalProcessV2 alloc] initWithNetworkingService:_networkingService - URLScheme:_URLScheme - APIKey:_APIKey - FDLSDKVersion:_FDLSDKVersion - delegate:_delegate]; -} - -@end - -NS_ASSUME_NONNULL_END - -#endif // TARGET_OS_IOS diff --git a/FirebaseDynamicLinks/Sources/FIRDLRetrievalProcessProtocols.h b/FirebaseDynamicLinks/Sources/FIRDLRetrievalProcessProtocols.h deleted file mode 100644 index aeb5916208e..00000000000 --- a/FirebaseDynamicLinks/Sources/FIRDLRetrievalProcessProtocols.h +++ /dev/null @@ -1,39 +0,0 @@ -/* - * 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. - */ - -#import - -NS_ASSUME_NONNULL_BEGIN - -@protocol FIRDLRetrievalProcessProtocol; -@class FIRDLRetrievalProcessResult; - -@protocol FIRDLRetrievalProcessDelegate - -- (void)retrievalProcess:(id)retrievalProcess - completedWithResult:(FIRDLRetrievalProcessResult *)result; - -@end - -@protocol FIRDLRetrievalProcessProtocol - -@property(weak, nonatomic, readonly) id delegate; - -- (void)retrievePendingDynamicLink; - -@end - -NS_ASSUME_NONNULL_END diff --git a/FirebaseDynamicLinks/Sources/FIRDLRetrievalProcessResult+Private.h b/FirebaseDynamicLinks/Sources/FIRDLRetrievalProcessResult+Private.h deleted file mode 100644 index c14a35a06ac..00000000000 --- a/FirebaseDynamicLinks/Sources/FIRDLRetrievalProcessResult+Private.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - * 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. - */ - -#import "FirebaseDynamicLinks/Sources/FIRDLRetrievalProcessResult.h" - -NS_ASSUME_NONNULL_BEGIN - -@interface FIRDLRetrievalProcessResult () - -- (instancetype)initWithDynamicLink:(nullable FIRDynamicLink *)dynamicLink - error:(nullable NSError *)error - message:(nullable NSString *)message - matchSource:(nullable NSString *)matchSource NS_DESIGNATED_INITIALIZER; - -@end - -NS_ASSUME_NONNULL_END diff --git a/FirebaseDynamicLinks/Sources/FIRDLRetrievalProcessResult.h b/FirebaseDynamicLinks/Sources/FIRDLRetrievalProcessResult.h deleted file mode 100644 index 5f7d5c35b7d..00000000000 --- a/FirebaseDynamicLinks/Sources/FIRDLRetrievalProcessResult.h +++ /dev/null @@ -1,38 +0,0 @@ -/* - * 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. - */ - -#import - -@class FIRDynamicLink; - -NS_ASSUME_NONNULL_BEGIN - -@interface FIRDLRetrievalProcessResult : NSObject - -- (instancetype)init NS_UNAVAILABLE; - -// Method to present retrieval result as custom URL scheme URL. -// Produced URL will be passed to an application via [UIApplicationDelegate openURL:] method. -- (NSURL *)URLWithCustomURLScheme:(NSString *)customURLScheme; - -@property(nonatomic, nullable, readonly) FIRDynamicLink *dynamicLink; -@property(nonatomic, nullable, readonly) NSError *error; -@property(nonatomic, nullable, copy, readonly) NSString *message; -@property(nonatomic, nullable, copy, readonly) NSString *matchSource; - -@end - -NS_ASSUME_NONNULL_END diff --git a/FirebaseDynamicLinks/Sources/FIRDLRetrievalProcessResult.m b/FirebaseDynamicLinks/Sources/FIRDLRetrievalProcessResult.m deleted file mode 100644 index 581950e4cf4..00000000000 --- a/FirebaseDynamicLinks/Sources/FIRDLRetrievalProcessResult.m +++ /dev/null @@ -1,65 +0,0 @@ -/* - * 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. - */ - -#import -#if TARGET_OS_IOS - -#import "FirebaseDynamicLinks/Sources/FIRDLRetrievalProcessResult.h" - -#import "FirebaseDynamicLinks/Sources/FIRDLRetrievalProcessResult+Private.h" -#import "FirebaseDynamicLinks/Sources/FIRDynamicLink+Private.h" -#import "FirebaseDynamicLinks/Sources/Utilities/FDLUtilities.h" - -NS_ASSUME_NONNULL_BEGIN - -@implementation FIRDLRetrievalProcessResult - -- (instancetype)initWithDynamicLink:(nullable FIRDynamicLink *)dynamicLink - error:(nullable NSError *)error - message:(nullable NSString *)message - matchSource:(nullable NSString *)matchSource { - if (self = [super init]) { - _dynamicLink = dynamicLink; - _error = error; - _message = [message copy]; - _matchSource = [matchSource copy]; - } - return self; -} - -- (NSURL *)URLWithCustomURLScheme:(NSString *)customURLScheme { - NSURL *URL; - if (_dynamicLink) { - NSString *queryString = FIRDLURLQueryStringFromDictionary(_dynamicLink.parametersDictionary); - NSMutableString *URLString = [[NSMutableString alloc] init]; - [URLString appendString:customURLScheme]; - [URLString appendString:@"://google/link/"]; - [URLString appendString:queryString]; - URL = [NSURL URLWithString:URLString]; - } else { - NSMutableString *URLString = [[NSMutableString alloc] init]; - [URLString appendString:customURLScheme]; - [URLString appendString:@"://google/link/?dismiss=1&is_weak_match=1"]; - URL = [NSURL URLWithString:URLString]; - } - return URL; -} - -@end - -NS_ASSUME_NONNULL_END - -#endif // TARGET_OS_IOS diff --git a/FirebaseDynamicLinks/Sources/FIRDLScionLogging.h b/FirebaseDynamicLinks/Sources/FIRDLScionLogging.h deleted file mode 100644 index 1ed65a21f74..00000000000 --- a/FirebaseDynamicLinks/Sources/FIRDLScionLogging.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * 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. - */ - -#import - -#import "Interop/Analytics/Public/FIRAnalyticsInterop.h" - -/** - * @enum FIRDLLogEvent - * @abstract Types of events that may be logged to Scion. - */ -typedef NS_ENUM(NSInteger, FIRDLLogEvent) { - /** Log event where the app is first opened with a DL. */ - FIRDLLogEventFirstOpen, - /** Log event where the app is subsequently opened with a DL. */ - FIRDLLogEventAppOpen, -}; - -/** - * @fn FIRDLLogEventToScion - * @abstract Logs a given event to Scion - * @param event The event type that occurred. - * @param source The utm_source URL parameter value. - * @param medium The utm_medium URL parameter value. - * @param campaign The utm_campaign URL parameter value. - * @param analytics The class to be used as the receiver of the logging method. - */ -void FIRDLLogEventToScion(FIRDLLogEvent event, - NSString* _Nullable source, - NSString* _Nullable medium, - NSString* _Nullable campaign, - id _Nullable analytics); diff --git a/FirebaseDynamicLinks/Sources/FIRDLScionLogging.m b/FirebaseDynamicLinks/Sources/FIRDLScionLogging.m deleted file mode 100644 index 145876465d9..00000000000 --- a/FirebaseDynamicLinks/Sources/FIRDLScionLogging.m +++ /dev/null @@ -1,59 +0,0 @@ -/* - * 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. - */ - -#import -#if TARGET_OS_IOS - -#import "FirebaseDynamicLinks/Sources/FIRDLScionLogging.h" - -#import "Interop/Analytics/Public/FIRInteropParameterNames.h" - -static NSString *const kFIRDLLogEventFirstOpenCampaign = @"dynamic_link_first_open"; -static NSString *const kFIRDLLogEventAppOpenCampaign = @"dynamic_link_app_open"; - -void FIRDLLogEventToScion(FIRDLLogEvent event, - NSString *_Nullable source, - NSString *_Nullable medium, - NSString *_Nullable campaign, - id _Nullable analytics) { - NSMutableDictionary *parameters = [NSMutableDictionary dictionary]; - - if (source) { - parameters[kFIRIParameterSource] = source; - } - if (medium) { - parameters[kFIRIParameterMedium] = medium; - } - if (campaign) { - parameters[kFIRIParameterCampaign] = campaign; - } - - NSString *name; - switch (event) { - case FIRDLLogEventFirstOpen: - name = kFIRDLLogEventFirstOpenCampaign; - break; - case FIRDLLogEventAppOpen: - name = kFIRDLLogEventAppOpenCampaign; - break; - } - - if (name) { - [analytics logEventWithOrigin:@"fdl" name:name parameters:parameters]; - } -} - -#endif // TARGET_OS_IOS diff --git a/FirebaseDynamicLinks/Sources/FIRDynamicLink+Private.h b/FirebaseDynamicLinks/Sources/FIRDynamicLink+Private.h deleted file mode 100644 index 8e26bf3a511..00000000000 --- a/FirebaseDynamicLinks/Sources/FIRDynamicLink+Private.h +++ /dev/null @@ -1,52 +0,0 @@ -/* - * 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. - */ - -#import "FirebaseDynamicLinks/Sources/Public/FirebaseDynamicLinks/FIRDynamicLink.h" - -NS_ASSUME_NONNULL_BEGIN - -@interface FIRDynamicLink () - -typedef NS_ENUM(NSUInteger, FIRDynamicLinkMatchConfidence) { - FIRDynamicLinkMatchConfidenceWeak, - FIRDynamicLinkMatchConfidenceStrong -} NS_SWIFT_NAME(DynamicLinkMatchConfidence) DEPRECATED_MSG_ATTRIBUTE("Use FIRDLMatchType instead."); - -@property(nonatomic, assign, readonly) - FIRDynamicLinkMatchConfidence matchConfidence DEPRECATED_MSG_ATTRIBUTE( - "Use FIRDynamicLink.matchType (DynamicLink.DLMatchType) instead."); - -@property(nonatomic, copy, nullable) NSURL *url; - -@property(nonatomic, copy, readwrite, nullable) NSString *minimumAppVersion; - -// The invite ID retrieved from the dynamic link. -@property(nonatomic, copy, nullable) NSString *inviteId; - -// Whether the received invite is matched via ipv4 or ipv6 endpoint. -@property(nonatomic, copy, nullable) NSString *weakMatchEndpoint; - -@property(nonatomic, copy, nullable) NSString *matchMessage; - -@property(nonatomic, copy, readonly) NSDictionary *parametersDictionary; - -@property(nonatomic, assign, readwrite) FIRDLMatchType matchType; - -- (instancetype)initWithParametersDictionary:(NSDictionary *)parametersDictionary; - -@end - -NS_ASSUME_NONNULL_END diff --git a/FirebaseDynamicLinks/Sources/FIRDynamicLink.m b/FirebaseDynamicLinks/Sources/FIRDynamicLink.m deleted file mode 100644 index 7a322a9ca09..00000000000 --- a/FirebaseDynamicLinks/Sources/FIRDynamicLink.m +++ /dev/null @@ -1,153 +0,0 @@ -/* - * 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. - */ - -#import -#if TARGET_OS_IOS - -#import "FirebaseDynamicLinks/Sources/FIRDynamicLink+Private.h" - -#import "FirebaseDynamicLinks/Sources/Utilities/FDLUtilities.h" - -@implementation FIRDynamicLink - -NSString *const FDLUTMParamPrefix = @"utm_"; - -- (NSString *)description { - return [NSString stringWithFormat:@"<%@: %p, url [%@], match type: %@, minimumAppVersion: %@, " - "match message: %@>", - NSStringFromClass([self class]), self, self.url, - [[self class] stringWithMatchType:_matchType], - self.minimumAppVersion ?: @"N/A", self.matchMessage]; -} - -- (instancetype)initWithParametersDictionary:(NSDictionary *)parameters { - NSParameterAssert(parameters.count > 0); - - if (self = [super init]) { - _parametersDictionary = [parameters copy]; - _utmParametersDictionary = [[self class] extractUTMParams:parameters]; - NSString *urlString = parameters[kFIRDLParameterDeepLinkIdentifier]; - _url = [NSURL URLWithString:urlString]; - _inviteId = parameters[kFIRDLParameterInviteId]; - _weakMatchEndpoint = parameters[kFIRDLParameterWeakMatchEndpoint]; - _minimumAppVersion = parameters[kFIRDLParameterMinimumAppVersion]; - - if (parameters[kFIRDLParameterMatchType]) { - [self setMatchType:[[self class] matchTypeWithString:parameters[kFIRDLParameterMatchType]]]; - } else if (_url || _inviteId) { - // If matchType not present assume unique match for compatibility with server side behavior - // on iOS 8. - [self setMatchType:FIRDLMatchTypeUnique]; - } - - _matchMessage = parameters[kFIRDLParameterMatchMessage]; - } - return self; -} - -#pragma mark - Properties - -- (void)setUrl:(NSURL *)url { - _url = [url copy]; - [self setParametersDictionaryValue:[_url absoluteString] - forKey:kFIRDLParameterDeepLinkIdentifier]; -} - -- (void)setMinimumAppVersion:(NSString *)minimumAppVersion { - _minimumAppVersion = [minimumAppVersion copy]; - [self setParametersDictionaryValue:_minimumAppVersion forKey:kFIRDLParameterMinimumAppVersion]; -} - -- (void)setInviteId:(NSString *)inviteId { - _inviteId = [inviteId copy]; - [self setParametersDictionaryValue:_inviteId forKey:kFIRDLParameterInviteId]; -} - -- (void)setWeakMatchEndpoint:(NSString *)weakMatchEndpoint { - _weakMatchEndpoint = [weakMatchEndpoint copy]; - [self setParametersDictionaryValue:_weakMatchEndpoint forKey:kFIRDLParameterWeakMatchEndpoint]; -} - -- (void)setMatchType:(FIRDLMatchType)matchType { - _matchType = matchType; - [self setParametersDictionaryValue:[[self class] stringWithMatchType:_matchType] - forKey:kFIRDLParameterMatchType]; -} - -- (void)setMatchMessage:(NSString *)matchMessage { - _matchMessage = [matchMessage copy]; - [self setParametersDictionaryValue:_matchMessage forKey:kFIRDLParameterMatchMessage]; -} - -- (void)setParametersDictionaryValue:(id)value forKey:(NSString *)key { - NSMutableDictionary *parametersDictionary = - [self.parametersDictionary mutableCopy]; - if (value == nil) { - [parametersDictionary removeObjectForKey:key]; - } else { - parametersDictionary[key] = value; - } - - _parametersDictionary = [parametersDictionary copy]; -} - -- (FIRDynamicLinkMatchConfidence)matchConfidence { - return (_matchType == FIRDLMatchTypeUnique) ? FIRDynamicLinkMatchConfidenceStrong - : FIRDynamicLinkMatchConfidenceWeak; -} - -+ (NSString *)stringWithMatchType:(FIRDLMatchType)matchType { - switch (matchType) { - case FIRDLMatchTypeNone: - return @"none"; - case FIRDLMatchTypeWeak: - return @"weak"; - case FIRDLMatchTypeDefault: - return @"default"; - case FIRDLMatchTypeUnique: - return @"unique"; - } -} - -+ (FIRDLMatchType)matchTypeWithString:(NSString *)string { - static NSDictionary *matchMap; - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ - matchMap = @{ - @"none" : @(FIRDLMatchTypeNone), - @"weak" : @(FIRDLMatchTypeWeak), - @"default" : @(FIRDLMatchTypeDefault), - @"unique" : @(FIRDLMatchTypeUnique), - }; - }); - return [matchMap[string] integerValue] ?: FIRDLMatchTypeNone; -} - -+ (NSDictionary *)extractUTMParams:(NSDictionary *)parameters { - NSMutableDictionary *utmParamsDictionary = [[NSMutableDictionary alloc] init]; - - for (NSString *key in parameters) { - if ([key hasPrefix:FDLUTMParamPrefix]) { - [utmParamsDictionary setObject:[parameters valueForKey:key] forKey:key]; - } - } - - return [[NSDictionary alloc] initWithDictionary:utmParamsDictionary]; -} - -@end - -#endif // TARGET_OS_IOS diff --git a/FirebaseDynamicLinks/Sources/FIRDynamicLinkNetworking+Private.h b/FirebaseDynamicLinks/Sources/FIRDynamicLinkNetworking+Private.h deleted file mode 100644 index 8a41ccfbd91..00000000000 --- a/FirebaseDynamicLinks/Sources/FIRDynamicLinkNetworking+Private.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - * 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. - */ - -#import "FirebaseDynamicLinks/Sources/FIRDynamicLinkNetworking.h" - -NS_ASSUME_NONNULL_BEGIN - -/** The key for the DL URL. */ -FOUNDATION_EXPORT NSString *const kFDLResolvedLinkDeepLinkURLKey; -/** The key for the minimum iOS app version. */ -FOUNDATION_EXPORT NSString *const kFDLResolvedLinkMinAppVersionKey; - -// Private interface for testing. -@interface FIRDynamicLinkNetworking () - -/** - * @method executeOnePlatformRequest:forURL:eventString:completionHandler: - * @abstract Creates and sends a OnePlatform HTTP request. Also adds the necessary header. - * @param requestBody The body of the request. Values may be added to this. - * @param requestURLString The URL to which to send the request. - * @param handler A block to be executed upon completion. Guaranteed to be called, but not - * always on the main thread. - */ -- (void)executeOnePlatformRequest:(NSDictionary *)requestBody - forURL:(NSString *)requestURLString - completionHandler:(FIRNetworkRequestCompletionHandler)handler; - -@end - -/** Encodes the API key in a query parameter string. */ -NSString *_Nullable FIRDynamicLinkAPIKeyParameter(NSString *apiKey); - -/** Creates and returns an NSData object from an NSDictionary along with any error. */ -NSData *_Nullable FIRDataWithDictionary(NSDictionary *dictionary, NSError **_Nullable error); - -NS_ASSUME_NONNULL_END diff --git a/FirebaseDynamicLinks/Sources/FIRDynamicLinkNetworking.h b/FirebaseDynamicLinks/Sources/FIRDynamicLinkNetworking.h deleted file mode 100644 index 6f59960dd3e..00000000000 --- a/FirebaseDynamicLinks/Sources/FIRDynamicLinkNetworking.h +++ /dev/null @@ -1,133 +0,0 @@ -/* - * 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. - */ - -#import - -#import "FirebaseDynamicLinks/Sources/Public/FirebaseDynamicLinks/FIRDynamicLinksCommon.h" - -NS_ASSUME_NONNULL_BEGIN - -/** A definition for a block used by methods that are asynchronous and may produce errors. */ -typedef void (^FIRDynamicLinkNetworkingErrorHandler)(NSError *_Nullable error); - -/** A definition for a block used to return a pending Dynamic Link. */ -typedef void (^FIRPostInstallAttributionCompletionHandler)( - NSDictionary *_Nullable dynamicLinkParameters, - NSString *_Nullable matchMessage, - NSError *_Nullable error); - -/** A definition for a block used to return data and errors after an asynchronous task. */ -typedef void (^FIRNetworkRequestCompletionHandler)(NSData *_Nullable data, - NSURLResponse *_Nullable response, - NSError *_Nullable error); - -// these enums must be in sync with google/firebase/dynamiclinks/v1/dynamic_links.proto -typedef NS_ENUM(NSInteger, FIRDynamicLinkNetworkingUniqueMatchVisualStyle) { - // Unknown style. - FIRDynamicLinkNetworkingUniqueMatchVisualStyleUnknown = 0, - // Default style. - FIRDynamicLinkNetworkingUniqueMatchVisualStyleDefault = 1, - // Custom style. - FIRDynamicLinkNetworkingUniqueMatchVisualStyleCustom = 2, -}; - -typedef NS_ENUM(NSInteger, FIRDynamicLinkNetworkingRetrievalProcessType) { - // Unknown method. - FIRDynamicLinkNetworkingRetrievalProcessTypeUnknown = 0, - // iSDK performs a server lookup using default match in the background - // when app is first-opened; no API called by developer. - FIRDynamicLinkNetworkingRetrievalProcessTypeImplicitDefault = 1, - // iSDK performs a server lookup by device heuristics upon a dev API call. - FIRDynamicLinkNetworkingRetrievalProcessTypeExplicitDefault = 2, - // iSDK performs a unique match only if default match is found upon a dev - // API call. - FIRDynamicLinkNetworkingRetrievalProcessTypeOptionalUnique = 3, -}; - -/** - * @fn FIRMakeHTTPRequest - * @abstract A basic and simple network request method. - * @param request The NSURLRequest with which to perform the network request. - * @param completion The handler executed after the request has completed. - */ -void FIRMakeHTTPRequest(NSURLRequest *request, FIRNetworkRequestCompletionHandler completion); - -/** The base of the FDL API URL */ -FOUNDATION_EXPORT NSString *const kApiaryRestBaseUrl; - -/** - * @class FIRDynamicLinkNetworking - * @abstract The class used to handle all network communications for the service. - */ -@interface FIRDynamicLinkNetworking : NSObject - -/** - * @method initWithAPIKey:URLScheme: - * @param URLScheme Custom URL scheme of the app. - * @param APIKey API Key value. - */ -- (instancetype)initWithAPIKey:(NSString *)APIKey - URLScheme:(NSString *)URLScheme NS_DESIGNATED_INITIALIZER; - -- (instancetype)init NS_UNAVAILABLE; - -/** - * @method resolveShortLink:URLScheme:APIKey:completion: - * @abstract Retrieves the details of the durable link that the shortened URL represents - * @param url A Short Dynamic Link. - * @param completion Block to be run upon completion. - */ -- (void)resolveShortLink:(NSURL *)url - FDLSDKVersion:(NSString *)FDLSDKVersion - completion:(FIRDynamicLinkResolverHandler)completion; - -/** - * @method - * retrievePendingDynamicLinkWithIOSVersion:resolutionHeight:resolutionWidth:locale:localeRaw:timezone:modelName:FDLSDKVersion:appInstallationDate:uniqueMatchVisualStyle:retrievalProcessType:handler: - * @abstract Retrieves a pending link from the server using the supplied device info and returns it - * by executing the completion handler. - */ -- (void)retrievePendingDynamicLinkWithIOSVersion:(NSString *)IOSVersion - resolutionHeight:(NSInteger)resolutionHeight - resolutionWidth:(NSInteger)resolutionWidth - locale:(NSString *)locale - localeRaw:(NSString *)localeRaw - localeFromWebView:(NSString *)localeFromWebView - timezone:(NSString *)timezone - modelName:(NSString *)modelName - FDLSDKVersion:(NSString *)FDLSDKVersion - appInstallationDate:(NSDate *_Nullable)appInstallationDate - uniqueMatchVisualStyle: - (FIRDynamicLinkNetworkingUniqueMatchVisualStyle)uniqueMatchVisualStyle - retrievalProcessType: - (FIRDynamicLinkNetworkingRetrievalProcessType)retrievalProcessType - uniqueMatchLinkToCheck:(NSURL *)uniqueMatchLinkToCheck - handler: - (FIRPostInstallAttributionCompletionHandler)handler; -/** - * @method convertInvitation:handler: - * @abstract Marks an invitation as converted. You should call this method in your application after - * the user performs an action that represents a successful conversion. - * @param invitationID The invitation ID of the link. - * @param handler A block that is called upon completion. If successful, the error parameter will be - * nil. This is always executed on the main thread. - */ -- (void)convertInvitation:(NSString *)invitationID - handler:(nullable FIRDynamicLinkNetworkingErrorHandler)handler; - -@end - -NS_ASSUME_NONNULL_END diff --git a/FirebaseDynamicLinks/Sources/FIRDynamicLinkNetworking.m b/FirebaseDynamicLinks/Sources/FIRDynamicLinkNetworking.m deleted file mode 100644 index 476bf044f0c..00000000000 --- a/FirebaseDynamicLinks/Sources/FIRDynamicLinkNetworking.m +++ /dev/null @@ -1,369 +0,0 @@ -/* - * 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. - */ - -#import -#if TARGET_OS_IOS - -#import "FirebaseDynamicLinks/Sources/FIRDynamicLinkNetworking+Private.h" - -#import "FirebaseDynamicLinks/Sources/GINInvocation/GINArgument.h" -#import "FirebaseDynamicLinks/Sources/GINInvocation/GINInvocation.h" -#import "FirebaseDynamicLinks/Sources/Utilities/FDLDeviceHeuristicsHelper.h" -#import "FirebaseDynamicLinks/Sources/Utilities/FDLUtilities.h" - -NS_ASSUME_NONNULL_BEGIN - -NSString *const kApiaryRestBaseUrl = @"https://appinvite-pa.googleapis.com/v1"; -static NSString *const kiOSReopenRestBaseUrl = @"https://firebasedynamiclinks.googleapis.com/v1"; - -// Endpoint for default retrieval process V2. (Endpoint version is V1) -static NSString *const kIosPostInstallAttributionRestBaseUrl = - @"https://firebasedynamiclinks.googleapis.com/v1"; - -static NSString *const kReasonString = @"reason"; -static NSString *const kiOSInviteReason = @"ios_invite"; - -NSString *const kFDLResolvedLinkDeepLinkURLKey = @"deepLink"; -NSString *const kFDLResolvedLinkMinAppVersionKey = @"iosMinAppVersion"; -static NSString *const kFDLAnalyticsDataSourceKey = @"utmSource"; -static NSString *const kFDLAnalyticsDataMediumKey = @"utmMedium"; -static NSString *const kFDLAnalyticsDataCampaignKey = @"utmCampaign"; -static NSString *const kFDLAnalyticsDataTermKey = @"utmTerm"; -static NSString *const kFDLAnalyticsDataContentKey = @"utmContent"; -static NSString *const kHeaderIosBundleIdentifier = @"X-Ios-Bundle-Identifier"; -static NSString *const kGenericErrorDomain = @"com.firebase.dynamicLinks"; - -typedef NSDictionary *_Nullable (^FIRDLNetworkingParserBlock)( - NSString *requestURLString, - NSData *data, - NSString *_Nullable *_Nonnull matchMessagePtr, - NSError *_Nullable *_Nullable errorPtr); - -NSString *FIRURLParameterString(NSString *key, NSString *value) { - if (key.length > 0) { - return [NSString stringWithFormat:@"?%@=%@", key, value]; - } - return @""; -} - -NSString *_Nullable FIRDynamicLinkAPIKeyParameter(NSString *apiKey) { - return apiKey ? FIRURLParameterString(@"key", apiKey) : nil; -} - -void FIRMakeHTTPRequest(NSURLRequest *request, FIRNetworkRequestCompletionHandler completion) { - NSURLSessionConfiguration *sessionConfig = - [NSURLSessionConfiguration defaultSessionConfiguration]; - NSURLSession *session = [NSURLSession sessionWithConfiguration:sessionConfig]; - NSURLSessionDataTask *dataTask = - [session dataTaskWithRequest:request - completionHandler:^(NSData *_Nullable data, NSURLResponse *_Nullable response, - NSError *_Nullable error) { - completion(data, response, error); - }]; - [dataTask resume]; -} - -NSData *_Nullable FIRDataWithDictionary(NSDictionary *dictionary, NSError **_Nullable error) { - return [NSJSONSerialization dataWithJSONObject:dictionary options:0 error:error]; -} - -@implementation FIRDynamicLinkNetworking { - NSString *_APIKey; - NSString *_URLScheme; -} - -- (instancetype)initWithAPIKey:(NSString *)APIKey URLScheme:(NSString *)URLScheme { - NSParameterAssert(APIKey); - NSParameterAssert(URLScheme); - if (self = [super init]) { - _APIKey = [APIKey copy]; - _URLScheme = [URLScheme copy]; - } - return self; -} - -+ (nullable NSError *)extractErrorForShortLink:(NSURL *)url - data:(NSData *)data - response:(NSURLResponse *)response - error:(nullable NSError *)error { - if (error) { - return error; - } - - NSInteger statusCode = [(NSHTTPURLResponse *)response statusCode]; - NSError *customError = nil; - - if (![response isKindOfClass:[NSHTTPURLResponse class]]) { - customError = - [NSError errorWithDomain:kGenericErrorDomain - code:0 - userInfo:@{@"message" : @"Response should be of type NSHTTPURLResponse."}]; - } else if ((statusCode < 200 || statusCode >= 300) && data) { - NSDictionary *result = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil]; - if ([result isKindOfClass:[NSDictionary class]] && [result objectForKey:@"error"]) { - id err = [result objectForKey:@"error"]; - customError = [NSError errorWithDomain:kGenericErrorDomain code:statusCode userInfo:err]; - } else { - customError = [NSError - errorWithDomain:kGenericErrorDomain - code:0 - userInfo:@{ - @"message" : - [NSString stringWithFormat:@"Failed to resolve link: %@", url.absoluteString] - }]; - } - } - - return customError; -} - -#pragma mark - Public interface - -- (void)resolveShortLink:(NSURL *)url - FDLSDKVersion:(NSString *)FDLSDKVersion - completion:(FIRDynamicLinkResolverHandler)handler { - NSParameterAssert(handler); - if (!url) { - handler(nil, nil); - return; - } - - NSDictionary *requestBody = @{ - @"requestedLink" : url.absoluteString, - @"bundle_id" : [NSBundle mainBundle].bundleIdentifier, - @"sdk_version" : FDLSDKVersion - }; - - FIRNetworkRequestCompletionHandler resolveLinkCallback = - ^(NSData *data, NSURLResponse *response, NSError *error) { - NSURL *resolvedURL = nil; - NSError *extractedError = [FIRDynamicLinkNetworking extractErrorForShortLink:url - data:data - response:response - error:error]; - - if (!extractedError && data) { - NSDictionary *result = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil]; - if ([result isKindOfClass:[NSDictionary class]]) { - id invitationIDObject = [result objectForKey:@"invitationId"]; - - NSString *invitationIDString; - if ([invitationIDObject isKindOfClass:[NSDictionary class]]) { - NSDictionary *invitationIDDictionary = invitationIDObject; - invitationIDString = invitationIDDictionary[@"id"]; - } else if ([invitationIDObject isKindOfClass:[NSString class]]) { - invitationIDString = invitationIDObject; - } - - NSString *deepLinkString = result[kFDLResolvedLinkDeepLinkURLKey]; - NSString *minAppVersion = result[kFDLResolvedLinkMinAppVersionKey]; - NSString *utmSource = result[kFDLAnalyticsDataSourceKey]; - NSString *utmMedium = result[kFDLAnalyticsDataMediumKey]; - NSString *utmCampaign = result[kFDLAnalyticsDataCampaignKey]; - NSString *utmContent = result[kFDLAnalyticsDataContentKey]; - NSString *utmTerm = result[kFDLAnalyticsDataTermKey]; - resolvedURL = FIRDLDeepLinkURLWithInviteID( - invitationIDString, deepLinkString, utmSource, utmMedium, utmCampaign, utmContent, - utmTerm, NO, nil, minAppVersion, self->_URLScheme, nil); - } - } - handler(resolvedURL, extractedError); - }; - - NSString *requestURLString = - [NSString stringWithFormat:@"%@/reopenAttribution%@", kiOSReopenRestBaseUrl, - FIRDynamicLinkAPIKeyParameter(_APIKey)]; - [self executeOnePlatformRequest:requestBody - forURL:requestURLString - completionHandler:resolveLinkCallback]; -} - -- (void)retrievePendingDynamicLinkWithIOSVersion:(NSString *)IOSVersion - resolutionHeight:(NSInteger)resolutionHeight - resolutionWidth:(NSInteger)resolutionWidth - locale:(NSString *)locale - localeRaw:(NSString *)localeRaw - localeFromWebView:(NSString *)localeFromWebView - timezone:(NSString *)timezone - modelName:(NSString *)modelName - FDLSDKVersion:(NSString *)FDLSDKVersion - appInstallationDate:(NSDate *_Nullable)appInstallationDate - uniqueMatchVisualStyle: - (FIRDynamicLinkNetworkingUniqueMatchVisualStyle)uniqueMatchVisualStyle - retrievalProcessType: - (FIRDynamicLinkNetworkingRetrievalProcessType)retrievalProcessType - uniqueMatchLinkToCheck:(NSURL *)uniqueMatchLinkToCheck - handler: - (FIRPostInstallAttributionCompletionHandler)handler { - NSParameterAssert(handler); - - NSMutableDictionary *requestBody = [@{ - @"bundleId" : [NSBundle mainBundle].bundleIdentifier, - @"device" : - [FDLDeviceHeuristicsHelper FDLDeviceInfoDictionaryFromResolutionHeight:resolutionHeight - resolutionWidth:resolutionWidth - locale:locale - localeRaw:localeRaw - localeFromWebview:localeFromWebView - timeZone:timezone - modelName:modelName], - @"iosVersion" : IOSVersion, - @"sdkVersion" : FDLSDKVersion, - @"visualStyle" : @(uniqueMatchVisualStyle), - @"retrievalMethod" : @(retrievalProcessType), - } mutableCopy]; - if (appInstallationDate) { - requestBody[@"appInstallationTime"] = @((NSInteger)[appInstallationDate timeIntervalSince1970]); - } - if (uniqueMatchLinkToCheck) { - requestBody[@"uniqueMatchLinkToCheck"] = uniqueMatchLinkToCheck.absoluteString; - } - - FIRDLNetworkingParserBlock responseParserBlock = ^NSDictionary *_Nullable( - NSString *requestURLString, NSData *data, NSString **matchMessagePtr, NSError **errorPtr) { - NSError *serializationError; - NSDictionary *result = [NSJSONSerialization JSONObjectWithData:data - options:0 - error:&serializationError]; - - if (serializationError) { - if (errorPtr != nil) { - *errorPtr = serializationError; - } - return nil; - } - - NSString *matchMessage = result[@"matchMessage"]; - if (matchMessage.length) { - *matchMessagePtr = matchMessage; - } - - // Create the dynamic link parameters - NSMutableDictionary *dynamicLinkParameters = [[NSMutableDictionary alloc] init]; - dynamicLinkParameters[kFIRDLParameterInviteId] = result[@"invitationId"]; - dynamicLinkParameters[kFIRDLParameterDeepLinkIdentifier] = result[@"deepLink"]; - if (result[@"deepLink"]) { - dynamicLinkParameters[kFIRDLParameterMatchType] = - FIRDLMatchTypeStringFromServerString(result[@"attributionConfidence"]); - } - dynamicLinkParameters[kFIRDLParameterSource] = result[@"utmSource"]; - dynamicLinkParameters[kFIRDLParameterMedium] = result[@"utmMedium"]; - dynamicLinkParameters[kFIRDLParameterCampaign] = result[@"utmCampaign"]; - dynamicLinkParameters[kFIRDLParameterMinimumAppVersion] = result[@"appMinimumVersion"]; - dynamicLinkParameters[kFIRDLParameterRequestIPVersion] = result[@"requestIpVersion"]; - dynamicLinkParameters[kFIRDLParameterMatchMessage] = matchMessage; - - return [dynamicLinkParameters copy]; - }; - - [self sendRequestWithBaseURLString:kIosPostInstallAttributionRestBaseUrl - requestBody:requestBody - endpointPath:@"installAttribution" - parserBlock:responseParserBlock - completion:handler]; -} - -- (void)convertInvitation:(NSString *)invitationID - handler:(nullable FIRDynamicLinkNetworkingErrorHandler)handler { - if (!invitationID) { - return; - } - - NSDictionary *requestBody = @{ - @"invitationId" : @{@"id" : invitationID}, - @"containerClientId" : @{ - @"type" : @"IOS", - } - }; - - FIRNetworkRequestCompletionHandler convertInvitationCallback = - ^(NSData *data, NSURLResponse *response, NSError *error) { - if (handler) { - dispatch_async(dispatch_get_main_queue(), ^{ - handler(error); - }); - } - }; - - NSString *requestURL = [NSString stringWithFormat:@"%@/convertInvitation%@", kApiaryRestBaseUrl, - FIRDynamicLinkAPIKeyParameter(_APIKey)]; - - [self executeOnePlatformRequest:requestBody - forURL:requestURL - completionHandler:convertInvitationCallback]; -} - -#pragma mark - Internal methods - -- (void)sendRequestWithBaseURLString:(NSString *)baseURL - requestBody:(NSDictionary *)requestBody - endpointPath:(NSString *)endpointPath - parserBlock:(FIRDLNetworkingParserBlock)parserBlock - completion:(FIRPostInstallAttributionCompletionHandler)handler { - NSParameterAssert(handler); - NSString *requestURLString = [NSString - stringWithFormat:@"%@/%@%@", baseURL, endpointPath, FIRDynamicLinkAPIKeyParameter(_APIKey)]; - - FIRNetworkRequestCompletionHandler completeInvitationByDeviceCallback = - ^(NSData *data, NSURLResponse *response, NSError *error) { - if (error || !data) { - dispatch_async(dispatch_get_main_queue(), ^{ - handler(nil, nil, error); - }); - return; - } - - NSString *matchMessage = nil; - NSError *parsingError = nil; - NSDictionary *parsedDynamicLinkParameters = - parserBlock(requestURLString, data, &matchMessage, &parsingError); - - dispatch_async(dispatch_get_main_queue(), ^{ - handler(parsedDynamicLinkParameters, matchMessage, parsingError); - }); - }; - - [self executeOnePlatformRequest:requestBody - forURL:requestURLString - completionHandler:completeInvitationByDeviceCallback]; -} - -- (void)executeOnePlatformRequest:(NSDictionary *)requestBody - forURL:(NSString *)requestURLString - completionHandler:(FIRNetworkRequestCompletionHandler)handler { - NSURL *requestURL = [NSURL URLWithString:requestURLString]; - - NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:requestURL]; - - // TODO: Verify that HTTPBody and HTTPMethod are iOS 8+ and find an alternative. - request.HTTPBody = FIRDataWithDictionary(requestBody, nil); - request.HTTPMethod = @"POST"; - - [request setValue:@"application/json; charset=utf-8" forHTTPHeaderField:@"Content-Type"]; - - // Set the iOS bundleID as a request header. - NSString *bundleID = [[NSBundle mainBundle] bundleIdentifier]; - if (bundleID) { - [request setValue:bundleID forHTTPHeaderField:kHeaderIosBundleIdentifier]; - } - FIRMakeHTTPRequest(request, handler); -} - -@end - -NS_ASSUME_NONNULL_END - -#endif // TARGET_OS_IOS diff --git a/FirebaseDynamicLinks/Sources/FIRDynamicLinks+FirstParty.h b/FirebaseDynamicLinks/Sources/FIRDynamicLinks+FirstParty.h deleted file mode 100644 index db277969d7a..00000000000 --- a/FirebaseDynamicLinks/Sources/FIRDynamicLinks+FirstParty.h +++ /dev/null @@ -1,122 +0,0 @@ -/* - * 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. - */ - -#import "FirebaseDynamicLinks/Sources/Public/FirebaseDynamicLinks/FIRDynamicLinks.h" // IWYU pragma: export - -#import "FirebaseDynamicLinks/Sources/FIRDynamicLink+Private.h" - -@class UIViewController; - -NS_ASSUME_NONNULL_BEGIN - -@interface FIRDynamicLinks (FirstParty) - -/** - * @method setUpWithLaunchOptions::apiKey:clientID:urlScheme:userDefaults: - * @abstract Set up Dynamic Links. - * @param launchOptions launchOptions from |application:didFinishLaunchingWithOptions:|. If nil, the - * deep link may appear twice on iOS 9 if a user clicks on a link before opening the app. - * @param apiKey API key for API access. - * @param clientID client ID for API access. - * @param urlScheme A custom url scheme used by the application. If nil, bundle id will be used. - * @param userDefaults The defaults from a user’s defaults database. If nil, standard - * NSUserDefaults will be used. - * @return whether the Dynamic Links was set up successfully. - */ -- (BOOL)setUpWithLaunchOptions:(nullable NSDictionary *)launchOptions - apiKey:(NSString *)apiKey - clientID:(NSString *)clientID - urlScheme:(nullable NSString *)urlScheme - userDefaults:(nullable NSUserDefaults *)userDefaults - DEPRECATED_MSG_ATTRIBUTE( - "Use [FIRDynamicLinks setUpWithLaunchOptions::apiKey:urlScheme:userDefaults:] instead."); - -/** - * @method setUpWithLaunchOptions::apiKey:urlScheme:userDefaults: - * @abstract Set up Dynamic Links. - * @param launchOptions launchOptions from |application:didFinishLaunchingWithOptions:|. If nil, the - * deep link may appear twice on iOS 9 if a user clicks on a link before opening the app. - * @param apiKey API key for API access. - * @param urlScheme A custom url scheme used by the application. If nil, bundle id will be used. - * @param userDefaults The defaults from a user’s defaults database. If nil, standard - * NSUserDefaults will be used. - * @return whether the Dynamic Links was set up successfully. - */ -- (BOOL)setUpWithLaunchOptions:(nullable NSDictionary *)launchOptions - apiKey:(NSString *)apiKey - urlScheme:(nullable NSString *)urlScheme - userDefaults:(nullable NSUserDefaults *)userDefaults; - -/** - * @method checkForPendingDynamicLink - * @abstract check for a pending Dynamic Link. This method should be called from your - * |UIApplicationDelegate|'s |application:didFinishLaunchingWithOptions:|. If a Dynamic Link is - * found, you'll receive an URL in |application:openURL:options:| on iOS9 or later, and - * |application:openURL:sourceApplication:annotation| on iOS 8 and earlier. From there you could - * get a |GINDeepLink| object by calling |dynamicLinkFromCustomSchemeURL:|. If no Dynamic Link - * is found, you will receive callback with "dismiss link". For "dismiss link" the - * FIRDynamicLink.url property is nil. - * For new integrations prefer to use method - * retrievePendingDynamicLinkWithRetrievalProcessType:retrievalOptions:delegate: . This method - * will be the only way to use FDL in near future. - */ -- (void)checkForPendingDynamicLink; - -/** - @method checkForPendingDynamicLinkUsingExperimentalRetrievalProcess - @abstract The same as checkForPendingDynamicLink. Will be using experimental retrieval process. - */ -- (void)checkForPendingDynamicLinkUsingExperimentalRetrievalProcess; - -/** - * @method sharedInstance - * @abstract Method for compatibility with old interface of the GINDurableDeepLinkService - */ -+ (instancetype) - sharedInstance DEPRECATED_MSG_ATTRIBUTE("Use [FIRDynamicLinks dynamicLinks] instead."); - -/** - * @method checkForPendingDeepLink - * @abstract Method for compatibility with old interface of the GINDurableDeepLinkService - */ -- (void)checkForPendingDeepLink DEPRECATED_MSG_ATTRIBUTE( - "Use [FIRDynamicLinks checkForPendingDynamicLink] instead."); - -/** - * @method deepLinkFromCustomSchemeURL: - * @abstract Method for compatibility with old interface of the GINDurableDeepLinkService - */ -- (nullable FIRDynamicLink *)deepLinkFromCustomSchemeURL:(NSURL *)url - DEPRECATED_MSG_ATTRIBUTE("Use [FIRDynamicLinks dynamicLinkFromCustomSchemeURL:] instead."); - -/** - * @method deepLinkFromUniversalLinkURL: - * @abstract Method for compatibility with old interface of the GINDurableDeepLinkService - */ -- (nullable FIRDynamicLink *)deepLinkFromUniversalLinkURL:(NSURL *)url - DEPRECATED_MSG_ATTRIBUTE("Use [FIRDynamicLinks dynamicLinkFromUniversalLinkURL:] instead."); - -/** - * @method shouldHandleDeepLinkFromCustomSchemeURL: - * @abstract Method for compatibility with old interface of the GINDurableDeepLinkService - */ -- (BOOL)shouldHandleDeepLinkFromCustomSchemeURL:(NSURL *)url - DEPRECATED_MSG_ATTRIBUTE("Use [FIRDynamicLinks shouldHandleDynamicLinkFromCustomSchemeURL:]" - " instead."); - -@end - -NS_ASSUME_NONNULL_END diff --git a/FirebaseDynamicLinks/Sources/FIRDynamicLinks+Private.h b/FirebaseDynamicLinks/Sources/FIRDynamicLinks+Private.h deleted file mode 100644 index 53db683e54a..00000000000 --- a/FirebaseDynamicLinks/Sources/FIRDynamicLinks+Private.h +++ /dev/null @@ -1,55 +0,0 @@ -/* - * 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. - */ - -#import "FirebaseDynamicLinks/Sources/Public/FirebaseDynamicLinks/FIRDynamicLinks.h" - -@class UIViewController; - -NS_ASSUME_NONNULL_BEGIN - -/** - * The version of the Firebase Dynamic Link Service SDK. - */ -FOUNDATION_EXPORT NSString *const kFIRDLVersion; - -/** - * Exposed for Unit Tests usage. - */ -FOUNDATION_EXPORT NSString *const kFIRDLReadDeepLinkAfterInstallKey; - -@interface FIRDynamicLinks (Private) - -/** - * @abstract Internal method to return is automatic retrieval of dynamic link enabled or not. - * To be used for internal purposes. - */ -+ (BOOL)isAutomaticRetrievalEnabled; - -/** - * @property APIKey - * @abstract API Key for API access. - */ -@property(nonatomic, copy, readonly) NSString *APIKey; - -/** - * @property URLScheme - * @abstract Custom URL scheme. - */ -@property(nonatomic, copy, readonly, nullable) NSString *URLScheme; - -@end - -NS_ASSUME_NONNULL_END diff --git a/FirebaseDynamicLinks/Sources/FIRDynamicLinks.m b/FirebaseDynamicLinks/Sources/FIRDynamicLinks.m deleted file mode 100644 index f7b0b0f5e3c..00000000000 --- a/FirebaseDynamicLinks/Sources/FIRDynamicLinks.m +++ /dev/null @@ -1,805 +0,0 @@ -/* - * 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. - */ - -#import -#if TARGET_OS_IOS - -#import "FirebaseDynamicLinks/Sources/Public/FirebaseDynamicLinks/FIRDynamicLinks.h" - -#import - -#ifdef FIRDynamicLinks3P -#import "FirebaseCore/Extension/FirebaseCoreInternal.h" -#import "FirebaseDynamicLinks/Sources/FIRDLScionLogging.h" -#import "Interop/Analytics/Public/FIRAnalyticsInterop.h" -#else -#import "FirebaseCore/Sources/Public/FirebaseCore/FIRVersion.h" -#endif - -#ifdef FIRDynamicLinks3P -#import "FirebaseDynamicLinks/Sources/FDLURLComponents/FDLURLComponents+Private.h" -#endif -#import "FirebaseDynamicLinks/Sources/FIRDLRetrievalProcessFactory.h" -#import "FirebaseDynamicLinks/Sources/FIRDLRetrievalProcessProtocols.h" -#import "FirebaseDynamicLinks/Sources/FIRDLRetrievalProcessResult.h" -#import "FirebaseDynamicLinks/Sources/FIRDynamicLink+Private.h" -#import "FirebaseDynamicLinks/Sources/FIRDynamicLinkNetworking.h" -#import "FirebaseDynamicLinks/Sources/FIRDynamicLinks+FirstParty.h" -#import "FirebaseDynamicLinks/Sources/FIRDynamicLinks+Private.h" -#import "FirebaseDynamicLinks/Sources/Logging/FDLLogging.h" -#import "FirebaseDynamicLinks/Sources/Utilities/FDLUtilities.h" - -// We should only read the deeplink after install once. We use the following key to store the state -// in the user defaults. -NSString *const kFIRDLReadDeepLinkAfterInstallKey = - @"com.google.appinvite.readDeeplinkAfterInstall"; - -// We should only open url once. We use the following key to store the state in the user defaults. -static NSString *const kFIRDLOpenURLKey = @"com.google.appinvite.openURL"; - -// Custom domains to be allowed are optionally added as an array to the info.plist. -static NSString *const kInfoPlistCustomDomainsKey = @"FirebaseDynamicLinksCustomDomains"; - -NS_ASSUME_NONNULL_BEGIN - -@interface FIRDynamicLinks () - -// API Key for API access. -@property(nonatomic, copy) NSString *APIKey; - -// Custom URL scheme. -@property(nonatomic, copy) NSString *URLScheme; - -// Networking object for Dynamic Links -@property(nonatomic, readonly) FIRDynamicLinkNetworking *dynamicLinkNetworking; - -@property(atomic, assign) BOOL retrievingPendingDynamicLink; - -@end - -#ifdef FIRDynamicLinks3P -// Error code from FDL. -static const NSInteger FIRErrorCodeDurableDeepLinkFailed = -119; - -@interface FIRDynamicLinks () { - /// Stored Analytics reference, if it exists. - id _Nullable _analytics; -} -@end - -// DynamicLinks doesn't provide any functionality to other components, -// so it provides a private, empty protocol that it conforms to and use it for registration. - -@protocol FIRDynamicLinksInstanceProvider -@end - -@interface FIRDynamicLinks () - -@end - -#endif - -@implementation FIRDynamicLinks { - // User defaults passed. - NSUserDefaults *_userDefaults; - - FIRDynamicLinkNetworking *_dynamicLinkNetworking; - - id _retrievalProcess; -} - -#pragma mark - Object lifecycle - -#ifdef FIRDynamicLinks3P - -+ (void)load { - [FIRApp registerInternalLibrary:self withName:@"fire-dl"]; -} - -+ (nonnull NSArray *)componentsToRegister { - FIRComponentCreationBlock creationBlock = - ^id _Nullable(FIRComponentContainer *container, BOOL *isCacheable) { - // Don't return an instance when it's not the default app. - if (!container.app.isDefaultApp) { - // Only configure for the default FIRApp. - FDLLog(FDLLogLevelInfo, FDLLogIdentifierSetupNonDefaultApp, - @"Firebase Dynamic Links only " - "works with the default app."); - return nil; - } - - // Ensure it's cached so it returns the same instance every time dynamicLinks is called. - *isCacheable = YES; - id analytics = FIR_COMPONENT(FIRAnalyticsInterop, container); - FIRDynamicLinks *dynamicLinks = [[FIRDynamicLinks alloc] initWithAnalytics:analytics]; - [dynamicLinks configureDynamicLinks:container.app]; - - if ([FIRDynamicLinks isAutomaticRetrievalEnabled]) { - [dynamicLinks checkForPendingDynamicLink]; - } - return dynamicLinks; - }; - FIRComponent *dynamicLinksProvider = - [FIRComponent componentWithProtocol:@protocol(FIRDynamicLinksInstanceProvider) - instantiationTiming:FIRInstantiationTimingEagerInDefaultApp - creationBlock:creationBlock]; - - return @[ dynamicLinksProvider ]; -} - -- (void)configureDynamicLinks:(FIRApp *)app { - FIROptions *options = app.options; - NSError *error; - NSMutableString *errorDescription; - NSString *urlScheme; - - if (options.APIKey.length == 0) { - errorDescription = [@"API key must not be nil or empty." mutableCopy]; - } - - if (!errorDescription) { - // setup FDL if no error detected - urlScheme = options.deepLinkURLScheme ?: [NSBundle mainBundle].bundleIdentifier; - [self setUpWithLaunchOptions:nil apiKey:options.APIKey urlScheme:urlScheme userDefaults:nil]; - } else { - NSString *description = - [NSString stringWithFormat:@"Configuration failed for service DynamicLinks."]; - NSDictionary *errorDict = @{ - NSLocalizedDescriptionKey : description, - NSLocalizedFailureReasonErrorKey : errorDescription - }; - error = [NSError errorWithDomain:kFirebaseDurableDeepLinkErrorDomain - code:FIRErrorCodeDurableDeepLinkFailed - userInfo:errorDict]; - } - if (error) { - NSString *message = - [NSString stringWithFormat: - @"Firebase Dynamic Links has stopped your project " - @"because there are incorrect values provided in Firebase's configuration " - @"options that may prevent your app from behaving as expected:\n\n" - @"Error: %@\n\n" - @"Please fix these issues to ensure that Firebase is correctly configured in " - @"your project.", - error.localizedFailureReason]; - [NSException raise:kFirebaseDurableDeepLinkErrorDomain format:@"%@", message]; - } - [self checkForCustomDomainEntriesInInfoPlist]; -} - -- (instancetype)initWithAnalytics:(nullable id)analytics { - self = [super init]; - if (self) { - _analytics = analytics; - } - return self; -} - -+ (instancetype)dynamicLinks { - FIRApp *defaultApp = [FIRApp defaultApp]; // Missing configure will be logged here. - id instance = - FIR_COMPONENT(FIRDynamicLinksInstanceProvider, defaultApp.container); - return (FIRDynamicLinks *)instance; -} - -#else -+ (instancetype)dynamicLinks { - static FIRDynamicLinks *dynamicLinks; - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ - dynamicLinks = [[self alloc] init]; - }); - return dynamicLinks; -} -#endif - -#pragma mark - Custom domains - -- (instancetype)init { - self = [super init]; - if (self) { - [self checkForCustomDomainEntriesInInfoPlist]; - } - return self; -} - -// Check for custom domains entry in PLIST file. -- (void)checkForCustomDomainEntriesInInfoPlist { - // Check to see if FirebaseDynamicLinksCustomDomains array is present. - NSDictionary *infoDictionary = [NSBundle mainBundle].infoDictionary; - NSArray *customDomains = infoDictionary[kInfoPlistCustomDomainsKey]; - if (customDomains) { - FIRDLAddToAllowListForCustomDomainsArray(customDomains); - } -} - -#pragma mark - First party interface - -- (BOOL)setUpWithLaunchOptions:(nullable NSDictionary *)launchOptions - apiKey:(NSString *)apiKey - urlScheme:(nullable NSString *)urlScheme - userDefaults:(nullable NSUserDefaults *)userDefaults { - if (apiKey == nil) { - FDLLog(FDLLogLevelError, FDLLogIdentifierSetupNilAPIKey, @"API Key must not be nil."); - return NO; - } - - _APIKey = [apiKey copy]; - _URLScheme = urlScheme.length ? [urlScheme copy] : [NSBundle mainBundle].bundleIdentifier; - - if (!userDefaults) { - _userDefaults = [NSUserDefaults standardUserDefaults]; - } else { - _userDefaults = userDefaults; - } - - NSURL *url = launchOptions[UIApplicationLaunchOptionsURLKey]; - if (url) { - if ([self canParseCustomSchemeURL:url] || [self canParseUniversalLinkURL:url]) { - // Make sure we don't call |checkForPendingDynamicLink| again if - // a strong deep link is found. - [_userDefaults setBool:YES forKey:kFIRDLReadDeepLinkAfterInstallKey]; - } - } - return YES; -} - -- (void)checkForPendingDynamicLinkUsingExperimentalRetrievalProcess { - [self checkForPendingDynamicLink]; -} - -- (void)checkForPendingDynamicLink { - // Make sure this method is called only once after the application was installed. - // kFIRDLOpenURLKey marks checkForPendingDynamic link had been called already so no need to do it - // again. kFIRDLReadDeepLinkAfterInstallKey marks we have already read a deeplink after the - // install and so no need to do check for pending dynamic link. - BOOL appInviteDeepLinkRead = [_userDefaults boolForKey:kFIRDLOpenURLKey] || - [_userDefaults boolForKey:kFIRDLReadDeepLinkAfterInstallKey]; - - if (appInviteDeepLinkRead || self.retrievingPendingDynamicLink) { - NSString *errorDescription = - appInviteDeepLinkRead ? NSLocalizedString(@"Link was already retrieved", @"Error message") - : NSLocalizedString(@"Already retrieving link", @"Error message"); - [self handlePendingDynamicLinkRetrievalFailureWithErrorCode:-1 - errorDescription:errorDescription - underlyingError:nil]; - return; - } - - self.retrievingPendingDynamicLink = YES; - - FIRDLRetrievalProcessFactory *factory = - [[FIRDLRetrievalProcessFactory alloc] initWithNetworkingService:self.dynamicLinkNetworking - URLScheme:_URLScheme - APIKey:_APIKey - FDLSDKVersion:FIRFirebaseVersion() - delegate:self]; - _retrievalProcess = [factory automaticRetrievalProcess]; - [_retrievalProcess retrievePendingDynamicLink]; -} - -// Disable deprecated warning for internal methods. -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wdeprecated-implementations" - -+ (instancetype)sharedInstance { - return [self dynamicLinks]; -} - -- (BOOL)setUpWithLaunchOptions:(nullable NSDictionary *)launchOptions - apiKey:(NSString *)apiKey - clientID:(NSString *)clientID - urlScheme:(nullable NSString *)urlScheme - userDefaults:(nullable NSUserDefaults *)userDefaults { - return [self setUpWithLaunchOptions:launchOptions - apiKey:apiKey - urlScheme:urlScheme - userDefaults:userDefaults]; -} - -- (void)checkForPendingDeepLink { - [self checkForPendingDynamicLink]; -} - -- (nullable FIRDynamicLink *)deepLinkFromCustomSchemeURL:(NSURL *)url { - return [self dynamicLinkFromCustomSchemeURL:url]; -} - -- (nullable FIRDynamicLink *)deepLinkFromUniversalLinkURL:(NSURL *)url { - return [self dynamicLinkFromUniversalLinkURL:url]; -} - -- (BOOL)shouldHandleDeepLinkFromCustomSchemeURL:(NSURL *)url { - return [self shouldHandleDynamicLinkFromCustomSchemeURL:url]; -} - -#pragma clang pop - -#pragma mark - Public interface - -- (BOOL)shouldHandleDynamicLinkFromCustomSchemeURL:(NSURL *)url { - // Return NO if the URL scheme does not match. - if (![self canParseCustomSchemeURL:url]) { - return NO; - } - - // We can handle "/link" and "/link/dismiss". The latter will return a nil deep link. - return ([url.path hasPrefix:@"/link"] && [url.host isEqualToString:@"google"]); -} - -- (nullable FIRDynamicLink *)dynamicLinkFromCustomSchemeURL:(NSURL *)url { - // Return nil if the URL scheme does not match. - if (![self canParseCustomSchemeURL:url]) { - return nil; - } - - if ([url.path isEqualToString:@"/link"] && [url.host isEqualToString:@"google"]) { - // This URL is a callback url from a device heuristics based match - // Extract information from query. - NSString *query = url.query; - - NSDictionary *parameters = FIRDLDictionaryFromQuery(query); - - // As long as the deepLink has some parameter, return it. - if (parameters.count > 0) { - FIRDynamicLink *dynamicLink = - [[FIRDynamicLink alloc] initWithParametersDictionary:parameters]; - -#ifdef GIN_SCION_LOGGING - if (dynamicLink.url) { - BOOL isFirstOpen = ![_userDefaults boolForKey:kFIRDLReadDeepLinkAfterInstallKey]; - FIRDLLogEvent event = isFirstOpen ? FIRDLLogEventFirstOpen : FIRDLLogEventAppOpen; - FIRDLLogEventToScion(event, parameters[kFIRDLParameterSource], - parameters[kFIRDLParameterMedium], parameters[kFIRDLParameterCampaign], - _analytics); - } -#endif - // Make sure we don't call |checkForPendingDynamicLink| again if we did this already. - if ([_userDefaults boolForKey:kFIRDLOpenURLKey]) { - [_userDefaults setBool:YES forKey:kFIRDLReadDeepLinkAfterInstallKey]; - } - return dynamicLink; - } - } - return nil; -} - -- (nullable FIRDynamicLink *) - dynamicLinkInternalFromUniversalLinkURL:(NSURL *)url - completion: - (nullable FIRDynamicLinkUniversalLinkHandler)completion { - // Make sure the completion is always called on the main queue. - FIRDynamicLinkUniversalLinkHandler mainQueueCompletion = - ^(FIRDynamicLink *_Nullable dynamicLink, NSError *_Nullable error) { - if (completion) { - dispatch_async(dispatch_get_main_queue(), ^{ - completion(dynamicLink, error); - }); - } - }; - - if ([self canParseUniversalLinkURL:url]) { - if (url.query.length > 0) { - NSDictionary *parameters = FIRDLDictionaryFromQuery(url.query); - if (parameters[kFIRDLParameterLink]) { - NSString *urlString = parameters[kFIRDLParameterLink]; - NSURL *deepLinkURL = [NSURL URLWithString:urlString]; - if (deepLinkURL) { - NSMutableDictionary *paramsDictionary = [[NSMutableDictionary alloc] - initWithDictionary:@{kFIRDLParameterDeepLinkIdentifier : urlString}]; - - if (parameters[kFIRDLParameterSource] != nil) { - [paramsDictionary setValue:parameters[kFIRDLParameterSource] - forKey:kFIRDLParameterSource]; - } - - if (parameters[kFIRDLParameterMedium] != nil) { - [paramsDictionary setValue:parameters[kFIRDLParameterMedium] - forKey:kFIRDLParameterMedium]; - } - - if (parameters[kFIRDLParameterTerm] != nil) { - [paramsDictionary setValue:parameters[kFIRDLParameterTerm] forKey:kFIRDLParameterTerm]; - } - - if (parameters[kFIRDLParameterCampaign] != nil) { - [paramsDictionary setValue:parameters[kFIRDLParameterCampaign] - forKey:(kFIRDLParameterCampaign)]; - } - - if (parameters[kFIRDLParameterContent] != nil) { - [paramsDictionary setValue:parameters[kFIRDLParameterContent] - forKey:kFIRDLParameterContent]; - } - - FIRDynamicLink *dynamicLink = - [[FIRDynamicLink alloc] initWithParametersDictionary:paramsDictionary]; - dynamicLink.matchType = FIRDLMatchTypeUnique; - dynamicLink.minimumAppVersion = parameters[kFIRDLParameterMinimumAppVersion]; - - // Call resolveShortLink:completion: to do logging. - // TODO: Create dedicated logging function to prevent this. - [self.dynamicLinkNetworking - resolveShortLink:url - FDLSDKVersion:FIRFirebaseVersion() - completion:^(NSURL *_Nullable resolverURL, NSError *_Nullable resolverError) { - mainQueueCompletion(dynamicLink, resolverError); - }]; -#ifdef GIN_SCION_LOGGING - FIRDLLogEventToScion(FIRDLLogEventAppOpen, parameters[kFIRDLParameterSource], - parameters[kFIRDLParameterMedium], - parameters[kFIRDLParameterCampaign], _analytics); -#endif - return dynamicLink; - } - } - } - } - - mainQueueCompletion( - nil, [[NSError alloc] initWithDomain:@"com.firebase.dynamicLinks" - code:1 - userInfo:@{ - NSLocalizedFailureReasonErrorKey : - @"Universal link URL could not be parsed by Dynamic Links." - }]); - return nil; -} - -- (nullable FIRDynamicLink *)dynamicLinkFromUniversalLinkURL:(NSURL *)url { - return [self dynamicLinkInternalFromUniversalLinkURL:url completion:nil]; -} - -- (void)dynamicLinkFromUniversalLinkURL:(NSURL *)url - completion:(FIRDynamicLinkUniversalLinkHandler)completion { - [self dynamicLinkInternalFromUniversalLinkURL:url completion:completion]; -} - -- (BOOL)handleUniversalLink:(NSURL *)universalLinkURL - completion:(FIRDynamicLinkUniversalLinkHandler)completion { - if ([self matchesShortLinkFormat:universalLinkURL]) { - __weak __typeof__(self) weakSelf = self; - [self resolveShortLink:universalLinkURL - completion:^(NSURL *url, NSError *error) { - __typeof__(self) strongSelf = weakSelf; - if (strongSelf) { - FIRDynamicLink *dynamicLink = [strongSelf dynamicLinkFromCustomSchemeURL:url]; - dispatch_async(dispatch_get_main_queue(), ^{ - completion(dynamicLink, error); - }); - } else { - completion(nil, nil); - } - }]; - return YES; - } else { - [self dynamicLinkFromUniversalLinkURL:universalLinkURL completion:completion]; - BOOL canHandleUniversalLink = - [self canParseUniversalLinkURL:universalLinkURL] && universalLinkURL.query.length > 0 && - FIRDLDictionaryFromQuery(universalLinkURL.query)[kFIRDLParameterLink]; - return canHandleUniversalLink; - } -} - -- (void)resolveShortLink:(NSURL *)url completion:(FIRDynamicLinkResolverHandler)completion { - [self.dynamicLinkNetworking resolveShortLink:url - FDLSDKVersion:FIRFirebaseVersion() - completion:completion]; -} - -- (BOOL)matchesShortLinkFormat:(NSURL *)url { - return FIRDLMatchesShortLinkFormat(url); -} - -#pragma mark - Private interface - -+ (BOOL)isAutomaticRetrievalEnabled { - id retrievalEnabledValue = - [[NSBundle mainBundle] infoDictionary][@"FirebaseDeepLinkAutomaticRetrievalEnabled"]; - if ([retrievalEnabledValue respondsToSelector:@selector(boolValue)]) { - return [retrievalEnabledValue boolValue]; - } - return YES; -} - -#pragma mark - Internal methods - -- (FIRDynamicLinkNetworking *)dynamicLinkNetworking { - if (!_dynamicLinkNetworking) { - _dynamicLinkNetworking = [[FIRDynamicLinkNetworking alloc] initWithAPIKey:_APIKey - URLScheme:_URLScheme]; - } - return _dynamicLinkNetworking; -} - -- (BOOL)canParseCustomSchemeURL:(nullable NSURL *)url { - if (url.scheme.length) { - NSString *bundleIdentifier = [NSBundle mainBundle].bundleIdentifier; - if ([url.scheme.lowercaseString isEqualToString:_URLScheme.lowercaseString] || - [url.scheme.lowercaseString isEqualToString:bundleIdentifier.lowercaseString]) { - return YES; - } - } - return NO; -} - -- (BOOL)canParseUniversalLinkURL:(nullable NSURL *)url { - return FIRDLCanParseUniversalLinkURL(url); -} - -- (BOOL)handleIncomingCustomSchemeDeepLink:(NSURL *)url { - return [self canParseCustomSchemeURL:url]; -} - -- (void)passRetrievedDynamicLinkToApplication:(NSURL *)url { - id applicationDelegate = [UIApplication sharedApplication].delegate; - if ([self isOpenUrlMethodPresentInAppDelegate:applicationDelegate]) { - // pass url directly to application delegate to avoid hop into - // iOS handling of the universal links - [applicationDelegate application:[UIApplication sharedApplication] openURL:url options:@{}]; - return; - } - - [[UIApplication sharedApplication] openURL:url options:@{} completionHandler:nil]; -} - -- (BOOL)isOpenUrlMethodPresentInAppDelegate:(id)applicationDelegate { - return applicationDelegate && - [applicationDelegate respondsToSelector:@selector(application:openURL:options:)]; -} - -- (void)handlePendingDynamicLinkRetrievalFailureWithErrorCode:(NSInteger)errorCode - errorDescription:(NSString *)errorDescription - underlyingError:(nullable NSError *)underlyingError { - self.retrievingPendingDynamicLink = NO; -} - -#pragma mark - FIRDLRetrievalProcessDelegate - -- (void)retrievalProcess:(id)retrievalProcess - completedWithResult:(FIRDLRetrievalProcessResult *)result { - self.retrievingPendingDynamicLink = NO; - _retrievalProcess = nil; - - if (![_userDefaults boolForKey:kFIRDLOpenURLKey]) { - // Once we complete the Pending dynamic link retrieval, regardless of whether the retrieval is - // success or failure, we don't want to do the retrieval again on next app start. - // If we try to redo the retrieval again because of some error, the user will experience - // unwanted deeplinking when they restart the app next time. - [_userDefaults setBool:YES forKey:kFIRDLOpenURLKey]; - } - - NSURL *linkToPassToApp = [result URLWithCustomURLScheme:_URLScheme]; - [self passRetrievedDynamicLinkToApplication:linkToPassToApp]; -} - -#pragma mark - Diagnostics methods - -static NSString *kSelfDiagnoseOutputHeader = - @"---- Firebase Dynamic Links diagnostic output start ----\n"; -static NSString *kSelfDiagnoseOutputFooter = - @"---- Firebase Dynamic Links diagnostic output end ----\n"; - -+ (NSString *)genericDiagnosticInformation { - NSMutableString *genericDiagnosticInfo = [[NSMutableString alloc] init]; - - [genericDiagnosticInfo - appendFormat:@"Firebase Dynamic Links framework version %@\n", FIRFirebaseVersion()]; - [genericDiagnosticInfo appendFormat:@"System information: OS %@, OS version %@, model %@\n", - [UIDevice currentDevice].systemName, - [UIDevice currentDevice].systemVersion, - [UIDevice currentDevice].model]; - [genericDiagnosticInfo appendFormat:@"Current date %@\n", [NSDate date]]; - // TODO: bring this diagnostic info back when we shipped non-automatic retrieval - // [genericDiagnosticInfo appendFormat:@"AutomaticRetrievalEnabled: %@\n", - // [self isAutomaticRetrievalEnabled] ? @"YES" : @"NO"]; - - // Disable deprecated warning for internal methods. -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wdeprecated-declarations" - [genericDiagnosticInfo appendFormat:@"Device locale %@ (raw %@), timezone %@\n", - FIRDLDeviceLocale(), FIRDLDeviceLocaleRaw(), - FIRDLDeviceTimezone()]; -#pragma clang pop - - return genericDiagnosticInfo; -} - -+ (NSString *)diagnosticAnalyzeEntitlements { - NSString *embeddedMobileprovisionFilePath = [[[NSBundle mainBundle] bundlePath] - stringByAppendingPathComponent:@"embedded.mobileprovision"]; - - NSError *error; - NSMutableData *profileData = [NSMutableData dataWithContentsOfFile:embeddedMobileprovisionFilePath - options:0 - error:&error]; - - if (!profileData.length || error) { - return @"\tSKIPPED: Not able to read entitlements (embedded.mobileprovision).\n"; - } - - // The "embedded.mobileprovision" sometimes contains characters with value 0, which signals the - // end of a c-string and halts the ASCII parser, or with value > 127, which violates strict 7-bit - // ASCII. Replace any 0s or invalid characters in the input. - uint8_t *profileBytes = (uint8_t *)profileData.bytes; - for (int i = 0; i < profileData.length; i++) { - uint8_t currentByte = profileBytes[i]; - if (!currentByte || currentByte > 127) { - profileBytes[i] = '.'; - } - } - - NSString *embeddedProfile = [[NSString alloc] initWithBytesNoCopy:profileBytes - length:profileData.length - encoding:NSASCIIStringEncoding - freeWhenDone:NO]; - - if (error || !embeddedProfile.length) { - return @"\tSKIPPED: Not able to read entitlements (embedded.mobileprovision).\n"; - } - - NSScanner *scanner = [NSScanner scannerWithString:embeddedProfile]; - NSString *plistContents; - if ([scanner scanUpToString:@"" intoString:&plistContents]) { - plistContents = [plistContents stringByAppendingString:@""]; - } - } - - if (!plistContents.length) { - return @"\tWARNING: Not able to read plist entitlements (embedded.mobileprovision).\n"; - } - - NSData *data = [plistContents dataUsingEncoding:NSUTF8StringEncoding]; - if (!data.length) { - return @"\tWARNING: Not able to parse entitlements (embedded.mobileprovision).\n"; - } - - NSError *plistMapError; - id plistData = [NSPropertyListSerialization propertyListWithData:data - options:NSPropertyListImmutable - format:nil - error:&plistMapError]; - if (plistMapError || ![plistData isKindOfClass:[NSDictionary class]]) { - return @"\tWARNING: Not able to deserialize entitlements (embedded.mobileprovision).\n"; - } - NSDictionary *plistMap = (NSDictionary *)plistData; - - // analyze entitlements and print diagnostic information - // we can't detect errors, information p[rinted here may hint developer or will help support - // to identify the issue - NSMutableString *outputString = [[NSMutableString alloc] init]; - - NSArray *appIdentifierPrefixes = plistMap[@"ApplicationIdentifierPrefix"]; - NSString *teamID = plistMap[@"Entitlements"][@"com.apple.developer.team-identifier"]; - - if (appIdentifierPrefixes.count > 1) { - // is this possible? anyway, we can handle it - [outputString - appendFormat:@"\tAppID Prefixes: %@, Team ID: %@, AppId Prefixes contains to Team ID: %@\n", - appIdentifierPrefixes, teamID, - ([appIdentifierPrefixes containsObject:teamID] ? @"YES" : @"NO")]; - } else { - [outputString - appendFormat:@"\tAppID Prefix: %@, Team ID: %@, AppId Prefix equal to Team ID: %@\n", - appIdentifierPrefixes[0], teamID, - ([appIdentifierPrefixes[0] isEqualToString:teamID] ? @"YES" : @"NO")]; - } - - return outputString; -} - -+ (NSString *)performDiagnosticsIncludingHeaderFooter:(BOOL)includingHeaderFooter - detectedErrors:(nullable NSInteger *)detectedErrors { - NSMutableString *diagnosticString = [[NSMutableString alloc] init]; - if (includingHeaderFooter) { - [diagnosticString appendString:@"\n"]; - [diagnosticString appendString:kSelfDiagnoseOutputHeader]; - } - - NSInteger detectedErrorsCnt = 0; - - [diagnosticString appendString:[self genericDiagnosticInformation]]; - -#if TARGET_IPHONE_SIMULATOR - // check is Simulator and print WARNING that Universal Links is not supported on Simulator - [diagnosticString - appendString:@"WARNING: iOS Simulator does not support Universal Links. Firebase " - @"Dynamic Links SDK functionality will be limited. Some FDL " - @"features may be missing or will not work correctly.\n"]; -#endif // TARGET_IPHONE_SIMULATOR - - id applicationDelegate = [UIApplication sharedApplication].delegate; - if (![applicationDelegate respondsToSelector:@selector(application:openURL:options:)]) { - detectedErrorsCnt++; - [diagnosticString appendFormat:@"ERROR: UIApplication delegate %@ does not implements selector " - @"%@. FDL depends on this implementation to retrieve pending " - @"dynamic link.\n", - applicationDelegate, - NSStringFromSelector(@selector(application:openURL:options:))]; - } - - // check that Info.plist has custom URL scheme and the scheme is the same as bundleID or - // as customURLScheme passed to FDL iOS SDK - NSString *URLScheme = [FIRDynamicLinks dynamicLinks].URLScheme; - BOOL URLSchemeFoundInPlist = NO; - NSArray *URLSchemesFromInfoPlist = [[NSBundle mainBundle] infoDictionary][@"CFBundleURLTypes"]; - for (NSDictionary *schemeDetails in URLSchemesFromInfoPlist) { - NSArray *arrayOfSchemes = schemeDetails[@"CFBundleURLSchemes"]; - for (NSString *scheme in arrayOfSchemes) { - if ([scheme isEqualToString:URLScheme]) { - URLSchemeFoundInPlist = YES; - break; - } - } - if (URLSchemeFoundInPlist) { - break; - } - } - if (!URLSchemeFoundInPlist) { - detectedErrorsCnt++; - [diagnosticString appendFormat:@"ERROR: Specified custom URL scheme is %@ but Info.plist do " - @"not contain such scheme in " - "CFBundleURLTypes key.\n", - URLScheme]; - } else { - [diagnosticString appendFormat:@"\tSpecified custom URL scheme is %@ and Info.plist contains " - @"such scheme in CFBundleURLTypes key.\n", - URLScheme]; - } - -#if !TARGET_IPHONE_SIMULATOR - // analyse information in entitlements file - NSString *entitlementsAnalysis = [self diagnosticAnalyzeEntitlements]; - if (entitlementsAnalysis.length) { - [diagnosticString appendString:entitlementsAnalysis]; - } -#endif // TARGET_IPHONE_SIMULATOR - - if (includingHeaderFooter) { - if (detectedErrorsCnt == 0) { - [diagnosticString - appendString:@"performDiagnostic completed successfully! No errors found.\n"]; - } else { - [diagnosticString - appendFormat:@"performDiagnostic detected %ld ERRORS.\n", (long)detectedErrorsCnt]; - } - [diagnosticString appendString:kSelfDiagnoseOutputFooter]; - } - if (detectedErrors) { - *detectedErrors = detectedErrorsCnt; - } - return [diagnosticString copy]; -} - -+ (void)performDiagnosticsWithCompletion:(void (^_Nullable)(NSString *diagnosticOutput, - BOOL hasErrors))completionHandler; -{ - NSInteger detectedErrorsCnt = 0; - NSString *diagnosticString = [self performDiagnosticsIncludingHeaderFooter:YES - detectedErrors:&detectedErrorsCnt]; - if (completionHandler) { - completionHandler(diagnosticString, detectedErrorsCnt > 0); - } else { - NSLog(@"%@", diagnosticString); - } -} - -@end - -NS_ASSUME_NONNULL_END - -#endif // TARGET_OS_IOS diff --git a/FirebaseDynamicLinks/Sources/GINInvocation/GINArgument.h b/FirebaseDynamicLinks/Sources/GINInvocation/GINArgument.h deleted file mode 100644 index f4077ca2a9b..00000000000 --- a/FirebaseDynamicLinks/Sources/GINInvocation/GINArgument.h +++ /dev/null @@ -1,52 +0,0 @@ -/* - * 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. - */ - -#import - -/** - * @class GINArgument - * @abstract Encapsulates an argument that is passed to a method. - */ -@interface GINArgument : NSObject - -/** - * @method argumentWithObject: - * @abstract Creates an GINArgument with an NSObject. - * @param object The NSObject representing the value of the argument. - * @return An instance of GINArgument. - */ -+ (instancetype)argumentWithObject:(NSObject *)object; - -/** - * @method argumentWithInteger: - * @abstract Creates an GINArgument with an NSObject. - * @param integer The NSInteger representing the value of the argument. - * @return An instance of GINArgument. - */ -+ (instancetype)argumentWithInteger:(NSInteger)integer; - -/** - * @method setNextArgumentInList:inInvocation: - * @abstract Reads the next argument in |argumentList| and sets it in the |invocation| object. - * @param argumentList The list of arguments. Each entry must be of type GINArgument. - * @param index The argument index to set on the |invocation| object. - * @param invocation The invocation object to set the argument to. - * @return YES if the argument was set, NO if there were no arguments left in the list. - */ -+ (BOOL)setNextArgumentInList:(va_list)argumentList - atIndex:(NSUInteger)index - inInvocation:(NSInvocation *)invocation; -@end diff --git a/FirebaseDynamicLinks/Sources/GINInvocation/GINArgument.m b/FirebaseDynamicLinks/Sources/GINInvocation/GINArgument.m deleted file mode 100644 index 66d26b2e96b..00000000000 --- a/FirebaseDynamicLinks/Sources/GINInvocation/GINArgument.m +++ /dev/null @@ -1,84 +0,0 @@ -/* - * 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. - */ - -#import "FirebaseDynamicLinks/Sources/GINInvocation/GINArgument.h" - -// Currently only supporting arguments of types id and integer. -// Will support more argument types when it is needed. -typedef NS_ENUM(NSUInteger, GINArgumentType) { - kGINArgumentTypeObject = 0, - kGINArgumentTypeInteger -}; - -@interface GINArgument () - -@property(nonatomic, assign) GINArgumentType type; - -@property(nonatomic, strong) id object; -@property(nonatomic, assign) NSInteger integer; - -@end - -@implementation GINArgument - -+ (instancetype)argumentWithObject:(NSObject *)object { - GINArgument *arg = [[GINArgument alloc] init]; - arg.type = kGINArgumentTypeObject; - arg.object = object; - return arg; -} - -+ (instancetype)argumentWithInteger:(NSInteger)integer { - GINArgument *arg = [[GINArgument alloc] init]; - arg.type = kGINArgumentTypeInteger; - arg.integer = integer; - return arg; -} - -+ (BOOL)setNextArgumentInList:(va_list)argumentList - atIndex:(NSUInteger)index - inInvocation:(NSInvocation *)invocation { - id argument = va_arg(argumentList, id); - - if (!argument) { - return NO; - } - - if (![argument isKindOfClass:[GINArgument class]]) { - [NSException raise:@"InvalidArgumentException" - format:@"Invalid argument type at index %lu", (unsigned long)index]; - } - - [argument setArgumentInInvocation:invocation atIndex:index]; - return YES; -} - -- (void)setArgumentInInvocation:(NSInvocation *)invocation atIndex:(NSUInteger)index { - switch (self.type) { - case kGINArgumentTypeObject: - [invocation setArgument:&_object atIndex:index]; - break; - - case kGINArgumentTypeInteger: - [invocation setArgument:&_integer atIndex:index]; - break; - - default: - break; - } -} - -@end diff --git a/FirebaseDynamicLinks/Sources/GINInvocation/GINInvocation.h b/FirebaseDynamicLinks/Sources/GINInvocation/GINInvocation.h deleted file mode 100644 index 67092d21692..00000000000 --- a/FirebaseDynamicLinks/Sources/GINInvocation/GINInvocation.h +++ /dev/null @@ -1,71 +0,0 @@ -/* - * 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. - */ - -#import - -// Calls a method on a class or object. -#define GINPerformSelector(target, selector) \ - GINPerformSelectorWithArguments(target, selector, 0, nil) - -// Calls a method on a class or object, that takes arguments. -#define GINPerformSelectorWithArguments(target, selector, numArgs, args...) \ - [GINInvocation objectByPerformingSelector:selector \ - onTarget:target \ - numberOfArguments:numArgs, args, nil] - -// Calls a method that returns double on a class or object. -#define GINDoubleByPerformingSelector(target, selector) \ - GINDoubleByPerformingSelectorWithArguments(target, selector, 0, nil) - -// Calls a method that returns double on a class or object, that takes arguments. -#define GINDoubleByPerformingSelectorWithArguments(target, selector, numArgs, args...) \ - [GINInvocation doubleByPerformingSelector:selector \ - onTarget:target \ - numberOfArguments:numArgs, args, nil] - -/** - * @class GINInvocation - * @abstract A utility class that provide helper methods to invoke methods on objects and classes. - */ -@interface GINInvocation : NSObject - -/** - * @method objectByPerformingSelector:onTarget:numberOfArguments:... - * @abstract Performs a selector on a class or object. - * @param selector The selector to perform. - * @param target The target class or object to perform the selector on. - * @param numberOfArguments Number of arguments in the argument list. - * @param ... An optional argument list, each argument should be of type GINArgument. - * @return id The result of the selector. - */ -+ (id)objectByPerformingSelector:(SEL)selector - onTarget:(id)target - numberOfArguments:(NSInteger)numberOfArguments, ...; - -/** - * @method doubleByPerformingSelector:onTarget:numberOfArguments:... - * @abstract Performs a selector on a class or object. - * @param selector The selector to perform. - * @param target The target class or object to perform the selector on. - * @param numberOfArguments Number of arguments in the argument list. - * @param ... An optional argument list, each argument should be of type GINArgument. - * @return double The result of the selector. - */ -+ (double)doubleByPerformingSelector:(SEL)selector - onTarget:(id)target - numberOfArguments:(NSInteger)numberOfArguments, ...; - -@end diff --git a/FirebaseDynamicLinks/Sources/GINInvocation/GINInvocation.m b/FirebaseDynamicLinks/Sources/GINInvocation/GINInvocation.m deleted file mode 100644 index 2ea2bf631f6..00000000000 --- a/FirebaseDynamicLinks/Sources/GINInvocation/GINInvocation.m +++ /dev/null @@ -1,98 +0,0 @@ -/* - * 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. - */ - -#import "FirebaseDynamicLinks/Sources/GINInvocation/GINInvocation.h" - -#import "FirebaseDynamicLinks/Sources/GINInvocation/GINArgument.h" - -@implementation GINInvocation - -// A method that performs a selector on a target object, and return the result. -+ (id)objectByPerformingSelector:(SEL)selector - onTarget:(id)target - numberOfArguments:(NSInteger)numberOfArguments, ... { - if (![target respondsToSelector:selector]) { -#if DEBUG - [NSException raise:@"InvalidSelectorException" format:@"Invalid selector send to target"]; -#endif - return nil; - } - - NSMethodSignature *methodSignature = [target methodSignatureForSelector:selector]; - NSInvocation *inv = [NSInvocation invocationWithMethodSignature:methodSignature]; - [inv setSelector:selector]; - [inv setTarget:target]; - - int index = 2; - va_list argumentList; - - va_start(argumentList, numberOfArguments); - for (NSInteger i = 0; i < numberOfArguments; i++) { - [GINArgument setNextArgumentInList:argumentList atIndex:index inInvocation:inv]; - } - va_end(argumentList); - - [inv invoke]; - - // This method only returns object. - if ([methodSignature methodReturnLength]) { - CFTypeRef result; - [inv getReturnValue:&result]; - if (result) { - CFRetain(result); - } - return (__bridge_transfer id)result; - } - return nil; -} - -// A method that performs a selector on a target object, and return the result. -+ (double)doubleByPerformingSelector:(SEL)selector - onTarget:(id)target - numberOfArguments:(NSInteger)numberOfArguments, ... { - if (![target respondsToSelector:selector]) { -#if DEBUG - [NSException raise:@"InvalidSelectorException" format:@"Invalid selector send to target"]; -#endif - return 0; - } - - NSMethodSignature *methodSignature = [target methodSignatureForSelector:selector]; - NSInvocation *inv = [NSInvocation invocationWithMethodSignature:methodSignature]; - [inv setSelector:selector]; - [inv setTarget:target]; - - int index = 2; - va_list argumentList; - - va_start(argumentList, numberOfArguments); - for (NSInteger i = 0; i < numberOfArguments; i++) { - [GINArgument setNextArgumentInList:argumentList atIndex:index inInvocation:inv]; - } - va_end(argumentList); - - [inv invoke]; - - // This method only returns double. - if ([methodSignature methodReturnLength]) { - double doubleValue; - [inv getReturnValue:&doubleValue]; - return doubleValue; - } - return 0; -} - -@end diff --git a/FirebaseDynamicLinks/Sources/Logging/FDLLogging.h b/FirebaseDynamicLinks/Sources/Logging/FDLLogging.h deleted file mode 100644 index f20727a096a..00000000000 --- a/FirebaseDynamicLinks/Sources/Logging/FDLLogging.h +++ /dev/null @@ -1,48 +0,0 @@ -/* - * 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. - */ - -#import - -/** Log level for FIRLogger. */ -typedef NS_ENUM(NSInteger, FDLLogLevel) { - FDLLogLevelError = 0, - FDLLogLevelWarning, - FDLLogLevelNotice, - FDLLogLevelInfo, - FDLLogLevelDebug, -}; - -/** - Used to specify a unique integer for FIRLogger. Add entries ONLY to the end of the enum. - Unique values are specified so that items can be safely removed without affecting the others. - */ -typedef NS_ENUM(NSInteger, FDLLogIdentifier) { - FDLLogIdentifierSetupNilAPIKey = 0, - FDLLogIdentifierSetupNilClientID = 1, // Not used anymore - FDLLogIdentifierSetupNonDefaultApp = 2, - FDLLogIdentifierSetupInvalidDomainURIPrefixScheme = 3, - FDLLogIdentifierSetupInvalidDomainURIPrefix = 4, - FDLLogIdentifierSetupWarnHTTPSScheme = 5, -}; - -/** The appropriate formatter for using NSInteger in FIRLogger. */ -FOUNDATION_EXPORT NSString *const FDLMessageCodeIntegerFormat; - -/** Logs a message with FIRLogger. */ -FOUNDATION_EXPORT void FDLLog(FDLLogLevel logLevel, - FDLLogIdentifier identifier, - NSString *message, - ...) NS_FORMAT_FUNCTION(3, 4); diff --git a/FirebaseDynamicLinks/Sources/Logging/FDLLogging.m b/FirebaseDynamicLinks/Sources/Logging/FDLLogging.m deleted file mode 100644 index a422007fe8e..00000000000 --- a/FirebaseDynamicLinks/Sources/Logging/FDLLogging.m +++ /dev/null @@ -1,73 +0,0 @@ -/* - * 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. - */ - -#import -#if TARGET_OS_IOS - -#import "FirebaseDynamicLinks/Sources/Logging/FDLLogging.h" - -#ifdef GIN_SCION_LOGGING -#import "FirebaseCore/Extension/FirebaseCoreInternal.h" - -FIRLoggerService kFIRLoggerDynamicLinks = @"[FirebaseDynamicLinks]"; -#endif // GIN_SCION_LOGGING - -#ifdef GIN_SCION_LOGGING - -#if __LP64__ // 64-bit -NSString *const FDLMessageCodeIntegerFormat = @"%06ld"; -#else // 32-bit -NSString *const FDLMessageCodeIntegerFormat = @"%06d"; -#endif // #if __LP64__ - -NSString *FDLMessageCodeForLogIdentifier(FDLLogIdentifier identifier) { - static NSString *const kMessageCodePrefix = @"I-FDL"; - NSString *intString = [NSString stringWithFormat:FDLMessageCodeIntegerFormat, identifier]; - return [kMessageCodePrefix stringByAppendingString:intString]; -} -#endif // GIN_SCION_LOGGING - -void FDLLog(FDLLogLevel logLevel, FDLLogIdentifier identifier, NSString *message, ...) { - va_list args_ptr; - va_start(args_ptr, message); -#ifdef GIN_SCION_LOGGING - NSString *messageCode = FDLMessageCodeForLogIdentifier(identifier); - - switch (logLevel) { - case FDLLogLevelError: - FIRLogError(kFIRLoggerDynamicLinks, messageCode, message, args_ptr); - break; - case FDLLogLevelWarning: - FIRLogWarning(kFIRLoggerDynamicLinks, messageCode, message, args_ptr); - break; - case FDLLogLevelNotice: - FIRLogNotice(kFIRLoggerDynamicLinks, messageCode, message, args_ptr); - break; - case FDLLogLevelInfo: - FIRLogInfo(kFIRLoggerDynamicLinks, messageCode, message, args_ptr); - break; - case FDLLogLevelDebug: - FIRLogDebug(kFIRLoggerDynamicLinks, messageCode, message, args_ptr); - break; - } - -#else - NSLogv(message, args_ptr); -#endif // GIN_SCION_LOGGING - va_end(args_ptr); -} - -#endif // TARGET_OS_IOS diff --git a/FirebaseDynamicLinks/Sources/Public/FirebaseDynamicLinks/FDLURLComponents.h b/FirebaseDynamicLinks/Sources/Public/FirebaseDynamicLinks/FDLURLComponents.h deleted file mode 100644 index a0b99105b76..00000000000 --- a/FirebaseDynamicLinks/Sources/Public/FirebaseDynamicLinks/FDLURLComponents.h +++ /dev/null @@ -1,560 +0,0 @@ -/* - * 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. - */ - -#import - -NS_ASSUME_NONNULL_BEGIN - -/** - * @abstract Enum used to define the desired path length for shortened Dynamic Link URLs. - */ -typedef NS_ENUM(NSInteger, FIRShortDynamicLinkPathLength) { - /** - * Uses the server-default for the path length. See https://goo.gl/8yDAqC for more information. - */ - FIRShortDynamicLinkPathLengthDefault = 0, - /** Typical short link for non-sensitive links. */ - FIRShortDynamicLinkPathLengthShort, - /** Short link with an extra long path for great difficulty in guessing. */ - FIRShortDynamicLinkPathLengthUnguessable, -} NS_SWIFT_NAME(ShortDynamicLinkPathLength); - -/** - * @abstract The definition of the completion block used by URL shortener. - * @param shortURL Shortened URL. - * @param warnings Warnings that describe usability or function limitations of the generated - * short link. Usually presence of warnings means parameters format error, parameters value - * error or missing parameter. - * @param error Error if URL can't be shortened. - */ -typedef void (^FIRDynamicLinkShortenerCompletion)(NSURL *_Nullable shortURL, - NSArray *_Nullable warnings, - NSError *_Nullable error) - NS_SWIFT_UNAVAILABLE("Use Swift's closure syntax instead."); - -/** - * @class FIRDynamicLinkGoogleAnalyticsParameters - * @abstract The Dynamic Link analytics parameters. - */ -NS_SWIFT_NAME(DynamicLinkGoogleAnalyticsParameters) -@interface FIRDynamicLinkGoogleAnalyticsParameters : NSObject - -/** - * @property source - * @abstract The utm_source analytics parameter. - */ -@property(nonatomic, copy, nullable) NSString *source; -/** - * @property medium - * @abstract The utm_medium analytics parameter. - */ -@property(nonatomic, copy, nullable) NSString *medium; -/** - * @property campaign - * @abstract The utm_campaign analytics parameter. - */ -@property(nonatomic, copy, nullable) NSString *campaign; -/** - * @property term - * @abstract The utm_term analytics parameter. - */ -@property(nonatomic, copy, nullable) NSString *term; -/** - * @property content - * @abstract The utm_content analytics parameter. - */ -@property(nonatomic, copy, nullable) NSString *content; - -/** - * @method parametersWithSource:medium:campaign: - * @abstract The preferred factory method for creating the analytics parameters object. It includes - * the commonly-used source, medium, and campaign fields. - * @param source The utm_source analytics parameter. - * @param medium The utm_medium analytics parameter. - * @param campaign The utm_campaign analytics parameter. - * @return Returns An object to be used with FIRDynamicLinkURLComponents to add analytics parameters - * to a generated Dynamic Link URL. - */ -+ (instancetype)parametersWithSource:(NSString *)source - medium:(NSString *)medium - campaign:(NSString *)campaign - NS_SWIFT_UNAVAILABLE("Use init(source:medium:campaign:)"); - -/** - * @method parameters - * @abstract A factory method for creating the analytics parameters object. - * @return Returns an object to be used with FIRDynamicLinkURLComponents to add analytics parameters - * to a generated Dynamic Link URL. - */ -+ (instancetype)parameters NS_SWIFT_UNAVAILABLE("Use init()"); - -/** - * @method initWithSource:medium:campaign: - * @abstract The preferred instance method for creating the analytics parameters object. It - * includes the commonly-used source, medium, and campaign fields. - * @param source The utm_source analytics parameter. - * @param medium The utm_medium analytics parameter. - * @param campaign The utm_campaign analytics parameter. - * @return Returns An object to be used with FIRDynamicLinkURLComponents to add analytics parameters - * to a generated Dynamic Link URL. - */ -- (instancetype)initWithSource:(NSString *)source - medium:(NSString *)medium - campaign:(NSString *)campaign; - -/** - * @method init - * @return Returns an object to be used with FIRDynamicLinkURLComponents to add analytics parameters - * to a generated Dynamic Link URL. - */ -- (instancetype)init; - -@end - -/** - * @class FIRDynamicLinkIOSParameters - * @abstract The Dynamic Link iOS parameters. - */ -NS_SWIFT_NAME(DynamicLinkIOSParameters) -@interface FIRDynamicLinkIOSParameters : NSObject - -/** - * @property bundleID - * @abstract The bundle ID of the iOS app to use to open the link. - */ -@property(nonatomic, copy, nullable, readonly) NSString *bundleID; - -/** - * @property appStoreID - * @abstract The appStore ID of the iOS app in AppStore. - */ -@property(nonatomic, copy, nullable) NSString *appStoreID; - -/** - * @property fallbackURL - * @abstract The link to open when the app isn't installed. Specify this to do something other than - * install the app from the App Store when the app isn't installed, such as open the mobile - * web version of the content, or display a promotional page for the app. - */ -@property(nonatomic, nullable) NSURL *fallbackURL; -/** - * @property customScheme - * @abstract The target app's custom URL scheme, if defined to be something other than the app's - * bundle ID - */ -@property(nonatomic, copy, nullable) NSString *customScheme; -/** - * @property iPadBundleID - * @abstract The bundle ID of the iOS app to use on iPads to open the link. This is only required if - * there are separate iPhone and iPad applications. - */ -@property(nonatomic, copy, nullable) NSString *iPadBundleID; -/** - * @property iPadFallbackURL - * @abstract The link to open on iPads when the app isn't installed. Specify this to do something - * other than install the app from the App Store when the app isn't installed, such as open the - * web version of the content, or display a promotional page for the app. - */ -@property(nonatomic, nullable) NSURL *iPadFallbackURL; - -/** - @property minimumAppVersion - @abstract The minimum version of your app that can open the link. If the - * installed app is an older version, the user is taken to the AppStore to upgrade the app. - * Note: It is app's developer responsibility to open AppStore when received link declares - * higher minimumAppVersion than currently installed. - */ -@property(nonatomic, copy, nullable) NSString *minimumAppVersion; - -/** - * @method parametersWithBundleID: - * @abstract A method for creating the iOS parameters object. - * @param bundleID The bundle ID of the iOS app to use to open the link. - * @return Returns an object to be used with FIRDynamicLinkURLComponents to add iOS parameters to a - * generated Dynamic Link URL. - */ -+ (instancetype)parametersWithBundleID:(NSString *)bundleID - NS_SWIFT_UNAVAILABLE("Use initWithBundleID()"); - -/** - * @method initWithBundleID: - * @abstract A method for creating the iOS parameters object. - * @param bundleID The bundle ID of the iOS app to use to open the link. - * @return Returns an object to be used with FIRDynamicLinkURLComponents to add iOS parameters to a - * generated Dynamic Link URL. - */ -- (instancetype)initWithBundleID:(NSString *)bundleID; - -@end - -/** - * @class FIRDynamicLinkItunesConnectAnalyticsParameters - * @abstract The Dynamic Link iTunes Connect parameters. - */ -NS_SWIFT_NAME(DynamicLinkItunesConnectAnalyticsParameters) -@interface FIRDynamicLinkItunesConnectAnalyticsParameters : NSObject - -/** - * @property affiliateToken - * @abstract The iTunes Connect affiliate token. - */ -@property(nonatomic, copy, nullable) NSString *affiliateToken; -/** - * @property campaignToken - * @abstract The iTunes Connect campaign token. - */ -@property(nonatomic, copy, nullable) NSString *campaignToken; -/** - * @property providerToken - * @abstract The iTunes Connect provider token. - */ -@property(nonatomic, copy, nullable) NSString *providerToken; - -/** - * @method parameters - * @abstract A method for creating the iTunes Connect parameters object. - * @return Returns an object to be used with FIRDynamicLinkURLComponents to add iTunes Connect - * parameters to a generated Dynamic Link URL. - */ -+ (instancetype)parameters NS_SWIFT_UNAVAILABLE("Use init()"); - -/** - * @method init - * @abstract A method for creating the iTunes Connect parameters object. - * @return Returns an object to be used with FIRDynamicLinkURLComponents to add iTunes Connect - * parameters to a generated Dynamic Link URL. - */ -- (instancetype)init; - -@end - -/** - * @class FIRDynamicLinkAndroidParameters - * @abstract The Dynamic Link Android parameters. - */ -NS_SWIFT_NAME(DynamicLinkAndroidParameters) -@interface FIRDynamicLinkAndroidParameters : NSObject - -/** - * @property packageName - * @abstract The Android app's package name. - */ -@property(nonatomic, copy, nullable, readonly) NSString *packageName; - -/** - * @property fallbackURL - * @abstract The link to open when the app isn't installed. Specify this to do something other than - * install the app from the Play Store when the app isn't installed, such as open the mobile web - * version of the content, or display a promotional page for the app. - */ -@property(nonatomic, nullable) NSURL *fallbackURL; -/** - @property minimumVersion - @abstract The version code of the minimum version of your app that can open the link. If the - * installed app is an older version, the user is taken to the Play Store to upgrade the app. - */ -@property(nonatomic) NSInteger minimumVersion; - -/** - * @method parametersWithPackageName: - * @abstract A method for creating the Android parameters object. - * @param packageName The Android app's package name. - * @return Returns an object to be used with FIRDynamicLinkURLComponents to add Android parameters - * to a generated Dynamic Link URL. - */ -+ (instancetype)parametersWithPackageName:(NSString *)packageName - NS_SWIFT_UNAVAILABLE("Use initWithPackageName()"); - -/** - * @method initWithPackageName: - * @abstract A method for creating the Android parameters object. - * @param packageName The Android app's package name. - * @return Returns an object to be used with FIRDynamicLinkURLComponents to add Android parameters - * to a generated Dynamic Link URL. - */ -- (instancetype)initWithPackageName:(NSString *)packageName; - -@end - -/** - * @class FIRDynamicLinkSocialMetaTagParameters - * @abstract The Dynamic Link Social Meta Tag parameters. - */ -NS_SWIFT_NAME(DynamicLinkSocialMetaTagParameters) -@interface FIRDynamicLinkSocialMetaTagParameters : NSObject - -/** - * @property title - * @abstract The title to use when the Dynamic Link is shared in a social post. - */ -@property(nonatomic, copy, nullable) NSString *title; -/** - * @property descriptionText - * @abstract The description to use when the Dynamic Link is shared in a social post. - */ -@property(nonatomic, copy, nullable) NSString *descriptionText; -/** - * @property imageURL - * @abstract The URL to an image related to this link. - */ -@property(nonatomic, nullable) NSURL *imageURL; - -/** - * @method parameters - * @abstract A method for creating the Social Meta Tag parameters object. - * @return Returns an object to be used with FIRDynamicLinkURLComponents to add Social Meta Tag - * parameters to a generated Dynamic Link URL. - */ -+ (instancetype)parameters NS_SWIFT_UNAVAILABLE("Use init()"); - -/** - * @method init - * @abstract A method for creating the Social Meta Tag parameters object. - * @return Returns an object to be used with FIRDynamicLinkURLComponents to add Social Meta Tag - * parameters to a generated Dynamic Link URL. - */ -- (instancetype)init; - -@end - -/** - * @class FIRDynamicLinkNavigationInfoParameters - * @abstract Options class for defining navigation behavior of the Dynamic Link. - */ -NS_SWIFT_NAME(DynamicLinkNavigationInfoParameters) -@interface FIRDynamicLinkNavigationInfoParameters : NSObject - -/** - * @property forcedRedirectEnabled - * @abstract Property defines should forced non-interactive redirect be used when link is tapped on - * mobile device. Default behavior is to disable force redirect and show interstitial page where - * user tap will initiate navigation to the App (or AppStore if not installed). Disabled force - * redirect normally improves reliability of the click. - */ -@property(nonatomic, getter=isForcedRedirectEnabled) BOOL forcedRedirectEnabled; - -/** - * @method parameters - * @abstract A method for creating the Navigation Info parameters object. - * @return Returns an object to be used with FIRDynamicLinkURLComponents to add Navigation Info - * parameters to a generated Dynamic Link URL. - */ -+ (instancetype)parameters NS_SWIFT_UNAVAILABLE("Use init()"); - -/** - * @method init - * @abstract A method for creating the Navigation Info parameters object. - * @return Returns an object to be used with FIRDynamicLinkURLComponents to add Navigation Info - * parameters to a generated Dynamic Link URL. - */ -- (instancetype)init; - -@end - -/** - * @class FIRDynamicLinkOtherPlatformParameters - * @abstract Options class for defining other platform(s) parameters of the Dynamic Link. - * Other here means not covered by specific parameters (not iOS and not Android). - */ -NS_SWIFT_NAME(DynamicLinkOtherPlatformParameters) -@interface FIRDynamicLinkOtherPlatformParameters : NSObject - -/** - * @property fallbackUrl - * @abstract Property defines fallback URL to navigate to when Dynamic Link is clicked on - * other platform. - */ -@property(nonatomic, nullable) NSURL *fallbackUrl; - -/** - * @method parameters - * @abstract A method for creating the Other platform parameters object. - * @return Returns an object to be used with FIRDynamicLinkURLComponents to add Other Platform - * parameters to a generated Dynamic Link URL. - */ -+ (instancetype)parameters NS_SWIFT_UNAVAILABLE("Use init()"); - -/** - * @method init - * @abstract A method for creating the Other platform parameters object. - * @return Returns an object to be used with FIRDynamicLinkURLComponents to add Other Platform - * parameters to a generated Dynamic Link URL. - */ -- (instancetype)init; - -@end - -/** - * @class FIRDynamicLinkComponentsOptions - * @abstract Options class for defining how Dynamic Link URLs are generated. - */ -NS_SWIFT_NAME(DynamicLinkComponentsOptions) -@interface FIRDynamicLinkComponentsOptions : NSObject - -/** - * @property pathLength - * @abstract Specifies the length of the path component of a short Dynamic Link. - */ -@property(nonatomic) FIRShortDynamicLinkPathLength pathLength; - -/** - * @method options - * @abstract A method for creating the Dynamic Link components options object. - * @return Returns an object to be used with FIRDynamicLinkURLComponents to specify options related - * to the generation of Dynamic Link URLs. - */ -+ (instancetype)options NS_SWIFT_UNAVAILABLE("Use init()"); - -/** - * @method init - * @abstract A method for creating the Dynamic Link components options object. - * @return Returns an object to be used with FIRDynamicLinkURLComponents to specify options related - * to the generation of Dynamic Link URLs. - */ -- (instancetype)init; - -@end - -/** - * @class FIRDynamicLinkComponents - * @abstract The class used for Dynamic Link URL generation; supports creation of short and long - * Dynamic Link URLs. Short URLs will have a domain and a randomized path; long URLs will have a - * domain and a query that contains all of the Dynamic Link parameters. - */ -NS_SWIFT_NAME(DynamicLinkComponents) -@interface FIRDynamicLinkComponents : NSObject - -/** - * @property analyticsParameters - * @abstract Applies Analytics parameters to a generated Dynamic Link URL. - */ -@property(nonatomic, nullable) FIRDynamicLinkGoogleAnalyticsParameters *analyticsParameters; -/** - * @property socialMetaTagParameters - * @abstract Applies Social Meta Tag parameters to a generated Dynamic Link URL. - */ -@property(nonatomic, nullable) FIRDynamicLinkSocialMetaTagParameters *socialMetaTagParameters; -/** - * @property iOSParameters - * @abstract Applies iOS parameters to a generated Dynamic Link URL. - */ -@property(nonatomic, nullable) FIRDynamicLinkIOSParameters *iOSParameters; -/** - * @property iTunesConnectParameters - * @abstract Applies iTunes Connect parameters to a generated Dynamic Link URL. - */ -@property(nonatomic, nullable) - FIRDynamicLinkItunesConnectAnalyticsParameters *iTunesConnectParameters; -/** - * @property androidParameters - * @abstract Applies Android parameters to a generated Dynamic Link URL. - */ -@property(nonatomic, nullable) FIRDynamicLinkAndroidParameters *androidParameters; -/** - * @property navigationInfoParameters - * @abstract Applies Navigation Info parameters to a generated Dynamic Link URL. - */ -@property(nonatomic, nullable) FIRDynamicLinkNavigationInfoParameters *navigationInfoParameters; -/** - * @property otherPlatformParameters - * @abstract Applies Other platform parameters to a generated Dynamic Link URL. - */ -@property(nonatomic, nullable) FIRDynamicLinkOtherPlatformParameters *otherPlatformParameters; -/** - * @property options - * @abstract Defines behavior for generating Dynamic Link URLs. - */ -@property(nonatomic, nullable) FIRDynamicLinkComponentsOptions *options; - -/** - * @property link - * @abstract The link the target app will open. You can specify any URL the app can handle, such as - * a link to the app's content, or a URL that initiates some app-specific logic such as - * crediting the user with a coupon, or displaying a specific welcome screen. This link must be - * a well-formatted URL, be properly URL-encoded, and use the HTTP or HTTPS scheme. - */ -@property(nonatomic) NSURL *link; -/** - * @property domain - * @abstract The Firebase project's Dynamic Links domain. You can find this value in the Dynamic - * Links section of the Firebase console. - * https://console.firebase.google.com/ - */ -@property(nonatomic, nullable, copy) NSString *domain; - -/** - * @property url - * @abstract A generated long Dynamic Link URL. - */ -@property(nonatomic, nullable, readonly) NSURL *url; - -/** - * @method componentsWithLink:domainURIPrefix: - * @abstract Generates a Dynamic Link URL components object with the minimum necessary parameters - * set to generate a fully-functional Dynamic Link. - * @param link Deep link to be stored in created Dynamic link. This link also called "payload" of - * the Dynamic link. - * @param domainURIPrefix Domain URI Prefix of your App. This value must be your assigned - * domain from the Firebase console. (e.g. https://xyz.page.link) The domain URI prefix must - * start with a valid HTTPS scheme (https://). - * @return Returns an instance of FIRDynamicLinkComponents if the parameters succeed validation, - * else returns nil. - */ -+ (nullable instancetype)componentsWithLink:(NSURL *)link - domainURIPrefix:(NSString *)domainURIPrefix - NS_SWIFT_UNAVAILABLE("Use init(link:domainURIPrefix:)"); - -/** - * @method initWithLink:domainURIPrefix: - * @abstract Generates a Dynamic Link URL components object with the minimum necessary parameters - * set to generate a fully-functional Dynamic Link. - * @param link Deep link to be stored in created Dynamic link. This link also called "payload" of - * the Dynamic link. - * @param domainURIPrefix Domain URI Prefix of your App. This value must be your assigned - * domain from the Firebase console. (e.g. https://xyz.page.link) The domain URI prefix must - * start with a valid HTTPS scheme (https://). - * @return Returns an instance of FIRDynamicLinkComponents if the parameters succeed validation, - * else returns nil. - */ -- (nullable instancetype)initWithLink:(NSURL *)link domainURIPrefix:(NSString *)domainURIPrefix; - -/** - * @method shortenURL:options:completion: - * @abstract Shortens a Dynamic Link URL. This method may be used for shortening a custom URL that - * was not generated using FIRDynamicLinkComponents. - * @param url A properly-formatted long Dynamic Link URL. - * @param completion A block to be executed upon completion of the shortening attempt. It is - * guaranteed to be executed once and on the main thread. - */ -+ (void)shortenURL:(NSURL *)url - options:(FIRDynamicLinkComponentsOptions *_Nullable)options - completion:(void (^)(NSURL *_Nullable shortURL, - NSArray *_Nullable warnings, - NSError *_Nullable error))completion; - -/** - * @method shortenWithCompletion: - * @abstract Generates a short Dynamic Link URL using all set parameters. - * @param completion A block to be executed upon completion of the shortening attempt. It is - * guaranteed to be executed once and on the main thread. - */ -- (void)shortenWithCompletion:(void (^)(NSURL *_Nullable shortURL, - NSArray *_Nullable warnings, - NSError *_Nullable error))completion; - -@end - -NS_ASSUME_NONNULL_END diff --git a/FirebaseDynamicLinks/Sources/Public/FirebaseDynamicLinks/FIRDynamicLink.h b/FirebaseDynamicLinks/Sources/Public/FirebaseDynamicLinks/FIRDynamicLink.h deleted file mode 100644 index 5524d3c52ee..00000000000 --- a/FirebaseDynamicLinks/Sources/Public/FirebaseDynamicLinks/FIRDynamicLink.h +++ /dev/null @@ -1,90 +0,0 @@ -/* - * 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. - */ - -#import - -NS_ASSUME_NONNULL_BEGIN - -/** - * @file FIRDynamicLink.h - * @abstract Dynamic Link object used in Firebase Dynamic Links. - */ - -/** - * @abstract The match type of the Dynamic Link. - */ -typedef NS_ENUM(NSUInteger, FIRDLMatchType) { - /** - * The match has not been achieved. - */ - FIRDLMatchTypeNone, - /** - * The match between the Dynamic Link and this device may not be perfect, hence you should not - * reveal any personal information related to the Dynamic Link. - */ - FIRDLMatchTypeWeak, - /** - * The match between the Dynamic Link and this device has high confidence but small possibility of - * error still exist. - */ - FIRDLMatchTypeDefault, - /** - * The match between the Dynamic Link and this device is exact, hence you may reveal personal - * information related to the Dynamic Link. - */ - FIRDLMatchTypeUnique, -} NS_SWIFT_NAME(DLMatchType); - -/** - * @class FIRDynamicLink - * @abstract A received Dynamic Link. - */ -NS_SWIFT_NAME(DynamicLink) -@interface FIRDynamicLink : NSObject - -/** - * @property url - * @abstract The URL that was passed to the app. - */ -@property(nonatomic, copy, readonly, nullable) NSURL *url; - -/** - * @property matchType - * @abstract The match type of the received Dynamic Link. - */ -@property(nonatomic, assign, readonly) FIRDLMatchType matchType; - -/** - * @property utmParametersDictionary - * @abstract UTM parameters associated with a Firebase Dynamic Link. - */ -@property(nonatomic, copy, readonly) NSDictionary *utmParametersDictionary; - -/** - * @property minimumAppVersion - * @abstract The minimum iOS application version that supports the Dynamic Link. This is retrieved - * from the imv= parameter of the Dynamic Link URL. Note: This is not the minimum iOS system - * version, but the minimum app version. If app version of the opening app is less than the - * value of this property, then app expected to open AppStore to allow user to download most - * recent version. App can notify or ask user before opening AppStore. - */ -@property(nonatomic, copy, readonly, nullable) NSString *minimumAppVersion; - -- (instancetype)init NS_UNAVAILABLE; - -@end - -NS_ASSUME_NONNULL_END diff --git a/FirebaseDynamicLinks/Sources/Public/FirebaseDynamicLinks/FIRDynamicLinks.h b/FirebaseDynamicLinks/Sources/Public/FirebaseDynamicLinks/FIRDynamicLinks.h deleted file mode 100644 index c07a88fa2bf..00000000000 --- a/FirebaseDynamicLinks/Sources/Public/FirebaseDynamicLinks/FIRDynamicLinks.h +++ /dev/null @@ -1,147 +0,0 @@ -/* - * 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. - */ - -#import - -#import "FIRDynamicLink.h" -#import "FIRDynamicLinksCommon.h" - -NS_ASSUME_NONNULL_BEGIN - -/** - * @file FIRDynamicLinks.h - * @abstract Firebase Dynamic Links - */ - -/** - * @class FIRDynamicLinks - * @abstract A class that checks for pending Dynamic Links and parses URLs. - * This class is available on iOS only. - */ -DEPRECATED_MSG_ATTRIBUTE( - "Firebase Dynamic Links is deprecated and the service will shut down on August 25, 2025.") -NS_EXTENSION_UNAVAILABLE_IOS("Firebase Dynamic Links is not supported for iOS extensions.") -API_UNAVAILABLE(macos, tvos, watchos) -NS_SWIFT_NAME(DynamicLinks) -@interface FIRDynamicLinks : NSObject - -/** - * @method dynamicLinks - * @abstract Shared instance of FIRDynamicLinks. - * @return Shared instance of FIRDynamicLinks. - */ -+ (instancetype)dynamicLinks NS_SWIFT_NAME(dynamicLinks()); - -/** - * @method shouldHandleDynamicLinkFromCustomSchemeURL: - * @abstract Determine whether FIRDynamicLinks should handle the given URL. This does not - * guarantee that |dynamicLinkFromCustomSchemeURL:| will return a non-nil value, but it means - * the client should not attempt to handle the URL. - * @param url Custom scheme URL. - * @return Whether the URL can be handled by FIRDynamicLinks. - */ -- (BOOL)shouldHandleDynamicLinkFromCustomSchemeURL:(NSURL *)url - NS_SWIFT_NAME(shouldHandleDynamicLink(fromCustomSchemeURL:)); - -/** - * @method dynamicLinkFromCustomSchemeURL: - * @abstract Get a Dynamic Link from a custom scheme URL. This method parses URLs with a custom - * scheme, for instance, "comgoogleapp://google/link?deep_link_id=abc123". It is suggested to - * call it inside your |UIApplicationDelegate|'s - * |application:openURL:sourceApplication:annotation| and |application:openURL:options:| - * methods. - * @param url Custom scheme URL. - * @return Dynamic Link object if the URL is valid and has link parameter, otherwise nil. - */ -- (nullable FIRDynamicLink *)dynamicLinkFromCustomSchemeURL:(NSURL *)url - NS_SWIFT_NAME(dynamicLink(fromCustomSchemeURL:)); - -/** - * @method dynamicLinkFromUniversalLinkURL:completion: - * @abstract Get a Dynamic Link from a universal link URL. This method parses universal link - * URLs, for instance, - * "https://example.page.link?link=https://www.google.com&ibi=com.google.app&ius=comgoogleapp". - * It is suggested to call it inside your |UIApplicationDelegate|'s - * |application:continueUserActivity:restorationHandler:| method. - * @param url Custom scheme URL. - * @param completion A block that handles the outcome of attempting to get a Dynamic Link from a - * universal link URL. - */ -- (void)dynamicLinkFromUniversalLinkURL:(NSURL *)url - completion:(void (^)(FIRDynamicLink *_Nullable dynamicLink, - NSError *_Nullable error))completion - NS_SWIFT_NAME(dynamicLink(fromUniversalLink:completion:)); - -/** - * @method dynamicLinkFromUniversalLinkURL: - * @abstract Get a Dynamic Link from a universal link URL. This method parses universal link - * URLs, for instance, - * "https://example.page.link?link=https://www.google.com&ibi=com.google.app&ius=comgoogleapp". - * It is suggested to call it inside your |UIApplicationDelegate|'s - * |application:continueUserActivity:restorationHandler:| method. - * @param url Custom scheme URL. - * @return Dynamic Link object if the URL is valid and has link parameter, otherwise nil. - */ -- (nullable FIRDynamicLink *)dynamicLinkFromUniversalLinkURL:(NSURL *)url - NS_SWIFT_NAME(dynamicLink(fromUniversalLink:)) - DEPRECATED_MSG_ATTRIBUTE("Use dynamicLinkFromUniversalLinkURL:completion: instead."); - -/** - * @method handleUniversalLink:completion: - * @abstract Convenience method to handle a Universal Link whether it is long or short. - * @param url A Universal Link URL. - * @param completion A block that handles the outcome of attempting to create a FIRDynamicLink. - * @return YES if FIRDynamicLinks is handling the link, otherwise, NO. - */ -- (BOOL)handleUniversalLink:(NSURL *)url - completion:(void (^)(FIRDynamicLink *_Nullable dynamicLink, - NSError *_Nullable error))completion; - -/** - * @method resolveShortLink:completion: - * @abstract Retrieves the details of the Dynamic Link that the shortened URL represents. - * @param url A Short Dynamic Link. - * @param completion Block to be run upon completion. - */ -- (void)resolveShortLink:(NSURL *)url - completion:(void (^)(NSURL *_Nullable url, NSError *_Nullable error))completion; - -/** - * @method matchesShortLinkFormat: - * @abstract Determines if a given URL matches the given short Dynamic Link format. - * @param url A URL. - * @return YES if the URL is a short Dynamic Link, otherwise, NO. - */ -- (BOOL)matchesShortLinkFormat:(NSURL *)url; - -/** - * @method performDiagnosticsWithCompletion: - * @abstract Performs basic FDL self diagnostic. Method effect on startup latency is quite small - * and no user-visible UI is presented. This method should be used for debugging purposes. - * App developers are encouraged to include output, generated by this method, to the support - * requests sent to Firebase support. - * @param completionHandler Handler that will be called when diagnostic completes. - * If value of the completionHandler is nil than diagnostic output will be printed to - * the standard output. - * diagnosticOutput String that includes diagnostic information. - * hasErrors Param will have YES value if diagnostic method detected error, NO otherwise. - */ -+ (void)performDiagnosticsWithCompletion:(void (^_Nullable)(NSString *diagnosticOutput, - BOOL hasErrors))completionHandler; - -@end - -NS_ASSUME_NONNULL_END diff --git a/FirebaseDynamicLinks/Sources/Public/FirebaseDynamicLinks/FIRDynamicLinksCommon.h b/FirebaseDynamicLinks/Sources/Public/FirebaseDynamicLinks/FIRDynamicLinksCommon.h deleted file mode 100644 index c4f0fdca6be..00000000000 --- a/FirebaseDynamicLinks/Sources/Public/FirebaseDynamicLinks/FIRDynamicLinksCommon.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - * 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. - */ - -#import - -@class FIRDynamicLink; - -NS_ASSUME_NONNULL_BEGIN - -/** - * @file FIRDynamicLinksCommon.h - * @abstract Commonly shared definitions within Firebase Dynamic Links. - */ - -/** - * @abstract The definition of the block used by |resolveShortLink:completion:| - */ -typedef void (^FIRDynamicLinkResolverHandler)(NSURL* _Nullable url, NSError* _Nullable error) - NS_SWIFT_UNAVAILABLE("Use Swift's closure syntax instead."); - -/** - * @abstract The definition of the block used by |handleUniversalLink:completion:| - */ -typedef void (^FIRDynamicLinkUniversalLinkHandler)(FIRDynamicLink* _Nullable dynamicLink, - NSError* _Nullable error) - NS_SWIFT_UNAVAILABLE("Use Swift's closure syntax instead."); - -NS_ASSUME_NONNULL_END diff --git a/FirebaseDynamicLinks/Sources/Public/FirebaseDynamicLinks/FirebaseDynamicLinks.h b/FirebaseDynamicLinks/Sources/Public/FirebaseDynamicLinks/FirebaseDynamicLinks.h deleted file mode 100755 index ea6f45f021e..00000000000 --- a/FirebaseDynamicLinks/Sources/Public/FirebaseDynamicLinks/FirebaseDynamicLinks.h +++ /dev/null @@ -1,20 +0,0 @@ -/* - * 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. - */ - -#import "FDLURLComponents.h" -#import "FIRDynamicLink.h" -#import "FIRDynamicLinks.h" -#import "FIRDynamicLinksCommon.h" diff --git a/FirebaseDynamicLinks/Sources/Resources/PrivacyInfo.xcprivacy b/FirebaseDynamicLinks/Sources/Resources/PrivacyInfo.xcprivacy deleted file mode 100644 index 0fccd3b0f69..00000000000 --- a/FirebaseDynamicLinks/Sources/Resources/PrivacyInfo.xcprivacy +++ /dev/null @@ -1,46 +0,0 @@ - - - - - NSPrivacyTracking - - NSPrivacyTrackingDomains - - - NSPrivacyCollectedDataTypes - - - NSPrivacyCollectedDataType - NSPrivacyCollectedDataTypeOtherDataTypes - NSPrivacyCollectedDataTypeLinked - - NSPrivacyCollectedDataTypeTracking - - NSPrivacyCollectedDataTypePurposes - - NSPrivacyCollectedDataTypePurposeAppFunctionality - - - - NSPrivacyAccessedAPITypes - - - NSPrivacyAccessedAPIType - NSPrivacyAccessedAPICategoryFileTimestamp - NSPrivacyAccessedAPITypeReasons - - C617.1 - - - - NSPrivacyAccessedAPIType - NSPrivacyAccessedAPICategoryUserDefaults - NSPrivacyAccessedAPITypeReasons - - 1C8F.1 - - - - - - diff --git a/FirebaseDynamicLinks/Sources/Utilities/FDLDeviceHeuristicsHelper.h b/FirebaseDynamicLinks/Sources/Utilities/FDLDeviceHeuristicsHelper.h deleted file mode 100644 index 84b3179e6ab..00000000000 --- a/FirebaseDynamicLinks/Sources/Utilities/FDLDeviceHeuristicsHelper.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * 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 - -@interface FDLDeviceHeuristicsHelper : NSObject - -/** - * Creates DeviceInfo dictionary based on the provided information. - */ -+ (NSDictionary *) - FDLDeviceInfoDictionaryFromResolutionHeight:(NSInteger)resolutionHeight - resolutionWidth:(NSInteger)resolutionWidth - locale:(NSString *)locale - localeRaw:(NSString *)localeRaw - localeFromWebview:(NSString *)localeFromWebView - timeZone:(NSString *)timezone - modelName:(NSString *)modelName; - -@end diff --git a/FirebaseDynamicLinks/Sources/Utilities/FDLDeviceHeuristicsHelper.m b/FirebaseDynamicLinks/Sources/Utilities/FDLDeviceHeuristicsHelper.m deleted file mode 100644 index ae9f18fc4da..00000000000 --- a/FirebaseDynamicLinks/Sources/Utilities/FDLDeviceHeuristicsHelper.m +++ /dev/null @@ -1,43 +0,0 @@ -/* - * 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 "FirebaseDynamicLinks/Sources/Utilities/FDLDeviceHeuristicsHelper.h" -#import - -@implementation FDLDeviceHeuristicsHelper - -/** - * Creates DeviceInfo dictionary based on the provided information. - */ -+ (NSDictionary *) - FDLDeviceInfoDictionaryFromResolutionHeight:(NSInteger)resolutionHeight - resolutionWidth:(NSInteger)resolutionWidth - locale:(NSString *)locale - localeRaw:(NSString *)localeRaw - localeFromWebview:(NSString *)localeFromWebView - timeZone:(NSString *)timezone - modelName:(NSString *)modelName { - return @{ - @"screenResolutionHeight" : @(resolutionHeight), - @"screenResolutionWidth" : @(resolutionWidth), - @"languageCode" : locale, - @"languageCodeRaw" : localeRaw, - @"languageCodeFromWebview" : localeFromWebView, - @"timezone" : timezone, - @"deviceModelName" : modelName, - }; -} -@end diff --git a/FirebaseDynamicLinks/Sources/Utilities/FDLUtilities.h b/FirebaseDynamicLinks/Sources/Utilities/FDLUtilities.h deleted file mode 100644 index a985355e907..00000000000 --- a/FirebaseDynamicLinks/Sources/Utilities/FDLUtilities.h +++ /dev/null @@ -1,148 +0,0 @@ -/* - * 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. - */ - -#import - -NS_ASSUME_NONNULL_BEGIN - -FOUNDATION_EXPORT NSString *const kFIRDLParameterDeepLinkIdentifier; -FOUNDATION_EXPORT NSString *const kFIRDLParameterLink; -FOUNDATION_EXPORT NSString *const kFIRDLParameterMinimumAppVersion; -FOUNDATION_EXPORT NSString *const kFIRDLParameterCampaign; -FOUNDATION_EXPORT NSString *const kFIRDLParameterContent; -FOUNDATION_EXPORT NSString *const kFIRDLParameterMedium; -FOUNDATION_EXPORT NSString *const kFIRDLParameterTerm; -FOUNDATION_EXPORT NSString *const kFIRDLParameterSource; -FOUNDATION_EXPORT NSString *const kFIRDLParameterMatchType; -FOUNDATION_EXPORT NSString *const kFIRDLParameterInviteId; -FOUNDATION_EXPORT NSString *const kFIRDLParameterWeakMatchEndpoint; -FOUNDATION_EXPORT NSString *const kFIRDLParameterMatchMessage; -FOUNDATION_EXPORT NSString *const kFIRDLParameterRequestIPVersion; - -/** - * After a Dynamic Link URL is opened in Safari, a cookie is dropped on the domain goo.gl. When a - * specific URL is used, JavaScript checks if there's a cookie and, if it exists, redirects to the - * custom-scheme URL stored in it. That causes application:openURL:options: to be called in - * AppDelegate with the custom-scheme URL. This method creates and returns the URL required to check - * for the presence of the FDL cookie on goo.gl. - */ -NSURL *FIRDLCookieRetrievalURL(NSString *urlScheme, NSString *bundleID); - -/** - * Creates a URL query string from the contents of an NSDictionary. Single-percent-encoded using - * allowed query characters. - */ -NSString *FIRDLURLQueryStringFromDictionary(NSDictionary *dictionary); - -/** - * @fn FIRDLDictionaryFromQuery - * @abstract This receives a URL query parameter string and parses it into a dictionary that - * represents the query. This method is necessary as |gtm_dictionaryWithHttpArgumentsString:| - * removes the pluses with spaces and, as a result, cannot be used without first replacing all - * instances of the plus character with '%2B'. - * @param queryString The query string of a URL. - * @return returns a dictionary of type that represents the query. - */ -NSDictionary *FIRDLDictionaryFromQuery(NSString *queryString); - -/** - * @fn FIRDLDeepLinkURLWithInviteID - * @abstract A method that takes the given parameters and constructs a url-scheme-based URL that can - * be opened within the containing app, so that the correct link handlers are fired. This is - * used after Firebase Dynamic Links either has found a pending deep link, or no link was found. - * @param inviteID The invitation ID associated with the Dynamic Link. Included in App Invite URLs. - * @param deepLinkString The deep link, if any, found in the response from a server lookup. - * @param utmSource The UTM source, if any, found in the response from a server lookup. - * @param utmMedium The UTM medium, if any, found in the response from a server lookup. - * @param utmCampaign The UTM campaign, if any, found in the response from a server lookup. - * @param isWeakLink This value provides information is deep link was weak-matched. - * @param weakMatchEndpoint This value provides information about which endpoint, IPv4 or IPv6, was - * used to perform the lookup if weak match is used. - * @param minAppVersion The minimum app version string, if any, found in the response from a server - * lookup. If this value is provided, the app developer can use it to determine whether or not - * to handle the deep link, or to encourage their users to perhaps upgrade their app. - * @param URLScheme Custom URL scheme of the Application. - */ -NSURL *FIRDLDeepLinkURLWithInviteID(NSString *_Nullable inviteID, - NSString *_Nullable deepLinkString, - NSString *_Nullable utmSource, - NSString *_Nullable utmMedium, - NSString *_Nullable utmCampaign, - NSString *_Nullable utmContent, - NSString *_Nullable utmTerm, - BOOL isWeakLink, - NSString *_Nullable weakMatchEndpoint, - NSString *_Nullable minAppVersion, - NSString *URLScheme, - NSString *_Nullable matchMessage); - -/** - * @fn FIRDLOSVersionSupported(NSString *systemVersion, NSString *minSupportedVersion) - * @abstract Determines if the system version is greater than or equal to the minSupportedVersion. - * @param systemVersion The iOS version to use as the current version in the comparison. - * @param minSupportedVersion The minimum iOS system version that is supported. - * @return YES if the system version is greater than or equal to the minimum, otherwise, NO. - */ -BOOL FIRDLOSVersionSupported(NSString *_Nullable systemVersion, NSString *minSupportedVersion); - -/** - Returns date of the App installation. Return value may be nil in case of failure. - */ -NSDate *_Nullable FIRDLAppInstallationDate(void); - -/** - Returns current device model name. - */ -NSString *FIRDLDeviceModelName(void); - -/** - Returns current device locale. The method will try to bring locale format to the same format as - reported by Safari/WebView. - */ -NSString *FIRDLDeviceLocale(void) __deprecated_msg("Use FIRDeviceLocaleRaw instead"); - -/** - Returns current device locale as reported by iOS. - */ -NSString *FIRDLDeviceLocaleRaw(void); - -/** - Returns current device timezone. - */ -NSString *FIRDLDeviceTimezone(void); - -/** - Returns is universal link (long FDL link) parsable. - */ -BOOL FIRDLCanParseUniversalLinkURL(NSURL *_Nullable URL); - -/** - Return is link matches FDL short link format. - */ -BOOL FIRDLMatchesShortLinkFormat(NSURL *URL); - -/** - Returns match type string using server side match type string. - Returned string can be used as customURLScheme URL with parameter kFIRDLParameterMatchType. - */ -NSString *FIRDLMatchTypeStringFromServerString(NSString *_Nullable serverMatchTypeString); - -/** - Add custom domains from the info.plist to the internal allowlist. - */ -void FIRDLAddToAllowListForCustomDomainsArray(NSArray *customDomains); - -NS_ASSUME_NONNULL_END diff --git a/FirebaseDynamicLinks/Sources/Utilities/FDLUtilities.m b/FirebaseDynamicLinks/Sources/Utilities/FDLUtilities.m deleted file mode 100644 index fa00871bce0..00000000000 --- a/FirebaseDynamicLinks/Sources/Utilities/FDLUtilities.m +++ /dev/null @@ -1,368 +0,0 @@ -/* - * 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. - */ - -#import -#if TARGET_OS_IOS - -#import "FirebaseDynamicLinks/Sources/Utilities/FDLUtilities.h" - -#import -#include - -NS_ASSUME_NONNULL_BEGIN - -NSString *const kFIRDLParameterDeepLinkIdentifier = @"deep_link_id"; -NSString *const kFIRDLParameterLink = @"link"; -NSString *const kFIRDLParameterMinimumAppVersion = @"imv"; -NSString *const kFIRDLParameterCampaign = @"utm_campaign"; -NSString *const kFIRDLParameterContent = @"utm_content"; -NSString *const kFIRDLParameterMedium = @"utm_medium"; -NSString *const kFIRDLParameterSource = @"utm_source"; -NSString *const kFIRDLParameterTerm = @"utm_term"; -NSString *const kFIRDLParameterMatchType = @"match_type"; -NSString *const kFIRDLParameterInviteId = @"invitation_id"; -NSString *const kFIRDLParameterWeakMatchEndpoint = @"invitation_weakMatchEndpoint"; -NSString *const kFIRDLParameterMatchMessage = @"match_message"; -NSString *const kFIRDLParameterRequestIPVersion = @"request_ip_version"; -static NSSet *FIRDLCustomDomains = nil; - -NSURL *FIRDLCookieRetrievalURL(NSString *urlScheme, NSString *bundleID) { - static NSString *const kFDLBundleIDQueryParameterName = @"fdl_ios_bundle_id"; - static NSString *const kFDLURLSchemeQueryParameterName = @"fdl_ios_url_scheme"; - - NSURLComponents *components = [[NSURLComponents alloc] init]; - components.scheme = @"https"; - components.host = @"goo.gl"; - components.path = @"/app/_/deeplink"; - NSMutableArray *queryItems = [NSMutableArray array]; - - [queryItems addObject:[NSURLQueryItem queryItemWithName:kFDLBundleIDQueryParameterName - value:bundleID]]; - [queryItems addObject:[NSURLQueryItem queryItemWithName:kFDLURLSchemeQueryParameterName - value:urlScheme]]; - [components setQueryItems:queryItems]; - - return [components URL]; -} - -NSString *FIRDLURLQueryStringFromDictionary(NSDictionary *dictionary) { - NSMutableString *parameters = [NSMutableString string]; - - NSCharacterSet *queryCharacterSet = [NSCharacterSet alphanumericCharacterSet]; - NSString *parameterFormatString = @"%@%@=%@"; - __block NSUInteger index = 0; - [dictionary enumerateKeysAndObjectsUsingBlock:^(NSString *_Nonnull key, NSString *_Nonnull value, - BOOL *_Nonnull stop) { - NSString *delimiter = index++ == 0 ? @"?" : @"&"; - NSString *encodedValue = - [value stringByAddingPercentEncodingWithAllowedCharacters:queryCharacterSet]; - NSString *parameter = - [NSString stringWithFormat:parameterFormatString, delimiter, key, encodedValue]; - [parameters appendString:parameter]; - }]; - - return parameters; -} - -NSDictionary *FIRDLDictionaryFromQuery(NSString *queryString) { - NSArray *keyValuePairs = [queryString componentsSeparatedByString:@"&"]; - - NSMutableDictionary *queryDictionary = - [NSMutableDictionary dictionaryWithCapacity:keyValuePairs.count]; - - for (NSString *pair in keyValuePairs) { - NSArray *keyValuePair = [pair componentsSeparatedByString:@"="]; - if (keyValuePair.count == 2) { - NSString *key = keyValuePair[0]; - NSString *value = [keyValuePair[1] stringByRemovingPercentEncoding]; - [queryDictionary setObject:value forKey:key]; - } - } - - return [queryDictionary copy]; -} - -NSURL *FIRDLDeepLinkURLWithInviteID(NSString *_Nullable inviteID, - NSString *_Nullable deepLinkString, - NSString *_Nullable utmSource, - NSString *_Nullable utmMedium, - NSString *_Nullable utmCampaign, - NSString *_Nullable utmContent, - NSString *_Nullable utmTerm, - BOOL isWeakLink, - NSString *_Nullable weakMatchEndpoint, - NSString *_Nullable minAppVersion, - NSString *URLScheme, - NSString *_Nullable matchMessage) { - // We are unable to use NSURLComponents as NSURLQueryItem is available beginning in iOS 8 and - // appending our query string with NSURLComponents improperly formats the query by adding - // a second '?' in the query. - NSMutableDictionary *queryDictionary = [NSMutableDictionary dictionary]; - if (inviteID != nil) { - queryDictionary[kFIRDLParameterInviteId] = inviteID; - } - if (deepLinkString != nil) { - queryDictionary[kFIRDLParameterDeepLinkIdentifier] = deepLinkString; - } - if (utmSource != nil) { - queryDictionary[kFIRDLParameterSource] = utmSource; - } - if (utmMedium != nil) { - queryDictionary[kFIRDLParameterMedium] = utmMedium; - } - if (utmCampaign != nil) { - queryDictionary[kFIRDLParameterCampaign] = utmCampaign; - } - - if (utmContent != nil) { - queryDictionary[kFIRDLParameterContent] = utmContent; - } - - if (utmTerm != nil) { - queryDictionary[kFIRDLParameterTerm] = utmTerm; - } - - if (isWeakLink) { - queryDictionary[kFIRDLParameterMatchType] = @"weak"; - } else { - queryDictionary[kFIRDLParameterMatchType] = @"unique"; - } - if (weakMatchEndpoint != nil) { - queryDictionary[kFIRDLParameterWeakMatchEndpoint] = weakMatchEndpoint; - } - if (minAppVersion != nil) { - queryDictionary[kFIRDLParameterMinimumAppVersion] = minAppVersion; - } - if (matchMessage != nil) { - queryDictionary[kFIRDLParameterMatchMessage] = matchMessage; - } - - NSString *scheme = [URLScheme lowercaseString]; - NSString *queryString = FIRDLURLQueryStringFromDictionary(queryDictionary); - NSString *urlString = [NSString stringWithFormat:@"%@://google/link/%@", scheme, queryString]; - - return [NSURL URLWithString:urlString]; -} - -BOOL FIRDLOSVersionSupported(NSString *_Nullable systemVersion, NSString *minSupportedVersion) { - systemVersion = systemVersion ?: [UIDevice currentDevice].systemVersion; - return [systemVersion compare:minSupportedVersion options:NSNumericSearch] != NSOrderedAscending; -} - -NSDate *_Nullable FIRDLAppInstallationDate(void) { - NSURL *documentsDirectoryURL = - [[[NSFileManager defaultManager] URLsForDirectory:NSApplicationSupportDirectory - inDomains:NSUserDomainMask] firstObject]; - if (!documentsDirectoryURL) { - return nil; - } - NSDictionary *attributes = - [[NSFileManager defaultManager] attributesOfItemAtPath:documentsDirectoryURL.path error:NULL]; - if (attributes[NSFileCreationDate] && - [attributes[NSFileCreationDate] isKindOfClass:[NSDate class]]) { - return attributes[NSFileCreationDate]; - } - return nil; -} - -NSString *FIRDLDeviceModelName(void) { - // this method will return string like iPad3,3 - // for Simulator this will be x86_64 - static NSString *machineString = @""; - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ - size_t size; - - // compute string size - if (sysctlbyname("hw.machine", NULL, &size, NULL, 0) == 0) { - // get device name - char *machine = calloc(1, size); - if (sysctlbyname("hw.machine", machine, &size, NULL, 0) == 0) { - machineString = [NSString stringWithCString:machine encoding:NSUTF8StringEncoding]; - } - free(machine); - } - }); - return machineString; -} - -NSString *FIRDLDeviceLocale(void) { - // expected return value from this method looks like: @"en-US" - return [[[NSLocale currentLocale] localeIdentifier] stringByReplacingOccurrencesOfString:@"_" - withString:@"-"]; -} - -NSString *FIRDLDeviceLocaleRaw(void) { - return [[NSLocale currentLocale] localeIdentifier]; -} - -NSString *FIRDLDeviceTimezone(void) { - NSString *timeZoneName = [[NSTimeZone localTimeZone] name]; - return timeZoneName; -} - -BOOL FIRDLIsURLForAllowedCustomDomain(NSURL *URL) { - if (URL) { - for (NSURL *allowedCustomDomain in FIRDLCustomDomains) { - // At least one custom domain host name should match at a minimum. - if ([URL.absoluteString hasPrefix:allowedCustomDomain.absoluteString]) { - NSString *urlWithoutDomainURIPrefix = - [URL.absoluteString substringFromIndex:allowedCustomDomain.absoluteString.length]; - - // The urlWithoutDomainURIPrefix should be starting with '/' or '?' otherwise it means the - // allowed domain is not exactly matching the incoming URL domain prefix. - if ([urlWithoutDomainURIPrefix hasPrefix:@"/"] || - [urlWithoutDomainURIPrefix hasPrefix:@"?"]) { - // For a valid custom domain DL Suffix the urlWithoutDomainURIPrefix should have: - // 1. At least one path exists OR - // 2. Should have a link query param with an http/https link - - NSURLComponents *components = - [[NSURLComponents alloc] initWithString:urlWithoutDomainURIPrefix]; - if (components.path && components.path.length > 1) { - // Have a path exists. So valid custom domain. - return true; - } - - if (components.queryItems && components.queryItems.count > 0) { - for (NSURLQueryItem *queryItem in components.queryItems) { - // Checks whether we have a link query param - if ([queryItem.name caseInsensitiveCompare:@"link"] == NSOrderedSame) { - // Checks whether link query param value starts with http/https - if (queryItem.value && ([queryItem.value hasPrefix:@"http://"] || - [queryItem.value hasPrefix:@"https://"])) { - return true; - } - } - } - } - } - } - } - } - return false; -} - -/* We are validating following domains in proper format. - *.page.link - *.app.goo.gl - *.page.link/i/ - *.app.goo.gl/i/ - */ -BOOL FIRDLIsAValidDLWithFDLDomain(NSURL *_Nullable URL) { - BOOL matchesRegularExpression = false; - NSString *urlStr = URL.absoluteString; - - if ([URL.host containsString:@".page.link"] || [URL.host containsString:@".app.goo.gl"] || - [URL.host containsString:@".app.google"]) { - // Matches the *.page.link and *.app.goo.gl domains. - matchesRegularExpression = - ([urlStr rangeOfString: - @"^https?://" - @"[a-zA-Z0-9]+((\\.app\\.goo\\.gl)|(\\.page\\.link)|(\\.app\\.google))((\\/" - @"?\\?.*link=https?.*)|(\\/[a-zA-Z0-9-_]+)((\\/?\\?.*=.*)?$|$))" - options:NSRegularExpressionSearch] - .location != NSNotFound); - - if (!matchesRegularExpression) { - // Matches the *.page.link/i/ and *.app.goo.gl/i/ domains. - // Checks whether the URL is of the format : - // http(s)://$DOMAIN(.page.link or .app.goo.gl)/i/$ANYTHING - matchesRegularExpression = - ([urlStr - rangeOfString: - @"^https?:\\/\\/" - @"[a-zA-Z0-9]+((\\.app\\.goo\\.gl)|(\\.page\\.link)|(\\.app\\.google))\\/i\\/.*$" - options:NSRegularExpressionSearch] - .location != NSNotFound); - } - } - - return matchesRegularExpression; -} - -/* - DL can be parsed if it : - 1. Has http(s)://goo.gl/app* or http(s)://page.link/app* format - 2. OR http(s)://$DomainPrefix.page.link or http(s)://$DomainPrefix.app.goo.gl domain with specific - format - 3. OR the domain is a listed custom domain - */ -BOOL FIRDLCanParseUniversalLinkURL(NSURL *_Nullable URL) { - // Handle universal links with format |https://goo.gl/app/?|. - // Also support page.link format. - BOOL isDDLWithAppcodeInPath = ([URL.host isEqual:@"goo.gl"] || [URL.host isEqual:@"page.link"] || - [URL.host isEqual:@"app.google"]) && - [URL.path hasPrefix:@"/app"]; - - return isDDLWithAppcodeInPath || FIRDLIsAValidDLWithFDLDomain(URL) || - FIRDLIsURLForAllowedCustomDomain(URL); -} - -BOOL FIRDLMatchesShortLinkFormat(NSURL *URL) { - // Short Durable Link URLs always have a path or it should be a custom domain. - BOOL hasPathOrCustomDomain = URL.path.length > 0 || FIRDLIsURLForAllowedCustomDomain(URL); - - // Must be able to parse (also checks if the URL conforms to *.app.goo.gl/* or goo.gl/app/* or - // *.page.link or custom domain with valid suffix) - BOOL canParse = FIRDLCanParseUniversalLinkURL(URL); - - // Path cannot be prefixed with /link/dismiss - BOOL isDismiss = [[URL.path lowercaseString] hasPrefix:@"/link/dismiss"]; - - // Checks short link format by having only one path after domain prefix. - BOOL matchesRegularExpression = - ([URL.path rangeOfString:@"/[^/]+" options:NSRegularExpressionSearch].location != NSNotFound); - - return hasPathOrCustomDomain && !isDismiss && canParse && matchesRegularExpression; -} - -NSString *FIRDLMatchTypeStringFromServerString(NSString *_Nullable serverMatchTypeString) { - static NSDictionary *matchMap; - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ - matchMap = @{ - @"WEAK" : @"weak", - @"DEFAULT" : @"default", - @"UNIQUE" : @"unique", - }; - }); - return matchMap[serverMatchTypeString] ?: @"none"; -} - -void FIRDLAddToAllowListForCustomDomainsArray(NSArray *_Nonnull customDomains) { - // Duplicates will be weeded out when converting to a set. - NSMutableArray *validCustomDomains = - [[NSMutableArray alloc] initWithCapacity:customDomains.count]; - for (NSString *customDomainEntry in customDomains) { - // We remove trailing slashes in the path if present. - NSString *domainEntry = - [customDomainEntry hasSuffix:@"/"] - ? [customDomainEntry substringToIndex:[customDomainEntry length] - 1] - : customDomainEntry; - NSURL *customDomainURL = [NSURL URLWithString:domainEntry]; - // We require a valid scheme for each custom domain enumerated in the info.plist file. - if (customDomainURL && customDomainURL.scheme) { - [validCustomDomains addObject:customDomainURL]; - } - } - // Duplicates will be weeded out when converting to a set. - FIRDLCustomDomains = [NSSet setWithArray:validCustomDomains]; -} - -NS_ASSUME_NONNULL_END - -#endif // TARGET_OS_IOS diff --git a/FirebaseDynamicLinks/Tests/Sample/FDLBuilderTestAppObjC.xcodeproj/project.pbxproj b/FirebaseDynamicLinks/Tests/Sample/FDLBuilderTestAppObjC.xcodeproj/project.pbxproj deleted file mode 100644 index 89d6a91da27..00000000000 --- a/FirebaseDynamicLinks/Tests/Sample/FDLBuilderTestAppObjC.xcodeproj/project.pbxproj +++ /dev/null @@ -1,442 +0,0 @@ -// !$*UTF8*$! -{ - archiveVersion = 1; - classes = { - }; - objectVersion = 51; - objects = { - -/* Begin PBXBuildFile section */ - 5B41DB1823E3A71C00929EC5 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 5B41DB1723E3A71C00929EC5 /* AppDelegate.m */; }; - 5B41DB1B23E3A71C00929EC5 /* SceneDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 5B41DB1A23E3A71C00929EC5 /* SceneDelegate.m */; }; - 5B41DB1E23E3A71C00929EC5 /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 5B41DB1D23E3A71C00929EC5 /* ViewController.m */; }; - 5B41DB2123E3A71C00929EC5 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 5B41DB1F23E3A71C00929EC5 /* Main.storyboard */; }; - 5B41DB2323E3A71E00929EC5 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 5B41DB2223E3A71E00929EC5 /* Assets.xcassets */; }; - 5B41DB2623E3A71E00929EC5 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 5B41DB2423E3A71E00929EC5 /* LaunchScreen.storyboard */; }; - 5B41DB2923E3A71E00929EC5 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 5B41DB2823E3A71E00929EC5 /* main.m */; }; - 5B41DB3323E3A7FA00929EC5 /* LinkTableViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 5B41DB2F23E3A7F900929EC5 /* LinkTableViewCell.m */; }; - 5B41DB3423E3A7FA00929EC5 /* ParamTableViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 5B41DB3123E3A7F900929EC5 /* ParamTableViewCell.m */; }; - 5B41DB3623E3A8F400929EC5 /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 5B41DB3523E3A8F400929EC5 /* GoogleService-Info.plist */; }; - CF16533A355AFED181ABDD38 /* Pods_FDLBuilderTestAppObjC.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B90D2E2F25A43DD8A8773AF2 /* Pods_FDLBuilderTestAppObjC.framework */; }; -/* End PBXBuildFile section */ - -/* Begin PBXFileReference section */ - 5B3E9BB723E3ADDC00FF3A1E /* FDLBuilderTestAppObjC.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = FDLBuilderTestAppObjC.entitlements; sourceTree = ""; }; - 5B41DB1323E3A71C00929EC5 /* FDLBuilderTestAppObjC.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = FDLBuilderTestAppObjC.app; sourceTree = BUILT_PRODUCTS_DIR; }; - 5B41DB1623E3A71C00929EC5 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; - 5B41DB1723E3A71C00929EC5 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; - 5B41DB1923E3A71C00929EC5 /* SceneDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SceneDelegate.h; sourceTree = ""; }; - 5B41DB1A23E3A71C00929EC5 /* SceneDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SceneDelegate.m; sourceTree = ""; }; - 5B41DB1C23E3A71C00929EC5 /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = ""; }; - 5B41DB1D23E3A71C00929EC5 /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = ""; }; - 5B41DB2023E3A71C00929EC5 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; - 5B41DB2223E3A71E00929EC5 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; - 5B41DB2523E3A71E00929EC5 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; - 5B41DB2723E3A71E00929EC5 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 5B41DB2823E3A71E00929EC5 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; - 5B41DB2F23E3A7F900929EC5 /* LinkTableViewCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LinkTableViewCell.m; sourceTree = ""; }; - 5B41DB3023E3A7F900929EC5 /* LinkTableViewCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LinkTableViewCell.h; sourceTree = ""; }; - 5B41DB3123E3A7F900929EC5 /* ParamTableViewCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ParamTableViewCell.m; sourceTree = ""; }; - 5B41DB3223E3A7FA00929EC5 /* ParamTableViewCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ParamTableViewCell.h; sourceTree = ""; }; - 5B41DB3523E3A8F400929EC5 /* GoogleService-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "GoogleService-Info.plist"; sourceTree = ""; }; - 8C3596C191E82DCECC6735C8 /* Pods-FDLBuilderTestAppObjC.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-FDLBuilderTestAppObjC.release.xcconfig"; path = "Target Support Files/Pods-FDLBuilderTestAppObjC/Pods-FDLBuilderTestAppObjC.release.xcconfig"; sourceTree = ""; }; - B90D2E2F25A43DD8A8773AF2 /* Pods_FDLBuilderTestAppObjC.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_FDLBuilderTestAppObjC.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - E8ED1BD19C174903FC5BDF2C /* Pods-FDLBuilderTestAppObjC.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-FDLBuilderTestAppObjC.debug.xcconfig"; path = "Target Support Files/Pods-FDLBuilderTestAppObjC/Pods-FDLBuilderTestAppObjC.debug.xcconfig"; sourceTree = ""; }; -/* End PBXFileReference section */ - -/* Begin PBXFrameworksBuildPhase section */ - 5B41DB1023E3A71C00929EC5 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - CF16533A355AFED181ABDD38 /* Pods_FDLBuilderTestAppObjC.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXFrameworksBuildPhase section */ - -/* Begin PBXGroup section */ - 165ECBBDCCBFA3107802A5B8 /* Pods */ = { - isa = PBXGroup; - children = ( - E8ED1BD19C174903FC5BDF2C /* Pods-FDLBuilderTestAppObjC.debug.xcconfig */, - 8C3596C191E82DCECC6735C8 /* Pods-FDLBuilderTestAppObjC.release.xcconfig */, - ); - path = Pods; - sourceTree = ""; - }; - 5B41DB0A23E3A71C00929EC5 = { - isa = PBXGroup; - children = ( - 5B41DB3523E3A8F400929EC5 /* GoogleService-Info.plist */, - 5B41DB1523E3A71C00929EC5 /* FDLBuilderTestAppObjC */, - 5B41DB1423E3A71C00929EC5 /* Products */, - 165ECBBDCCBFA3107802A5B8 /* Pods */, - 8AB095C8794DB7CBE5853D77 /* Frameworks */, - ); - sourceTree = ""; - }; - 5B41DB1423E3A71C00929EC5 /* Products */ = { - isa = PBXGroup; - children = ( - 5B41DB1323E3A71C00929EC5 /* FDLBuilderTestAppObjC.app */, - ); - name = Products; - sourceTree = ""; - }; - 5B41DB1523E3A71C00929EC5 /* FDLBuilderTestAppObjC */ = { - isa = PBXGroup; - children = ( - 5B3E9BB723E3ADDC00FF3A1E /* FDLBuilderTestAppObjC.entitlements */, - 5B41DB3023E3A7F900929EC5 /* LinkTableViewCell.h */, - 5B41DB2F23E3A7F900929EC5 /* LinkTableViewCell.m */, - 5B41DB3223E3A7FA00929EC5 /* ParamTableViewCell.h */, - 5B41DB3123E3A7F900929EC5 /* ParamTableViewCell.m */, - 5B41DB1623E3A71C00929EC5 /* AppDelegate.h */, - 5B41DB1723E3A71C00929EC5 /* AppDelegate.m */, - 5B41DB1923E3A71C00929EC5 /* SceneDelegate.h */, - 5B41DB1A23E3A71C00929EC5 /* SceneDelegate.m */, - 5B41DB1C23E3A71C00929EC5 /* ViewController.h */, - 5B41DB1D23E3A71C00929EC5 /* ViewController.m */, - 5B41DB1F23E3A71C00929EC5 /* Main.storyboard */, - 5B41DB2223E3A71E00929EC5 /* Assets.xcassets */, - 5B41DB2423E3A71E00929EC5 /* LaunchScreen.storyboard */, - 5B41DB2723E3A71E00929EC5 /* Info.plist */, - 5B41DB2823E3A71E00929EC5 /* main.m */, - ); - path = FDLBuilderTestAppObjC; - sourceTree = ""; - }; - 8AB095C8794DB7CBE5853D77 /* Frameworks */ = { - isa = PBXGroup; - children = ( - B90D2E2F25A43DD8A8773AF2 /* Pods_FDLBuilderTestAppObjC.framework */, - ); - name = Frameworks; - sourceTree = ""; - }; -/* End PBXGroup section */ - -/* Begin PBXNativeTarget section */ - 5B41DB1223E3A71C00929EC5 /* FDLBuilderTestAppObjC */ = { - isa = PBXNativeTarget; - buildConfigurationList = 5B41DB2C23E3A71E00929EC5 /* Build configuration list for PBXNativeTarget "FDLBuilderTestAppObjC" */; - buildPhases = ( - 064F9DD0B6255FE37CE6E06D /* [CP] Check Pods Manifest.lock */, - 5B41DB0F23E3A71C00929EC5 /* Sources */, - 5B41DB1023E3A71C00929EC5 /* Frameworks */, - 5B41DB1123E3A71C00929EC5 /* Resources */, - 94C2948974AD9FEF43500B54 /* [CP] Embed Pods Frameworks */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = FDLBuilderTestAppObjC; - productName = FDLBuilderTestAppObjC; - productReference = 5B41DB1323E3A71C00929EC5 /* FDLBuilderTestAppObjC.app */; - productType = "com.apple.product-type.application"; - }; -/* End PBXNativeTarget section */ - -/* Begin PBXProject section */ - 5B41DB0B23E3A71C00929EC5 /* Project object */ = { - isa = PBXProject; - attributes = { - LastUpgradeCheck = 1130; - ORGANIZATIONNAME = "Google Inc"; - TargetAttributes = { - 5B41DB1223E3A71C00929EC5 = { - CreatedOnToolsVersion = 11.3.1; - }; - }; - }; - buildConfigurationList = 5B41DB0E23E3A71C00929EC5 /* Build configuration list for PBXProject "FDLBuilderTestAppObjC" */; - compatibilityVersion = "Xcode 9.3"; - developmentRegion = en; - hasScannedForEncodings = 0; - knownRegions = ( - en, - Base, - ); - mainGroup = 5B41DB0A23E3A71C00929EC5; - productRefGroup = 5B41DB1423E3A71C00929EC5 /* Products */; - projectDirPath = ""; - projectRoot = ""; - targets = ( - 5B41DB1223E3A71C00929EC5 /* FDLBuilderTestAppObjC */, - ); - }; -/* End PBXProject section */ - -/* Begin PBXResourcesBuildPhase section */ - 5B41DB1123E3A71C00929EC5 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 5B41DB2623E3A71E00929EC5 /* LaunchScreen.storyboard in Resources */, - 5B41DB3623E3A8F400929EC5 /* GoogleService-Info.plist in Resources */, - 5B41DB2323E3A71E00929EC5 /* Assets.xcassets in Resources */, - 5B41DB2123E3A71C00929EC5 /* Main.storyboard in Resources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXResourcesBuildPhase section */ - -/* Begin PBXShellScriptBuildPhase section */ - 064F9DD0B6255FE37CE6E06D /* [CP] Check Pods Manifest.lock */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - ); - inputPaths = ( - "${PODS_PODFILE_DIR_PATH}/Podfile.lock", - "${PODS_ROOT}/Manifest.lock", - ); - name = "[CP] Check Pods Manifest.lock"; - outputFileListPaths = ( - ); - outputPaths = ( - "$(DERIVED_FILE_DIR)/Pods-FDLBuilderTestAppObjC-checkManifestLockResult.txt", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; - showEnvVarsInLog = 0; - }; - 94C2948974AD9FEF43500B54 /* [CP] Embed Pods Frameworks */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-FDLBuilderTestAppObjC/Pods-FDLBuilderTestAppObjC-frameworks-${CONFIGURATION}-input-files.xcfilelist", - ); - name = "[CP] Embed Pods Frameworks"; - outputFileListPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-FDLBuilderTestAppObjC/Pods-FDLBuilderTestAppObjC-frameworks-${CONFIGURATION}-output-files.xcfilelist", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-FDLBuilderTestAppObjC/Pods-FDLBuilderTestAppObjC-frameworks.sh\"\n"; - showEnvVarsInLog = 0; - }; -/* End PBXShellScriptBuildPhase section */ - -/* Begin PBXSourcesBuildPhase section */ - 5B41DB0F23E3A71C00929EC5 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 5B41DB1E23E3A71C00929EC5 /* ViewController.m in Sources */, - 5B41DB3423E3A7FA00929EC5 /* ParamTableViewCell.m in Sources */, - 5B41DB1823E3A71C00929EC5 /* AppDelegate.m in Sources */, - 5B41DB3323E3A7FA00929EC5 /* LinkTableViewCell.m in Sources */, - 5B41DB2923E3A71E00929EC5 /* main.m in Sources */, - 5B41DB1B23E3A71C00929EC5 /* SceneDelegate.m in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXSourcesBuildPhase section */ - -/* Begin PBXVariantGroup section */ - 5B41DB1F23E3A71C00929EC5 /* Main.storyboard */ = { - isa = PBXVariantGroup; - children = ( - 5B41DB2023E3A71C00929EC5 /* Base */, - ); - name = Main.storyboard; - sourceTree = ""; - }; - 5B41DB2423E3A71E00929EC5 /* LaunchScreen.storyboard */ = { - isa = PBXVariantGroup; - children = ( - 5B41DB2523E3A71E00929EC5 /* Base */, - ); - name = LaunchScreen.storyboard; - sourceTree = ""; - }; -/* End PBXVariantGroup section */ - -/* Begin XCBuildConfiguration section */ - 5B41DB2A23E3A71E00929EC5 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_NONNULL = YES; - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_ENABLE_OBJC_WEAK = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = dwarf; - ENABLE_STRICT_OBJC_MSGSEND = YES; - ENABLE_TESTABILITY = YES; - GCC_C_LANGUAGE_STANDARD = gnu11; - GCC_DYNAMIC_NO_PIC = NO; - GCC_NO_COMMON_BLOCKS = YES; - GCC_OPTIMIZATION_LEVEL = 0; - GCC_PREPROCESSOR_DEFINITIONS = ( - "DEBUG=1", - "$(inherited)", - ); - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 13.2; - MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; - MTL_FAST_MATH = YES; - ONLY_ACTIVE_ARCH = YES; - SDKROOT = iphoneos; - }; - name = Debug; - }; - 5B41DB2B23E3A71E00929EC5 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_NONNULL = YES; - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_ENABLE_OBJC_WEAK = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - ENABLE_NS_ASSERTIONS = NO; - ENABLE_STRICT_OBJC_MSGSEND = YES; - GCC_C_LANGUAGE_STANDARD = gnu11; - GCC_NO_COMMON_BLOCKS = YES; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 13.2; - MTL_ENABLE_DEBUG_INFO = NO; - MTL_FAST_MATH = YES; - SDKROOT = iphoneos; - VALIDATE_PRODUCT = YES; - }; - name = Release; - }; - 5B41DB2D23E3A71E00929EC5 /* Debug */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = E8ED1BD19C174903FC5BDF2C /* Pods-FDLBuilderTestAppObjC.debug.xcconfig */; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CODE_SIGN_ENTITLEMENTS = FDLBuilderTestAppObjC/FDLBuilderTestAppObjC.entitlements; - CODE_SIGN_IDENTITY = "iPhone Developer"; - CODE_SIGN_STYLE = Manual; - DEVELOPMENT_TEAM = EQHXZ8M8AV; - INFOPLIST_FILE = FDLBuilderTestAppObjC/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - ); - PRODUCT_BUNDLE_IDENTIFIER = com.google.firebase.dynamiclinks.demo.dev; - PRODUCT_NAME = "$(TARGET_NAME)"; - PROVISIONING_PROFILE_SPECIFIER = "Firebase Dynamic Links Demo Dev"; - TARGETED_DEVICE_FAMILY = "1,2"; - }; - name = Debug; - }; - 5B41DB2E23E3A71E00929EC5 /* Release */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 8C3596C191E82DCECC6735C8 /* Pods-FDLBuilderTestAppObjC.release.xcconfig */; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CODE_SIGN_ENTITLEMENTS = FDLBuilderTestAppObjC/FDLBuilderTestAppObjC.entitlements; - CODE_SIGN_IDENTITY = "iPhone Developer"; - CODE_SIGN_STYLE = Manual; - DEVELOPMENT_TEAM = EQHXZ8M8AV; - INFOPLIST_FILE = FDLBuilderTestAppObjC/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - ); - PRODUCT_BUNDLE_IDENTIFIER = com.google.firebase.dynamiclinks.demo.dev; - PRODUCT_NAME = "$(TARGET_NAME)"; - PROVISIONING_PROFILE_SPECIFIER = "Firebase Dynamic Links Demo Dev"; - TARGETED_DEVICE_FAMILY = "1,2"; - }; - name = Release; - }; -/* End XCBuildConfiguration section */ - -/* Begin XCConfigurationList section */ - 5B41DB0E23E3A71C00929EC5 /* Build configuration list for PBXProject "FDLBuilderTestAppObjC" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 5B41DB2A23E3A71E00929EC5 /* Debug */, - 5B41DB2B23E3A71E00929EC5 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 5B41DB2C23E3A71E00929EC5 /* Build configuration list for PBXNativeTarget "FDLBuilderTestAppObjC" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 5B41DB2D23E3A71E00929EC5 /* Debug */, - 5B41DB2E23E3A71E00929EC5 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; -/* End XCConfigurationList section */ - }; - rootObject = 5B41DB0B23E3A71C00929EC5 /* Project object */; -} diff --git a/FirebaseDynamicLinks/Tests/Sample/FDLBuilderTestAppObjC/AppDelegate.h b/FirebaseDynamicLinks/Tests/Sample/FDLBuilderTestAppObjC/AppDelegate.h deleted file mode 100644 index 31bd7f7f20a..00000000000 --- a/FirebaseDynamicLinks/Tests/Sample/FDLBuilderTestAppObjC/AppDelegate.h +++ /dev/null @@ -1,23 +0,0 @@ -/* - * 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. - */ - -#import - -@interface AppDelegate : UIResponder - -@property(strong, nonatomic) UIWindow *window; - -@end diff --git a/FirebaseDynamicLinks/Tests/Sample/FDLBuilderTestAppObjC/AppDelegate.m b/FirebaseDynamicLinks/Tests/Sample/FDLBuilderTestAppObjC/AppDelegate.m deleted file mode 100644 index a318e3fea17..00000000000 --- a/FirebaseDynamicLinks/Tests/Sample/FDLBuilderTestAppObjC/AppDelegate.m +++ /dev/null @@ -1,103 +0,0 @@ -/* - * 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. - */ - -#import "AppDelegate.h" -#import "ViewController.h" - -#import -#import - -@implementation AppDelegate - -- (BOOL)application:(UIApplication *)application - didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { - [FIRApp configure]; - - self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; - UINavigationController *navController = [[UINavigationController alloc] - initWithRootViewController:[[ViewController alloc] initWithNibName:nil bundle:nil]]; - self.window.rootViewController = navController; - [self.window makeKeyAndVisible]; - -#ifdef DEBUG - [FIRDynamicLinks performDiagnosticsWithCompletion:nil]; -#endif // DEBUG - - return YES; -} - -- (BOOL)application:(UIApplication *)app - openURL:(NSURL *)url - options:(NSDictionary *)options { - FIRDynamicLink *dynamicLink = [[FIRDynamicLinks dynamicLinks] dynamicLinkFromCustomSchemeURL:url]; - - if (dynamicLink) { - [self _showDynamicLinkInfo:dynamicLink]; - } - return YES; -} - -- (BOOL)application:(UIApplication *)application - openURL:(NSURL *)url - sourceApplication:(NSString *)sourceApplication - annotation:(id)annotation { - return [self application:application openURL:url options:@{}]; -} - -- (BOOL)application:(UIApplication *)application - continueUserActivity:(NSUserActivity *)userActivity - restorationHandler: -#if __has_include() - (void (^)(NSArray> *_Nullable))restorationHandler { -#else - (void (^)(NSArray *))restorationHandler { -#endif - BOOL handled = [[FIRDynamicLinks dynamicLinks] - handleUniversalLink:userActivity.webpageURL - completion:^(FIRDynamicLink *_Nullable dynamicLink, NSError *_Nullable error) { - [self _showDynamicLinkInfo:dynamicLink]; - }]; - - if (!handled) { - // Show the deep link URL from userActivity. - NSLog(@"Unhandled link %@", userActivity.webpageURL); - } - - return handled; -} - -- (void)_showDynamicLinkInfo:(FIRDynamicLink *)dynamicLink { - NSLog(@"Got dynamic link %@", dynamicLink); - - UIAlertController *alertVC = [UIAlertController - alertControllerWithTitle:@"Got Dynamic Link!" - message:[NSString stringWithFormat:@"URL [%@], matchType [%ld], " - @"minimumAppVersion [%@], utmParams [%@]", - dynamicLink.url, - (unsigned long)dynamicLink.matchType, - dynamicLink.minimumAppVersion, - dynamicLink.utmParametersDictionary] - preferredStyle:UIAlertControllerStyleAlert]; - [alertVC addAction:[UIAlertAction actionWithTitle:@"Dismiss" - style:UIAlertActionStyleCancel - handler:NULL]]; - - [[UIApplication sharedApplication].keyWindow.rootViewController presentViewController:alertVC - animated:YES - completion:NULL]; -} - -@end diff --git a/FirebaseDynamicLinks/Tests/Sample/FDLBuilderTestAppObjC/Assets.xcassets/AppIcon.appiconset/Contents.json b/FirebaseDynamicLinks/Tests/Sample/FDLBuilderTestAppObjC/Assets.xcassets/AppIcon.appiconset/Contents.json deleted file mode 100644 index b542ec24d24..00000000000 --- a/FirebaseDynamicLinks/Tests/Sample/FDLBuilderTestAppObjC/Assets.xcassets/AppIcon.appiconset/Contents.json +++ /dev/null @@ -1,98 +0,0 @@ -{ - "images" : [ - { - "idiom" : "iphone", - "size" : "20x20", - "scale" : "2x" - }, - { - "idiom" : "iphone", - "size" : "20x20", - "scale" : "3x" - }, - { - "idiom" : "iphone", - "size" : "29x29", - "scale" : "2x" - }, - { - "idiom" : "iphone", - "size" : "29x29", - "scale" : "3x" - }, - { - "idiom" : "iphone", - "size" : "40x40", - "scale" : "2x" - }, - { - "idiom" : "iphone", - "size" : "40x40", - "scale" : "3x" - }, - { - "idiom" : "iphone", - "size" : "60x60", - "scale" : "2x" - }, - { - "idiom" : "iphone", - "size" : "60x60", - "scale" : "3x" - }, - { - "idiom" : "ipad", - "size" : "20x20", - "scale" : "1x" - }, - { - "idiom" : "ipad", - "size" : "20x20", - "scale" : "2x" - }, - { - "idiom" : "ipad", - "size" : "29x29", - "scale" : "1x" - }, - { - "idiom" : "ipad", - "size" : "29x29", - "scale" : "2x" - }, - { - "idiom" : "ipad", - "size" : "40x40", - "scale" : "1x" - }, - { - "idiom" : "ipad", - "size" : "40x40", - "scale" : "2x" - }, - { - "idiom" : "ipad", - "size" : "76x76", - "scale" : "1x" - }, - { - "idiom" : "ipad", - "size" : "76x76", - "scale" : "2x" - }, - { - "idiom" : "ipad", - "size" : "83.5x83.5", - "scale" : "2x" - }, - { - "idiom" : "ios-marketing", - "size" : "1024x1024", - "scale" : "1x" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - } -} diff --git a/FirebaseDynamicLinks/Tests/Sample/FDLBuilderTestAppObjC/Assets.xcassets/Contents.json b/FirebaseDynamicLinks/Tests/Sample/FDLBuilderTestAppObjC/Assets.xcassets/Contents.json deleted file mode 100644 index 2d92bd53fdb..00000000000 --- a/FirebaseDynamicLinks/Tests/Sample/FDLBuilderTestAppObjC/Assets.xcassets/Contents.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "info" : { - "version" : 1, - "author" : "xcode" - } -} diff --git a/FirebaseDynamicLinks/Tests/Sample/FDLBuilderTestAppObjC/Base.lproj/LaunchScreen.storyboard b/FirebaseDynamicLinks/Tests/Sample/FDLBuilderTestAppObjC/Base.lproj/LaunchScreen.storyboard deleted file mode 100644 index 865e9329f37..00000000000 --- a/FirebaseDynamicLinks/Tests/Sample/FDLBuilderTestAppObjC/Base.lproj/LaunchScreen.storyboard +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/FirebaseDynamicLinks/Tests/Sample/FDLBuilderTestAppObjC/Base.lproj/Main.storyboard b/FirebaseDynamicLinks/Tests/Sample/FDLBuilderTestAppObjC/Base.lproj/Main.storyboard deleted file mode 100644 index 9c999bcaa25..00000000000 --- a/FirebaseDynamicLinks/Tests/Sample/FDLBuilderTestAppObjC/Base.lproj/Main.storyboard +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/FirebaseDynamicLinks/Tests/Sample/FDLBuilderTestAppObjC/FDLBuilderTestAppObjC.entitlements b/FirebaseDynamicLinks/Tests/Sample/FDLBuilderTestAppObjC/FDLBuilderTestAppObjC.entitlements deleted file mode 100644 index 1c9bada1bf6..00000000000 --- a/FirebaseDynamicLinks/Tests/Sample/FDLBuilderTestAppObjC/FDLBuilderTestAppObjC.entitlements +++ /dev/null @@ -1,20 +0,0 @@ - - - - - application-identifier - $(AppIdentifierPrefix)$(CFBundleIdentifier) - com.apple.developer.associated-domains - - applinks:goo.gl - applinks:testfdl.app.goo.gl - applinks:testfdl.page.link - - keychain-access-groups - - $(AppIdentifierPrefix)$(CFBundleIdentifier) - $(AppIdentifierPrefix)$(CFBundleIdentifier).sso - $(AppIdentifierPrefix)com.google.common.SSO - - - diff --git a/FirebaseDynamicLinks/Tests/Sample/FDLBuilderTestAppObjC/Info.plist b/FirebaseDynamicLinks/Tests/Sample/FDLBuilderTestAppObjC/Info.plist deleted file mode 100644 index 9a257ed9341..00000000000 --- a/FirebaseDynamicLinks/Tests/Sample/FDLBuilderTestAppObjC/Info.plist +++ /dev/null @@ -1,83 +0,0 @@ - - - - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - $(PRODUCT_BUNDLE_PACKAGE_TYPE) - CFBundleShortVersionString - 1.0 - CFBundleURLTypes - - - CFBundleTypeRole - Editor - CFBundleURLName - Dev url scheme - CFBundleURLSchemes - - com.google.firebase.dynamiclinks.demo.dev - - - - CFBundleVersion - 1 - LSRequiresIPhoneOS - - UIApplicationSceneManifest - - UIApplicationSupportsMultipleScenes - - UISceneConfigurations - - UIWindowSceneSessionRoleApplication - - - UISceneConfigurationName - Default Configuration - UISceneDelegateClassName - SceneDelegate - UISceneStoryboardFile - Main - - - - - UILaunchStoryboardName - LaunchScreen - UIMainStoryboardFile - Main - UIRequiredDeviceCapabilities - - armv7 - - UISupportedInterfaceOrientations - - UIInterfaceOrientationPortrait - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - FirebaseDynamicLinksCustomDomains - - https://google.com - https://google.com/one/ - https://a.firebase.com/mypath - - UISupportedInterfaceOrientations~ipad - - UIInterfaceOrientationPortrait - UIInterfaceOrientationPortraitUpsideDown - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - - diff --git a/FirebaseDynamicLinks/Tests/Sample/FDLBuilderTestAppObjC/LinkTableViewCell.h b/FirebaseDynamicLinks/Tests/Sample/FDLBuilderTestAppObjC/LinkTableViewCell.h deleted file mode 100644 index d2f3701099d..00000000000 --- a/FirebaseDynamicLinks/Tests/Sample/FDLBuilderTestAppObjC/LinkTableViewCell.h +++ /dev/null @@ -1,23 +0,0 @@ -/* - * 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. - */ - -#import - -@interface LinkTableViewCell : UITableViewCell - -- (void)setTitle:(NSString *)title link:(NSString *)link; - -@end diff --git a/FirebaseDynamicLinks/Tests/Sample/FDLBuilderTestAppObjC/LinkTableViewCell.m b/FirebaseDynamicLinks/Tests/Sample/FDLBuilderTestAppObjC/LinkTableViewCell.m deleted file mode 100644 index c38ca7787b5..00000000000 --- a/FirebaseDynamicLinks/Tests/Sample/FDLBuilderTestAppObjC/LinkTableViewCell.m +++ /dev/null @@ -1,69 +0,0 @@ -/* - * 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. - */ - -#import "LinkTableViewCell.h" - -static const NSUInteger kHInset = 10; -static const NSUInteger kVInset = 4; - -@implementation LinkTableViewCell { - UILabel *_titleLabel; - UITextView *_linkTextView; -} - -- (instancetype)init { - self = [super initWithStyle:UITableViewCellStyleDefault - reuseIdentifier:NSStringFromClass(self.class)]; - if (self) { - _titleLabel = [[UILabel alloc] init]; - _titleLabel.font = [UIFont systemFontOfSize:15]; - _linkTextView = [[UITextView alloc] init]; - _linkTextView.font = [UIFont boldSystemFontOfSize:15]; - _linkTextView.editable = NO; - _linkTextView.scrollEnabled = NO; - _linkTextView.dataDetectorTypes = UIDataDetectorTypeLink; - [self.contentView addSubview:_titleLabel]; - [self.contentView addSubview:_linkTextView]; - } - return self; -} - -- (void)layoutSubviews { - _titleLabel.frame = CGRectMake(kHInset, kVInset, self.contentView.frame.size.width - 2 * kHInset, - (self.contentView.frame.size.height / 2) - 2 * kVInset); - _linkTextView.frame = CGRectMake(kHInset, (self.contentView.frame.size.height / 2) + kVInset, - self.contentView.frame.size.width - 2 * kHInset, - (self.contentView.frame.size.height / 2) - 2 * kVInset); -} - -- (void)setTitle:(NSString *)title link:(NSString *)link { - self.accessibilityIdentifier = - [NSString stringWithFormat:@"%@-%@", NSStringFromClass(self.class), title]; - _linkTextView.accessibilityIdentifier = - [NSString stringWithFormat:@"%@-LinkTextView-%@", NSStringFromClass(self.class), title]; - - _titleLabel.text = title; - - if (link) { - NSURL *URL = [NSURL URLWithString:link]; - NSAttributedString *attributedLink = - [[NSAttributedString alloc] initWithString:link attributes:@{NSLinkAttributeName : URL}]; - _linkTextView.attributedText = attributedLink; - } - _linkTextView.accessibilityValue = link; -} - -@end diff --git a/FirebaseDynamicLinks/Tests/Sample/FDLBuilderTestAppObjC/ParamTableViewCell.h b/FirebaseDynamicLinks/Tests/Sample/FDLBuilderTestAppObjC/ParamTableViewCell.h deleted file mode 100644 index bd3a67a8d91..00000000000 --- a/FirebaseDynamicLinks/Tests/Sample/FDLBuilderTestAppObjC/ParamTableViewCell.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * 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. - */ - -#import - -@class ParamTableViewCell; - -@protocol ParamTableViewCellDelegate - -- (void)paramTableViewCellUpdatedValue:(ParamTableViewCell *)cell; - -@end - -@interface ParamTableViewCell : UITableViewCell - -@property(nonatomic, readwrite, copy) NSDictionary *paramConfig; -@property(nonatomic, readwrite, copy) NSString *textFieldValue; -@property(nonatomic, weak) id delegate; - -@end diff --git a/FirebaseDynamicLinks/Tests/Sample/FDLBuilderTestAppObjC/ParamTableViewCell.m b/FirebaseDynamicLinks/Tests/Sample/FDLBuilderTestAppObjC/ParamTableViewCell.m deleted file mode 100644 index 78af6f8f3c5..00000000000 --- a/FirebaseDynamicLinks/Tests/Sample/FDLBuilderTestAppObjC/ParamTableViewCell.m +++ /dev/null @@ -1,82 +0,0 @@ -/* - * 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. - */ - -#import "ParamTableViewCell.h" - -static const NSUInteger kHInset = 10; -static const NSUInteger kVInset = 4; - -@implementation ParamTableViewCell { - UILabel *_label; - UITextField *_textField; -} - -@synthesize paramConfig = _paramConfig; - -- (instancetype)init { - self = [super initWithStyle:UITableViewCellStyleDefault - reuseIdentifier:NSStringFromClass(self.class)]; - if (self) { - self.selectionStyle = UITableViewCellSelectionStyleNone; - _label = [[UILabel alloc] init]; - _label.font = [UIFont italicSystemFontOfSize:[UIFont systemFontSize]]; - _textField = [[UITextField alloc] init]; - _textField.autocapitalizationType = UITextAutocapitalizationTypeNone; - [self.contentView addSubview:_label]; - [self.contentView addSubview:_textField]; - [_textField addTarget:self - action:@selector(onTextFieldValueChanged) - forControlEvents:UIControlEventEditingChanged]; - [_textField addTarget:self - action:@selector(onTextFieldDidEndOnExit) - forControlEvents:UIControlEventEditingDidEndOnExit]; - } - return self; -} - -- (void)layoutSubviews { - _label.frame = CGRectMake(kHInset, kVInset, self.contentView.frame.size.width - 2 * kHInset, - (self.contentView.frame.size.height / 2) - 2 * kVInset); - _textField.frame = CGRectMake(kHInset, (self.contentView.frame.size.height / 2) + kVInset, - self.contentView.frame.size.width - 2 * kHInset, - (self.contentView.frame.size.height / 2) - 2 * kVInset); -} - -- (void)onTextFieldValueChanged { - if (![self.textFieldValue isEqualToString:_textField.text]) { - self.textFieldValue = _textField.text; - [_delegate paramTableViewCellUpdatedValue:self]; - } -} - -- (void)onTextFieldDidEndOnExit { - [_textField resignFirstResponder]; -} - -- (void)setTextFieldValue:(NSString *)textFieldValue { - _textFieldValue = textFieldValue; - if (![_textFieldValue isEqualToString:_textField.text]) { - _textField.text = self.textFieldValue; - } -} - -- (void)setParamConfig:(NSDictionary *)paramConfig { - _paramConfig = [paramConfig copy]; - self.accessibilityIdentifier = _paramConfig[@"id"]; - _label.text = _paramConfig[@"label"]; -} - -@end diff --git a/FirebaseDynamicLinks/Tests/Sample/FDLBuilderTestAppObjC/SceneDelegate.h b/FirebaseDynamicLinks/Tests/Sample/FDLBuilderTestAppObjC/SceneDelegate.h deleted file mode 100644 index c7bebfeae6b..00000000000 --- a/FirebaseDynamicLinks/Tests/Sample/FDLBuilderTestAppObjC/SceneDelegate.h +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright 2020 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 - -@interface SceneDelegate : UIResponder - -@property(strong, nonatomic) UIWindow* window; - -@end diff --git a/FirebaseDynamicLinks/Tests/Sample/FDLBuilderTestAppObjC/SceneDelegate.m b/FirebaseDynamicLinks/Tests/Sample/FDLBuilderTestAppObjC/SceneDelegate.m deleted file mode 100644 index 2cc043aef9b..00000000000 --- a/FirebaseDynamicLinks/Tests/Sample/FDLBuilderTestAppObjC/SceneDelegate.m +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Copyright 2020 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 "SceneDelegate.h" - -#import - -@interface SceneDelegate () - -@end - -@implementation SceneDelegate - -- (void)scene:(UIScene *)scene - willConnectToSession:(UISceneSession *)session - options:(UISceneConnectionOptions *)connectionOptions { - // Use this method to optionally configure and attach the UIWindow `window` to the provided - // UIWindowScene `scene`. If using a storyboard, the `window` property will automatically be - // initialized and attached to the scene. This delegate does not imply the connecting scene or - // session are new (see `application:configurationForConnectingSceneSession` instead). - if (connectionOptions.userActivities && connectionOptions.userActivities.count > 0) { - NSUserActivity *userActivity = connectionOptions.userActivities.allObjects.firstObject; - [self handleDynamicLinkFromActivity:userActivity]; - } -} - -- (void)sceneDidDisconnect:(UIScene *)scene { - // Called as the scene is being released by the system. - // This occurs shortly after the scene enters the background, or when its session is discarded. - // Release any resources associated with this scene that can be re-created the next time the scene - // connects. The scene may re-connect later, as its session was not necessarily discarded (see - // `application:didDiscardSceneSessions` instead). -} - -- (void)sceneDidBecomeActive:(UIScene *)scene { - // Called when the scene has moved from an inactive state to an active state. - // Use this method to restart any tasks that were paused (or not yet started) when the scene was - // inactive. -} - -- (void)sceneWillResignActive:(UIScene *)scene { - // Called when the scene will move from an active state to an inactive state. - // This may occur due to temporary interruptions (ex. an incoming phone call). -} - -- (void)sceneWillEnterForeground:(UIScene *)scene { - // Called as the scene transitions from the background to the foreground. - // Use this method to undo the changes made on entering the background. -} - -- (void)sceneDidEnterBackground:(UIScene *)scene { - // Called as the scene transitions from the foreground to the background. - // Use this method to save data, release shared resources, and store enough scene-specific state - // information to restore the scene back to its current state. -} - -- (void)scene:(UIScene *)scene continueUserActivity:(NSUserActivity *)userActivity { - [self handleDynamicLinkFromActivity:userActivity]; -} - -- (void)handleDynamicLinkFromActivity:(NSUserActivity *)userActivity { - if (!userActivity) { - return; - } - BOOL handled = [[FIRDynamicLinks dynamicLinks] - handleUniversalLink:userActivity.webpageURL - completion:^(FIRDynamicLink *_Nullable dynamicLink, NSError *_Nullable error) { - [self _showDynamicLinkInfo:dynamicLink]; - }]; - - if (!handled) { - // Show the deep link URL from userActivity. - NSLog(@"Unhandled link %@", userActivity.webpageURL); - } -} - -- (void)_showDynamicLinkInfo:(FIRDynamicLink *)dynamicLink { - NSLog(@"Got dynamic link %@", dynamicLink); - - UIAlertController *alertVC = [UIAlertController - alertControllerWithTitle:@"Got Dynamic Link!" - message:[NSString stringWithFormat:@"URL [%@], matchType [%ld], " - @"minimumAppVersion [%@], utmParams [%@]", - dynamicLink.url, - (unsigned long)dynamicLink.matchType, - dynamicLink.minimumAppVersion, - dynamicLink.utmParametersDictionary] - preferredStyle:UIAlertControllerStyleAlert]; - [alertVC addAction:[UIAlertAction actionWithTitle:@"Dismiss" - style:UIAlertActionStyleCancel - handler:NULL]]; - [self.window.rootViewController presentViewController:alertVC animated:YES completion:NULL]; -} - -@end diff --git a/FirebaseDynamicLinks/Tests/Sample/FDLBuilderTestAppObjC/ViewController.h b/FirebaseDynamicLinks/Tests/Sample/FDLBuilderTestAppObjC/ViewController.h deleted file mode 100644 index 9096b8f39d5..00000000000 --- a/FirebaseDynamicLinks/Tests/Sample/FDLBuilderTestAppObjC/ViewController.h +++ /dev/null @@ -1,21 +0,0 @@ -/* - * 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. - */ - -#import - -@interface ViewController : UITableViewController - -@end diff --git a/FirebaseDynamicLinks/Tests/Sample/FDLBuilderTestAppObjC/ViewController.m b/FirebaseDynamicLinks/Tests/Sample/FDLBuilderTestAppObjC/ViewController.m deleted file mode 100644 index dc4a55e8286..00000000000 --- a/FirebaseDynamicLinks/Tests/Sample/FDLBuilderTestAppObjC/ViewController.m +++ /dev/null @@ -1,399 +0,0 @@ -/* - * 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. - */ - -#import "ViewController.h" - -#import -#import - -#import "LinkTableViewCell.h" -#import "ParamTableViewCell.h" - -static NSArray *kParamsConfiguration; - -@interface ViewController () -@end - -@implementation ViewController { - NSArray *_paramsConfiguration; - NSMutableDictionary *_paramValues; - - NSURL *_longLink; - NSURL *_shortLink; -} - -- (void)viewDidLoad { - [super viewDidLoad]; - - self.view.backgroundColor = [UIColor whiteColor]; - self.title = @"FDL Builder"; - - self.tableView.rowHeight = 60; - - [self _initDefaultValues]; -} - -#pragma mark - UITableViewDelegate - -- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { - if (indexPath.section == 0 && indexPath.row == (kParamsConfiguration.count + 0)) { - [self _buildFDLLink]; - } - if (indexPath.section == 0 && indexPath.row == (kParamsConfiguration.count + 1)) { - // copy long link - if (_longLink) { - [UIPasteboard generalPasteboard].string = _longLink.absoluteString; - [self _presentMessage:@"Long Link copied to Clipboard" description:nil]; - } else { - [self _presentMessage:@"Long Link is empty" description:nil]; - } - } - if (indexPath.section == 0 && indexPath.row == (kParamsConfiguration.count + 2)) { - // copy short link - if (_shortLink) { - [UIPasteboard generalPasteboard].string = _shortLink.absoluteString; - [self _presentMessage:@"Short Link copied to Clipboard" description:nil]; - } else { - [self _presentMessage:@"Short Link is empty" description:nil]; - } - } -} - -#pragma mark - UITableViewDataSource - -- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { - if (section == 0) { - return kParamsConfiguration.count + 3; - } else { - return 0; - } -} - -- (UITableViewCell *)tableView:(UITableView *)tableView - cellForRowAtIndexPath:(NSIndexPath *)indexPath { - if (indexPath.row >= kParamsConfiguration.count) { - return [self _customCellForRow:indexPath.row - kParamsConfiguration.count]; - } else { - ParamTableViewCell *cell = - (ParamTableViewCell *)[tableView dequeueReusableCellWithIdentifier:@"ParamTableViewCell"]; - if (!cell) { - cell = [[ParamTableViewCell alloc] init]; - } - NSDictionary *paramConfig = kParamsConfiguration[indexPath.row]; - cell.paramConfig = paramConfig; - cell.textFieldValue = _paramValues[paramConfig[@"id"]]; - cell.delegate = self; - return cell; - } -} - -- (void)paramTableViewCellUpdatedValue:(ParamTableViewCell *)cell; -{ _paramValues[cell.paramConfig[@"id"]] = cell.textFieldValue; } - -#pragma mark - Private methods - -- (UITableViewCell *)_customCellForRow:(NSUInteger)row { - switch (row) { - case 0: { - UITableViewCell *cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault - reuseIdentifier:@"cell"]; - cell.textLabel.text = @"Generate Link"; - cell.accessibilityIdentifier = @"generate-link"; - cell.textLabel.textAlignment = NSTextAlignmentCenter; - cell.textLabel.font = [UIFont boldSystemFontOfSize:22]; - return cell; - } break; - - case 1: - case 2: { - LinkTableViewCell *cell = (LinkTableViewCell *)[self.tableView - dequeueReusableCellWithIdentifier:@"LinkTableViewCell"]; - if (!cell) { - cell = [[LinkTableViewCell alloc] init]; - } - if (row == 1) { - [cell setTitle:@"Long link" link:_longLink.absoluteString]; - } else { - [cell setTitle:@"Short link" link:_shortLink.absoluteString]; - } - return cell; - } break; - case 3: { - UITableViewCell *cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault - reuseIdentifier:@"cell"]; - cell.textLabel.text = @"Perform FDL self diagnostic"; - cell.textLabel.textAlignment = NSTextAlignmentCenter; - cell.textLabel.font = [UIFont systemFontOfSize:22]; - return cell; - } break; - } - return nil; -} - -- (void)_initDefaultValues { - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ - kParamsConfiguration = @[ - // general link params - @{ - @"id" : @"linkString", - @"label" : @"Link value (required)", - @"defaultValue" : @"https://www.google.com?q=jump", - }, - // The default value of domain appcode belongs to project: app-invites-qa - @{ - @"id" : @"domainURIPrefix", - @"label" : @"App domainURIPrefix (required)", - @"defaultValue" : @"https://testfdl.page.link", - }, - // analytics params - @{ - @"id" : @"FIRDynamicLinkGoogleAnalyticsParameters.source", - @"label" : @"Google Analytics source (optional)", - @"defaultValue" : @"", - }, - @{ - @"id" : @"FIRDynamicLinkGoogleAnalyticsParameters.medium", - @"label" : @"Google Analytics medium (optional)", - @"defaultValue" : @"", - }, - @{ - @"id" : @"FIRDynamicLinkGoogleAnalyticsParameters.campaign", - @"label" : @"Google Analytics campaign (optional)", - @"defaultValue" : @"", - }, - @{ - @"id" : @"FIRDynamicLinkGoogleAnalyticsParameters.term", - @"label" : @"Google Analytics term (optional)", - @"defaultValue" : @"", - }, - @{ - @"id" : @"FIRDynamicLinkGoogleAnalyticsParameters.content", - @"label" : @"Google Analytics content (optional)", - @"defaultValue" : @"", - }, - // iOS params - @{ - @"id" : @"FIRDynamicLinkIOSParameters.bundleId", - @"label" : @"iOS App bundle ID", - @"defaultValue" : [[NSBundle mainBundle] bundleIdentifier] ?: @"", - }, - @{ - @"id" : @"FIRDynamicLinkIOSParameters.fallbackURL", - @"label" : @"Fallback URL iOS (optional)", - }, - @{ - @"id" : @"FIRDynamicLinkIOSParameters.minimumAppVersion", - @"label" : @"minimum version of iOS App (optional)", - @"defaultValue" : @"1.0", - }, - @{ - @"id" : @"FIRDynamicLinkIOSParameters.customScheme", - @"label" : @"iOS App custom scheme (optional)", - }, - @{ - @"id" : @"FIRDynamicLinkIOSParameters.iPadBundleID", - @"label" : @"iPad App bundleID (optional)", - @"defaultValue" : @"", - }, - @{ - @"id" : @"FIRDynamicLinkIOSParameters.iPadFallbackURL", - @"label" : @"Fallback URL on iPad (optional)", - }, - @{ - @"id" : @"FIRDynamicLinkIOSParameters.appStoreID", - @"label" : @"iOS AppStore ID (optional)", - }, - - // iTunesConnect params - @{ - @"id" : @"FIRDynamicLinkItunesConnectAnalyticsParameters.affiliateToken", - @"label" : @"iTunesConnect affiliate token (optional)", - @"defaultValue" : @"", - }, - @{ - @"id" : @"FIRDynamicLinkItunesConnectAnalyticsParameters.campaignToken", - @"label" : @"iTunesConnect campaign token (optional)", - @"defaultValue" : @"", - }, - @{ - @"id" : @"FIRDynamicLinkItunesConnectAnalyticsParameters.providerToken", - @"label" : @"iTunesConnect provider token (optional)", - @"defaultValue" : @"", - }, - - // Android params - @{ - @"id" : @"FIRDynamicLinkAndroidParameters.packageName", - @"label" : @"Android App package name (optional)", - @"defaultValue" : @"", - }, - @{ - @"id" : @"FIRDynamicLinkAndroidParameters.fallbackURL", - @"label" : @"Android fallback URL (optional)", - @"defaultValue" : @"", - }, - @{ - @"id" : @"FIRDynamicLinkAndroidParameters.minimumVersion", - @"label" : @"Andropid App minimum version, integer number (optional)", - @"defaultValue" : @"", - }, - - // social tag params - @{ - @"id" : @"FIRDynamicLinkSocialMetaTagParameters.title", - @"label" : @"Social meta tag title (optional)", - @"defaultValue" : @"", - }, - @{ - @"id" : @"FIRDynamicLinkSocialMetaTagParameters.descriptionText", - @"label" : @"Social meta tag description text (optional)", - @"defaultValue" : @"", - }, - @{ - @"id" : @"FIRDynamicLinkSocialMetaTagParameters.imageURL", - @"label" : @"Social meta tag image URL (optional)", - @"defaultValue" : @"", - }, - - // OtherPlatform params - @{ - @"id" : @"FIRDynamicLinkOtherPlatformParameters.fallbackUrl", - @"label" : @"OtherPlatform Fallback link (optional)", - @"defaultValue" : @"", - }, - ]; - }); - - _paramValues = [[NSMutableDictionary alloc] initWithCapacity:kParamsConfiguration.count]; - for (NSDictionary *paramConfig in kParamsConfiguration) { - if (paramConfig[@"defaultValue"]) { - _paramValues[paramConfig[@"id"]] = paramConfig[@"defaultValue"]; - } - } -} - -- (void)_buildFDLLink { - NSURL *link = [NSURL URLWithString:_paramValues[@"linkString"]]; - FIRDynamicLinkComponents *components = - [FIRDynamicLinkComponents componentsWithLink:link - domainURIPrefix:_paramValues[@"domainURIPrefix"]]; - - FIRDynamicLinkGoogleAnalyticsParameters *analyticsParams = - [FIRDynamicLinkGoogleAnalyticsParameters - parametersWithSource:_paramValues[@"FIRDynamicLinkGoogleAnalyticsParameters.source"] - medium:_paramValues[@"FIRDynamicLinkGoogleAnalyticsPara" - @"meters.medium"] - campaign:_paramValues[@"FIRDynamicLinkGoogleAnalyticsPara" - @"meters.campaign"]]; - analyticsParams.term = _paramValues[@"FIRDynamicLinkGoogleAnalyticsParameters.term"]; - analyticsParams.content = _paramValues[@"FIRDynamicLinkGoogleAnalyticsParameters.content"]; - - FIRDynamicLinkIOSParameters *iOSParams; - if (_paramValues[@"FIRDynamicLinkIOSParameters.bundleId"]) { - iOSParams = [FIRDynamicLinkIOSParameters - parametersWithBundleID:_paramValues[@"FIRDynamicLinkIOSParameters.bundleId"]]; - iOSParams.fallbackURL = - [NSURL URLWithString:_paramValues[@"FIRDynamicLinkIOSParameters.fallbackURL"]]; - iOSParams.customScheme = _paramValues[@"FIRDynamicLinkIOSParameters.customScheme"]; - iOSParams.iPadBundleID = _paramValues[@"FIRDynamicLinkIOSParameters.iPadBundleID"]; - iOSParams.iPadFallbackURL = - [NSURL URLWithString:_paramValues[@"FIRDynamicLinkIOSParameters.iPadFallbackURL"]]; - iOSParams.appStoreID = _paramValues[@"FIRDynamicLinkIOSParameters.appStoreId"]; - iOSParams.minimumAppVersion = _paramValues[@"FIRDynamicLinkIOSParameters.minimumAppVersion"]; - } - - FIRDynamicLinkItunesConnectAnalyticsParameters *appStoreParams = - [FIRDynamicLinkItunesConnectAnalyticsParameters parameters]; - appStoreParams.affiliateToken = - _paramValues[@"FIRDynamicLinkItunesConnectAnalyticsParameters.affiliateToken"]; - appStoreParams.campaignToken = - _paramValues[@"FIRDynamicLinkItunesConnectAnalyticsParameters.campaignToken"]; - appStoreParams.providerToken = - _paramValues[@"FIRDynamicLinkItunesConnectAnalyticsParameters.providerToken"]; - - FIRDynamicLinkAndroidParameters *androidParams; - if (_paramValues[@"FIRDynamicLinkAndroidParameters.packageName"]) { - androidParams = [FIRDynamicLinkAndroidParameters - parametersWithPackageName:_paramValues[@"FIRDynamicLinkAndroidParameters.packageName"]]; - androidParams.fallbackURL = - [NSURL URLWithString:_paramValues[@"FIRDynamicLinkAndroidParameters.fallbackURL"]]; - if ([_paramValues[@"FIRDynamicLinkAndroidParameters.minimumVersion"] integerValue] > 0) { - androidParams.minimumVersion = - [_paramValues[@"FIRDynamicLinkAndroidParameters.minimumVersion"] integerValue]; - } - } - - FIRDynamicLinkSocialMetaTagParameters *socialParams = - [FIRDynamicLinkSocialMetaTagParameters parameters]; - socialParams.title = _paramValues[@"FIRDynamicLinkSocialMetaTagParameters.title"]; - socialParams.descriptionText = - _paramValues[@"FIRDynamicLinkSocialMetaTagParameters.descriptionText"]; - socialParams.imageURL = - [NSURL URLWithString:_paramValues[@"FIRDynamicLinkSocialMetaTagParameters.imageURL"]]; - - FIRDynamicLinkOtherPlatformParameters *otherPlatformParams = - [FIRDynamicLinkOtherPlatformParameters parameters]; - otherPlatformParams.fallbackUrl = - [NSURL URLWithString:_paramValues[@"FIRDynamicLinkOtherPlatformParameters.fallbackUrl"]]; - - FIRDynamicLinkComponentsOptions *options = [FIRDynamicLinkComponentsOptions options]; - options.pathLength = FIRShortDynamicLinkPathLengthShort; - - components.analyticsParameters = analyticsParams; - components.iOSParameters = iOSParams; - components.iTunesConnectParameters = appStoreParams; - components.androidParameters = androidParams; - components.socialMetaTagParameters = socialParams; - components.otherPlatformParameters = otherPlatformParams; - components.options = options; - - NSURL *longURL = components.url; - // Handle longURL. - NSLog(@"Long URL: %@", longURL); - _longLink = longURL; - [self.tableView - reloadRowsAtIndexPaths:@[ [NSIndexPath indexPathForRow:kParamsConfiguration.count + 1 - inSection:0] ] - withRowAnimation:UITableViewRowAnimationNone]; - - [components shortenWithCompletion:^(NSURL *_Nullable shortURL, NSArray *_Nullable warnings, - NSError *_Nullable error) { - // Handle shortURL or error. - NSLog(@"Short URL: %@, warnings: %@ error: %@", shortURL, warnings, error); - if (error) { - [self _presentMessage:@"Error generating short link" description:[error description]]; - } - _shortLink = shortURL; - [self.tableView - reloadRowsAtIndexPaths:@[ [NSIndexPath indexPathForRow:kParamsConfiguration.count + 2 - inSection:0] ] - withRowAnimation:UITableViewRowAnimationNone]; - }]; -} - -- (void)_presentMessage:(NSString *)message description:(NSString *)description { - UIAlertController *alertVC = - [UIAlertController alertControllerWithTitle:message - message:description - preferredStyle:UIAlertControllerStyleAlert]; - [alertVC addAction:[UIAlertAction actionWithTitle:@"Dismiss" - style:UIAlertActionStyleCancel - handler:NULL]]; - [self presentViewController:alertVC animated:YES completion:NULL]; -} - -@end diff --git a/FirebaseDynamicLinks/Tests/Sample/FDLBuilderTestAppObjC/main.m b/FirebaseDynamicLinks/Tests/Sample/FDLBuilderTestAppObjC/main.m deleted file mode 100644 index 7dc9d63f8d6..00000000000 --- a/FirebaseDynamicLinks/Tests/Sample/FDLBuilderTestAppObjC/main.m +++ /dev/null @@ -1,27 +0,0 @@ -/* - * 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. - */ - -#import -#import "AppDelegate.h" - -int main(int argc, char* argv[]) { - NSString* appDelegateClassName; - @autoreleasepool { - // Setup code that might create autoreleased objects goes here. - appDelegateClassName = NSStringFromClass([AppDelegate class]); - } - return UIApplicationMain(argc, argv, nil, appDelegateClassName); -} diff --git a/FirebaseDynamicLinks/Tests/Sample/Podfile b/FirebaseDynamicLinks/Tests/Sample/Podfile deleted file mode 100644 index 5db03c20125..00000000000 --- a/FirebaseDynamicLinks/Tests/Sample/Podfile +++ /dev/null @@ -1,11 +0,0 @@ -source 'https://github.com/firebase/SpecsDev.git' -source 'https://github.com/firebase/SpecsStaging.git' -source 'https://cdn.cocoapods.org/' - -target 'FDLBuilderTestAppObjC' do - platform :ios, '13.0' - use_frameworks! - - pod 'FirebaseCore', :path => '../../../' - pod 'FirebaseDynamicLinks', :path => '../../../' -end diff --git a/FirebaseDynamicLinks/Tests/Unit/DL-Info.plist b/FirebaseDynamicLinks/Tests/Unit/DL-Info.plist deleted file mode 100644 index 034e43597cc..00000000000 --- a/FirebaseDynamicLinks/Tests/Unit/DL-Info.plist +++ /dev/null @@ -1,56 +0,0 @@ - - - - - CFBundleDevelopmentRegion - en - CFBundleDisplayName - ${PRODUCT_NAME} - CFBundleExecutable - ${EXECUTABLE_NAME} - CFBundleIdentifier - org.cocoapods-generate.App-iOS - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - ${PRODUCT_NAME} - CFBundlePackageType - APPL - CFBundleShortVersionString - 1.0 - CFBundleSignature - ???? - CFBundleVersion - 1.0 - LSRequiresIPhoneOS - - NSAppTransportSecurity - - NSAllowsArbitraryLoads - - - UIRequiredDeviceCapabilities - - armv7 - - UISupportedInterfaceOrientations - - UIInterfaceOrientationPortrait - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - UISupportedInterfaceOrientations~ipad - - UIInterfaceOrientationPortrait - UIInterfaceOrientationPortraitUpsideDown - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - FirebaseDynamicLinksCustomDomains - - https://google.com - https://google.com/one/ - https://a.firebase.com/mypath - - - diff --git a/FirebaseDynamicLinks/Tests/Unit/FDLURLComponentsTests.m b/FirebaseDynamicLinks/Tests/Unit/FDLURLComponentsTests.m deleted file mode 100644 index e7d9dce6a79..00000000000 --- a/FirebaseDynamicLinks/Tests/Unit/FDLURLComponentsTests.m +++ /dev/null @@ -1,779 +0,0 @@ -/* - * 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. - */ - -#import - -#import "FirebaseDynamicLinks/Sources/FDLURLComponents/FDLURLComponents+Private.h" -#import "FirebaseDynamicLinks/Sources/FDLURLComponents/FIRDynamicLinkComponentsKeyProvider.h" - -#import - -static NSString *const kFDLURLDomain = @"https://xyz.page.link"; -static NSString *const kFDLURLCustomDomain = @"https://foo.com/path"; - -@interface FDLURLComponentsTests : XCTestCase -@end - -@implementation FDLURLComponentsTests - -#pragma mark - FIRDynamicLinkGoogleAnalyticsParameters - -- (void)testAnalyticsParamsFactoryReturnsInstanceOfCorrectClass { - id returnValue = [FIRDynamicLinkGoogleAnalyticsParameters parameters]; - XCTAssertTrue([returnValue isKindOfClass:[FIRDynamicLinkGoogleAnalyticsParameters class]]); -} - -- (void)testAnalyticsParamsFactoryReturnsInstanceWithAllNilProperties { - FIRDynamicLinkGoogleAnalyticsParameters *params = - [FIRDynamicLinkGoogleAnalyticsParameters parameters]; - - XCTAssertNil(params.source); - XCTAssertNil(params.medium); - XCTAssertNil(params.campaign); - XCTAssertNil(params.term); - XCTAssertNil(params.content); -} - -- (void)testAnalyticsParamsPropertiesSetProperly { - FIRDynamicLinkGoogleAnalyticsParameters *params = - [FIRDynamicLinkGoogleAnalyticsParameters parameters]; - - params.source = @"s"; - params.medium = @"m"; - params.campaign = @"ca"; - params.term = @"t"; - params.content = @"co"; - - XCTAssertEqualObjects(params.source, @"s"); - XCTAssertEqualObjects(params.medium, @"m"); - XCTAssertEqualObjects(params.campaign, @"ca"); - XCTAssertEqualObjects(params.term, @"t"); - XCTAssertEqualObjects(params.content, @"co"); - - params.source = nil; - params.medium = nil; - params.campaign = nil; - params.term = nil; - params.content = nil; - - XCTAssertNil(params.source); - XCTAssertNil(params.medium); - XCTAssertNil(params.campaign); - XCTAssertNil(params.term); - XCTAssertNil(params.content); -} - -- (void)testAnalyticsParamsDictionaryRepresentationReturnsCorrectDictionaryFull { - FIRDynamicLinkGoogleAnalyticsParameters *params = - [FIRDynamicLinkGoogleAnalyticsParameters parameters]; - - params.source = @"s"; - params.medium = @"m"; - params.campaign = @"ca"; - params.term = @"t"; - params.content = @"co"; - - NSDictionary *expectedDictionary = @{ - @"utm_source" : @"s", - @"utm_medium" : @"m", - @"utm_campaign" : @"ca", - @"utm_term" : @"t", - @"utm_content" : @"co", - }; - - XCTAssertEqualObjects(expectedDictionary, params.dictionaryRepresentation); -} - -- (void)testAnalyticsParamsDictionaryRepresentationReturnsCorrectDictionaryEmpty { - FIRDynamicLinkGoogleAnalyticsParameters *params = - [FIRDynamicLinkGoogleAnalyticsParameters parameters]; - XCTAssertEqualObjects(@{}, params.dictionaryRepresentation); -} - -- (void)testAnalyticsParamsFactoryWithParamsReturnsInstanceOfCorrectClass { - id returnValue = [FIRDynamicLinkGoogleAnalyticsParameters parametersWithSource:@"s" - medium:@"m" - campaign:@"c"]; - XCTAssertTrue([returnValue isKindOfClass:[FIRDynamicLinkGoogleAnalyticsParameters class]]); -} - -- (void)testAnalyticsParamsFactoryWithParamsReturnsInstanceWithCorrectInitialPropertyValues { - FIRDynamicLinkGoogleAnalyticsParameters *params = - [FIRDynamicLinkGoogleAnalyticsParameters parametersWithSource:@"s" medium:@"m" campaign:@"c"]; - - XCTAssertEqualObjects(params.source, @"s"); - XCTAssertEqualObjects(params.medium, @"m"); - XCTAssertEqualObjects(params.campaign, @"c"); - XCTAssertNil(params.term); - XCTAssertNil(params.content); -} - -#pragma mark - FIRDynamicLinkIOSParameters - -- (void)testIOSParamsFactoryReturnsInstanceOfCorrectClass { - id returnValue = [FIRDynamicLinkIOSParameters parametersWithBundleID:@"com.iphone.app"]; - XCTAssertTrue([returnValue isKindOfClass:[FIRDynamicLinkIOSParameters class]]); -} - -- (void)testIOSParamsFactoryReturnsInstanceWithAllOptionalNilProperties { - FIRDynamicLinkIOSParameters *params = - [FIRDynamicLinkIOSParameters parametersWithBundleID:@"com.iphone.app"]; - - XCTAssertNil(params.fallbackURL); - XCTAssertNil(params.customScheme); - XCTAssertNil(params.minimumAppVersion); - XCTAssertNil(params.iPadBundleID); - XCTAssertNil(params.iPadFallbackURL); - XCTAssertNil(params.appStoreID); -} - -- (void)testIOSParamsPropertiesSetProperly { - FIRDynamicLinkIOSParameters *params = - [FIRDynamicLinkIOSParameters parametersWithBundleID:@"com.iphone.app"]; - - params.fallbackURL = [NSURL URLWithString:@"https://google.com/iphone"]; - params.customScheme = @"mycustomsheme"; - params.minimumAppVersion = @"1.2.3"; - params.iPadBundleID = @"com.ipad.app"; - params.iPadFallbackURL = [NSURL URLWithString:@"https://google.com/ipad"]; - params.appStoreID = @"666"; - - XCTAssertEqualObjects(params.bundleID, @"com.iphone.app"); - XCTAssertEqualObjects(params.fallbackURL, [NSURL URLWithString:@"https://google.com/iphone"]); - XCTAssertEqualObjects(params.customScheme, @"mycustomsheme"); - XCTAssertEqualObjects(params.minimumAppVersion, @"1.2.3"); - XCTAssertEqualObjects(params.iPadBundleID, @"com.ipad.app"); - XCTAssertEqualObjects(params.iPadFallbackURL, [NSURL URLWithString:@"https://google.com/ipad"]); - XCTAssertEqualObjects(params.appStoreID, @"666"); - - params.fallbackURL = nil; - params.customScheme = nil; - params.minimumAppVersion = nil; - params.iPadBundleID = nil; - params.iPadFallbackURL = nil; - params.appStoreID = nil; - - XCTAssertNil(params.fallbackURL); - XCTAssertNil(params.customScheme); - XCTAssertNil(params.minimumAppVersion); - XCTAssertNil(params.iPadBundleID); - XCTAssertNil(params.iPadFallbackURL); - XCTAssertNil(params.appStoreID); -} - -- (void)testIOSParamsDictionaryRepresentationReturnsCorrectDictionaryFull { - FIRDynamicLinkIOSParameters *params = - [FIRDynamicLinkIOSParameters parametersWithBundleID:@"com.iphone.app"]; - - params.fallbackURL = [NSURL URLWithString:@"https://google.com/iphone"]; - params.customScheme = @"mycustomscheme"; - params.minimumAppVersion = @"1.2.3"; - params.iPadBundleID = @"com.ipad.app"; - params.iPadFallbackURL = [NSURL URLWithString:@"https://google.com/ipad"]; - params.appStoreID = @"666"; - - NSDictionary *expectedDictionary = @{ - @"ibi" : @"com.iphone.app", - @"ifl" : [NSURL URLWithString:@"https://google.com/iphone"].absoluteString, - @"ius" : @"mycustomscheme", - @"imv" : @"1.2.3", - @"ipbi" : @"com.ipad.app", - @"ipfl" : [NSURL URLWithString:@"https://google.com/ipad"].absoluteString, - @"isi" : @"666" - }; - - XCTAssertEqualObjects(expectedDictionary, params.dictionaryRepresentation); -} - -- (void)testIOSParamsDictionaryRepresentationReturnsCorrectDictionaryOnlyReqParams { - FIRDynamicLinkIOSParameters *params = - [FIRDynamicLinkIOSParameters parametersWithBundleID:@"com.iphone.app"]; - XCTAssertEqualObjects(@{@"ibi" : @"com.iphone.app"}, params.dictionaryRepresentation); -} - -#pragma mark - FIRDynamicLinkItunesConnectAnalyticsParameters - -- (void)testIOSAppStoreParamsFactoryReturnsInstanceOfCorrectClass { - id returnValue = [FIRDynamicLinkItunesConnectAnalyticsParameters parameters]; - XCTAssertTrue([returnValue isKindOfClass:[FIRDynamicLinkItunesConnectAnalyticsParameters class]]); -} - -- (void)testIOSAppStoreParamsFactoryReturnsInstanceWithAllNilProperties { - FIRDynamicLinkItunesConnectAnalyticsParameters *params = - [FIRDynamicLinkItunesConnectAnalyticsParameters parameters]; - - XCTAssertNil(params.affiliateToken); - XCTAssertNil(params.campaignToken); - XCTAssertNil(params.providerToken); -} - -- (void)testIOSAppStoreParamsPropertiesSetProperly { - FIRDynamicLinkItunesConnectAnalyticsParameters *params = - [FIRDynamicLinkItunesConnectAnalyticsParameters parameters]; - - params.affiliateToken = @"affiliate"; - params.campaignToken = @"campaign"; - params.providerToken = @"provider"; - - XCTAssertEqualObjects(params.affiliateToken, @"affiliate"); - XCTAssertEqualObjects(params.campaignToken, @"campaign"); - XCTAssertEqualObjects(params.providerToken, @"provider"); - - params.affiliateToken = nil; - params.campaignToken = nil; - params.providerToken = nil; - - XCTAssertNil(params.affiliateToken); - XCTAssertNil(params.campaignToken); - XCTAssertNil(params.providerToken); -} - -- (void)testIOSAppStoreDictionaryRepresentationReturnsCorrectDictionaryFull { - FIRDynamicLinkItunesConnectAnalyticsParameters *params = - [FIRDynamicLinkItunesConnectAnalyticsParameters parameters]; - - params.affiliateToken = @"affiliate"; - params.campaignToken = @"campaign"; - params.providerToken = @"provider"; - - NSDictionary *expectedDictionary = @{ - @"at" : @"affiliate", - @"ct" : @"campaign", - @"pt" : @"provider", - }; - - XCTAssertEqualObjects(expectedDictionary, params.dictionaryRepresentation); -} - -- (void)testIOSAppStoreDictionaryRepresentationReturnsCorrectDictionaryEmpty { - FIRDynamicLinkItunesConnectAnalyticsParameters *params = - [FIRDynamicLinkItunesConnectAnalyticsParameters parameters]; - XCTAssertEqualObjects(@{}, params.dictionaryRepresentation); -} - -#pragma mark - FIRDynamicLinkAndroidParameters - -- (void)testAndroidParamsFactoryReturnsInstanceOfCorrectClass { - id returnValue = - [FIRDynamicLinkAndroidParameters parametersWithPackageName:@"com.google.android.gms"]; - XCTAssertTrue([returnValue isKindOfClass:[FIRDynamicLinkAndroidParameters class]]); -} - -- (void)testAndroidParamsFactoryReturnsInstanceWithAllOptionalNilProperties { - FIRDynamicLinkAndroidParameters *params = - [FIRDynamicLinkAndroidParameters parametersWithPackageName:@"com.google.android.gms"]; - - XCTAssertNil(params.fallbackURL); - XCTAssertEqual(params.minimumVersion, 0); -} - -- (void)testAndroidParamsPropertiesSetProperly { - FIRDynamicLinkAndroidParameters *params = - [FIRDynamicLinkAndroidParameters parametersWithPackageName:@"com.google.android.gms"]; - - params.fallbackURL = [NSURL URLWithString:@"https://google.com/android"]; - params.minimumVersion = 14; - - XCTAssertEqualObjects(params.packageName, @"com.google.android.gms"); - XCTAssertEqualObjects(params.fallbackURL, [NSURL URLWithString:@"https://google.com/android"]); - XCTAssertEqual(params.minimumVersion, 14); - - params.fallbackURL = nil; - params.minimumVersion = 0; - - XCTAssertNil(params.fallbackURL); - XCTAssertEqual(params.minimumVersion, 0); -} - -- (void)testAndroidParamsDictionaryRepresentationReturnsCorrectDictionaryFull { - FIRDynamicLinkAndroidParameters *params = - [FIRDynamicLinkAndroidParameters parametersWithPackageName:@"com.google.android.gms"]; - - params.fallbackURL = [NSURL URLWithString:@"https://google.com/android"]; - params.minimumVersion = 14; - - NSDictionary *expectedDictionary = @{ - @"apn" : @"com.google.android.gms", - @"afl" : [NSURL URLWithString:@"https://google.com/android"].absoluteString, - @"amv" : @"14", - }; - - XCTAssertEqualObjects(expectedDictionary, params.dictionaryRepresentation); -} - -- (void)testAndroidParamsDictionaryRepresentationReturnsCorrectDictionaryEmpty { - FIRDynamicLinkAndroidParameters *params = - [FIRDynamicLinkAndroidParameters parametersWithPackageName:@"com.google.android.gms"]; - XCTAssertEqualObjects(@{@"apn" : @"com.google.android.gms"}, params.dictionaryRepresentation); -} - -#pragma mark - FIRDynamicLinkSocialMetaTagParameters - -- (void)testSocialParamsFactoryReturnsInstanceOfCorrectClass { - id returnValue = [FIRDynamicLinkSocialMetaTagParameters parameters]; - XCTAssertTrue([returnValue isKindOfClass:[FIRDynamicLinkSocialMetaTagParameters class]]); -} - -- (void)testSocialParamsFactoryReturnsInstanceWithAllNilProperties { - FIRDynamicLinkSocialMetaTagParameters *params = - [FIRDynamicLinkSocialMetaTagParameters parameters]; - - XCTAssertNil(params.title); - XCTAssertNil(params.descriptionText); - XCTAssertNil(params.imageURL); -} - -- (void)testSocialParamsPropertiesSetProperly { - FIRDynamicLinkSocialMetaTagParameters *params = - [FIRDynamicLinkSocialMetaTagParameters parameters]; - - params.title = @"title"; - params.descriptionText = @"description"; - params.imageURL = [NSURL URLWithString:@"https://google.com/someimage"]; - - XCTAssertEqualObjects(params.title, @"title"); - XCTAssertEqualObjects(params.descriptionText, @"description"); - XCTAssertEqualObjects(params.imageURL, [NSURL URLWithString:@"https://google.com/someimage"]); - - params.title = nil; - params.descriptionText = nil; - params.imageURL = nil; - - XCTAssertNil(params.title); - XCTAssertNil(params.descriptionText); - XCTAssertNil(params.imageURL); -} - -- (void)testSocialParamsDictionaryRepresentationReturnsCorrectDictionaryFull { - FIRDynamicLinkSocialMetaTagParameters *params = - [FIRDynamicLinkSocialMetaTagParameters parameters]; - - params.title = @"title"; - params.descriptionText = @"description"; - params.imageURL = [NSURL URLWithString:@"https://google.com/someimage"]; - - NSDictionary *expectedDictionary = @{ - @"st" : @"title", - @"sd" : @"description", - @"si" : [NSURL URLWithString:@"https://google.com/someimage"].absoluteString, - }; - - XCTAssertEqualObjects(expectedDictionary, params.dictionaryRepresentation); -} - -- (void)testSocialParamsDictionaryRepresentationReturnsCorrectDictionaryEmpty { - FIRDynamicLinkSocialMetaTagParameters *params = - [FIRDynamicLinkSocialMetaTagParameters parameters]; - XCTAssertEqualObjects(@{}, params.dictionaryRepresentation); -} - -#pragma mark - FIRDynamicLinkNavigationInfoParameters - -- (void)testNavigationOptionsReturnsCorrectClass { - id returnValue = [FIRDynamicLinkNavigationInfoParameters parameters]; - XCTAssertTrue([returnValue isKindOfClass:[FIRDynamicLinkNavigationInfoParameters class]]); -} - -- (void)testNavigationOptionsFactoryReturnsInstanceWithAllNilProperties { - FIRDynamicLinkNavigationInfoParameters *options = - [FIRDynamicLinkNavigationInfoParameters parameters]; - - XCTAssertEqual(options.forcedRedirectEnabled, NO); -} - -- (void)testNavigationOptionsParamsPropertiesSetProperly { - FIRDynamicLinkNavigationInfoParameters *options = - [FIRDynamicLinkNavigationInfoParameters parameters]; - - options.forcedRedirectEnabled = YES; - - XCTAssertEqual(options.forcedRedirectEnabled, YES); - - options.forcedRedirectEnabled = NO; - - XCTAssertEqual(options.forcedRedirectEnabled, NO); -} - -#pragma mark - FIRDynamicLinkOtherPlatformParameters - -- (void)testOtherPlatformParametersReturnsCorrectClass { - id returnValue = [FIRDynamicLinkOtherPlatformParameters parameters]; - XCTAssertTrue([returnValue isKindOfClass:[FIRDynamicLinkOtherPlatformParameters class]]); -} - -- (void)testOtherPlatformParametersFactoryReturnsInstanceWithAllNilProperties { - FIRDynamicLinkOtherPlatformParameters *options = - [FIRDynamicLinkOtherPlatformParameters parameters]; - - XCTAssertNil(options.fallbackUrl); -} - -- (void)testOtherPlatformParametersParamsPropertiesSetProperly { - FIRDynamicLinkOtherPlatformParameters *options = - [FIRDynamicLinkOtherPlatformParameters parameters]; - - options.fallbackUrl = [NSURL URLWithString:@"https://google.com"]; - - XCTAssertEqualObjects(options.fallbackUrl, [NSURL URLWithString:@"https://google.com"]); - - options.fallbackUrl = nil; - - XCTAssertNil(options.fallbackUrl); -} - -#pragma mark - FIRDynamicLinkComponentsOptions - -- (void)testLinkOptionsFactoryReturnsInstanceOfCorrectClass { - id returnValue = [FIRDynamicLinkComponentsOptions options]; - XCTAssertTrue([returnValue isKindOfClass:[FIRDynamicLinkComponentsOptions class]]); -} - -- (void)testLinkOptionsParamsFactoryReturnsInstanceWithAllNilProperties { - FIRDynamicLinkComponentsOptions *options = [FIRDynamicLinkComponentsOptions options]; - - XCTAssertEqual(options.pathLength, FIRShortDynamicLinkPathLengthDefault); -} - -- (void)testLinkOptionsParamsPropertiesSetProperly { - FIRDynamicLinkComponentsOptions *options = [FIRDynamicLinkComponentsOptions options]; - - options.pathLength = FIRShortDynamicLinkPathLengthUnguessable; - - XCTAssertEqual(options.pathLength, FIRShortDynamicLinkPathLengthUnguessable); - - options.pathLength = FIRShortDynamicLinkPathLengthShort; - - XCTAssertEqual(options.pathLength, FIRShortDynamicLinkPathLengthShort); -} - -#pragma mark - FIRDynamicLinkComponents - -- (void)testFDLComponentsFactoryReturnsInstanceOfCorrectClass { - NSURL *link = [NSURL URLWithString:@"https://google.com"]; - id returnValue = [FIRDynamicLinkComponents componentsWithLink:link domainURIPrefix:kFDLURLDomain]; - XCTAssertTrue([returnValue isKindOfClass:[FIRDynamicLinkComponents class]]); -} - -- (void)testFDLComponentsFactoryReturnsInstanceWithAllNilProperties { - NSURL *link = [NSURL URLWithString:@"https://google.com"]; - FIRDynamicLinkComponents *components = - [FIRDynamicLinkComponents componentsWithLink:link domainURIPrefix:kFDLURLDomain]; - - XCTAssertNil(components.analyticsParameters); - XCTAssertNil(components.socialMetaTagParameters); - XCTAssertNil(components.iOSParameters); - XCTAssertNil(components.iTunesConnectParameters); - XCTAssertNil(components.analyticsParameters); - XCTAssertNil(components.options); -} - -- (void)testFDLComponentsCreatesSimplestLinkCorrectly { - NSString *linkString = @"https://google.com"; - NSString *encodedLinkString = @"https%3A%2F%2Fgoogle%2Ecom"; - NSURL *link = [NSURL URLWithString:linkString]; - - NSString *expectedURLString = - [NSString stringWithFormat:@"%@/?link=%@", kFDLURLDomain, encodedLinkString]; - NSURL *expectedURL = [NSURL URLWithString:expectedURLString]; - - FIRDynamicLinkComponents *components = - [FIRDynamicLinkComponents componentsWithLink:link domainURIPrefix:kFDLURLDomain]; - NSURL *actualURL = components.url; - - XCTAssertEqualObjects(actualURL, expectedURL); -} - -- (void)testFDLComponentsCustomDomainWithPath { - NSString *linkString = @"https://google.com"; - NSString *encodedLinkString = @"https%3A%2F%2Fgoogle%2Ecom"; - NSURL *link = [NSURL URLWithString:linkString]; - - NSString *expectedURLString = - [NSString stringWithFormat:@"%@/?link=%@", kFDLURLCustomDomain, encodedLinkString]; - NSURL *expectedURL = [NSURL URLWithString:expectedURLString]; - - FIRDynamicLinkComponents *components = - [FIRDynamicLinkComponents componentsWithLink:link domainURIPrefix:kFDLURLCustomDomain]; - NSURL *actualURL = components.url; - - XCTAssertEqualObjects(actualURL, expectedURL); -} - -- (void)testFDLComponentsFailsOnMalformedDomainURIPrefix { - NSString *linkString = @"https://google.com"; - NSURL *link = [NSURL URLWithString:linkString]; - - FIRDynamicLinkComponents *components = - [FIRDynamicLinkComponents componentsWithLink:link - domainURIPrefix:@"this is invalid domain URI Prefix"]; - - XCTAssertNil(components.url); -} - -- (void)testFDLComponentsNotNilOnDomainWithHTTPScheme { - NSString *linkString = @"https://google.com"; - NSURL *link = [NSURL URLWithString:linkString]; - - FIRDynamicLinkComponents *components = - [FIRDynamicLinkComponents componentsWithLink:link domainURIPrefix:@"https://xyz.page.link"]; - - XCTAssertNotNil(components); -} - -- (void)testFDLComponentsNotNilOnDomainWithHTTPSScheme { - NSString *linkString = @"https://google.com"; - NSURL *link = [NSURL URLWithString:linkString]; - - FIRDynamicLinkComponents *components = - [FIRDynamicLinkComponents componentsWithLink:link domainURIPrefix:@"https://xyz.page.link"]; - - XCTAssertNotNil(components); -} - -- (void)testFDLComponentsFailsOnMalformedDomain { - NSString *linkString = @"https://google.com"; - NSURL *link = [NSURL URLWithString:linkString]; - - FIRDynamicLinkComponents *components = - [FIRDynamicLinkComponents componentsWithLink:link - domainURIPrefix:@"this is invalid domain URI Prefix"]; - - XCTAssertNil(components); -} - -- (void)testFDLComponentsCreatesFullLinkCorrectly { - FIRDynamicLinkGoogleAnalyticsParameters *analyticsParams = - [FIRDynamicLinkGoogleAnalyticsParameters parameters]; - analyticsParams.source = @"s"; - analyticsParams.medium = @"m"; - analyticsParams.campaign = @"ca"; - analyticsParams.term = @"t"; - analyticsParams.content = @"co"; - - FIRDynamicLinkIOSParameters *iosParams = - [FIRDynamicLinkIOSParameters parametersWithBundleID:@"com.iphone.app"]; - iosParams.fallbackURL = [NSURL URLWithString:@"https://google.com/iphone"]; - iosParams.customScheme = @"mycustomsheme"; - iosParams.minimumAppVersion = @"1.2.3"; - iosParams.iPadBundleID = @"com.ipad.app"; - iosParams.iPadFallbackURL = [NSURL URLWithString:@"https://google.com/ipad"]; - iosParams.appStoreID = @"666"; - - FIRDynamicLinkItunesConnectAnalyticsParameters *itcParams = - [FIRDynamicLinkItunesConnectAnalyticsParameters parameters]; - itcParams.affiliateToken = @"affiliate"; - itcParams.campaignToken = @"campaign"; - itcParams.providerToken = @"provider"; - - FIRDynamicLinkAndroidParameters *androidParams = - [FIRDynamicLinkAndroidParameters parametersWithPackageName:@"com.google.android.gms"]; - androidParams.fallbackURL = [NSURL URLWithString:@"https://google.com/android"]; - androidParams.minimumVersion = 14; - - FIRDynamicLinkSocialMetaTagParameters *socialParams = - [FIRDynamicLinkSocialMetaTagParameters parameters]; - socialParams.title = @"title"; - socialParams.descriptionText = @"description"; - socialParams.imageURL = [NSURL URLWithString:@"https://google.com/someimage"]; - - FIRDynamicLinkOtherPlatformParameters *otherPlatformParams = - [FIRDynamicLinkOtherPlatformParameters parameters]; - otherPlatformParams.fallbackUrl = - [NSURL URLWithString:@"https://google.com/fallbackForOtherPlatform"]; - - FIRDynamicLinkNavigationInfoParameters *navInfo = - [FIRDynamicLinkNavigationInfoParameters parameters]; - navInfo.forcedRedirectEnabled = YES; - - FIRDynamicLinkComponentsOptions *options = [FIRDynamicLinkComponentsOptions options]; - options.pathLength = FIRShortDynamicLinkPathLengthUnguessable; - - NSURL *link = [NSURL URLWithString:@"https://google.com"]; - FIRDynamicLinkComponents *fdlComponents = - [FIRDynamicLinkComponents componentsWithLink:link domainURIPrefix:kFDLURLDomain]; - fdlComponents.analyticsParameters = analyticsParams; - fdlComponents.iOSParameters = iosParams; - fdlComponents.iTunesConnectParameters = itcParams; - fdlComponents.androidParameters = androidParams; - fdlComponents.socialMetaTagParameters = socialParams; - fdlComponents.navigationInfoParameters = navInfo; - fdlComponents.otherPlatformParameters = otherPlatformParams; - fdlComponents.options = options; - - // This is a long FDL URL that has been verified to be a correct representation of the expected - // URL. Since the parameters are not guaranteed to be in any specific order, we must compare - // arrays of properties of the URLs rather than the URLs themselves. - NSString *possibleExpectedURLString = - @"https://xyz.page.link/?afl=https%3A%2F%2Fgoogle%2Ecom%2F" - "android&amv=14&apn=com.google.android.gms&ibi=com%2Eiphone%2Eapp&utm_term=t&link=https%3A%" - "2F" - "%2Fgoogle%2Ecom&ipbi=com%2Eipad%2Eapp&ius=mycustomsheme&ifl=https%3A%2F%2Fgoogle%2Ecom%2" - "Fiphone&isi=666&utm_content=co&utm_source=s&utm_medium=m&imv=1%2E2%2E3&ct=campaign&ipfl=" - "http" - "s%3A%2F%2Fgoogle%2Ecom%2Fipad&si=https%3A%2F%2Fgoogle%2Ecom%2Fsomeimage&at=affiliate&pt=" - "prov" - "ider&st=title&utm_campaign=ca&sd=description&efr=1&ofl=https%3A%2F%2Fgoogle%2Ecom%" - "2Ffallback" - "ForOtherPlatform"; - NSURL *possibleExpectedURL = [NSURL URLWithString:possibleExpectedURLString]; - NSURLComponents *expectedURLComponents = - [NSURLComponents componentsWithString:possibleExpectedURLString]; - // sort both expected/actual arrays to prevent order influencing the test results - NSSortDescriptor *sort = [NSSortDescriptor sortDescriptorWithKey:@"name" ascending:YES]; - NSArray *expectedURLQueryItems = - [expectedURLComponents.queryItems sortedArrayUsingDescriptors:@[ sort ]]; - - NSURL *actualURL = fdlComponents.url; - NSURLComponents *actualURLComponents = - [NSURLComponents componentsWithString:actualURL.absoluteString]; - NSArray *actualQueryItems = - [actualURLComponents.queryItems sortedArrayUsingDescriptors:@[ sort ]]; - - XCTAssertEqualObjects(actualQueryItems, expectedURLQueryItems); - XCTAssertEqualObjects(actualURL.host, possibleExpectedURL.host); -} - -- (void)testFDLComponentsCorrectlySetsPathLengthInRequest { - NSURL *url = [NSURL URLWithString:@"https://google.com/abc"]; - NSURLRequest *request; - NSDictionary *JSON; - - FIRDynamicLinkComponentsOptions *options = [FIRDynamicLinkComponentsOptions options]; - - // Default path-length - request = [FIRDynamicLinkComponents shorteningRequestForLongURL:url options:options]; - JSON = [NSJSONSerialization JSONObjectWithData:request.HTTPBody options:0 error:nil]; - XCTAssertNil(JSON[@"suffix"]); - - // Unguessable - options.pathLength = FIRShortDynamicLinkPathLengthUnguessable; - request = [FIRDynamicLinkComponents shorteningRequestForLongURL:url options:options]; - JSON = [NSJSONSerialization JSONObjectWithData:request.HTTPBody options:0 error:nil]; - XCTAssertTrue([JSON[@"suffix"][@"option"] isEqualToString:@"UNGUESSABLE"]); - - // Short - options.pathLength = FIRShortDynamicLinkPathLengthShort; - request = [FIRDynamicLinkComponents shorteningRequestForLongURL:url options:options]; - JSON = [NSJSONSerialization JSONObjectWithData:request.HTTPBody options:0 error:nil]; - XCTAssertTrue([JSON[@"suffix"][@"option"] isEqualToString:@"SHORT"]); -} - -- (void)testShortenURL { - NSString *shortURLString = @"https://xyz.page.link/abcd"; - - // Mock key provider - id keyProviderClassMock = OCMClassMock([FIRDynamicLinkComponentsKeyProvider class]); - [[[keyProviderClassMock expect] andReturn:@"fake-api-key"] APIKey]; - - id componentsClassMock = OCMClassMock([FIRDynamicLinkComponents class]); - [[componentsClassMock expect] - sendHTTPRequest:OCMOCK_ANY - completion:[OCMArg checkWithBlock:^BOOL(id obj) { - void (^completion)(NSData *_Nullable, NSError *_Nullable) = obj; - NSDictionary *JSON = @{@"shortLink" : shortURLString}; - NSData *JSONData = [NSJSONSerialization dataWithJSONObject:JSON options:0 error:0]; - completion(JSONData, nil); - return YES; - }]]; - - XCTestExpectation *expectation = [self expectationWithDescription:@"completion called"]; - NSURL *link = [NSURL URLWithString:@"https://google.com/abc"]; - FIRDynamicLinkComponents *components = - [FIRDynamicLinkComponents componentsWithLink:link domainURIPrefix:kFDLURLDomain]; - [components - shortenWithCompletion:^(NSURL *_Nullable shortURL, NSArray *_Nullable warnings, - NSError *_Nullable error) { - XCTAssertEqualObjects(shortURL.absoluteString, shortURLString); - [expectation fulfill]; - }]; - [self waitForExpectationsWithTimeout:0.1 handler:nil]; - - [keyProviderClassMock verify]; - [keyProviderClassMock stopMocking]; - [componentsClassMock verify]; - [componentsClassMock stopMocking]; -} - -- (void)testShortenURLReturnsErrorWhenAPIKeyMissing { - NSString *shortURLString = @"https://xyz.page.link/abcd"; - - // Mock key provider - id keyProviderClassMock = OCMClassMock([FIRDynamicLinkComponentsKeyProvider class]); - [[[keyProviderClassMock expect] andReturn:nil] APIKey]; - - id componentsClassMock = OCMClassMock([FIRDynamicLinkComponents class]); - [[componentsClassMock stub] - sendHTTPRequest:OCMOCK_ANY - completion:[OCMArg checkWithBlock:^BOOL(id obj) { - void (^completion)(NSData *_Nullable, NSError *_Nullable) = obj; - NSDictionary *JSON = @{@"shortLink" : shortURLString}; - NSData *JSONData = [NSJSONSerialization dataWithJSONObject:JSON options:0 error:0]; - completion(JSONData, nil); - return YES; - }]]; - - XCTestExpectation *expectation = - [self expectationWithDescription:@"completion called with error"]; - NSURL *link = [NSURL URLWithString:@"https://google.com/abc"]; - FIRDynamicLinkComponents *components = - [FIRDynamicLinkComponents componentsWithLink:link domainURIPrefix:kFDLURLDomain]; - [components - shortenWithCompletion:^(NSURL *_Nullable shortURL, NSArray *_Nullable warnings, - NSError *_Nullable error) { - XCTAssertNil(shortURL); - if (error) { - [expectation fulfill]; - } - }]; - [self waitForExpectationsWithTimeout:0.1 handler:nil]; - - [keyProviderClassMock verify]; - [keyProviderClassMock stopMocking]; - [componentsClassMock verify]; - [componentsClassMock stopMocking]; -} - -- (void)testShortenURLReturnsErrorWhenDomainIsMalformed { - NSString *shortURLString = @"https://xyz.page.link/abcd"; - - // Mock key provider - id keyProviderClassMock = OCMClassMock([FIRDynamicLinkComponentsKeyProvider class]); - [[keyProviderClassMock reject] APIKey]; - - id componentsClassMock = OCMClassMock([FIRDynamicLinkComponents class]); - [[componentsClassMock reject] - sendHTTPRequest:OCMOCK_ANY - completion:[OCMArg checkWithBlock:^BOOL(id obj) { - void (^completion)(NSData *_Nullable, NSError *_Nullable) = obj; - NSDictionary *JSON = @{@"shortLink" : shortURLString}; - NSData *JSONData = [NSJSONSerialization dataWithJSONObject:JSON options:0 error:0]; - completion(JSONData, nil); - return YES; - }]]; - - NSURL *link = [NSURL URLWithString:@"https://google.com/abc"]; - FIRDynamicLinkComponents *components = - [FIRDynamicLinkComponents componentsWithLink:link - domainURIPrefix:@"this is invalid domain URI Prefix"]; - XCTAssertNil(components); - - [keyProviderClassMock verify]; - [keyProviderClassMock stopMocking]; - [componentsClassMock verify]; - [componentsClassMock stopMocking]; -} - -@end diff --git a/FirebaseDynamicLinks/Tests/Unit/FIRDLScionLoggingTest.m b/FirebaseDynamicLinks/Tests/Unit/FIRDLScionLoggingTest.m deleted file mode 100644 index c313b96ea90..00000000000 --- a/FirebaseDynamicLinks/Tests/Unit/FIRDLScionLoggingTest.m +++ /dev/null @@ -1,182 +0,0 @@ -/* - * 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. - */ - -#import - -#import -#import "FirebaseDynamicLinks/Sources/FIRDLScionLogging.h" - -static const NSTimeInterval kAsyncTestTimeout = 0.5; - -typedef void (^FakeAnalyticsLogEventWithOriginNameParametersHandler)(NSString *origin, - NSString *name, - NSDictionary *parameters); - -@interface FakeAnalytics : NSObject - -- (instancetype)initWithHandler:(FakeAnalyticsLogEventWithOriginNameParametersHandler)handler; - -@end - -@implementation FakeAnalytics - -static FakeAnalyticsLogEventWithOriginNameParametersHandler _handler; - -- (instancetype)initWithHandler:(FakeAnalyticsLogEventWithOriginNameParametersHandler)handler { - self = [super init]; - if (self) { - _handler = handler; - } - return self; -} - -- (void)logEventWithOrigin:(nonnull NSString *)origin - name:(nonnull NSString *)name - parameters:(nullable NSDictionary *)parameters { - if (_handler) { - _handler(origin, name, parameters); - } -} - -// Stubs -- (void)clearConditionalUserProperty:(nonnull NSString *)userPropertyName - clearEventName:(nonnull NSString *)clearEventName - clearEventParameters:(nonnull NSDictionary *)clearEventParameters { -} - -- (NSInteger)maxUserProperties:(nonnull NSString *)origin { - return -1; -} - -- (void)setUserPropertyWithOrigin:(nonnull NSString *)origin - name:(nonnull NSString *)name - value:(nonnull id)value { -} - -- (void)checkLastNotificationForOrigin:(nonnull NSString *)origin - queue:(nonnull dispatch_queue_t)queue - callback:(nonnull void (^)(NSString *_Nullable)) - currentLastNotificationProperty { -} - -- (void)registerAnalyticsListener:(nonnull id)listener - withOrigin:(nonnull NSString *)origin { -} - -- (void)unregisterAnalyticsListenerWithOrigin:(nonnull NSString *)origin { -} - -- (void)clearConditionalUserProperty:(nonnull NSString *)userPropertyName - forOrigin:(nonnull NSString *)origin - clearEventName:(nonnull NSString *)clearEventName - clearEventParameters: - (nonnull NSDictionary *)clearEventParameters { -} - -- (nonnull NSArray *> *) - conditionalUserProperties:(nonnull NSString *)origin - propertyNamePrefix:(nonnull NSString *)propertyNamePrefix { - return nil; -} - -- (void)setConditionalUserProperty:(nonnull NSDictionary *)conditionalUserProperty { -} - -- (void)getUserPropertiesWithCallback:(nonnull FIRAInteropUserPropertiesCallback)callback { -} -@end - -@interface FIRDLScionLoggingTest : XCTestCase -@end - -@implementation FIRDLScionLoggingTest - -- (void)testGINLogEventToScionCallsLogMethodWithFirstOpen { - XCTestExpectation *expectation = [self expectationWithDescription:@"completion"]; - - FakeAnalytics *analytics = [[FakeAnalytics alloc] - initWithHandler:^(NSString *origin, NSString *name, NSDictionary *parameters) { - [expectation fulfill]; - }]; - - FIRDLLogEventToScion(FIRDLLogEventFirstOpen, nil, nil, nil, analytics); - [self waitForExpectationsWithTimeout:kAsyncTestTimeout handler:nil]; -} - -- (void)testGINLogEventToScionContainsCorrectNameWithFirstOpen { - XCTestExpectation *expectation = [self expectationWithDescription:@"completion"]; - - FakeAnalytics *analytics = [[FakeAnalytics alloc] - initWithHandler:^(NSString *origin, NSString *name, NSDictionary *parameters) { - XCTAssertEqualObjects(name, @"dynamic_link_first_open", @"scion name param was incorrect"); - [expectation fulfill]; - }]; - - FIRDLLogEventToScion(FIRDLLogEventFirstOpen, nil, nil, nil, analytics); - [self waitForExpectationsWithTimeout:kAsyncTestTimeout handler:nil]; -} - -- (void)testGINLogEventToScionCallsLogMethodWithAppOpen { - XCTestExpectation *expectation = [self expectationWithDescription:@"completion"]; - - FakeAnalytics *analytics = [[FakeAnalytics alloc] - initWithHandler:^(NSString *origin, NSString *name, NSDictionary *parameters) { - [expectation fulfill]; - }]; - FIRDLLogEventToScion(FIRDLLogEventAppOpen, nil, nil, nil, analytics); - - [self waitForExpectationsWithTimeout:kAsyncTestTimeout handler:nil]; -} - -- (void)testGINLogEventToScionContainsCorrectNameWithAppOpen { - XCTestExpectation *expectation = [self expectationWithDescription:@"completion"]; - - FakeAnalytics *analytics = [[FakeAnalytics alloc] - initWithHandler:^(NSString *origin, NSString *name, NSDictionary *parameters) { - XCTAssertEqualObjects(name, @"dynamic_link_app_open", @"scion name param was incorrect"); - [expectation fulfill]; - }]; - FIRDLLogEventToScion(FIRDLLogEventAppOpen, nil, nil, nil, analytics); - - [self waitForExpectationsWithTimeout:kAsyncTestTimeout handler:nil]; -} - -- (void)testGINLogEventToScionLogsParametersCorrectly { - NSString *source = @"9-2nkg"; - NSString *medium = @"fjg0"; - NSString *campaign = @"gjoo3u5"; - - NSString *sourceKey = @"source"; - NSString *mediumKey = @"medium"; - NSString *campaignKey = @"campaign"; - - XCTestExpectation *expectation = [self expectationWithDescription:@"completion"]; - - FakeAnalytics *analytics = [[FakeAnalytics alloc] - initWithHandler:^(NSString *origin, NSString *name, NSDictionary *params) { - XCTAssertEqualObjects(params[sourceKey], source, @"scion logger has incorrect source."); - XCTAssertEqualObjects(params[mediumKey], medium, @"scion logger has incorrect medium."); - XCTAssertEqualObjects(params[campaignKey], campaign, - @"scion logger has incorrect campaign."); - [expectation fulfill]; - }]; - - FIRDLLogEventToScion(FIRDLLogEventAppOpen, source, medium, campaign, analytics); - - [self waitForExpectationsWithTimeout:kAsyncTestTimeout handler:nil]; -} - -@end diff --git a/FirebaseDynamicLinks/Tests/Unit/FIRDynamicLinkNetworkingTests.m b/FirebaseDynamicLinks/Tests/Unit/FIRDynamicLinkNetworkingTests.m deleted file mode 100644 index b93e8e92332..00000000000 --- a/FirebaseDynamicLinks/Tests/Unit/FIRDynamicLinkNetworkingTests.m +++ /dev/null @@ -1,100 +0,0 @@ -/* - * 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. - */ - -#import - -#import - -#import - -#import -#import "FirebaseDynamicLinks/Sources/FIRDynamicLinkNetworking+Private.h" - -static NSString *const kAPIKey = @"myfakeapikey"; -const NSInteger kJSONParsingErrorCode = 3840; -static NSString *const kURLScheme = @"gindeeplinkurl"; -static const NSTimeInterval kAsyncTestTimeout = 5.0; - -@interface FIRDynamicLinkNetworkingTests : XCTestCase - -@property(strong, nonatomic) FIRDynamicLinkNetworking *service; - -@end - -@implementation FIRDynamicLinkNetworkingTests - -- (void)tearDown { - self.service = nil; -} - -- (FIRDynamicLinkNetworking *)service { - if (!_service) { - _service = [[FIRDynamicLinkNetworking alloc] initWithAPIKey:kAPIKey URLScheme:kURLScheme]; - } - return _service; -} - -- (void)testFIRDynamicLinkAPIKeyParameterReturnsCorrectlyFormattedParameterString { - NSString *expectedValue = [NSString stringWithFormat:@"?key=%@", kAPIKey]; - - NSString *parameter = FIRDynamicLinkAPIKeyParameter(kAPIKey); - - XCTAssertEqualObjects(parameter, expectedValue, - @"FIRDynamicLinkAPIKeyParameter() returned incorrect parameter string"); -} - -- (void)testFIRDynamicLinkAPIKeyParameterReturnsNilParameterStringWhenAPIKeyIsNil { -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wnonnull" - NSString *parameter = FIRDynamicLinkAPIKeyParameter(nil); -#pragma clang diagnostic pop - - XCTAssertNil(parameter, - @"FIRDynamicLinkAPIKeyParameter() returned non-nil result when API key was nil"); -} - -- (void)testResolveShortLinkServiceCompletionDoesntCrashWhenNilDataIsRetrieved { - NSURL *url = [NSURL URLWithString:@"https://google.com"]; - - void (^executeRequestBlock)(id, NSDictionary *, NSString *, FIRNetworkRequestCompletionHandler) = - ^(id p1, NSDictionary *requestBody, NSString *requestURLString, - FIRNetworkRequestCompletionHandler handler) { - handler(nil, nil, nil); - }; - - SEL executeRequestSelector = @selector(executeOnePlatformRequest:forURL:completionHandler:); - - [GULSwizzler swizzleClass:[FIRDynamicLinkNetworking class] - selector:executeRequestSelector - isClassSelector:NO - withBlock:executeRequestBlock]; - - XCTestExpectation *expectation = [self expectationWithDescription:@"completion called"]; - - [self.service resolveShortLink:url - FDLSDKVersion:@"1.0.0" - completion:^(NSURL *_Nullable url, NSError *_Nullable error) { - [expectation fulfill]; - }]; - - [self waitForExpectationsWithTimeout:kAsyncTestTimeout handler:nil]; - - [GULSwizzler unswizzleClass:[FIRDynamicLinkNetworking class] - selector:executeRequestSelector - isClassSelector:NO]; -} - -@end diff --git a/FirebaseDynamicLinks/Tests/Unit/FIRDynamicLinkTest.m b/FirebaseDynamicLinks/Tests/Unit/FIRDynamicLinkTest.m deleted file mode 100644 index b2dfb50381a..00000000000 --- a/FirebaseDynamicLinks/Tests/Unit/FIRDynamicLinkTest.m +++ /dev/null @@ -1,79 +0,0 @@ -/* - * 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 -#import -#import "FirebaseDynamicLinks/Sources/FIRDynamicLink+Private.h" - -@interface FIRDynamicLinkTest : XCTestCase { -} -@end - -@implementation FIRDynamicLinkTest - -NSMutableDictionary *fdlParameters = nil; -NSDictionary *linkParameters = nil; -NSDictionary *utmParameters = nil; - -- (void)setUp { - [super setUp]; - - linkParameters = @{ - @"deep_link_id" : @"https://mmaksym.com/test-app1", - @"match_message" : @"Link is uniquely matched for this device.", - @"match_type" : @"unique", - @"a_parameter" : @"a_value" - }; - utmParameters = @{ - @"utm_campaign" : @"eldhosembabu Test", - @"utm_medium" : @"test_medium", - @"utm_source" : @"test_source", - }; - - fdlParameters = [[NSMutableDictionary alloc] initWithDictionary:linkParameters]; - [fdlParameters addEntriesFromDictionary:utmParameters]; -} - -- (void)testDynamicLinkParameters_InitWithParameters { - FIRDynamicLink *dynamicLink = [[FIRDynamicLink alloc] initWithParametersDictionary:fdlParameters]; - XCTAssertEqual([fdlParameters count], [[dynamicLink parametersDictionary] count]); - for (NSString *key in fdlParameters) { - NSString *expectedValue = [fdlParameters valueForKey:key]; - NSString *derivedValue = [[dynamicLink parametersDictionary] valueForKey:key]; - XCTAssertNotNil(derivedValue, @"Cannot be null!"); - XCTAssertEqualObjects(derivedValue, expectedValue); - } -} - -- (void)testDynamicLinkUtmParameters_InitWithParameters { - FIRDynamicLink *dynamicLink = [[FIRDynamicLink alloc] initWithParametersDictionary:fdlParameters]; - XCTAssertEqual([[dynamicLink utmParametersDictionary] count], [utmParameters count]); - for (NSString *key in utmParameters) { - NSString *expectedValue = [utmParameters valueForKey:key]; - NSString *derivedValue = [[dynamicLink utmParametersDictionary] valueForKey:key]; - XCTAssertNotNil(derivedValue, @"Cannot be null!"); - XCTAssertEqualObjects(derivedValue, expectedValue); - } -} - -- (void)testDynamicLinkParameters_InitWithNoUtmParameters { - FIRDynamicLink *dynamicLink = - [[FIRDynamicLink alloc] initWithParametersDictionary:linkParameters]; - XCTAssertEqual([[dynamicLink parametersDictionary] count], [linkParameters count]); - XCTAssertEqual([[dynamicLink utmParametersDictionary] count], 0); -} - -@end diff --git a/FirebaseDynamicLinks/Tests/Unit/FIRDynamicLinksImportsTest3P.m b/FirebaseDynamicLinks/Tests/Unit/FIRDynamicLinksImportsTest3P.m deleted file mode 100644 index 8e91ff87d82..00000000000 --- a/FirebaseDynamicLinks/Tests/Unit/FIRDynamicLinksImportsTest3P.m +++ /dev/null @@ -1,33 +0,0 @@ -/* - * 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. - */ - -#import - -#import "FirebaseDynamicLinks/Sources/Public/FirebaseDynamicLinks/FIRDynamicLinks.h" - -@interface FIRDynamicLinksImportsTest3P : XCTestCase - -@end - -@implementation FIRDynamicLinksImportsTest3P - -- (void)testPlaceholder { - // This is empty test case. - // The test file designed to test successful build if source file, that includes - // FIRDynamicLinks.h, does not includes any other headers, like UIKit. -} - -@end diff --git a/FirebaseDynamicLinks/Tests/Unit/FIRDynamicLinksTest.m b/FirebaseDynamicLinks/Tests/Unit/FIRDynamicLinksTest.m deleted file mode 100644 index d53ee7d6660..00000000000 --- a/FirebaseDynamicLinks/Tests/Unit/FIRDynamicLinksTest.m +++ /dev/null @@ -1,1787 +0,0 @@ -/* - * 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. - */ - -#import - -#import - -#import -#import -#import "FirebaseCore/Extension/FirebaseCoreInternal.h" -#import "FirebaseDynamicLinks/Sources/FIRDLDefaultRetrievalProcessV2.h" -#import "FirebaseDynamicLinks/Sources/FIRDLRetrievalProcessFactory.h" -#import "FirebaseDynamicLinks/Sources/FIRDLRetrievalProcessResult+Private.h" -#import "FirebaseDynamicLinks/Sources/FIRDynamicLink+Private.h" -#import "FirebaseDynamicLinks/Sources/FIRDynamicLinkNetworking+Private.h" -#import "FirebaseDynamicLinks/Sources/FIRDynamicLinks+FirstParty.h" -#import "FirebaseDynamicLinks/Sources/FIRDynamicLinks+Private.h" -#import "FirebaseDynamicLinks/Sources/Utilities/FDLUtilities.h" -#import "Interop/Analytics/Public/FIRAnalyticsInterop.h" - -static NSString *const kAPIKey = @"myAPIKey"; -static NSString *const kStructuredLinkFmtFreeform = @"%@://google/link/%@"; -static NSString *const kStructuredLinkFmtDeepLink = @"%@://google/link/?deep_link_id=%@"; -static NSString *const kStructuredLinkFmtInvitation = @"%@://google/link/?invitation_id=%@"; -static NSString *const kStructuredLinkFmtInvitationWeak = - @"%@://google/link/?invitation_id=%@&match_type=weak"; -static NSString *const kStructuredLinkFmtDeepLinkAndInvitation = - @"%@://google/link/?deep_link_id=%@&invitation_id=%@"; -static NSString *const kStructuredUniversalLinkFmtFreeForm = @"https://goo.gl/app/sample%@"; -static NSString *const kStructuredUniversalLinkFmtDeepLink = - @"https://goo.gl/app/sample?link=%@&isi=585027354"; -static NSString *const kStructuredUniversalLinkFmtSubdomain = @"https://sample.page.link%@"; -static NSString *const kStructuredUniversalLinkFmtSubdomainDeepLink = - @"https://sample.page.link?link=%@&isi=585027354"; -static NSString *const kURLScheme = @"gindeeplinkurl"; - -static const NSTimeInterval kAsyncTestTimeout = 5.0; - -/** - * This string was generated by percent-encoding the Tactile URL for the Tokyo American Club in - * Tokyo, and then replacing a '%2B' with a '+' to verify that the '+' does not cause our parsing to - * fail and double-encoding one value to verify that only one decoding pass is run. - */ -NSString *kEncodedComplicatedURLString = - @"https%3A%2F%2Fwww.google.com%252Fmaps%2Fplace%2FTokyo+Am" - @"erican%2BClub%2F%4035.658578%2C139.741588%2C3a%2C75y%2C90t%2Fdata%3D%213m8%211e2%213m6%211s42" - @"66698%212e1%213e10%216s%252F%252Fstorage.googleapis.com%252Fstatic.panoramio.com%252Fphotos%2" - @"52Fmedium%252F4266698.jpg%217i640%218i480%214m2%213m1%211s0x0000000000000000%3A0x1b8b8130c791" - @"48e1%216m1%211e1"; -/** This string was generated by percent-decoding kEncodedComplicatedURLString. */ -NSString *kDecodedComplicatedURLString = - @"https://www.google.com%2Fmaps/place/Tokyo+American+Club/" - @"@35.658578,139.741588,3a,75y,90t/data=!3m8!1e2!3m6!1s4266698!2e1!3e10!6s%2F%2Fstorage.googlea" - @"pis.com%2Fstatic.panoramio.com%2Fphotos%2Fmedium%2F4266698.jpg!7i640!8i480!4m2!3m1!1s0x000000" - @"0000000000:0x1b8b8130c79148e1!6m1!1e1"; - -static void *kOpenURLHandlerKey = &kOpenURLHandlerKey; - -typedef NSURL * (^FakeShortLinkResolverHandler)(NSURL *shortLink); - -@interface FIRDynamicLinks (FIRApp) -- (void)configureDynamicLinks:(FIRApp *)app; -- (BOOL)setUpWithLaunchOptions:(nullable NSDictionary *)launchOptions - apiKey:(NSString *)apiKey - urlScheme:(nullable NSString *)urlScheme - userDefaults:(nullable NSUserDefaults *)userDefaults; -- (BOOL)canParseUniversalLinkURL:(nullable NSURL *)url; -- (void)passRetrievedDynamicLinkToApplication:(NSURL *)url; -- (BOOL)isOpenUrlMethodPresentInAppDelegate:(id)applicationDelegate; -@end - -@interface FakeShortLinkResolver : FIRDynamicLinkNetworking -+ (instancetype)resolverWithBlock:(FakeShortLinkResolverHandler)resolverHandler; -@end - -@implementation FakeShortLinkResolver { - FakeShortLinkResolverHandler _resolverHandler; -} - -+ (instancetype)resolverWithBlock:(FakeShortLinkResolverHandler)resolverHandler { - // The parameters don't matter since they aren't validated or used here. - FakeShortLinkResolver *resolver = [[self alloc] initWithAPIKey:@"" URLScheme:@""]; - resolver->_resolverHandler = [resolverHandler copy]; - return resolver; -} - -- (void)resolveShortLink:(NSURL *)url - FDLSDKVersion:(NSString *)FDLSDKVersion - completion:(FIRDynamicLinkResolverHandler)completion { - if (_resolverHandler && completion) { - NSURL *resolvedLink = _resolverHandler(url); - completion(resolvedLink, nil); - } -} - -@end - -// dummy protocol to prevent compile warning -@protocol DummyProtocol - -@property(atomic, assign) BOOL retrievingPendingDynamicLink; - -@property(nonatomic, readonly) FIRDynamicLinkNetworking *dynamicLinkNetworking; - -- (void)handlePendingDynamicLinkRetrievalFailureWithErrorCode:(NSInteger)errorCode - errorDescription:(NSString *)errorDescription - underlyingError:(nullable NSError *)underlyingError; - -@end - -// Swizzle DynamicLinks.dynamicLinkNetworking property to return fake resolver. -static void SwizzleDynamicLinkNetworking(id linkResolver) { - id (^dynamicLinkNetworkingBlock)(void) = ^id(void) { - return linkResolver; - }; - [GULSwizzler swizzleClass:[FIRDynamicLinks class] - selector:@selector(dynamicLinkNetworking) - isClassSelector:NO - withBlock:dynamicLinkNetworkingBlock]; -} - -static void SwizzleDynamicLinkNetworkingWithMock(void) { - id linkResolver = OCMPartialMock([[FIRDynamicLinkNetworking alloc] initWithAPIKey:kAPIKey - URLScheme:kURLScheme]); - [[linkResolver stub] resolveShortLink:OCMOCK_ANY FDLSDKVersion:@"1.0.0" completion:OCMOCK_ANY]; - - SwizzleDynamicLinkNetworking(linkResolver); -} - -static void UnswizzleDynamicLinkNetworking(void) { - [GULSwizzler unswizzleClass:[FIRDynamicLinks class] - selector:@selector(dynamicLinkNetworking) - isClassSelector:NO]; -} - -@interface FIRDynamicLinksTest : XCTestCase { - id _bundleMock; -} - -// An instance of |GINDurableDeepLinkService| used for testing. -@property(nonatomic, strong) FIRDynamicLinks *service; -// An instance of |NSUserDefaults| that have all default values removed. -@property(nonatomic, strong) NSUserDefaults *userDefaults; -// FIRAnalytics mock. Necessary because we don't call [FIRAPP configure]. -@property(nonatomic, strong) id analytics; - -@end - -@implementation FIRDynamicLinksTest - -// Disable deprecated warning for internal methods. -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wdeprecated-declarations" - -#pragma mark - Test lifecycle - -static NSString *const kInfoPlistCustomDomainsKey = @"FirebaseDynamicLinksCustomDomains"; - -- (void)setUp { - [super setUp]; - - // Mock the mainBundle infoDictionary with version from DL-Info.plist for custom domain testing. - NSBundle *bundle = [NSBundle bundleForClass:[self class]]; - NSString *filePath = [bundle pathForResource:@"DL-Info" ofType:@"plist"]; - _bundleMock = OCMPartialMock([NSBundle mainBundle]); - OCMStub([_bundleMock infoDictionary]) - .andReturn([NSDictionary dictionaryWithContentsOfFile:filePath]); - - if (![FIRApp isDefaultAppConfigured]) { - XCTAssertNoThrow([FIRApp configureWithOptions:[self appOptions]]); - } - - self.service = [[FIRDynamicLinks alloc] init]; - self.userDefaults = [[NSUserDefaults alloc] init]; - [self.userDefaults removePersistentDomainForName:[[NSBundle mainBundle] bundleIdentifier]]; - self.analytics = OCMProtocolMock(@protocol(FIRAnalyticsInterop)); -} - -- (void)tearDown { - self.service = nil; - self.userDefaults = nil; - [self.analytics stopMocking]; - self.analytics = nil; - [_bundleMock stopMocking]; - _bundleMock = nil; - [super tearDown]; -} - -- (FIROptions *)appOptions { - // TODO: Evaluate if we want to hardcode things here instead. - FIROptions *options = [[FIROptions alloc] initWithGoogleAppID:@"1:123:ios:123abc" - GCMSenderID:@"correct_gcm_sender_id"]; - options.APIKey = @"correct_api_key"; - options.projectID = @"abc-xyz-123"; - return options; -} - -#pragma mark - Set Up. - -- (void)testURLScheme_NoApiKey { -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wnonnull" - BOOL setUpSucceed = [self.service setUpWithLaunchOptions:nil - apiKey:nil - urlScheme:nil - userDefaults:nil]; -#pragma clang diagnostic pop - XCTAssertFalse(setUpSucceed, @"Should fail when apiKey is nil."); -} - -- (void)testURLScheme_MinimumParameters { - BOOL setUpSucceed = [self.service setUpWithLaunchOptions:nil - apiKey:kAPIKey - urlScheme:nil - userDefaults:nil]; - XCTAssertTrue(setUpSucceed, @"Should not fail when apiKey is set."); -} - -- (void)testFactoryMethodReturnsProperClassObject { - id service = [FIRDynamicLinks dynamicLinks]; - - XCTAssertNotNil(service, @"Factory method returned nil"); - XCTAssertEqualObjects([service class], [FIRDynamicLinks class], - @"Factory returned incorrect class object"); -} - -- (void)testURLScheme_LaunchOptionsWithCustomSchemeURL { - NSString *deepLinkString = - [NSString stringWithFormat:kStructuredLinkFmtDeepLink, - [[NSBundle mainBundle] bundleIdentifier], @"abc123"]; - NSDictionary *launchOptions = - @{UIApplicationLaunchOptionsURLKey : [NSURL URLWithString:deepLinkString]}; - - [self.userDefaults setBool:NO forKey:kFIRDLReadDeepLinkAfterInstallKey]; - [self.service setUpWithLaunchOptions:launchOptions - apiKey:kAPIKey - urlScheme:nil - userDefaults:self.userDefaults]; - XCTAssertTrue([self.userDefaults boolForKey:kFIRDLReadDeepLinkAfterInstallKey]); -} - -- (void)testURLScheme_LaunchOptionsWithUniversalLinkURL { - NSString *deepLinkString = - [NSString stringWithFormat:kStructuredUniversalLinkFmtDeepLink, @"abc123"]; - NSDictionary *launchOptions = - @{UIApplicationLaunchOptionsURLKey : [NSURL URLWithString:deepLinkString]}; - - [self.userDefaults setBool:NO forKey:kFIRDLReadDeepLinkAfterInstallKey]; - [self.service setUpWithLaunchOptions:launchOptions - apiKey:kAPIKey - urlScheme:nil - userDefaults:self.userDefaults]; - XCTAssertTrue([self.userDefaults boolForKey:kFIRDLReadDeepLinkAfterInstallKey]); -} - -- (void)testURLScheme_LaunchOptionsWithInvalidURLWillNotResetUserDefaultsFlag { - NSDictionary *launchOptions = - @{UIApplicationLaunchOptionsURLKey : [NSURL URLWithString:@"https://www.google.com"]}; - - [self.userDefaults setBool:YES forKey:kFIRDLReadDeepLinkAfterInstallKey]; - [self.service setUpWithLaunchOptions:launchOptions - apiKey:kAPIKey - urlScheme:nil - userDefaults:self.userDefaults]; - XCTAssertTrue([self.userDefaults boolForKey:kFIRDLReadDeepLinkAfterInstallKey]); -} - -- (void)testURLScheme_Nil { - BOOL setUpSucceed = [self.service setUpWithLaunchOptions:nil - apiKey:kAPIKey - urlScheme:nil - userDefaults:nil]; - XCTAssertTrue(setUpSucceed); - XCTAssertEqualObjects(self.service.URLScheme, [NSBundle mainBundle].bundleIdentifier); -} - -- (void)testURLScheme_EmptyString { - BOOL setUpSucceed = [self.service setUpWithLaunchOptions:nil - apiKey:kAPIKey - urlScheme:@"" - userDefaults:nil]; - XCTAssertTrue(setUpSucceed); - XCTAssertEqualObjects(self.service.URLScheme, [NSBundle mainBundle].bundleIdentifier); -} - -- (void)testURLScheme_NonNil { - [self.service setUpWithLaunchOptions:nil - apiKey:kAPIKey - urlScheme:kURLScheme - userDefaults:self.userDefaults]; - XCTAssertEqualObjects(self.service.URLScheme, kURLScheme, - @"URLScheme should be the same as in argument"); -} - -// TODO (b/63079414) Re-enable this -- (void)DISABLED_testConfigNamedFIRApp { - [self removeAllFIRApps]; - - id deepLinkServicePartialMock = OCMPartialMock([FIRDynamicLinks dynamicLinks]); - [[deepLinkServicePartialMock reject] configureDynamicLinks:[OCMArg any]]; - [FIRApp configureWithName:@"NonDefaultName" options:[FIROptions defaultOptions]]; - [deepLinkServicePartialMock stopMocking]; -} - -// TODO (b/37855379) re-enable the test -- (void)DISABLED_testConfigForFIRApp { - [self removeAllFIRApps]; - - id deepLinkServicePartialMock = OCMPartialMock([FIRDynamicLinks dynamicLinks]); - [FIRApp configure]; - OCMVerify([deepLinkServicePartialMock configureDynamicLinks:[OCMArg any]]); - [deepLinkServicePartialMock stopMocking]; -} - -#pragma mark - dynamicLinkFromCustomSchemeURL - -- (void)testCustomScheme_NoDeepLink { - NSString *urlString = - [NSString stringWithFormat:kStructuredLinkFmtFreeform, kURLScheme, @"abc123xyz"]; - NSURL *url = [NSURL URLWithString:urlString]; - - [self.service setUpWithLaunchOptions:nil - apiKey:kAPIKey - urlScheme:kURLScheme - userDefaults:self.userDefaults]; - FIRDynamicLink *dynamicLink = [self.service dynamicLinkFromCustomSchemeURL:url]; - XCTAssertNil(dynamicLink, @"invite should be nil since there is no parameter."); -} - -- (void)testCustomScheme_DeepLinkOnly { - NSString *deepLinkString = @"https://developers.google.com/products/"; - NSString *urlString = - [NSString stringWithFormat:kStructuredLinkFmtDeepLink, kURLScheme, deepLinkString]; - NSURL *url = [NSURL URLWithString:urlString]; - - [self.service setUpWithLaunchOptions:nil - apiKey:kAPIKey - urlScheme:kURLScheme - userDefaults:self.userDefaults]; - FIRDynamicLink *dynamicLink = [self.service dynamicLinkFromCustomSchemeURL:url]; - XCTAssertEqualObjects(dynamicLink.url.absoluteString, deepLinkString); - XCTAssertNil(dynamicLink.inviteId); -} - -- (void)testCustomScheme_InvitationOnly { - NSString *invitationId = @"213920940217491274389172947"; - - NSString *urlString = - [NSString stringWithFormat:kStructuredLinkFmtInvitation, kURLScheme, invitationId]; - NSURL *url = [NSURL URLWithString:urlString]; - - [self.service setUpWithLaunchOptions:nil - apiKey:kAPIKey - urlScheme:kURLScheme - userDefaults:self.userDefaults]; - FIRDynamicLink *dynamicLink = [self.service dynamicLinkFromCustomSchemeURL:url]; - XCTAssertNil(dynamicLink.url); - XCTAssertEqualObjects(dynamicLink.inviteId, invitationId); -} - -- (void)testCustomScheme_DeepLinkAndInvitation { - NSString *deepLinkString = @"https://developers.google.com/products/"; - NSString *invitationId = @"21392094021749127-4389172947"; - - NSString *urlString = [NSString stringWithFormat:kStructuredLinkFmtDeepLinkAndInvitation, - [[NSBundle mainBundle] bundleIdentifier], - deepLinkString, invitationId]; - NSURL *url = [NSURL URLWithString:urlString]; - - [self.service setUpWithLaunchOptions:nil - apiKey:kAPIKey - urlScheme:kURLScheme - userDefaults:self.userDefaults]; - FIRDynamicLink *dynamicLink = [self.service dynamicLinkFromCustomSchemeURL:url]; - XCTAssertEqualObjects(dynamicLink.url.absoluteString, deepLinkString); - XCTAssertEqualObjects(dynamicLink.inviteId, invitationId); -} - -- (void)testCustomScheme_FirstTimeOpenedWithCustomSchemeShouldGetStrongMatch { - NSString *invitationId = @"21392094021749127-4389172947"; - - NSString *urlString = - [NSString stringWithFormat:kStructuredLinkFmtInvitation, kURLScheme, invitationId]; - NSURL *url = [NSURL URLWithString:urlString]; - - [self.service setUpWithLaunchOptions:nil - apiKey:kAPIKey - urlScheme:kURLScheme - userDefaults:self.userDefaults]; - FIRDynamicLink *dynamicLink = [self.service dynamicLinkFromCustomSchemeURL:url]; - XCTAssertEqual(dynamicLink.matchConfidence, FIRDynamicLinkMatchConfidenceStrong, - @"matchConfidence should be strong when app is first opened with custom scheme."); - XCTAssertNil(dynamicLink.url); - XCTAssertEqualObjects(dynamicLink.inviteId, invitationId); -} - -- (void)testCustomScheme_FirstTimeOpenedFromDeviceHeuristicsCodepathShouldGetWeakMatch { - NSString *invitationId = @"21392094021749127-4389172947"; - - NSString *urlString = - [NSString stringWithFormat:kStructuredLinkFmtInvitationWeak, kURLScheme, invitationId]; - NSURL *url = [NSURL URLWithString:urlString]; - - [self.service setUpWithLaunchOptions:nil - apiKey:kAPIKey - urlScheme:kURLScheme - userDefaults:self.userDefaults]; - FIRDynamicLink *dynamicLink = [self.service dynamicLinkFromCustomSchemeURL:url]; - XCTAssertEqual( - dynamicLink.matchConfidence, FIRDynamicLinkMatchConfidenceWeak, - @"matchConfidence should be weak when app is first opened from device heuristics codepath."); - XCTAssertNil(dynamicLink.url); - XCTAssertEqualObjects(dynamicLink.inviteId, invitationId); -} - -- (void)testCustomScheme_StrongMatch { - NSString *invitationId = @"21392094021749127-4389172947"; - - NSString *urlString = - [NSString stringWithFormat:kStructuredLinkFmtInvitation, kURLScheme, invitationId]; - NSURL *url = [NSURL URLWithString:urlString]; - - // Simulate opening the app. - [[NSUserDefaults standardUserDefaults] setBool:YES forKey:kFIRDLReadDeepLinkAfterInstallKey]; - - [self.service setUpWithLaunchOptions:nil - apiKey:kAPIKey - urlScheme:kURLScheme - userDefaults:self.userDefaults]; - FIRDynamicLink *dynamicLink = [self.service dynamicLinkFromCustomSchemeURL:url]; - XCTAssertEqual(dynamicLink.matchConfidence, FIRDynamicLinkMatchConfidenceStrong, - @"matchConfidence should be strong when opening an url after app is installed."); - XCTAssertNil(dynamicLink.url); - XCTAssertEqualObjects(dynamicLink.inviteId, invitationId); -} - -- (void)testLinkParamWithPlus { - [self.service setUpWithLaunchOptions:nil - apiKey:kAPIKey - urlScheme:kURLScheme - userDefaults:self.userDefaults]; - NSString *durableDeepLinkString = - [NSString stringWithFormat:@"gindeeplinkurl://google/link?deep_link_id=%@", - kEncodedComplicatedURLString]; - NSURL *durabledeepLinkURL = [NSURL URLWithString:durableDeepLinkString]; - - FIRDynamicLink *dynamicLink = [self.service dynamicLinkFromCustomSchemeURL:durabledeepLinkURL]; - - NSString *deepLinkURLString = dynamicLink.url.absoluteString; - - XCTAssertEqualObjects(kDecodedComplicatedURLString, deepLinkURLString, - @"ddl url parameter and deep link url should be the same"); -} - -#pragma mark - dynamicLinkFromUniversalLinkURL - -- (void)testUniversalLink_NoDeepLink { - NSString *webPageURLString = - [NSString stringWithFormat:kStructuredUniversalLinkFmtFreeForm, @"/abc123"]; - NSURL *url = [NSURL URLWithString:webPageURLString]; - - NSUserActivity *activity = - [[NSUserActivity alloc] initWithActivityType:NSUserActivityTypeBrowsingWeb]; - activity.webpageURL = [NSURL URLWithString:webPageURLString]; - - [self.service setUpWithLaunchOptions:nil - apiKey:kAPIKey - urlScheme:kURLScheme - userDefaults:self.userDefaults]; - FIRDynamicLink *dynamicLink = [self.service dynamicLinkFromCustomSchemeURL:url]; - XCTAssertNil(dynamicLink, @"invite should be nil since there is no parameter."); -} - -// Custom domain entries in plist file: -// https://google.com -// https://google.com/one -// https://a.firebase.com/mypath -- (void)testDynamicLinkFromUniversalLinkURLWithCustomDomainLink { - self.service = [[FIRDynamicLinks alloc] init]; - NSString *durableDeepLinkString = @"https://a.firebase.com/mypath/?link=http://abcd"; - NSURL *durabledeepLinkURL = [NSURL URLWithString:durableDeepLinkString]; - - SwizzleDynamicLinkNetworkingWithMock(); - - FIRDynamicLink *dynamicLink = [self.service dynamicLinkFromUniversalLinkURL:durabledeepLinkURL]; - - XCTAssertNotNil(dynamicLink); - NSString *deepLinkURLString = dynamicLink.url.absoluteString; - - XCTAssertEqualObjects(@"http://abcd", deepLinkURLString, - @"ddl url parameter and deep link url should be the same"); - UnswizzleDynamicLinkNetworking(); -} - -- (void)testDynamicLinkFromUniversalLinkURLCompletionWithCustomDomainLink { - self.service = [[FIRDynamicLinks alloc] init]; - NSString *durableDeepLinkString = @"https://a.firebase.com/mypath/?link=http://abcd"; - NSURL *durabledeepLinkURL = [NSURL URLWithString:durableDeepLinkString]; - - SwizzleDynamicLinkNetworkingWithMock(); - - XCTestExpectation *expectation = [self expectationWithDescription:@"completion called"]; - [self.service - dynamicLinkFromUniversalLinkURL:durabledeepLinkURL - completion:^(FIRDynamicLink *_Nullable dynamicLink, - NSError *_Nullable error) { - XCTAssertTrue([NSThread isMainThread]); - XCTAssertNotNil(dynamicLink); - NSString *deepLinkURLString = dynamicLink.url.absoluteString; - - XCTAssertEqualObjects( - @"http://abcd", deepLinkURLString, - @"ddl url parameter and deep link url should be the same"); - [expectation fulfill]; - }]; - [self waitForExpectationsWithTimeout:kAsyncTestTimeout handler:nil]; - - UnswizzleDynamicLinkNetworking(); -} - -- (void)testDynamicLinkFromUniversalLinkURLWithSpecialCharacters { - NSString *durableDeepLinkString = - [NSString stringWithFormat:@"https://xyz.page.link/?link=%@", kEncodedComplicatedURLString]; - NSURL *durabledeepLinkURL = [NSURL URLWithString:durableDeepLinkString]; - - SwizzleDynamicLinkNetworkingWithMock(); - - FIRDynamicLink *dynamicLink = [self.service dynamicLinkFromUniversalLinkURL:durabledeepLinkURL]; - - NSString *deepLinkURLString = dynamicLink.url.absoluteString; - - XCTAssertEqualObjects(kDecodedComplicatedURLString, deepLinkURLString, - @"ddl url parameter and deep link url should be the same"); - UnswizzleDynamicLinkNetworking(); -} - -- (void)testDynamicLinkFromUniversalLinkURLCompletionWithSpecialCharacters { - NSString *durableDeepLinkString = - [NSString stringWithFormat:@"https://xyz.page.link/?link=%@", kEncodedComplicatedURLString]; - NSURL *durabledeepLinkURL = [NSURL URLWithString:durableDeepLinkString]; - - SwizzleDynamicLinkNetworkingWithMock(); - - XCTestExpectation *expectation = [self expectationWithDescription:@"completion called"]; - [self.service - dynamicLinkFromUniversalLinkURL:durabledeepLinkURL - completion:^(FIRDynamicLink *_Nullable dynamicLink, - NSError *_Nullable error) { - XCTAssertTrue([NSThread isMainThread]); - NSString *deepLinkURLString = dynamicLink.url.absoluteString; - - XCTAssertEqualObjects( - kDecodedComplicatedURLString, deepLinkURLString, - @"ddl url parameter and deep link url should be the same"); - [expectation fulfill]; - }]; - [self waitForExpectationsWithTimeout:kAsyncTestTimeout handler:nil]; - - UnswizzleDynamicLinkNetworking(); -} - -- (void)testDynamicLinkFromUniversalLinkURLWithEncodedCharacters { - NSString *durableDeepLinkString = - [NSString stringWithFormat:@"https://xyz.page.link/?link=%@", kEncodedComplicatedURLString]; - NSURL *durabledeepLinkURL = [NSURL URLWithString:durableDeepLinkString]; - - SwizzleDynamicLinkNetworkingWithMock(); - - FIRDynamicLink *dynamicLink = [self.service dynamicLinkFromUniversalLinkURL:durabledeepLinkURL]; - - NSString *deepLinkURLString = dynamicLink.url.absoluteString; - - XCTAssertEqualObjects(kDecodedComplicatedURLString, deepLinkURLString, - @"ddl url parameter and deep link url should be the same"); - UnswizzleDynamicLinkNetworking(); -} - -- (void)testDynamicLinkFromUniversalLinkURLCompletionWithEncodedCharacters { - NSString *durableDeepLinkString = - [NSString stringWithFormat:@"https://xyz.page.link/?link=%@", kEncodedComplicatedURLString]; - NSURL *durabledeepLinkURL = [NSURL URLWithString:durableDeepLinkString]; - - SwizzleDynamicLinkNetworkingWithMock(); - - XCTestExpectation *expectation = [self expectationWithDescription:@"completion called"]; - [self.service - dynamicLinkFromUniversalLinkURL:durabledeepLinkURL - completion:^(FIRDynamicLink *_Nullable dynamicLink, - NSError *_Nullable error) { - XCTAssertTrue([NSThread isMainThread]); - NSString *deepLinkURLString = dynamicLink.url.absoluteString; - - XCTAssertEqualObjects( - kDecodedComplicatedURLString, deepLinkURLString, - @"ddl url parameter and deep link url should be the same"); - [expectation fulfill]; - }]; - [self waitForExpectationsWithTimeout:kAsyncTestTimeout handler:nil]; - - UnswizzleDynamicLinkNetworking(); -} - -- (void)testUniversalLink_DeepLink { - NSString *deepLinkString = @"https://www.google.com/maps/place/Minneapolis"; - NSString *webPageURLString = - [NSString stringWithFormat:kStructuredUniversalLinkFmtDeepLink, deepLinkString]; - NSURL *url = [NSURL URLWithString:webPageURLString]; - - [self.service setUpWithLaunchOptions:nil - apiKey:kAPIKey - urlScheme:kURLScheme - userDefaults:self.userDefaults]; - - SwizzleDynamicLinkNetworkingWithMock(); - - FIRDynamicLink *dynamicLink = [self.service dynamicLinkFromUniversalLinkURL:url]; - - XCTAssertEqual(dynamicLink.matchConfidence, FIRDynamicLinkMatchConfidenceStrong); - XCTAssertEqualObjects(dynamicLink.url.absoluteString, deepLinkString); - UnswizzleDynamicLinkNetworking(); -} - -- (void)testUniversalLinkWithCompletion_DeepLink { - NSString *deepLinkString = @"https://www.google.com/maps/place/Minneapolis"; - NSString *webPageURLString = - [NSString stringWithFormat:kStructuredUniversalLinkFmtDeepLink, deepLinkString]; - NSURL *url = [NSURL URLWithString:webPageURLString]; - - [self.service setUpWithLaunchOptions:nil - apiKey:kAPIKey - urlScheme:kURLScheme - userDefaults:self.userDefaults]; - - SwizzleDynamicLinkNetworkingWithMock(); - - XCTestExpectation *expectation = [self expectationWithDescription:@"completion called"]; - [self.service - dynamicLinkFromUniversalLinkURL:url - completion:^(FIRDynamicLink *_Nullable dynamicLink, - NSError *_Nullable error) { - XCTAssertTrue([NSThread isMainThread]); - XCTAssertEqual(dynamicLink.matchConfidence, - FIRDynamicLinkMatchConfidenceStrong); - XCTAssertEqualObjects(dynamicLink.url.absoluteString, deepLinkString); - [expectation fulfill]; - }]; - [self waitForExpectationsWithTimeout:kAsyncTestTimeout handler:nil]; - - UnswizzleDynamicLinkNetworking(); -} - -- (void)testUniversalLink_DeepLinkWithParameters { - NSString *deepLinkString = @"https://www.google.com?key1%3Dvalue1%26key2%3Dvalue2"; - NSString *parsedDeepLinkString = @"https://www.google.com?key1=value1&key2=value2"; - NSString *webPageURLString = - [NSString stringWithFormat:kStructuredUniversalLinkFmtDeepLink, deepLinkString]; - NSURL *url = [NSURL URLWithString:webPageURLString]; - - [self.service setUpWithLaunchOptions:nil - apiKey:kAPIKey - urlScheme:kURLScheme - userDefaults:self.userDefaults]; - - SwizzleDynamicLinkNetworkingWithMock(); - - FIRDynamicLink *dynamicLink = [self.service dynamicLinkFromUniversalLinkURL:url]; - XCTAssertEqual(dynamicLink.matchConfidence, FIRDynamicLinkMatchConfidenceStrong); - XCTAssertEqualObjects(dynamicLink.url.absoluteString, parsedDeepLinkString); - UnswizzleDynamicLinkNetworking(); -} - -- (void)testUniversalLinkWithCompletion_DeepLinkWithParameters { - NSString *deepLinkString = @"https://www.google.com?key1%3Dvalue1%26key2%3Dvalue2"; - NSString *parsedDeepLinkString = @"https://www.google.com?key1=value1&key2=value2"; - NSString *webPageURLString = - [NSString stringWithFormat:kStructuredUniversalLinkFmtDeepLink, deepLinkString]; - NSURL *url = [NSURL URLWithString:webPageURLString]; - - [self.service setUpWithLaunchOptions:nil - apiKey:kAPIKey - urlScheme:kURLScheme - userDefaults:self.userDefaults]; - - SwizzleDynamicLinkNetworkingWithMock(); - - XCTestExpectation *expectation = [self expectationWithDescription:@"completion called"]; - [self.service dynamicLinkFromUniversalLinkURL:url - completion:^(FIRDynamicLink *_Nullable dynamicLink, - NSError *_Nullable error) { - XCTAssertTrue([NSThread isMainThread]); - XCTAssertEqual(dynamicLink.matchConfidence, - FIRDynamicLinkMatchConfidenceStrong); - XCTAssertEqualObjects(dynamicLink.url.absoluteString, - parsedDeepLinkString); - [expectation fulfill]; - }]; - [self waitForExpectationsWithTimeout:kAsyncTestTimeout handler:nil]; - UnswizzleDynamicLinkNetworking(); -} - -- (void)testResolveLinkReturnsDLWithNilMinAppVersionWhenNotPresent { - [self.service setUpWithLaunchOptions:nil - apiKey:kAPIKey - urlScheme:kURLScheme - userDefaults:self.userDefaults]; - - NSString *urlString = @"http://reinl.page.link/t4ionvr"; - NSURL *url = [NSURL URLWithString:urlString]; - - void (^executeRequestBlock)(id, NSDictionary *, NSString *, FIRNetworkRequestCompletionHandler) = - ^(id p1, NSDictionary *requestBody, NSString *requestURLString, - FIRNetworkRequestCompletionHandler handler) { - NSDictionary *dictionary = @{kFDLResolvedLinkDeepLinkURLKey : kEncodedComplicatedURLString}; - NSData *data = FIRDataWithDictionary(dictionary, nil); - - handler(data, nil, nil); - }; - - SEL executeRequestSelector = @selector(executeOnePlatformRequest:forURL:completionHandler:); - [GULSwizzler swizzleClass:[FIRDynamicLinkNetworking class] - selector:executeRequestSelector - isClassSelector:NO - withBlock:executeRequestBlock]; - - XCTestExpectation *expectation = [self expectationWithDescription:@"handler called"]; - - [self.service - handleUniversalLink:url - completion:^(FIRDynamicLink *_Nullable dynamicLink, NSError *_Nullable error) { - XCTAssertNil(dynamicLink.minimumAppVersion, - @"Min app version not nil when not present."); - [expectation fulfill]; - }]; - - [self waitForExpectationsWithTimeout:kAsyncTestTimeout handler:nil]; -} - -- (void)testResolveLinkReturnsDLWithMinAppVersionWhenPresent { - NSString *expectedMinVersion = @"8g5u3e"; - - [self.service setUpWithLaunchOptions:nil - apiKey:kAPIKey - urlScheme:kURLScheme - userDefaults:self.userDefaults]; - - NSString *urlString = @"http://reinl.page.link/t4ionvr"; - NSURL *url = [NSURL URLWithString:urlString]; - - void (^executeRequestBlock)(id, NSDictionary *, NSString *, FIRNetworkRequestCompletionHandler) = - ^(id p1, NSDictionary *requestBody, NSString *requestURLString, - FIRNetworkRequestCompletionHandler handler) { - NSDictionary *dictionary = @{ - kFDLResolvedLinkDeepLinkURLKey : kEncodedComplicatedURLString, - kFDLResolvedLinkMinAppVersionKey : expectedMinVersion, - }; - NSData *data = FIRDataWithDictionary(dictionary, nil); - NSHTTPURLResponse *response = [[NSHTTPURLResponse alloc] initWithURL:url - statusCode:200 - HTTPVersion:nil - headerFields:nil]; - handler(data, response, nil); - }; - - SEL executeRequestSelector = @selector(executeOnePlatformRequest:forURL:completionHandler:); - [GULSwizzler swizzleClass:[FIRDynamicLinkNetworking class] - selector:executeRequestSelector - isClassSelector:NO - withBlock:executeRequestBlock]; - - XCTestExpectation *expectation = [self expectationWithDescription:@"handler called"]; - - [self.service - handleUniversalLink:url - completion:^(FIRDynamicLink *_Nullable dynamicLink, NSError *_Nullable error) { - XCTAssertEqualObjects(expectedMinVersion, dynamicLink.minimumAppVersion, - @"min app version did not match imv parameter."); - [expectation fulfill]; - }]; - - [self waitForExpectationsWithTimeout:kAsyncTestTimeout handler:nil]; -} - -- (void)testUniversalLinkWithSubdomain_NoDeepLink { - NSString *webPageURLString = - [NSString stringWithFormat:kStructuredUniversalLinkFmtSubdomain, @"/abc123"]; - NSURL *url = [NSURL URLWithString:webPageURLString]; - - [self.service setUpWithLaunchOptions:nil - apiKey:kAPIKey - urlScheme:kURLScheme - userDefaults:self.userDefaults]; - FIRDynamicLink *dynamicLink = [self.service dynamicLinkFromCustomSchemeURL:url]; - XCTAssertNil(dynamicLink, @"deepLink should be nil since there is no parameter."); -} - -- (void)testDynamicLinkFromCustomSchemeURLReturnsDLWithNilMinimumVersion { - [self.service setUpWithLaunchOptions:nil - apiKey:kAPIKey - urlScheme:kURLScheme - userDefaults:self.userDefaults]; - NSURL *url = FIRDLDeepLinkURLWithInviteID(nil, kEncodedComplicatedURLString, nil, nil, nil, nil, - nil, NO, nil, nil, kURLScheme, nil); - FIRDynamicLink *dynamicLink = [self.service dynamicLinkFromCustomSchemeURL:url]; - - XCTAssertNil(dynamicLink.minimumAppVersion, @"Min app version was not nil when not set."); -} - -- (void)testDynamicLinkFromCustomSchemeURLReturnsDLMinimumVersion { - NSString *expectedMinVersion = @"03-9g03hfd"; - - [self.service setUpWithLaunchOptions:nil - apiKey:kAPIKey - urlScheme:kURLScheme - userDefaults:self.userDefaults]; - NSURL *url = FIRDLDeepLinkURLWithInviteID(nil, kEncodedComplicatedURLString, nil, nil, nil, nil, - nil, NO, nil, expectedMinVersion, kURLScheme, nil); - FIRDynamicLink *dynamicLink = [self.service dynamicLinkFromCustomSchemeURL:url]; - - NSString *minVersion = dynamicLink.minimumAppVersion; - - XCTAssertEqualObjects(expectedMinVersion, minVersion, - @"Min version didn't match the min app version parameter"); -} - -- (void)testDynamicLinkFromUniversalLinkURLReturnsDLWithNilMinimumVersion { - [self.service setUpWithLaunchOptions:nil - apiKey:kAPIKey - urlScheme:kURLScheme - userDefaults:self.userDefaults]; - - NSURL *url = FIRDLDeepLinkURLWithInviteID(nil, kEncodedComplicatedURLString, nil, nil, nil, nil, - nil, NO, nil, nil, kURLScheme, nil); - - FIRDynamicLink *dynamicLink = [self.service dynamicLinkFromUniversalLinkURL:url]; - - NSString *minVersion = dynamicLink.minimumAppVersion; - - XCTAssertNil(minVersion, @"Min app version was not nil when not set."); -} - -- (void)testDynamicLinkFromUniversalLinkURLCompletionReturnsDLWithNilMinimumVersion { - [self.service setUpWithLaunchOptions:nil - apiKey:kAPIKey - urlScheme:kURLScheme - userDefaults:self.userDefaults]; - - NSURL *url = FIRDLDeepLinkURLWithInviteID(nil, kEncodedComplicatedURLString, nil, nil, nil, nil, - nil, NO, nil, nil, kURLScheme, nil); - - XCTestExpectation *expectation = [self expectationWithDescription:@"completion called"]; - [self.service - dynamicLinkFromUniversalLinkURL:url - completion:^(FIRDynamicLink *_Nullable dynamicLink, - NSError *_Nullable error) { - XCTAssertTrue([NSThread isMainThread]); - NSString *minVersion = dynamicLink.minimumAppVersion; - - XCTAssertNil(minVersion, @"Min app version was not nil when not set."); - [expectation fulfill]; - }]; - [self waitForExpectationsWithTimeout:kAsyncTestTimeout handler:nil]; -} - -- (void)testDynamicLinkFromUniversalLinkURLReturnsDLMinimumVersion { - NSString *expectedMinVersion = @"03-9g03hfd"; - NSString *urlSuffix = - [NSString stringWithFormat:@"%@&imv=%@", kEncodedComplicatedURLString, expectedMinVersion]; - NSString *urlString = - [NSString stringWithFormat:kStructuredUniversalLinkFmtSubdomainDeepLink, urlSuffix]; - NSURL *url = [NSURL URLWithString:urlString]; - - [self.service setUpWithLaunchOptions:nil - apiKey:kAPIKey - urlScheme:kURLScheme - userDefaults:self.userDefaults]; - - FIRDynamicLink *dynamicLink = [self.service dynamicLinkFromUniversalLinkURL:url]; - - NSString *minVersion = dynamicLink.minimumAppVersion; - - XCTAssertEqualObjects(expectedMinVersion, minVersion, @"Min version didn't match imv= parameter"); -} - -- (void)testDynamicLinkFromUniversalLinkURLReturnsUTMParams { - NSString *expectedUtmSource = @"utm_source"; - NSString *expectedUtmMedium = @"utm_medium"; - NSString *expectedUtmCampaign = @"utm_campaign"; - NSString *expectedUtmTerm = @"utm_term"; - NSString *expectedUtmContent = @"utm_content"; - - NSString *utmParamsString = [NSString - stringWithFormat:@"utm_source=%@&utm_medium=%@&utm_campaign=%@&utm_term=%@&utm_content=%@", - expectedUtmSource, expectedUtmMedium, expectedUtmCampaign, expectedUtmTerm, - expectedUtmContent]; - NSString *urlSuffix = - [NSString stringWithFormat:@"%@&%@", kEncodedComplicatedURLString, utmParamsString]; - - NSString *urlString = - [NSString stringWithFormat:kStructuredUniversalLinkFmtSubdomainDeepLink, urlSuffix]; - NSURL *url = [NSURL URLWithString:urlString]; - - [self.service setUpWithLaunchOptions:nil - apiKey:kAPIKey - urlScheme:kURLScheme - userDefaults:self.userDefaults]; - XCTestExpectation *expectation = [self expectationWithDescription:@"completion called"]; - [self.service - dynamicLinkFromUniversalLinkURL:url - completion:^(FIRDynamicLink *_Nullable dynamicLink, - NSError *_Nullable error) { - XCTAssertTrue([NSThread isMainThread]); - NSDictionary *utmParameters = dynamicLink.utmParametersDictionary; - NSString *utmSource = [utmParameters objectForKey:@"utm_source"]; - XCTAssertEqualObjects(utmSource, expectedUtmSource, - @"UtmSource doesn't match utm_source parameter"); - - NSString *utmMedium = [utmParameters objectForKey:@"utm_medium"]; - XCTAssertEqualObjects(utmMedium, expectedUtmMedium, - @"UtmMedium doesn't match utm_medium parameter"); - - NSString *utmCampaign = [utmParameters objectForKey:@"utm_campaign"]; - XCTAssertEqualObjects( - utmCampaign, expectedUtmCampaign, - @"UtmCampaign doesn't match utm_campaign parameter"); - - NSString *utmTerm = [utmParameters objectForKey:@"utm_term"]; - XCTAssertEqualObjects(utmTerm, expectedUtmTerm, - @"UtmTerm doesn't match utm_term parameter"); - - NSString *utmContent = [utmParameters objectForKey:@"utm_content"]; - XCTAssertEqualObjects( - utmContent, expectedUtmContent, - @"UtmContent doesn't match utm_content parameter"); - - [expectation fulfill]; - }]; - - [self waitForExpectationsWithTimeout:kAsyncTestTimeout handler:nil]; -} - -- (void)testDynamicLinkFromUniversalLinkURLCompletionReturnsDLMinimumVersion { - NSString *expectedMinVersion = @"03-9g03hfd"; - NSString *urlSuffix = - [NSString stringWithFormat:@"%@&imv=%@", kEncodedComplicatedURLString, expectedMinVersion]; - NSString *urlString = - [NSString stringWithFormat:kStructuredUniversalLinkFmtSubdomainDeepLink, urlSuffix]; - NSURL *url = [NSURL URLWithString:urlString]; - - [self.service setUpWithLaunchOptions:nil - apiKey:kAPIKey - urlScheme:kURLScheme - userDefaults:self.userDefaults]; - - XCTestExpectation *expectation = [self expectationWithDescription:@"completion called"]; - [self.service - dynamicLinkFromUniversalLinkURL:url - completion:^(FIRDynamicLink *_Nullable dynamicLink, - NSError *_Nullable error) { - XCTAssertTrue([NSThread isMainThread]); - NSString *minVersion = dynamicLink.minimumAppVersion; - - XCTAssertEqualObjects(expectedMinVersion, minVersion, - @"Min version didn't match imv= parameter"); - [expectation fulfill]; - }]; - [self waitForExpectationsWithTimeout:kAsyncTestTimeout handler:nil]; -} - -- (void)testUniversalLinkWithSubdomain_DeepLink { - NSString *deepLinkString = @"https://www.google.com/maps/place/Minneapolis"; - NSString *webPageURLString = - [NSString stringWithFormat:kStructuredUniversalLinkFmtSubdomainDeepLink, deepLinkString]; - NSURL *url = [NSURL URLWithString:webPageURLString]; - - [self.service setUpWithLaunchOptions:nil - apiKey:kAPIKey - urlScheme:kURLScheme - userDefaults:self.userDefaults]; - - SwizzleDynamicLinkNetworkingWithMock(); - - FIRDynamicLink *dynamicLink = [self.service dynamicLinkFromUniversalLinkURL:url]; - XCTAssertEqual(dynamicLink.matchConfidence, FIRDynamicLinkMatchConfidenceStrong); - XCTAssertEqualObjects(dynamicLink.url.absoluteString, deepLinkString); - UnswizzleDynamicLinkNetworking(); -} - -- (void)testUniversalLinkWithCompletionWithSubdomain_DeepLink { - NSString *deepLinkString = @"https://www.google.com/maps/place/Minneapolis"; - NSString *webPageURLString = - [NSString stringWithFormat:kStructuredUniversalLinkFmtSubdomainDeepLink, deepLinkString]; - NSURL *url = [NSURL URLWithString:webPageURLString]; - - [self.service setUpWithLaunchOptions:nil - apiKey:kAPIKey - urlScheme:kURLScheme - userDefaults:self.userDefaults]; - - SwizzleDynamicLinkNetworkingWithMock(); - - XCTestExpectation *expectation = [self expectationWithDescription:@"completion called"]; - [self.service - dynamicLinkFromUniversalLinkURL:url - completion:^(FIRDynamicLink *_Nullable dynamicLink, - NSError *_Nullable error) { - XCTAssertTrue([NSThread isMainThread]); - XCTAssertEqual(dynamicLink.matchConfidence, - FIRDynamicLinkMatchConfidenceStrong); - XCTAssertEqualObjects(dynamicLink.url.absoluteString, deepLinkString); - [expectation fulfill]; - }]; - [self waitForExpectationsWithTimeout:kAsyncTestTimeout handler:nil]; - - UnswizzleDynamicLinkNetworking(); -} - -- (void)testUniversalLinkWithSubdomain_DeepLinkWithParameters { - NSString *deepLinkString = @"https://www.google.com?key1%3Dvalue1%26key2%3Dvalue2"; - NSString *parsedDeepLinkString = @"https://www.google.com?key1=value1&key2=value2"; - NSString *webPageURLString = - [NSString stringWithFormat:kStructuredUniversalLinkFmtSubdomainDeepLink, deepLinkString]; - NSURL *url = [NSURL URLWithString:webPageURLString]; - - [self.service setUpWithLaunchOptions:nil - apiKey:kAPIKey - urlScheme:kURLScheme - userDefaults:self.userDefaults]; - - FIRDynamicLink *dynamicLink = [self.service dynamicLinkFromUniversalLinkURL:url]; - XCTAssertEqual(dynamicLink.matchConfidence, FIRDynamicLinkMatchConfidenceStrong); - XCTAssertEqualObjects(dynamicLink.url.absoluteString, parsedDeepLinkString); -} - -- (void)testUniversalLinkWithCompletionWithSubdomain_DeepLinkWithParameters { - NSString *deepLinkString = @"https://www.google.com?key1%3Dvalue1%26key2%3Dvalue2"; - NSString *parsedDeepLinkString = @"https://www.google.com?key1=value1&key2=value2"; - NSString *webPageURLString = - [NSString stringWithFormat:kStructuredUniversalLinkFmtSubdomainDeepLink, deepLinkString]; - NSURL *url = [NSURL URLWithString:webPageURLString]; - - [self.service setUpWithLaunchOptions:nil - apiKey:kAPIKey - urlScheme:kURLScheme - userDefaults:self.userDefaults]; - - XCTestExpectation *expectation = [self expectationWithDescription:@"completion called"]; - [self.service dynamicLinkFromUniversalLinkURL:url - completion:^(FIRDynamicLink *_Nullable dynamicLink, - NSError *_Nullable error) { - XCTAssertTrue([NSThread isMainThread]); - XCTAssertEqual(dynamicLink.matchConfidence, - FIRDynamicLinkMatchConfidenceStrong); - XCTAssertEqualObjects(dynamicLink.url.absoluteString, - parsedDeepLinkString); - [expectation fulfill]; - }]; - [self waitForExpectationsWithTimeout:kAsyncTestTimeout handler:nil]; -} - -- (void)testResolveLinkRespectsResponseSuccessStatusCode { - [self.service setUpWithLaunchOptions:nil - apiKey:kAPIKey - urlScheme:kURLScheme - userDefaults:self.userDefaults]; - - NSString *urlString = @"http://domain"; - NSURL *url = [NSURL URLWithString:urlString]; - - void (^executeRequestBlock)(id, NSDictionary *, NSString *, FIRNetworkRequestCompletionHandler) = - ^(id p1, NSDictionary *requestBody, NSString *requestURLString, - FIRNetworkRequestCompletionHandler handler) { - NSData *data = FIRDataWithDictionary(@{}, nil); - NSHTTPURLResponse *response = [[NSHTTPURLResponse alloc] initWithURL:url - statusCode:200 - HTTPVersion:nil - headerFields:nil]; - handler(data, response, nil); - }; - - SEL executeRequestSelector = @selector(executeOnePlatformRequest:forURL:completionHandler:); - [GULSwizzler swizzleClass:[FIRDynamicLinkNetworking class] - selector:executeRequestSelector - isClassSelector:NO - withBlock:executeRequestBlock]; - - XCTestExpectation *expectation = [self expectationWithDescription:@"handler called"]; - - [self.service resolveShortLink:url - completion:^(NSURL *_Nullable url, NSError *_Nullable error) { - XCTAssertNotNil(url); - XCTAssertNil(error); - [expectation fulfill]; - }]; - - [self waitForExpectationsWithTimeout:kAsyncTestTimeout handler:nil]; -} - -- (void)testResolveLinkRespectsResponseErrorStatusCode { - [self.service setUpWithLaunchOptions:nil - apiKey:kAPIKey - urlScheme:kURLScheme - userDefaults:self.userDefaults]; - - NSString *urlString = @"http://domain"; - NSURL *url = [NSURL URLWithString:urlString]; - - NSError *expectedError = [NSError - errorWithDomain:@"com.firebase.dynamicLinks" - code:0 - userInfo:@{ - @"message" : [NSString stringWithFormat:@"Failed to resolve link: %@", urlString] - }]; - - void (^executeRequestBlock)(id, NSDictionary *, NSString *, FIRNetworkRequestCompletionHandler) = - ^(id p1, NSDictionary *requestBody, NSString *requestURLString, - FIRNetworkRequestCompletionHandler handler) { - NSData *data = FIRDataWithDictionary(@{}, nil); - NSHTTPURLResponse *response = [[NSHTTPURLResponse alloc] initWithURL:url - statusCode:400 - HTTPVersion:nil - headerFields:nil]; - handler(data, response, nil); - }; - - SEL executeRequestSelector = @selector(executeOnePlatformRequest:forURL:completionHandler:); - [GULSwizzler swizzleClass:[FIRDynamicLinkNetworking class] - selector:executeRequestSelector - isClassSelector:NO - withBlock:executeRequestBlock]; - - XCTestExpectation *expectation = [self expectationWithDescription:@"handler called"]; - - [self.service resolveShortLink:url - completion:^(NSURL *_Nullable url, NSError *_Nullable error) { - XCTAssertNil(url); - XCTAssertNotNil(error); - XCTAssertEqualObjects(error, expectedError, - @"Handle universal link returned unexpected error"); - [expectation fulfill]; - }]; - - [self waitForExpectationsWithTimeout:kAsyncTestTimeout handler:nil]; -} - -- (void)testPassMatchesShortLinkFormatForDDLDomains { - NSArray *urlStrings = @[ - @"https://someapp.app.goo.gl/somepath", - @"https://someapp.app.goo.gl/link", - @"https://someapp.app.goo.gl/somepath?link=https://somedomain", - @"https://someapp.app.goo.gl/somepath?somekey=somevalue", - @"https://someapp.app.goo.gl/somepath/?link=https://somedomain", - @"https://someapp.app.goo.gl/somepath/?somekey=somevalue", - @"https://someapp.app.google/somepath", - @"https://someapp.app.google/link", - @"https://someapp.app.google/somepath?link=https://somedomain", - @"https://someapp.app.google/somepath?somekey=somevalue", - @"https://someapp.app.google/somepath/?link=https://somedomain", - @"https://someapp.app.google/somepath/?somekey=somevalue", - @"https://someapp.page.link/somepath", - @"https://someapp.page.link/link", - @"https://someapp.page.link/somepath?link=https://somedomain", - @"https://someapp.page.link/somepath?somekey=somevalue", - @"https://someapp.page.link/somepath/?link=https://somedomain", - @"https://someapp.page.link/somepath/?somekey=somevalue", - @"http://someapp.page.link/somepath", - @"http://someapp.page.link/link", - @"http://someapp.page.link/somepath?link=https://somedomain", - @"http://someapp.page.link/somepath?somekey=somevalue", - @"http://someapp.page.link/somepath/?link=http://somedomain", - @"http://someapp.page.link/somepath/?somekey=somevalue" - ]; - - for (NSString *urlString in urlStrings) { - NSURL *url = [NSURL URLWithString:urlString]; - BOOL matchesShortLinkFormat = [self.service matchesShortLinkFormat:url]; - - XCTAssertTrue(matchesShortLinkFormat, - @"Non-DDL domain URL matched short link format with URL: %@", url); - } -} - -- (void)testFailMatchesShortLinkFormat { - NSArray *urlStrings = @[ - @"https://someapp.app.goo.gl", - @"https://someapp.app.goo.gl/", - @"https://someapp.app.goo.gl?", - @"https://someapp.app.goo.gl/?", - @"https://someapp.app.goo.gl?somekey=somevalue", - @"https://someapp.app.goo.gl/?somekey=somevalue", - @"https://someapp.app.goo.gl/somepath/somepath2", - @"https://someapp.app.goo.gl/somepath/somepath2?somekey=somevalue", - @"https://someapp.app.goo.gl/somepath/somepath2?link=https://somedomain", - @"https://someapp.app.google", - @"https://someapp.app.google/", - @"https://someapp.app.google?", - @"https://someapp.app.google/?", - @"https://someapp.app.google?somekey=somevalue", - @"https://someapp.app.google/?somekey=somevalue", - @"https://someapp.app.google/somepath/somepath2", - @"https://someapp.app.google/somepath/somepath2?somekey=somevalue", - @"https://someapp.app.google/somepath/somepath2?link=https://somedomain", - @"https://someapp.page.link", - @"https://someapp.page.link/", - @"https://someapp.page.link?", - @"https://someapp.page.link/?", - @"https://someapp.page.link?somekey=somevalue", - @"https://someapp.page.link/?somekey=somevalue", - @"https://someapp.page.link/somepath/somepath2", - @"https://someapp.page.link/somepath/somepath2?somekey=somevalue", - @"https://someapp.page.link/somepath/somepath2?link=https://somedomain", - @"https://www.google.com/maps/place/@1,1/My+Home/", - @"https://mydomain.com/t439gfde", - @"https://goo.gl/309dht4", - @"https://59eh.goo.gl/309dht4", - @"https://app.59eh.goo.gl/309dht4", - @"https://goo.gl/i/309dht4", - @"https://page.link/i/309dht4", - @"https://fjo3eh.goo.gl/i/309dht4", - @"https://app.fjo3eh.goo.gl/i/309dht4", - @"https://1234.page.link/link/dismiss" - ]; - - for (NSString *urlString in urlStrings) { - NSURL *url = [NSURL URLWithString:urlString]; - BOOL matchesShortLinkFormat = [self.service matchesShortLinkFormat:url]; - - XCTAssertFalse(matchesShortLinkFormat, - @"Non-DDL domain URL matched short link format with URL: %@", url); - } -} - -// Custom domain entries in plist file: -// https://google.com -// https://google.com/one -// https://a.firebase.com/mypath -- (void)testFailMatchesShortLinkFormatForCustomDomains { - NSArray *urlStrings = @[ - @"https://google.com", - @"https://a.firebase.com", - @"https://google.com/", - @"https://google.com?", - @"https://google.com/?", - @"https://google.com?utm_campgilink=someval", - @"https://google.com?somekey=someval", - ]; - - for (NSString *urlString in urlStrings) { - NSURL *url = [NSURL URLWithString:urlString]; - BOOL matchesShortLinkFormat = [self.service matchesShortLinkFormat:url]; - - XCTAssertFalse(matchesShortLinkFormat, - @"Non-DDL domain URL matched short link format with URL: %@", url); - } -} - -// Custom domain entries in plist file: -// https://google.com -// https://google.com/one -// https://a.firebase.com/mypath -- (void)testPassMatchesShortLinkFormatForCustomDomains { - NSArray *urlStrings = @[ - @"https://google.com/xyz", @"https://google.com/xyz/?link=https://somedomain", - @"https://google.com/xyz?link=https://somedomain", - @"https://google.com/xyz/?link=https://somedomain", @"https://google.com/one/xyz", - @"https://google.com/one/xyz?link=https://somedomain", - @"https://google.com/one/xyz/?link=https://somedomain", - @"https://google.com/one?utm_campaignlink=https://somedomain", - @"https://google.com/one/?utm_campaignlink=https://somedomain", @"https://google.com/mylink", - @"https://google.com/one/mylink", @"https://a.firebase.com/mypath/mylink" - ]; - - for (NSString *urlString in urlStrings) { - NSURL *url = [NSURL URLWithString:urlString]; - BOOL matchesShortLinkFormat = [self.service matchesShortLinkFormat:url]; - - XCTAssertTrue(matchesShortLinkFormat, - @"Non-DDL domain URL matched short link format with URL: %@", url); - } -} - -- (void)testMatchesUnversalLinkWithShortDurableLink { - NSString *urlString = @"https://sample.page.link/79g49s"; - NSURL *url = [NSURL URLWithString:urlString]; - BOOL matchesShort = [self.service matchesShortLinkFormat:url]; - - XCTAssertTrue(matchesShort, @"Short Durable Link didn't match short link"); -} - -- (void)testMatchesUnversalLinkWithAppInvite { - NSString *urlString = @"https://sample.page.link/i/79g49s"; - NSURL *url = [NSURL URLWithString:urlString]; - BOOL matchesShort = [self.service matchesShortLinkFormat:url]; - - XCTAssertTrue(matchesShort, @"AppInvite didn't match short link"); -} - -- (void)testDoesNotMatchesShortLinkFormatWithNonDDLDomains { - NSArray *urlStrings = @[ - @"https://www.google.com/maps/place/@1,1/My+Home/", @"https://mydomain.com/t439gfde", - @"https://goo.gl/309dht4", @"https://59eh.goo.gl/309dht4", @"https://app.59eh.goo.gl/309dht4", - @"https://goo.gl/i/309dht4", @"https://page.link/i/309dht4", @"https://fjo3eh.goo.gl/i/309dht4", - @"https://app.fjo3eh.goo.gl/i/309dht4", @"https://1234.page.link/link/dismiss" - ]; - - for (NSString *urlString in urlStrings) { - NSURL *url = [NSURL URLWithString:urlString]; - BOOL matchesShortLinkFormat = [self.service matchesShortLinkFormat:url]; - - XCTAssertFalse(matchesShortLinkFormat, - @"Non-DDL domain URL matched short link format with URL: %@", url); - } -} - -- (void)testHandleUniversalLinkWithShortLink { - NSString *shortLinkString = @"https://sample.page.link/549igo"; - - NSString *bundleID = [NSBundle mainBundle].bundleIdentifier; - - NSString *customSchemeURLString = [NSString - stringWithFormat:kStructuredLinkFmtDeepLink, bundleID, kEncodedComplicatedURLString]; - - XCTestExpectation *handleLinkCompletionExpectation = - [self expectationWithDescription:@"handleLink"]; - XCTestExpectation *linkResolverCompletionExpectation = - [self expectationWithDescription:@"linkResolver"]; - - FakeShortLinkResolver *resolver = - [FakeShortLinkResolver resolverWithBlock:^NSURL *(NSURL *shortLink) { - [linkResolverCompletionExpectation fulfill]; - return [NSURL URLWithString:customSchemeURLString]; - }]; - - SwizzleDynamicLinkNetworking(resolver); - - [self.service - handleUniversalLink:[NSURL URLWithString:shortLinkString] - completion:^(FIRDynamicLink *_Nonnull dynamicLink, NSError *_Nullable error) { - NSString *returnedURLString = dynamicLink.url.absoluteString; - XCTAssertEqualObjects(kDecodedComplicatedURLString, returnedURLString, - @"Handle universal link returned unexpected link"); - [handleLinkCompletionExpectation fulfill]; - }]; - - [self waitForExpectationsWithTimeout:kAsyncTestTimeout handler:nil]; - UnswizzleDynamicLinkNetworking(); -} - -- (void)testHandleUniversalLinkWithLongLink { - NSString *longLinkString = [NSString - stringWithFormat:@"https://sample.page.link?link=%@&ibi=com.google.sample&ius=79306483", - kEncodedComplicatedURLString]; - - XCTestExpectation *handleLinkCompletionExpectation = - [self expectationWithDescription:@"handleLink"]; - __block NSUInteger resolverInvocationsCount = 0; - - // should not be used. - FakeShortLinkResolver *resolver = - [FakeShortLinkResolver resolverWithBlock:^NSURL *(NSURL *shortLink) { - resolverInvocationsCount++; - return [NSURL URLWithString:kDecodedComplicatedURLString]; - }]; - - id handleUniversalLinkBlock = ^(FIRDynamicLink *_Nonnull dynamicLink, NSError *_Nullable error) { - [handleLinkCompletionExpectation fulfill]; - NSURL *expectedResolvedLink = [NSURL URLWithString:kDecodedComplicatedURLString]; - XCTAssertEqualObjects(expectedResolvedLink, dynamicLink.url, - @"Resolve short link returned unexpected link"); - }; - - SwizzleDynamicLinkNetworking(resolver); - - [self.service handleUniversalLink:[NSURL URLWithString:longLinkString] - completion:handleUniversalLinkBlock]; - - [self waitForExpectationsWithTimeout:kAsyncTestTimeout handler:nil]; - - // It is expected to call resolveLink once for logging. - XCTAssertEqual(resolverInvocationsCount, 1, - @"handleUniversalLink called resolveLink more than once"); - UnswizzleDynamicLinkNetworking(); -} - -- (void)testHandleUniversalLinkCallsHandleUniversalLinkResolver { - XCTestExpectation *handleLinkCompletionExpectation = - [self expectationWithDescription:@"handleLink"]; - void (^replacementBlock)(void) = ^{ - [handleLinkCompletionExpectation fulfill]; - }; - - SEL selectorToSwizzle = @selector(handleUniversalLink:completion:); - - [GULSwizzler swizzleClass:[FIRDynamicLinks class] - selector:selectorToSwizzle - isClassSelector:NO - withBlock:replacementBlock]; - - NSURL *url = [NSURL URLWithString:@"https://google.com"]; - - [self.service - handleUniversalLink:url - completion:^(FIRDynamicLink *_Nullable dynamicLink, NSError *_Nullable error){ - }]; - - [self waitForExpectationsWithTimeout:kAsyncTestTimeout handler:nil]; - - [GULSwizzler unswizzleClass:[FIRDynamicLinks class] - selector:selectorToSwizzle - isClassSelector:NO]; -} - -- (void)testHandleUniversalLinkCompletionReturnsNoForNonDDL { - NSArray *urlStrings = @[ - @"https://www.google.com/maps/place/@1,1/My+Home/", @"https://mydomain.com/t439gfde", - @"https://goo.gl/309dht4", @"https://59eh.goo.gl/309dht4", @"https://app.59eh.goo.gl/309dht4", - @"https://goo.gl/i/309dht4", @"https://page.link/i/309dht4", @"https://fjo3eh.goo.gl/i/309dht4", - @"https://app.fjo3eh.goo.gl/i/309dht4", @"https://1234.page.link/link/dismiss" - ]; - - [urlStrings enumerateObjectsUsingBlock:^(NSString *_Nonnull urlString, NSUInteger idx, - BOOL *_Nonnull stop) { - NSURL *url = [NSURL URLWithString:urlString]; - BOOL handled = [self.service - handleUniversalLink:url - completion:^(FIRDynamicLink *_Nullable dynamicLink, NSError *_Nullable error) { - XCTAssertNil(dynamicLink, @"Non DDL returned FIRDynamicLink"); - }]; - - XCTAssertFalse(handled, @"Non DDL Universal Link was handled"); - }]; -} - -- (void)testHandleUniversalLinkCompletionReturnsYesForValidDDL { - [self.service setUpWithLaunchOptions:nil - apiKey:kAPIKey - urlScheme:kURLScheme - userDefaults:self.userDefaults]; - - NSArray *urlStrings = @[ - @"https://some.page.link/test", @"https://some.page.link/test-test", - @"https://some.page.link/test_test", @"https://some.page.link/test_test-test", - @"https://some.app.goo.gl/test_test-test", @"https://some.app.google/test_test-test", - @"https://n8r9f.app.goo.gl/?ibi=com%2Egoogle%2EGCMTestApp%2Edev&amv=0&imv=1%2E0&link=https%3A%2F%2Fwww%2Egoogle%2Ecom", - @"https://n8r9f.app.goo.gl/?link=https%3A%2F%2Fwww%2Egoogle%2Ecom&ibi=com%2Egoogle%2EGCMTestApp%2Edev&amv=0&imv=1%2E0", - @"https://n8r9f.app.google/?ibi=com%2Egoogle%2EGCMTestApp%2Edev&amv=0&imv=1%2E0&link=https%3A%2F%2Fwww%2Egoogle%2Ecom", - @"https://n8r9f.app.google/?link=https%3A%2F%2Fwww%2Egoogle%2Ecom&ibi=com%2Egoogle%2EGCMTestApp%2Edev&amv=0&imv=1%2E0" - ]; - - for (NSString *urlString in urlStrings) { - NSURL *url = [NSURL URLWithString:urlString]; - - void (^executeRequestBlock)(id, NSDictionary *, NSString *, - FIRNetworkRequestCompletionHandler) = - ^(id p1, NSDictionary *requestBody, NSString *requestURLString, - FIRNetworkRequestCompletionHandler handler) { - NSData *data = FIRDataWithDictionary(@{}, nil); - NSHTTPURLResponse *response = [[NSHTTPURLResponse alloc] initWithURL:url - statusCode:200 - HTTPVersion:nil - headerFields:nil]; - handler(data, response, nil); - }; - - SEL executeRequestSelector = @selector(executeOnePlatformRequest:forURL:completionHandler:); - [GULSwizzler swizzleClass:[FIRDynamicLinkNetworking class] - selector:executeRequestSelector - isClassSelector:NO - withBlock:executeRequestBlock]; - - XCTestExpectation *expectation = [self expectationWithDescription:@"handler called"]; - - BOOL handled = [self.service - handleUniversalLink:url - completion:^(FIRDynamicLink *_Nullable dynamicLink, NSError *_Nullable error) { - XCTAssertNotNil(dynamicLink, @"Non DDL returned FIRDynamicLink"); - [expectation fulfill]; - }]; - - XCTAssertTrue(handled, @"Valid DDL Universal Link was not handled"); - - [self waitForExpectationsWithTimeout:kAsyncTestTimeout handler:nil]; - } -} - -- (void)test_ensureInternalMethodsNotRenamed { - // sanity check to ensure these methods has not been renamed - // we relaying on these to be the same for tests to work properly - // we are not exposing these methods in internal headers as we do not have "internal headers" - // 1P apps can import all of our headers - XCTAssertTrue([self.service - respondsToSelector:@selector - (handlePendingDynamicLinkRetrievalFailureWithErrorCode:errorDescription:underlyingError:)]); - XCTAssertTrue([self.service respondsToSelector:@selector(setRetrievingPendingDynamicLink:)]); - XCTAssertTrue([self.service respondsToSelector:@selector(dynamicLinkNetworking)]); -} - -- (void)testCheckForPendingDynamicLinkReturnsImmediatelyIfAlreadyRead { - id mockService = OCMPartialMock(self.service); - [[mockService expect] handlePendingDynamicLinkRetrievalFailureWithErrorCode:-1 - errorDescription:[OCMArg any] - underlyingError:[OCMArg any]]; - [[mockService reject] setRetrievingPendingDynamicLink:YES]; - - [mockService setUpWithLaunchOptions:nil - apiKey:kAPIKey - urlScheme:nil - userDefaults:[NSUserDefaults standardUserDefaults]]; - - [[NSUserDefaults standardUserDefaults] setBool:YES forKey:kFIRDLReadDeepLinkAfterInstallKey]; - - [mockService checkForPendingDynamicLink]; - - [mockService verify]; - [mockService stopMocking]; -} - -- (void)testRetrievalProcessResultURLContainsAllParametersPassedToDynamicLinkInitializer { - NSDictionary *linkParameters = @{ - @"deep_link_id" : @"https://mmaksym.com/test-app1", - @"match_message" : @"Link is uniquely matched for this device.", - @"match_type" : @"unique", - @"utm_campaign" : @"Maksym M Test", - @"utm_medium" : @"test_medium", - @"utm_source" : @"test_source", - @"utm_content" : @"test_content", - @"utm_term" : @"test_term", - @"a_parameter" : @"a_value" - }; - - FIRDynamicLink *dynamicLink = - [[FIRDynamicLink alloc] initWithParametersDictionary:linkParameters]; - FIRDLRetrievalProcessResult *result = - [[FIRDLRetrievalProcessResult alloc] initWithDynamicLink:dynamicLink - error:nil - message:nil - matchSource:nil]; - - NSURL *customSchemeURL = [result URLWithCustomURLScheme:@"scheme"]; - XCTAssertNotNil(customSchemeURL); - - // Validate URL parameters - NSURLComponents *urlComponents = [NSURLComponents componentsWithURL:customSchemeURL - resolvingAgainstBaseURL:NO]; - XCTAssertNotNil(urlComponents); - XCTAssertEqualObjects(urlComponents.scheme, @"scheme"); - - NSMutableDictionary *notEncodedParameters = [linkParameters mutableCopy]; - - for (NSURLQueryItem *queryItem in urlComponents.queryItems) { - NSString *expectedValue = notEncodedParameters[queryItem.name]; - XCTAssertNotNil(expectedValue, @"Extra parameter encoded: %@ = %@", queryItem.name, - queryItem.value); - - XCTAssertEqualObjects(queryItem.value, expectedValue); - [notEncodedParameters removeObjectForKey:queryItem.name]; - } - - XCTAssertEqual(notEncodedParameters.count, 0, @"The parameters must have been encoded: %@", - notEncodedParameters); -} - -- (void)test_multipleRequestsToRetrievePendingDeepLinkShouldNotCrash { - id mockService = OCMPartialMock(self.service); - [[mockService expect] handlePendingDynamicLinkRetrievalFailureWithErrorCode:-1 - errorDescription:[OCMArg any] - underlyingError:[OCMArg any]]; - // swizzle method to prevent actual retrieval, this will ensure that first pending link - // retrieval will stuck and second will fail with error - id (^replacementBlock)(void) = (id) ^ { return nil; }; - - SEL selectorToSwizzle = @selector(automaticRetrievalProcess); - - [GULSwizzler swizzleClass:[FIRDLRetrievalProcessFactory class] - selector:selectorToSwizzle - isClassSelector:NO - withBlock:replacementBlock]; - - [mockService setUpWithLaunchOptions:nil - apiKey:kAPIKey - urlScheme:kURLScheme - userDefaults:self.userDefaults]; - - [mockService checkForPendingDynamicLink]; - // we should not crash here - [mockService checkForPendingDynamicLink]; - - [mockService verify]; - [mockService stopMocking]; - [GULSwizzler unswizzleClass:[FIRDLRetrievalProcessFactory class] - selector:selectorToSwizzle - isClassSelector:NO]; -} - -- (void)test_retrievePendingDeepLinkShouldSetkFIRDLOpenURLKeyRegardlessOfFailures { - [self.service setUpWithLaunchOptions:nil - apiKey:kAPIKey - urlScheme:nil - userDefaults:[NSUserDefaults standardUserDefaults]]; - FIRDynamicLinks *delegate = - (FIRDynamicLinks *)self.service; - - // Error Result to pass - FIRDLRetrievalProcessResult *result = [[FIRDLRetrievalProcessResult alloc] - initWithDynamicLink:nil - error:[NSError errorWithDomain:@"unknown domain" code:500 userInfo:nil] - message:nil - matchSource:nil]; - - FIRDLDefaultRetrievalProcessV2 *defaultRetrievalProcess = [FIRDLDefaultRetrievalProcessV2 alloc]; - - [delegate retrievalProcess:defaultRetrievalProcess completedWithResult:result]; - - NSString *kFIRDLOpenURLKey = @"com.google.appinvite.openURL"; - XCTAssertEqual([[NSUserDefaults standardUserDefaults] boolForKey:kFIRDLOpenURLKey], YES, - @"kFIRDLOpenURL key should be set regardless of failures"); -} - -- (void)test_passRetrievedDynamicLinkToApplicationDelegatesProperly { - // Creating ApplicationDelegate partial mock object. - id applicationDelegate = OCMPartialMock([UIApplication sharedApplication].delegate); - // Creating FIRDynamicLinks partial mock object. - id firebaseDynamicLinks = OCMPartialMock(self.service); - // Stubbing Application delegate to return YES when application:openURL:options method is called. - // Not sure why this is required as we are not concerned about its return, but without this, the - // test will throw NSInvalidArgumentException with message "unrecognized selector sent to - // instance". - OCMStub([applicationDelegate application:[OCMArg any] openURL:[OCMArg any] options:[OCMArg any]]) - .andReturn(YES); - // Stubbing firebase dynamiclinks instance to return YES when isOpenUrlMethodPresentInAppDelegate - // is called. - OCMStub([firebaseDynamicLinks isOpenUrlMethodPresentInAppDelegate:[OCMArg any]]).andReturn(YES); - - // Executing the function with a URL. - NSURL *url = [NSURL URLWithString:@"http://www.google.com"]; - [firebaseDynamicLinks passRetrievedDynamicLinkToApplication:url]; - - // Verifying the application:openURL:options method is called in AppDelegate. - OCMVerify([applicationDelegate application:[OCMArg any] openURL:url options:[OCMArg any]]); -} - -#pragma mark - Self-diagnose tests - -- (void)testSelfDiagnoseWithNilCompletion { - [FIRDynamicLinks performDiagnosticsWithCompletion:nil]; -} - -- (void)testSelfDiagnoseCompletionCalled { - XCTestExpectation *expectation = - [self expectationWithDescription:@"Self diagnose completion block must be called"]; - - [FIRDynamicLinks - performDiagnosticsWithCompletion:^(NSString *_Nonnull diagnosticOutput, BOOL hasErrors) { - XCTAssert(diagnosticOutput.length > 0, @"Diagnostic expected to provide output"); - [expectation fulfill]; - }]; - - [self waitForExpectationsWithTimeout:2.0 handler:nil]; -} - -#pragma mark - Custom domain tests -- (void)testValidCustomDomainNames { - // Entries in plist file: - // https://google.com - // https://google.com/one - // https://a.firebase.com/mypath - - NSArray *urlStrings = @[ - @"https://google.com/mylink", // Short FDL starting with 'https://google.com' - @"https://google.com/one", // Short FDL starting with 'https://google.com' - @"https://google.com/one/", // Short FDL starting with 'https://google.com' - @"https://google.com/one?", // Short FDL starting with 'https://google.com' - @"https://google.com/one/mylink", // Short FDL starting with 'https://google.com/one' - @"https://a.firebase.com/mypath/mylink", // Short FDL starting https://a.firebase.com/mypath - @"https://google.com/somepath?link=https://somedomain", - @"https://google.com/somepath/?link=https://somedomain", - @"https://google.com/somepath/somepath2?link=https://somedomain", - @"https://google.com/somepath/somepath2/?link=https://somedomain", - @"https://google.com/somepath?utm_campgilink=someval" - ]; - - NSArray *longFDLURLStrings = @[ - @"https://a.firebase.com/mypath/?link=https://abcd&test=1", // Long FDL starting with - // https://a.firebase.com/mypath - @"https://google.com?link=http://abcd", // Long FDL starting with 'https://google.com' - @"https://google.com/?link=http://abcd", // Long FDL starting with 'https://google.com' - @"https://google.com?link=https://somedomain&some=qry", // Long FDL with link param as another - // argument. - @"https://google.com/?link=https://somedomain&some=qry", // Long FDL with link param as another - // argument. - @"https://google.com?some=qry&link=https://somedomain", // Long FDL with link param as second - // argument. - @"https://google.com/?some=qry&link=https://somedomain", // Long FDL with link param as second - // argument - @"https://google.com/?a=b&c=d&link=https://somedomain&y=z", // Long FDL with link param as - // middle argument argument - @"https://google.com?some=qry&link=https%3A%2F%2Fsomedomain", // Long FDL with Url encoded link - // param - ]; - for (NSString *urlString in urlStrings) { - NSURL *url = [NSURL URLWithString:urlString]; - BOOL matchesShortLinkFormat = [self.service matchesShortLinkFormat:url]; - - XCTAssertTrue(matchesShortLinkFormat, @"URL did not validate as short link: %@", url); - } - for (NSString *urlString in longFDLURLStrings) { - NSURL *url = [NSURL URLWithString:urlString]; - BOOL matchesLongLinkFormat = [self.service canParseUniversalLinkURL:url]; - - XCTAssertTrue(matchesLongLinkFormat, @"URL did not validate as long link: %@", url); - } -} - -- (void)testInvalidCustomDomainNames { - // Entries in plist file: - // https://google.com - // https://google.com/one - // https://a.firebase.com/mypath - - NSArray *urlStrings = @[ - @"google.com", // Valid domain. No scheme. - @"https://google.com", // Valid domain. No path after domainURIPrefix. - @"https://google.com/", // Valid domain. No path after domainURIPrefix. - @"https://google.co.in/mylink", // No matching domainURIPrefix. - @"https://google.com/?some=qry", // Valid domain with no path and link param - @"https://google.com/?some=qry&link=bla", // Valid domain with no path and no valid link param - @"https://firebase.com/mypath", // No matching domainURIPrefix: Invalid (sub)domain. - @"https://b.firebase.com/mypath", // No matching domainURIPrefix: Invalid subdomain. - @"https://a.firebase.com/mypathabc", // No matching domainURIPrefix: Invalid subdomain. - @"mydomain.com", // https scheme not specified for domainURIPrefix. - @"http://mydomain", // Domain not in plist. No path after domainURIPrefix. - @"https://somecustom.com?", @"https://somecustom.com/?", - @"https://somecustom.com?somekey=someval", - @"https://google.com?some=qry&somelink=https%3A%2F%2Fsomedomain", // Having somelink param - // instead of link param to - // confuse validation. - @"https://a.firebase.com/mypaths?some=qry&link=https%3A%2F%2Fsomedomain", // Additional 's' in - // path param - @"https://a.firebase.com/mypath/?some=qry#other=b&link=https://somedomain", // link param comes - // in fragmentation - @"https://a.firebase.com/mypath/?some=qry#other=b&link=https%3A%2F%2Fsomedomain", // link param - // which is - // url - // encoded - // and comes - // in - // fragmentation. - @"https://google.com?link=https1://abcd", // link query param is not a valid http link - ]; - - for (NSString *urlString in urlStrings) { - NSURL *url = [NSURL URLWithString:urlString]; - BOOL matchesShortLinkFormat = [self.service canParseUniversalLinkURL:url]; - - XCTAssertFalse(matchesShortLinkFormat, - @"Non-DDL domain URL matched short link format with URL: %@", url); - } -} - -#pragma mark - Private Helpers - -- (void)removeAllFIRApps { - NSDictionary *apps = [FIRApp allApps]; - for (FIRApp *app in apps.allValues) { - [app deleteApp:^(BOOL success) { - if (!success) { - NSLog(@"Error deleting FIRApp before tests - config tests may fail."); - } - }]; - } -} - -#pragma clang pop - -@end diff --git a/FirebaseDynamicLinks/Tests/Unit/UtilitiesTests.m b/FirebaseDynamicLinks/Tests/Unit/UtilitiesTests.m deleted file mode 100644 index 2a6ac0fa523..00000000000 --- a/FirebaseDynamicLinks/Tests/Unit/UtilitiesTests.m +++ /dev/null @@ -1,198 +0,0 @@ -/* - * 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. - */ - -#import - -#import "FirebaseDynamicLinks/Sources/Utilities/FDLUtilities.h" - -static NSString *const kURLScheme = @"gindeeplinkurl"; - -@interface FDLUtilitiesTests : XCTestCase -@end - -@implementation FDLUtilitiesTests - -- (void)testFDLCookieRetrievalURLCreatesCorrectURL { - static NSString *const kCustomScheme = @"customscheme"; - static NSString *const kBundleID = @"com.My.Bundle.ID"; - - NSString *expectedURLString = [NSString stringWithFormat:@"https://goo.gl/app/_/deeplink?fdl_ios_" - "bundle_id=%@&fdl_ios_url_scheme=%@", - kBundleID, kCustomScheme]; - - NSURL *url = FIRDLCookieRetrievalURL(kCustomScheme, kBundleID); - - XCTAssertEqualObjects(url.absoluteString, expectedURLString); -} - -- (void)testFDLURLQueryStringFromDictionaryReturnsEmptyStringWithEmptyDictionary { - NSString *query = FIRDLURLQueryStringFromDictionary(@{}); - - XCTAssertEqualObjects(query, @""); -} - -- (void)testFDLURLQueryStringFromDictionaryReturnsCorrectStringWithSingleKVP { - NSString *key = @"key"; - NSString *value = @"value"; - - NSDictionary *queryDict = @{key : value}; - NSString *query = FIRDLURLQueryStringFromDictionary(queryDict); - - NSString *expectedQuery = [NSString stringWithFormat:@"?%@=%@", key, value]; - - XCTAssertEqualObjects(query, expectedQuery); -} - -- (void)testFDLURLQueryStringFromDictionary { - NSDictionary *expectedQueryDict = @{ - @"key1" : @"va!lue1", - @"key2" : @"val=ue2", - @"key3" : @"val&ue3", - @"key4" : @"valu?e4", - @"key5" : @"val$ue5", - }; - - NSString *query = FIRDLURLQueryStringFromDictionary(expectedQueryDict); - NSString *prefixToRemove = @"?"; - NSString *queryWithoutPrefix = [query substringFromIndex:prefixToRemove.length]; - - NSDictionary *retrievedQueryDict = FIRDLDictionaryFromQuery(queryWithoutPrefix); - - XCTAssertEqualObjects(retrievedQueryDict, expectedQueryDict); -} - -- (void)testGINDictionaryFromQueryWithNormalQuery { - NSString *query = @"key1=value1&key2=value2"; - - NSDictionary *returnedDictionary = FIRDLDictionaryFromQuery(query); - NSDictionary *expectedDictionary = @{@"key1" : @"value1", @"key2" : @"value2"}; - - XCTAssertEqualObjects(returnedDictionary, expectedDictionary); -} - -- (void)testGINDictionaryFromQueryWithQueryMissingValue { - NSString *query = @"key1=value1&key2="; - - NSDictionary *returnedDictionary = FIRDLDictionaryFromQuery(query); - NSDictionary *expectedDictionary = @{@"key1" : @"value1", @"key2" : @""}; - - XCTAssertEqualObjects(returnedDictionary, expectedDictionary); -} - -- (void)testGINDictionaryFromQueryWithQueryMissingKey { - NSString *query = @"key1=value1&=value2"; - - NSDictionary *returnedDictionary = FIRDLDictionaryFromQuery(query); - NSDictionary *expectedDictionary = @{@"key1" : @"value1", @"" : @"value2"}; - - XCTAssertEqualObjects(returnedDictionary, expectedDictionary); -} - -- (void)testGINDictionaryFromQueryWithQueryMissingKeyAndValue { - NSString *query = @"key1=value1&="; - - NSDictionary *returnedDictionary = FIRDLDictionaryFromQuery(query); - NSDictionary *expectedDictionary = @{@"key1" : @"value1", @"" : @""}; - - XCTAssertEqualObjects(returnedDictionary, expectedDictionary); -} - -- (void)testGINDictionaryFromQueryWithQueryMissingPairAtTheEnd { - NSString *query = @"key1=value1&"; - - NSDictionary *returnedDictionary = FIRDLDictionaryFromQuery(query); - NSDictionary *expectedDictionary = @{@"key1" : @"value1"}; - - XCTAssertEqualObjects(returnedDictionary, expectedDictionary); -} - -- (void)testGINDictionaryFromQueryWithQueryMissingPairAtTheBeginning { - NSString *query = @"&key1=value1"; - - NSDictionary *returnedDictionary = FIRDLDictionaryFromQuery(query); - NSDictionary *expectedDictionary = @{@"key1" : @"value1"}; - - XCTAssertEqualObjects(returnedDictionary, expectedDictionary); -} - -- (void)testGINDictionaryFromQueryWithQueryMissingPairInTheMiddle { - NSString *query = @"key1=value1&&key2=value2"; - - NSDictionary *returnedDictionary = FIRDLDictionaryFromQuery(query); - NSDictionary *expectedDictionary = @{@"key1" : @"value1", @"key2" : @"value2"}; - - XCTAssertEqualObjects(returnedDictionary, expectedDictionary); -} - -- (void)testDeepLinkURLWithInviteIDDeepLinkStringWeakMatchEndpointCreatesExpectedCustomSchemeURL { - NSString *inviteID = @"3082906yht4i02"; - NSString *deepLinkString = @"https://google.com/a%b!c=d"; - NSString *encodedDeepLinkString = @"https%3A%2F%2Fgoogle%2Ecom%2Fa%25b%21c%3Dd"; - NSString *weakMatchEndpoint = @"IPV6"; - NSString *utmSource = @"firebase"; - NSString *utmMedium = @"email"; - NSString *utmCampaign = @"testCampaign"; - NSString *utmTerm = @"testTerm"; - NSString *utmContent = @"testContent"; - NSString *matchType = @"unique"; - - NSString *expectedURLString = [NSString - stringWithFormat:@"%@://google/link/?utm_campaign=%@" - @"&deep_link_id=%@&utm_medium=%@&invitation_weakMatchEndpoint=%@" - @"&utm_source=%@&invitation_id=%@&match_type=%@" - @"&utm_content=%@&utm_term=%@", - kURLScheme, utmCampaign, encodedDeepLinkString, utmMedium, weakMatchEndpoint, - utmSource, inviteID, matchType, utmContent, utmTerm]; - NSURLComponents *expectedURLComponents = [NSURLComponents componentsWithString:expectedURLString]; - - NSURL *actualURL = FIRDLDeepLinkURLWithInviteID(inviteID, deepLinkString, utmSource, utmMedium, - utmCampaign, utmContent, utmTerm, NO, - weakMatchEndpoint, nil, kURLScheme, nil); - - NSURLComponents *actualURLComponents = [NSURLComponents componentsWithURL:actualURL - resolvingAgainstBaseURL:NO]; - - // Since the parameters are not guaranteed to be in any specific order, we must compare - // arrays of properties of the URLs rather than the URLs themselves. - // sort both expected/actual arrays to prevent order influencing the test results - NSSortDescriptor *sort = [NSSortDescriptor sortDescriptorWithKey:@"name" ascending:YES]; - NSArray *expectedURLQueryItems = - [expectedURLComponents.queryItems sortedArrayUsingDescriptors:@[ sort ]]; - - NSArray *actualQueryItems = - [actualURLComponents.queryItems sortedArrayUsingDescriptors:@[ sort ]]; - - XCTAssertEqualObjects(actualQueryItems, expectedURLQueryItems); - XCTAssertEqualObjects(actualURLComponents.host, expectedURLComponents.host); -} - -- (void)testGINOSVersionSupportedReturnsYESWhenCurrentIsGreaterThanMin { - BOOL supported = FIRDLOSVersionSupported(@"8.0.1", @"8.0"); - XCTAssertTrue(supported, @"FIRDLOSVersionSupported() returned NO when the OS was supported."); -} - -- (void)testGINOSVersionSupportedReturnsYESWhenCurrentIsEqualToMin { - BOOL supported = FIRDLOSVersionSupported(@"8.0", @"8.0"); - XCTAssertTrue(supported, @"FIRDLOSVersionSupported() returned NO when the OS was supported."); -} - -- (void)testGINOSVersionSupportedReturnsNOWhenCurrentIsLessThanMin { - BOOL supported = FIRDLOSVersionSupported(@"7.1", @"8.1"); - XCTAssertFalse(supported, - @"FIRDLOSVersionSupported() returned YES when the OS was not supported."); -} - -@end diff --git a/IntegrationTesting/ClientApp/ClientApp.xcodeproj/project.pbxproj b/IntegrationTesting/ClientApp/ClientApp.xcodeproj/project.pbxproj index 645924782b1..363cc8ff7cb 100644 --- a/IntegrationTesting/ClientApp/ClientApp.xcodeproj/project.pbxproj +++ b/IntegrationTesting/ClientApp/ClientApp.xcodeproj/project.pbxproj @@ -29,7 +29,6 @@ EA7DF58D29EF3326005664A7 /* FirebaseAppDistribution-Beta in Frameworks */ = {isa = PBXBuildFile; platformFilter = ios; productRef = EA7DF58C29EF3326005664A7 /* FirebaseAppDistribution-Beta */; }; EA7DF59329EF3326005664A7 /* FirebaseCrashlytics in Frameworks */ = {isa = PBXBuildFile; productRef = EA7DF59229EF3326005664A7 /* FirebaseCrashlytics */; }; EA7DF59529EF3326005664A7 /* FirebaseDatabase in Frameworks */ = {isa = PBXBuildFile; productRef = EA7DF59429EF3326005664A7 /* FirebaseDatabase */; }; - EA7DF59929EF3326005664A7 /* FirebaseDynamicLinks in Frameworks */ = {isa = PBXBuildFile; platformFilter = ios; productRef = EA7DF59829EF3326005664A7 /* FirebaseDynamicLinks */; }; EA7DF59B29EF3326005664A7 /* FirebaseFirestore in Frameworks */ = {isa = PBXBuildFile; productRef = EA7DF59A29EF3326005664A7 /* FirebaseFirestore */; }; EA7DF59D29EF3326005664A7 /* FirebaseFirestoreCombine-Community in Frameworks */ = {isa = PBXBuildFile; productRef = EA7DF59C29EF3326005664A7 /* FirebaseFirestoreCombine-Community */; }; EA7DF5A129EF3327005664A7 /* FirebaseFunctions in Frameworks */ = {isa = PBXBuildFile; productRef = EA7DF5A029EF3327005664A7 /* FirebaseFunctions */; }; @@ -81,7 +80,6 @@ EA7DF5A129EF3327005664A7 /* FirebaseFunctions in Frameworks */, EA7DF58D29EF3326005664A7 /* FirebaseAppDistribution-Beta in Frameworks */, EA7DF5AF29EF3328005664A7 /* FirebasePerformance in Frameworks */, - EA7DF59929EF3326005664A7 /* FirebaseDynamicLinks in Frameworks */, EA7DF59D29EF3326005664A7 /* FirebaseFirestoreCombine-Community in Frameworks */, EA7DF5A929EF3327005664A7 /* FirebaseInstallations in Frameworks */, ); @@ -203,7 +201,6 @@ EA7DF58C29EF3326005664A7 /* FirebaseAppDistribution-Beta */, EA7DF59229EF3326005664A7 /* FirebaseCrashlytics */, EA7DF59429EF3326005664A7 /* FirebaseDatabase */, - EA7DF59829EF3326005664A7 /* FirebaseDynamicLinks */, EA7DF59A29EF3326005664A7 /* FirebaseFirestore */, EA7DF59C29EF3326005664A7 /* FirebaseFirestoreCombine-Community */, EA7DF5A029EF3327005664A7 /* FirebaseFunctions */, @@ -661,10 +658,6 @@ isa = XCSwiftPackageProductDependency; productName = FirebaseDatabase; }; - EA7DF59829EF3326005664A7 /* FirebaseDynamicLinks */ = { - isa = XCSwiftPackageProductDependency; - productName = FirebaseDynamicLinks; - }; EA7DF59A29EF3326005664A7 /* FirebaseFirestore */ = { isa = XCSwiftPackageProductDependency; productName = FirebaseFirestore; diff --git a/IntegrationTesting/ClientApp/Podfile b/IntegrationTesting/ClientApp/Podfile index 9a2a124703f..43ffaf35960 100644 --- a/IntegrationTesting/ClientApp/Podfile +++ b/IntegrationTesting/ClientApp/Podfile @@ -22,7 +22,6 @@ target 'ClientApp-CocoaPods' do pod 'FirebaseAuth', :path => '../../' pod 'FirebaseCrashlytics', :path => '../../' pod 'FirebaseDatabase', :path => '../../' - pod 'FirebaseDynamicLinks', :path => '../../' pod 'FirebaseFirestore', :path => '../../' pod 'FirebaseFirestoreInternal', :path => '../../' pod 'FirebaseFunctions', :path => '../../' diff --git a/IntegrationTesting/ClientApp/Shared/objc-header-import-test.m b/IntegrationTesting/ClientApp/Shared/objc-header-import-test.m index 83727384a57..5691ee8df4e 100644 --- a/IntegrationTesting/ClientApp/Shared/objc-header-import-test.m +++ b/IntegrationTesting/ClientApp/Shared/objc-header-import-test.m @@ -31,16 +31,12 @@ #import #import #import -#import "FirebaseCore/FirebaseCore.h" -#import "FirebaseCrashlytics/FirebaseCrashlytics.h" -#import "FirebaseDatabase/FirebaseDatabase.h" -#if TARGET_OS_IOS && !TARGET_OS_MACCATALYST -#import -#import "FirebaseDynamicLinks/FirebaseDynamicLinks.h" -#endif #import #import #import +#import "FirebaseCore/FirebaseCore.h" +#import "FirebaseCrashlytics/FirebaseCrashlytics.h" +#import "FirebaseDatabase/FirebaseDatabase.h" #import "FirebaseFirestore/FirebaseFirestore.h" #import "FirebaseInstallations/FirebaseInstallations.h" #import "FirebaseMessaging/FirebaseMessaging.h" diff --git a/IntegrationTesting/ClientApp/Shared/objc-module-import-test.m b/IntegrationTesting/ClientApp/Shared/objc-module-import-test.m index e465a83c86a..0b334f4aace 100644 --- a/IntegrationTesting/ClientApp/Shared/objc-module-import-test.m +++ b/IntegrationTesting/ClientApp/Shared/objc-module-import-test.m @@ -27,9 +27,6 @@ @import FirebaseAuth; @import FirebaseCore; @import FirebaseCrashlytics; -#if TARGET_OS_IOS && !TARGET_OS_MACCATALYST -@import FirebaseDynamicLinks; -#endif #if (TARGET_OS_IOS && !TARGET_OS_MACCATALYST) || TARGET_OS_TV @import FirebasePerformance; @import FirebaseInAppMessaging; diff --git a/IntegrationTesting/ClientApp/Shared/objcxx-header-import-test.mm b/IntegrationTesting/ClientApp/Shared/objcxx-header-import-test.mm index 4bb988bbfb6..e3b04630a6e 100644 --- a/IntegrationTesting/ClientApp/Shared/objcxx-header-import-test.mm +++ b/IntegrationTesting/ClientApp/Shared/objcxx-header-import-test.mm @@ -34,16 +34,12 @@ #import #import #import -#import "FirebaseCore/FirebaseCore.h" -#import "FirebaseCrashlytics/FirebaseCrashlytics.h" -#import "FirebaseDatabase/FirebaseDatabase.h" -#if TARGET_OS_IOS && !TARGET_OS_MACCATALYST -#import -#import "FirebaseDynamicLinks/FirebaseDynamicLinks.h" -#endif #import #import #import +#import "FirebaseCore/FirebaseCore.h" +#import "FirebaseCrashlytics/FirebaseCrashlytics.h" +#import "FirebaseDatabase/FirebaseDatabase.h" #import "FirebaseFirestore/FirebaseFirestore.h" #import "FirebaseInstallations/FirebaseInstallations.h" #import "FirebaseMessaging/FirebaseMessaging.h" diff --git a/IntegrationTesting/ClientApp/Shared/swift-import-test.swift b/IntegrationTesting/ClientApp/Shared/swift-import-test.swift index 2965a289ab5..25cb2f01962 100644 --- a/IntegrationTesting/ClientApp/Shared/swift-import-test.swift +++ b/IntegrationTesting/ClientApp/Shared/swift-import-test.swift @@ -32,9 +32,6 @@ import FirebaseAuth import FirebaseCore import FirebaseCrashlytics import FirebaseDatabase -#if os(iOS) && !targetEnvironment(macCatalyst) - import FirebaseDynamicLinks -#endif import FirebaseFirestore #if SWIFT_PACKAGE import FirebaseFirestoreCombineSwift diff --git a/IntegrationTesting/CocoapodsIntegrationTest/TestEnvironments/Cocoapods_multiprojects_frameworks/Podfile b/IntegrationTesting/CocoapodsIntegrationTest/TestEnvironments/Cocoapods_multiprojects_frameworks/Podfile index cf2128071c6..e422c6b350c 100644 --- a/IntegrationTesting/CocoapodsIntegrationTest/TestEnvironments/Cocoapods_multiprojects_frameworks/Podfile +++ b/IntegrationTesting/CocoapodsIntegrationTest/TestEnvironments/Cocoapods_multiprojects_frameworks/Podfile @@ -18,7 +18,6 @@ target 'CocoapodsIntegrationTest' do pod 'FirebaseAuth', :path => '../../' pod 'FirebaseAuthInterop', :path => '../../' pod 'FirebaseDatabase', :path => '../../' - pod 'FirebaseDynamicLinks', :path => '../../' pod 'FirebaseFirestore', :path => '../../' pod 'FirebaseFunctions', :path => '../../' pod 'FirebaseInAppMessaging', :path => '../../' diff --git a/Package.swift b/Package.swift index 2627e79daca..ec21d0b86d1 100644 --- a/Package.swift +++ b/Package.swift @@ -108,10 +108,6 @@ let package = Package( name: "FirebaseDatabase", targets: ["FirebaseDatabase"] ), - .library( - name: "FirebaseDynamicLinks", - targets: ["FirebaseDynamicLinksTarget"] - ), .library( name: "FirebaseFirestore", targets: ["FirebaseFirestoreTarget"] @@ -777,28 +773,6 @@ let package = Package( dependencies: ["FirebaseSharedSwift"], path: "FirebaseSharedSwift/Tests/" ), - .target( - name: "FirebaseDynamicLinksTarget", - dependencies: [.target(name: "FirebaseDynamicLinks", - condition: .when(platforms: [.iOS]))], - path: "SwiftPM-PlatformExclude/FirebaseDynamicLinksWrap" - ), - - .target( - name: "FirebaseDynamicLinks", - dependencies: ["FirebaseCore"], - path: "FirebaseDynamicLinks/Sources", - resources: [.process("Resources/PrivacyInfo.xcprivacy")], - publicHeadersPath: "Public", - cSettings: [ - .headerSearchPath("../../"), - .define("FIRDynamicLinks3P", to: "1"), - .define("GIN_SCION_LOGGING", to: "1"), - ], - linkerSettings: [ - .linkedFramework("QuartzCore"), - ] - ), firestoreWrapperTarget(), @@ -1292,7 +1266,6 @@ let package = Package( "FirebaseCrashlytics", "FirebaseCore", "FirebaseDatabase", - "FirebaseDynamicLinks", "FirebaseFirestoreTarget", "FirebaseFunctions", .target(name: "FirebaseInAppMessaging", @@ -1328,7 +1301,6 @@ let package = Package( "FirebaseCrashlytics", "FirebaseCore", "FirebaseDatabase", - "FirebaseDynamicLinks", "FirebaseFirestoreTarget", "FirebaseFunctions", .target(name: "FirebaseInAppMessaging", diff --git a/ReleaseTooling/Sources/FirebaseManifest/FirebaseManifest.swift b/ReleaseTooling/Sources/FirebaseManifest/FirebaseManifest.swift index ae578987656..d807ec0e69e 100755 --- a/ReleaseTooling/Sources/FirebaseManifest/FirebaseManifest.swift +++ b/ReleaseTooling/Sources/FirebaseManifest/FirebaseManifest.swift @@ -45,7 +45,6 @@ public let shared = Manifest( Pod("FirebaseAuth", zip: true), Pod("FirebaseCrashlytics", zip: true), Pod("FirebaseDatabase", platforms: ["ios", "macos", "tvos"], zip: true), - Pod("FirebaseDynamicLinks", allowWarnings: true, platforms: ["ios"], zip: true), Pod("FirebaseFirestoreInternal", allowWarnings: true, platforms: ["ios", "macos", "tvos"]), Pod("FirebaseFirestore", allowWarnings: true, platforms: ["ios", "macos", "tvos"], zip: true), Pod("FirebaseFunctions", zip: true), diff --git a/SwiftPM-PlatformExclude/FirebaseDynamicLinksWrap/dummy.m b/SwiftPM-PlatformExclude/FirebaseDynamicLinksWrap/dummy.m deleted file mode 100644 index c7b9e82f08a..00000000000 --- a/SwiftPM-PlatformExclude/FirebaseDynamicLinksWrap/dummy.m +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright 2020 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 -#if !TARGET_OS_IOS -#warning "Firebase Dynamic Links only supports the iOS platform" -#endif diff --git a/SwiftPM-PlatformExclude/FirebaseDynamicLinksWrap/include/dummy.h b/SwiftPM-PlatformExclude/FirebaseDynamicLinksWrap/include/dummy.h deleted file mode 100644 index 5224d0b2249..00000000000 --- a/SwiftPM-PlatformExclude/FirebaseDynamicLinksWrap/include/dummy.h +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2020 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. - -// Prevent a missing umbrella header warning. diff --git a/SwiftPMTests/objc-import-test/objc-header.m b/SwiftPMTests/objc-import-test/objc-header.m index b00070f99c7..1e994c3bbd5 100644 --- a/SwiftPMTests/objc-import-test/objc-header.m +++ b/SwiftPMTests/objc-import-test/objc-header.m @@ -21,7 +21,6 @@ #import "FirebaseCore/FirebaseCore.h" #import "FirebaseCrashlytics/FirebaseCrashlytics.h" #import "FirebaseDatabase/FirebaseDatabase.h" -#import "FirebaseDynamicLinks/FirebaseDynamicLinks.h" #import "FirebaseFirestore/FirebaseFirestore.h" #import "FirebaseInstallations/FirebaseInstallations.h" #import "FirebaseMessaging/FirebaseMessaging.h" @@ -40,7 +39,6 @@ #import #import #import -#import #import #if TARGET_OS_IOS || TARGET_OS_TV #import diff --git a/SwiftPMTests/objc-import-test/objc-module.m b/SwiftPMTests/objc-import-test/objc-module.m index 3f60b824127..02ce7ce6539 100644 --- a/SwiftPMTests/objc-import-test/objc-module.m +++ b/SwiftPMTests/objc-import-test/objc-module.m @@ -22,7 +22,6 @@ @import FirebaseCrashlytics; @import FirebaseCore; @import FirebaseDatabase; -@import FirebaseDynamicLinks; @import FirebaseFirestore; @import FirebaseFunctions; @import FirebaseInstallations; diff --git a/SwiftPMTests/swift-test/all-imports.swift b/SwiftPMTests/swift-test/all-imports.swift index e06afa311d4..f7548373f5c 100644 --- a/SwiftPMTests/swift-test/all-imports.swift +++ b/SwiftPMTests/swift-test/all-imports.swift @@ -23,7 +23,6 @@ import Foundation #endif import FirebaseCrashlytics import FirebaseDatabase -import FirebaseDynamicLinks import FirebaseFirestore import FirebaseFunctions import FirebaseInstallations diff --git a/SymbolCollisionTest/Podfile b/SymbolCollisionTest/Podfile index 95dfd255f4c..e0047ee2631 100644 --- a/SymbolCollisionTest/Podfile +++ b/SymbolCollisionTest/Podfile @@ -18,7 +18,6 @@ target 'SymbolCollisionTest' do pod 'FirebaseCoreInternal', :path => '../' pod 'FirebaseCrashlytics', :path => '../' pod 'FirebaseDatabase', :path => '../' - pod 'FirebaseDynamicLinks', :path => '../' pod 'FirebaseFirestore', :path => '../' pod 'FirebaseFunctions', :path => '../' pod 'FirebaseInAppMessaging', :path => '../' diff --git a/docs/ContinuousIntegration.md b/docs/ContinuousIntegration.md index 40f8d85b99c..3ea518ee4a8 100644 --- a/docs/ContinuousIntegration.md +++ b/docs/ContinuousIntegration.md @@ -97,7 +97,7 @@ repo. The previous setup will run podspecs testing nightly. This enables presubmits of pod spec lint podspecs and accelerates the testing process. This is to run presubmit tests for Firebase Apple SDKs in the SDK repo. A job to run `pod spec lint` is added to SDK testing workflows, including ABTesting, -Analytics, Auth, Core, Crashlytics, Database, DynamicLinks, Firestore, Functions, GoogleUtilities, +Analytics, Auth, Core, Crashlytics, Database, Firestore, Functions, GoogleUtilities, InAppMessaging, Installations, Messaging, MLModelDownloader, Performance, RemoteConfig and Storage. These jobs will be triggered in presubmit and run pod spec lint with a source of Firebase/SpecsTesting repo, which is updated to the head of main nightly in the prerelease diff --git a/scripts/api_diff_report/icore_module.py b/scripts/api_diff_report/icore_module.py index 313180c14a1..4e088347956 100644 --- a/scripts/api_diff_report/icore_module.py +++ b/scripts/api_diff_report/icore_module.py @@ -31,7 +31,6 @@ 'FirebaseCore', 'FirebaseCrashlytics', 'FirebaseDatabase', - 'FirebaseDynamicLinks', 'FirebaseFirestoreInternal', 'FirebaseFirestore', 'FirebaseFunctions', diff --git a/scripts/change_headers.swift b/scripts/change_headers.swift index ee6f1c44b02..80beb9dbcaa 100755 --- a/scripts/change_headers.swift +++ b/scripts/change_headers.swift @@ -25,7 +25,7 @@ let findHeaders = ["FirebaseMessaging"] // Update with directories in which to change imports. let changeImports = ["GoogleUtilities", "FirebaseAuth", "FirebaseCore", "Firebase", "FirebaseDatabase", "GoogleDataTransport", - "FirebaseDynamicLinks", "FirebaseInAppMessaging", "FirebaseMessaging", + "FirebaseInAppMessaging", "FirebaseMessaging", "FirebaseRemoteConfig", "FirebaseInstallations", "FirebaseFunctions", "FirebaseABTesting", "FirebaseAppDistribution", "Example", "Crashlytics", "FirebaseStorage"] diff --git a/scripts/check_imports.swift b/scripts/check_imports.swift index b21af3fcd4c..6f5e5a9ebb3 100755 --- a/scripts/check_imports.swift +++ b/scripts/check_imports.swift @@ -25,7 +25,6 @@ import Foundation // Skip these directories. Imports should only be repo-relative in libraries // and unit tests. let skipDirPatterns = ["/Sample/", "/Pods/", - "FirebaseDynamicLinks/Tests/Integration", "FirebaseInAppMessaging/Tests/Integration/", "FirebaseAuth/", // TODO: Turn Combine back on without Auth includes. diff --git a/scripts/health_metrics/file_patterns.json b/scripts/health_metrics/file_patterns.json index 4b488a28df3..ad7840f354d 100644 --- a/scripts/health_metrics/file_patterns.json +++ b/scripts/health_metrics/file_patterns.json @@ -66,15 +66,6 @@ "FirebaseAuth/Interop/[^/]+\\.h" ] }, - { - "sdk": "dynamiclinks", - "podspecs": ["FirebaseDynamicLinks.podspec"], - "filePatterns": [ - "^FirebaseDynamicLinks.*", - "\\.github/workflows/dynamiclinks\\.yml", - "Interop/Analytics/Public/[^/]+\\.h" - ] - }, { "sdk": "firebase", "podspecs": ["Firebase.podspec"], diff --git a/scripts/health_metrics/pod_test_code_coverage_report.sh b/scripts/health_metrics/pod_test_code_coverage_report.sh index ff742a89965..1908c92d0d6 100755 --- a/scripts/health_metrics/pod_test_code_coverage_report.sh +++ b/scripts/health_metrics/pod_test_code_coverage_report.sh @@ -60,8 +60,6 @@ if [ $SDK == "FirebasePerformance" ]; then elif [ $SDK == "FirebaseFirestore" ]; then scripts/install_prereqs.sh Firestore ${PLATFORM} xcodebuild scripts/third_party/travis/retry.sh scripts/build.sh Firestore ${PLATFORM} xcodebuild -elif [ $SDK == "FirebaseDynamicLinks" ]; then - scripts/third_party/travis/retry.sh scripts/pod_lib_lint.rb "${SDK}".podspec --verbose --allow-warnings --platforms="$(tr '[:upper:]' '[:lower:]'<<<${PLATFORM})" --test-specs="${TEST_SPEC}" else # Run unit tests of pods and put xcresult bundles into OUTPUT_PATH, which # should be a targeted dir of actions/upload-artifact in workflows. From 318edd423178775d6ebb049b7aa782ecb3915a9a Mon Sep 17 00:00:00 2001 From: Nick Cooke <36927374+ncooke3@users.noreply.github.com> Date: Fri, 20 Jun 2025 14:59:17 -0400 Subject: [PATCH 095/113] [Core] Remove `Options.androidClientID` and `Options.trackingID` (#15013) Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com> --- FirebaseCore/CHANGELOG.md | 3 +++ FirebaseCore/Sources/FIROptions.m | 20 ------------------- .../Sources/Public/FirebaseCore/FIROptions.h | 10 ---------- docs/FirebaseOptionsPerProduct.md | 6 ------ 4 files changed, 3 insertions(+), 36 deletions(-) diff --git a/FirebaseCore/CHANGELOG.md b/FirebaseCore/CHANGELOG.md index 326642f51f8..a30f93d02aa 100644 --- a/FirebaseCore/CHANGELOG.md +++ b/FirebaseCore/CHANGELOG.md @@ -4,6 +4,9 @@ - [removed] **Breaking change**: Removed the `Options.deepLinkURLScheme` property. This API was exclusively used by the Dynamic Links SDK, which has been removed. +- [removed] **Breaking change**: Removed the following unused API. + - `Options.androidClientID` + - `Options.trackingID` # Firebase 11.15.0 - [fixed] Remove c99 as the required C language standard. (#14950) diff --git a/FirebaseCore/Sources/FIROptions.m b/FirebaseCore/Sources/FIROptions.m index c3b10b06bdb..1f82a09bc99 100644 --- a/FirebaseCore/Sources/FIROptions.m +++ b/FirebaseCore/Sources/FIROptions.m @@ -20,11 +20,9 @@ // Keys for the strings in the plist file. NSString *const kFIRAPIKey = @"API_KEY"; -NSString *const kFIRTrackingID = @"TRACKING_ID"; NSString *const kFIRGoogleAppID = @"GOOGLE_APP_ID"; NSString *const kFIRClientID = @"CLIENT_ID"; NSString *const kFIRGCMSenderID = @"GCM_SENDER_ID"; -NSString *const kFIRAndroidClientID = @"ANDROID_CLIENT_ID"; NSString *const kFIRDatabaseURL = @"DATABASE_URL"; NSString *const kFIRStorageBucket = @"STORAGE_BUCKET"; // The key to locate the expected bundle identifier in the plist file. @@ -232,15 +230,6 @@ - (void)setClientID:(NSString *)clientID { _optionsDictionary[kFIRClientID] = [clientID copy]; } -- (NSString *)trackingID { - return self.optionsDictionary[kFIRTrackingID]; -} - -- (void)setTrackingID:(NSString *)trackingID { - [self checkEditingLocked]; - _optionsDictionary[kFIRTrackingID] = [trackingID copy]; -} - - (NSString *)GCMSenderID { return self.optionsDictionary[kFIRGCMSenderID]; } @@ -259,15 +248,6 @@ - (void)setProjectID:(NSString *)projectID { _optionsDictionary[kFIRProjectID] = [projectID copy]; } -- (NSString *)androidClientID { - return self.optionsDictionary[kFIRAndroidClientID]; -} - -- (void)setAndroidClientID:(NSString *)androidClientID { - [self checkEditingLocked]; - _optionsDictionary[kFIRAndroidClientID] = [androidClientID copy]; -} - - (NSString *)googleAppID { return self.optionsDictionary[kFIRGoogleAppID]; } diff --git a/FirebaseCore/Sources/Public/FirebaseCore/FIROptions.h b/FirebaseCore/Sources/Public/FirebaseCore/FIROptions.h index 4272b8433e2..4e9f8853097 100644 --- a/FirebaseCore/Sources/Public/FirebaseCore/FIROptions.h +++ b/FirebaseCore/Sources/Public/FirebaseCore/FIROptions.h @@ -49,11 +49,6 @@ NS_SWIFT_NAME(FirebaseOptions) */ @property(nonatomic, copy, nullable) NSString *clientID; -/** - * Unused. - */ -@property(nonatomic, copy, nullable) NSString *trackingID DEPRECATED_ATTRIBUTE; - /** * The Project Number from the Google Developer's console, for example @"012345678901", used to * configure Firebase Cloud Messaging. @@ -65,11 +60,6 @@ NS_SWIFT_NAME(FirebaseOptions) */ @property(nonatomic, copy, nullable) NSString *projectID; -/** - * Unused. - */ -@property(nonatomic, copy, nullable) NSString *androidClientID DEPRECATED_ATTRIBUTE; - /** * The Google App ID that is used to uniquely identify an instance of an app. */ diff --git a/docs/FirebaseOptionsPerProduct.md b/docs/FirebaseOptionsPerProduct.md index 434258e167c..bd85332cd85 100644 --- a/docs/FirebaseOptionsPerProduct.md +++ b/docs/FirebaseOptionsPerProduct.md @@ -37,12 +37,6 @@ to GoogleService-Info.plist attributes. * Is there a better way to manage the fields that are only used by one product? *clientID*, *databaseURL*, and *storageBucket*. -## Unused FirebaseOptions -Proposal: Deprecate these in the SDK and stop generating them for GoogleService-Info.plist. - -* *androidClientID* -* *trackingID* - ## Unread GoogleService-Info.plist fields Proposal: Stop generating these for GoogleService-Info.plist. From a945ff3d9ca017d8452dab003150b9d44d3b3826 Mon Sep 17 00:00:00 2001 From: Haibo Yang Date: Mon, 23 Jun 2025 11:31:02 -0700 Subject: [PATCH 096/113] [FirebaseAI] update the jump link in README.md for quickstart-ios (#15019) --- FirebaseAI/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/FirebaseAI/README.md b/FirebaseAI/README.md index 8a5d2cb853a..9f9c4b0cabb 100644 --- a/FirebaseAI/README.md +++ b/FirebaseAI/README.md @@ -1,7 +1,7 @@ # Firebase AI SDK - For developer documentation, please visit https://firebase.google.com/docs/vertex-ai. -- Try out the [sample app](https://github.com/firebase/quickstart-ios/tree/main/vertexai to get started. +- Try out the [sample app](https://github.com/firebase/quickstart-ios/tree/main/firebaseai) to get started. ## Development From bb17e641e155c70c0d0267321815a8ab64ef2d07 Mon Sep 17 00:00:00 2001 From: Paul Beusterien Date: Mon, 23 Jun 2025 11:53:06 -0700 Subject: [PATCH 097/113] Carthage 11.15.0 (#15022) --- ReleaseTooling/CarthageJSON/FirebaseABTestingBinary.json | 1 + ReleaseTooling/CarthageJSON/FirebaseAIBinary.json | 3 ++- ReleaseTooling/CarthageJSON/FirebaseAdMobBinary.json | 1 + ReleaseTooling/CarthageJSON/FirebaseAnalyticsBinary.json | 1 + .../FirebaseAnalyticsOnDeviceConversionBinary.json | 1 + ReleaseTooling/CarthageJSON/FirebaseAppCheckBinary.json | 1 + ReleaseTooling/CarthageJSON/FirebaseAppDistributionBinary.json | 1 + ReleaseTooling/CarthageJSON/FirebaseAuthBinary.json | 1 + ReleaseTooling/CarthageJSON/FirebaseCrashlyticsBinary.json | 1 + ReleaseTooling/CarthageJSON/FirebaseDatabaseBinary.json | 1 + ReleaseTooling/CarthageJSON/FirebaseDynamicLinksBinary.json | 1 + ReleaseTooling/CarthageJSON/FirebaseFirestoreBinary.json | 1 + ReleaseTooling/CarthageJSON/FirebaseFunctionsBinary.json | 1 + ReleaseTooling/CarthageJSON/FirebaseGoogleSignInBinary.json | 1 + ReleaseTooling/CarthageJSON/FirebaseInAppMessagingBinary.json | 1 + .../CarthageJSON/FirebaseMLModelDownloaderBinary.json | 1 + ReleaseTooling/CarthageJSON/FirebaseMessagingBinary.json | 1 + ReleaseTooling/CarthageJSON/FirebasePerformanceBinary.json | 1 + ReleaseTooling/CarthageJSON/FirebaseRemoteConfigBinary.json | 1 + ReleaseTooling/CarthageJSON/FirebaseStorageBinary.json | 1 + ReleaseTooling/CarthageJSON/FirebaseVertexAIBinary.json | 1 + 21 files changed, 22 insertions(+), 1 deletion(-) diff --git a/ReleaseTooling/CarthageJSON/FirebaseABTestingBinary.json b/ReleaseTooling/CarthageJSON/FirebaseABTestingBinary.json index 8350853be9b..a2a0118d1fb 100644 --- a/ReleaseTooling/CarthageJSON/FirebaseABTestingBinary.json +++ b/ReleaseTooling/CarthageJSON/FirebaseABTestingBinary.json @@ -35,6 +35,7 @@ "11.12.0": "https://dl.google.com/dl/firebase/ios/carthage/11.12.0/FirebaseABTesting-17c1a20424ac54c7.zip", "11.13.0": "https://dl.google.com/dl/firebase/ios/carthage/11.13.0/FirebaseABTesting-1a75b2ffead6cd9d.zip", "11.14.0": "https://dl.google.com/dl/firebase/ios/carthage/11.14.0/FirebaseABTesting-d4a41d6f862a8547.zip", + "11.15.0": "https://dl.google.com/dl/firebase/ios/carthage/11.15.0/FirebaseABTesting-7257632ed78c5c4c.zip", "11.2.0": "https://dl.google.com/dl/firebase/ios/carthage/11.2.0/FirebaseABTesting-0d51fde82d49f9e8.zip", "11.3.0": "https://dl.google.com/dl/firebase/ios/carthage/11.3.0/FirebaseABTesting-2233510ff87da3b6.zip", "11.4.0": "https://dl.google.com/dl/firebase/ios/carthage/11.4.0/FirebaseABTesting-4d0b187af6fd8d67.zip", diff --git a/ReleaseTooling/CarthageJSON/FirebaseAIBinary.json b/ReleaseTooling/CarthageJSON/FirebaseAIBinary.json index bb2bd796541..4e7b9056455 100644 --- a/ReleaseTooling/CarthageJSON/FirebaseAIBinary.json +++ b/ReleaseTooling/CarthageJSON/FirebaseAIBinary.json @@ -1,4 +1,5 @@ { "11.13.0": "https://dl.google.com/dl/firebase/ios/carthage/11.13.0/FirebaseAI-b1e75ff6284775b1.zip", - "11.14.0": "https://dl.google.com/dl/firebase/ios/carthage/11.14.0/FirebaseAI-0991ef5c3a83833a.zip" + "11.14.0": "https://dl.google.com/dl/firebase/ios/carthage/11.14.0/FirebaseAI-0991ef5c3a83833a.zip", + "11.15.0": "https://dl.google.com/dl/firebase/ios/carthage/11.15.0/FirebaseAI-ba1237ee5b7a5baa.zip" } diff --git a/ReleaseTooling/CarthageJSON/FirebaseAdMobBinary.json b/ReleaseTooling/CarthageJSON/FirebaseAdMobBinary.json index 4f6b05e5a87..ba6b80fcff6 100644 --- a/ReleaseTooling/CarthageJSON/FirebaseAdMobBinary.json +++ b/ReleaseTooling/CarthageJSON/FirebaseAdMobBinary.json @@ -35,6 +35,7 @@ "11.12.0": "https://dl.google.com/dl/firebase/ios/carthage/11.12.0/Google-Mobile-Ads-SDK-f8af4dfdc3318376.zip", "11.13.0": "https://dl.google.com/dl/firebase/ios/carthage/11.13.0/Google-Mobile-Ads-SDK-cafdcb68e4493534.zip", "11.14.0": "https://dl.google.com/dl/firebase/ios/carthage/11.14.0/Google-Mobile-Ads-SDK-9667edd0361b0417.zip", + "11.15.0": "https://dl.google.com/dl/firebase/ios/carthage/11.15.0/Google-Mobile-Ads-SDK-030b504727644b39.zip", "11.2.0": "https://dl.google.com/dl/firebase/ios/carthage/11.2.0/Google-Mobile-Ads-SDK-4f24527af297e7f1.zip", "11.3.0": "https://dl.google.com/dl/firebase/ios/carthage/11.3.0/Google-Mobile-Ads-SDK-80ba4cb995505158.zip", "11.4.0": "https://dl.google.com/dl/firebase/ios/carthage/11.4.0/Google-Mobile-Ads-SDK-3df614a58e6a5fa6.zip", diff --git a/ReleaseTooling/CarthageJSON/FirebaseAnalyticsBinary.json b/ReleaseTooling/CarthageJSON/FirebaseAnalyticsBinary.json index ee48b39c89c..f7ff0a95f02 100644 --- a/ReleaseTooling/CarthageJSON/FirebaseAnalyticsBinary.json +++ b/ReleaseTooling/CarthageJSON/FirebaseAnalyticsBinary.json @@ -35,6 +35,7 @@ "11.12.0": "https://dl.google.com/dl/firebase/ios/carthage/11.12.0/FirebaseAnalytics-15d238d1b49f4aff.zip", "11.13.0": "https://dl.google.com/dl/firebase/ios/carthage/11.13.0/FirebaseAnalytics-65ff9a1a6c9e6497.zip", "11.14.0": "https://dl.google.com/dl/firebase/ios/carthage/11.14.0/FirebaseAnalytics-12acfc103ccaf7a6.zip", + "11.15.0": "https://dl.google.com/dl/firebase/ios/carthage/11.15.0/FirebaseAnalytics-9a411c918346c8ea.zip", "11.2.0": "https://dl.google.com/dl/firebase/ios/carthage/11.2.0/FirebaseAnalytics-a93a6c81da535385.zip", "11.3.0": "https://dl.google.com/dl/firebase/ios/carthage/11.3.0/FirebaseAnalytics-fd2c71a90d62b88a.zip", "11.4.0": "https://dl.google.com/dl/firebase/ios/carthage/11.4.0/FirebaseAnalytics-525b465eb296d09e.zip", diff --git a/ReleaseTooling/CarthageJSON/FirebaseAnalyticsOnDeviceConversionBinary.json b/ReleaseTooling/CarthageJSON/FirebaseAnalyticsOnDeviceConversionBinary.json index 0fc94414c96..8c8c23c8683 100644 --- a/ReleaseTooling/CarthageJSON/FirebaseAnalyticsOnDeviceConversionBinary.json +++ b/ReleaseTooling/CarthageJSON/FirebaseAnalyticsOnDeviceConversionBinary.json @@ -35,6 +35,7 @@ "11.12.0": "https://dl.google.com/dl/firebase/ios/carthage/11.12.0/FirebaseAnalyticsOnDeviceConversion-74e82e4c9ac69336.zip", "11.13.0": "https://dl.google.com/dl/firebase/ios/carthage/11.13.0/FirebaseAnalyticsOnDeviceConversion-78d60e37985a869e.zip", "11.14.0": "https://dl.google.com/dl/firebase/ios/carthage/11.14.0/FirebaseAnalyticsOnDeviceConversion-5b8b3b9300f67f33.zip", + "11.15.0": "https://dl.google.com/dl/firebase/ios/carthage/11.15.0/FirebaseAnalyticsOnDeviceConversion-f03a6283e3772033.zip", "11.2.0": "https://dl.google.com/dl/firebase/ios/carthage/11.2.0/FirebaseAnalyticsOnDeviceConversion-09d94624a2de0ac8.zip", "11.3.0": "https://dl.google.com/dl/firebase/ios/carthage/11.3.0/FirebaseAnalyticsOnDeviceConversion-918bc6e0b7a2fd94.zip", "11.4.0": "https://dl.google.com/dl/firebase/ios/carthage/11.4.0/FirebaseAnalyticsOnDeviceConversion-1640c514418a23da.zip", diff --git a/ReleaseTooling/CarthageJSON/FirebaseAppCheckBinary.json b/ReleaseTooling/CarthageJSON/FirebaseAppCheckBinary.json index cc437682f19..2344d3aed80 100644 --- a/ReleaseTooling/CarthageJSON/FirebaseAppCheckBinary.json +++ b/ReleaseTooling/CarthageJSON/FirebaseAppCheckBinary.json @@ -35,6 +35,7 @@ "11.12.0": "https://dl.google.com/dl/firebase/ios/carthage/11.12.0/FirebaseAppCheck-0c2c90b1b6b95fc9.zip", "11.13.0": "https://dl.google.com/dl/firebase/ios/carthage/11.13.0/FirebaseAppCheck-11e2868920731911.zip", "11.14.0": "https://dl.google.com/dl/firebase/ios/carthage/11.14.0/FirebaseAppCheck-4eff92b9a211beb7.zip", + "11.15.0": "https://dl.google.com/dl/firebase/ios/carthage/11.15.0/FirebaseAppCheck-b0eff608f83f7797.zip", "11.2.0": "https://dl.google.com/dl/firebase/ios/carthage/11.2.0/FirebaseAppCheck-d0c5f46e6a2bf4a3.zip", "11.3.0": "https://dl.google.com/dl/firebase/ios/carthage/11.3.0/FirebaseAppCheck-89c39bdcf0bb90fe.zip", "11.4.0": "https://dl.google.com/dl/firebase/ios/carthage/11.4.0/FirebaseAppCheck-9b0c4a9489968b07.zip", diff --git a/ReleaseTooling/CarthageJSON/FirebaseAppDistributionBinary.json b/ReleaseTooling/CarthageJSON/FirebaseAppDistributionBinary.json index cb9a34c1c13..b86174efba7 100644 --- a/ReleaseTooling/CarthageJSON/FirebaseAppDistributionBinary.json +++ b/ReleaseTooling/CarthageJSON/FirebaseAppDistributionBinary.json @@ -35,6 +35,7 @@ "11.12.0": "https://dl.google.com/dl/firebase/ios/carthage/11.12.0/FirebaseAppDistribution-7c36126c08bc3ffc.zip", "11.13.0": "https://dl.google.com/dl/firebase/ios/carthage/11.13.0/FirebaseAppDistribution-e955d19576007871.zip", "11.14.0": "https://dl.google.com/dl/firebase/ios/carthage/11.14.0/FirebaseAppDistribution-c472cb29b072dcb7.zip", + "11.15.0": "https://dl.google.com/dl/firebase/ios/carthage/11.15.0/FirebaseAppDistribution-4a78ab72ee174613.zip", "11.2.0": "https://dl.google.com/dl/firebase/ios/carthage/11.2.0/FirebaseAppDistribution-9b05f4873b275347.zip", "11.3.0": "https://dl.google.com/dl/firebase/ios/carthage/11.3.0/FirebaseAppDistribution-6d2eccaccfd3145f.zip", "11.4.0": "https://dl.google.com/dl/firebase/ios/carthage/11.4.0/FirebaseAppDistribution-20ac94ca344af731.zip", diff --git a/ReleaseTooling/CarthageJSON/FirebaseAuthBinary.json b/ReleaseTooling/CarthageJSON/FirebaseAuthBinary.json index 46ea1d6a93e..596d5a8116a 100644 --- a/ReleaseTooling/CarthageJSON/FirebaseAuthBinary.json +++ b/ReleaseTooling/CarthageJSON/FirebaseAuthBinary.json @@ -35,6 +35,7 @@ "11.12.0": "https://dl.google.com/dl/firebase/ios/carthage/11.12.0/FirebaseAuth-eb54b6a712749cc9.zip", "11.13.0": "https://dl.google.com/dl/firebase/ios/carthage/11.13.0/FirebaseAuth-88c4514b7d5eb6a2.zip", "11.14.0": "https://dl.google.com/dl/firebase/ios/carthage/11.14.0/FirebaseAuth-db785a3ce2245ee8.zip", + "11.15.0": "https://dl.google.com/dl/firebase/ios/carthage/11.15.0/FirebaseAuth-d6d3264758ea5270.zip", "11.2.0": "https://dl.google.com/dl/firebase/ios/carthage/11.2.0/FirebaseAuth-eade26b5390baf84.zip", "11.3.0": "https://dl.google.com/dl/firebase/ios/carthage/11.3.0/FirebaseAuth-93dd2965b3f79b98.zip", "11.4.0": "https://dl.google.com/dl/firebase/ios/carthage/11.4.0/FirebaseAuth-5faf6dc3bb16c732.zip", diff --git a/ReleaseTooling/CarthageJSON/FirebaseCrashlyticsBinary.json b/ReleaseTooling/CarthageJSON/FirebaseCrashlyticsBinary.json index d83ca12cc27..e86ca152e55 100644 --- a/ReleaseTooling/CarthageJSON/FirebaseCrashlyticsBinary.json +++ b/ReleaseTooling/CarthageJSON/FirebaseCrashlyticsBinary.json @@ -35,6 +35,7 @@ "11.12.0": "https://dl.google.com/dl/firebase/ios/carthage/11.12.0/FirebaseCrashlytics-6174ffabf4502bb8.zip", "11.13.0": "https://dl.google.com/dl/firebase/ios/carthage/11.13.0/FirebaseCrashlytics-b653e61e196e22a4.zip", "11.14.0": "https://dl.google.com/dl/firebase/ios/carthage/11.14.0/FirebaseCrashlytics-c1b09641c4cde67d.zip", + "11.15.0": "https://dl.google.com/dl/firebase/ios/carthage/11.15.0/FirebaseCrashlytics-6c0391d0cb3de2ad.zip", "11.2.0": "https://dl.google.com/dl/firebase/ios/carthage/11.2.0/FirebaseCrashlytics-13851523ad6df088.zip", "11.3.0": "https://dl.google.com/dl/firebase/ios/carthage/11.3.0/FirebaseCrashlytics-282a6f3cf3445787.zip", "11.4.0": "https://dl.google.com/dl/firebase/ios/carthage/11.4.0/FirebaseCrashlytics-d5c125d6416f6e0a.zip", diff --git a/ReleaseTooling/CarthageJSON/FirebaseDatabaseBinary.json b/ReleaseTooling/CarthageJSON/FirebaseDatabaseBinary.json index 3ca76074eea..71718147ec6 100644 --- a/ReleaseTooling/CarthageJSON/FirebaseDatabaseBinary.json +++ b/ReleaseTooling/CarthageJSON/FirebaseDatabaseBinary.json @@ -35,6 +35,7 @@ "11.12.0": "https://dl.google.com/dl/firebase/ios/carthage/11.12.0/FirebaseDatabase-f2f974b2b124d51a.zip", "11.13.0": "https://dl.google.com/dl/firebase/ios/carthage/11.13.0/FirebaseDatabase-c90d9d681a963528.zip", "11.14.0": "https://dl.google.com/dl/firebase/ios/carthage/11.14.0/FirebaseDatabase-d2469ab8369633b1.zip", + "11.15.0": "https://dl.google.com/dl/firebase/ios/carthage/11.15.0/FirebaseDatabase-d0e4e892d5ecbffb.zip", "11.2.0": "https://dl.google.com/dl/firebase/ios/carthage/11.2.0/FirebaseDatabase-06dbb1f7d3c8a3e1.zip", "11.3.0": "https://dl.google.com/dl/firebase/ios/carthage/11.3.0/FirebaseDatabase-38634b55050b94fe.zip", "11.4.0": "https://dl.google.com/dl/firebase/ios/carthage/11.4.0/FirebaseDatabase-ed125984da534e96.zip", diff --git a/ReleaseTooling/CarthageJSON/FirebaseDynamicLinksBinary.json b/ReleaseTooling/CarthageJSON/FirebaseDynamicLinksBinary.json index bd082b476fd..5b27047d4ac 100644 --- a/ReleaseTooling/CarthageJSON/FirebaseDynamicLinksBinary.json +++ b/ReleaseTooling/CarthageJSON/FirebaseDynamicLinksBinary.json @@ -35,6 +35,7 @@ "11.12.0": "https://dl.google.com/dl/firebase/ios/carthage/11.12.0/FirebaseDynamicLinks-f5c8594e8040c69a.zip", "11.13.0": "https://dl.google.com/dl/firebase/ios/carthage/11.13.0/FirebaseDynamicLinks-cadebc4c288fe390.zip", "11.14.0": "https://dl.google.com/dl/firebase/ios/carthage/11.14.0/FirebaseDynamicLinks-d0cf6dba1f1d395c.zip", + "11.15.0": "https://dl.google.com/dl/firebase/ios/carthage/11.15.0/FirebaseDynamicLinks-e46c284d68552c13.zip", "11.2.0": "https://dl.google.com/dl/firebase/ios/carthage/11.2.0/FirebaseDynamicLinks-e61c61fa80e5ea8a.zip", "11.3.0": "https://dl.google.com/dl/firebase/ios/carthage/11.3.0/FirebaseDynamicLinks-95f7e222d8456304.zip", "11.4.0": "https://dl.google.com/dl/firebase/ios/carthage/11.4.0/FirebaseDynamicLinks-f3f9d6cc60c8b832.zip", diff --git a/ReleaseTooling/CarthageJSON/FirebaseFirestoreBinary.json b/ReleaseTooling/CarthageJSON/FirebaseFirestoreBinary.json index bff1e093edf..d482b503303 100644 --- a/ReleaseTooling/CarthageJSON/FirebaseFirestoreBinary.json +++ b/ReleaseTooling/CarthageJSON/FirebaseFirestoreBinary.json @@ -35,6 +35,7 @@ "11.12.0": "https://dl.google.com/dl/firebase/ios/carthage/11.12.0/FirebaseFirestore-860c013c1e20d6f3.zip", "11.13.0": "https://dl.google.com/dl/firebase/ios/carthage/11.13.0/FirebaseFirestore-c4f5b2c5b7a568a1.zip", "11.14.0": "https://dl.google.com/dl/firebase/ios/carthage/11.14.0/FirebaseFirestore-f5ff5063a1f53d77.zip", + "11.15.0": "https://dl.google.com/dl/firebase/ios/carthage/11.15.0/FirebaseFirestore-f374bf8c4f273d0d.zip", "11.2.0": "https://dl.google.com/dl/firebase/ios/carthage/11.2.0/FirebaseFirestore-43af85b854ac842e.zip", "11.3.0": "https://dl.google.com/dl/firebase/ios/carthage/11.3.0/FirebaseFirestore-e1283f8cd2e0f3ec.zip", "11.4.0": "https://dl.google.com/dl/firebase/ios/carthage/11.4.0/FirebaseFirestore-f5864e67ddbbc9e8.zip", diff --git a/ReleaseTooling/CarthageJSON/FirebaseFunctionsBinary.json b/ReleaseTooling/CarthageJSON/FirebaseFunctionsBinary.json index 785c35655db..ba156e8b3c3 100644 --- a/ReleaseTooling/CarthageJSON/FirebaseFunctionsBinary.json +++ b/ReleaseTooling/CarthageJSON/FirebaseFunctionsBinary.json @@ -35,6 +35,7 @@ "11.12.0": "https://dl.google.com/dl/firebase/ios/carthage/11.12.0/FirebaseFunctions-5ab1be0d8d70d377.zip", "11.13.0": "https://dl.google.com/dl/firebase/ios/carthage/11.13.0/FirebaseFunctions-63e0b73f4514e67f.zip", "11.14.0": "https://dl.google.com/dl/firebase/ios/carthage/11.14.0/FirebaseFunctions-581350611b7e5c69.zip", + "11.15.0": "https://dl.google.com/dl/firebase/ios/carthage/11.15.0/FirebaseFunctions-74f3deb4b5a5bb48.zip", "11.2.0": "https://dl.google.com/dl/firebase/ios/carthage/11.2.0/FirebaseFunctions-307f00117c2efc62.zip", "11.3.0": "https://dl.google.com/dl/firebase/ios/carthage/11.3.0/FirebaseFunctions-02693a7583303912.zip", "11.4.0": "https://dl.google.com/dl/firebase/ios/carthage/11.4.0/FirebaseFunctions-8fce8623ed1c6b86.zip", diff --git a/ReleaseTooling/CarthageJSON/FirebaseGoogleSignInBinary.json b/ReleaseTooling/CarthageJSON/FirebaseGoogleSignInBinary.json index 6fb7e093f8f..945e0372292 100644 --- a/ReleaseTooling/CarthageJSON/FirebaseGoogleSignInBinary.json +++ b/ReleaseTooling/CarthageJSON/FirebaseGoogleSignInBinary.json @@ -35,6 +35,7 @@ "11.12.0": "https://dl.google.com/dl/firebase/ios/carthage/11.12.0/GoogleSignIn-359f9a827460f64a.zip", "11.13.0": "https://dl.google.com/dl/firebase/ios/carthage/11.13.0/GoogleSignIn-865a20796d87317c.zip", "11.14.0": "https://dl.google.com/dl/firebase/ios/carthage/11.14.0/GoogleSignIn-c95d586e8128eb80.zip", + "11.15.0": "https://dl.google.com/dl/firebase/ios/carthage/11.15.0/GoogleSignIn-eebded978006aa85.zip", "11.2.0": "https://dl.google.com/dl/firebase/ios/carthage/11.2.0/GoogleSignIn-4e8837ef9594b57b.zip", "11.3.0": "https://dl.google.com/dl/firebase/ios/carthage/11.3.0/GoogleSignIn-8ce1c31ca2236212.zip", "11.4.0": "https://dl.google.com/dl/firebase/ios/carthage/11.4.0/GoogleSignIn-59eb371d148a2e3a.zip", diff --git a/ReleaseTooling/CarthageJSON/FirebaseInAppMessagingBinary.json b/ReleaseTooling/CarthageJSON/FirebaseInAppMessagingBinary.json index 89d1cfb02b0..f7d04b01c31 100644 --- a/ReleaseTooling/CarthageJSON/FirebaseInAppMessagingBinary.json +++ b/ReleaseTooling/CarthageJSON/FirebaseInAppMessagingBinary.json @@ -35,6 +35,7 @@ "11.12.0": "https://dl.google.com/dl/firebase/ios/carthage/11.12.0/FirebaseInAppMessaging-713d93418e005e14.zip", "11.13.0": "https://dl.google.com/dl/firebase/ios/carthage/11.13.0/FirebaseInAppMessaging-db00d9a8196980fe.zip", "11.14.0": "https://dl.google.com/dl/firebase/ios/carthage/11.14.0/FirebaseInAppMessaging-934596e813fe5d6e.zip", + "11.15.0": "https://dl.google.com/dl/firebase/ios/carthage/11.15.0/FirebaseInAppMessaging-00c827248fb20a3b.zip", "11.2.0": "https://dl.google.com/dl/firebase/ios/carthage/11.2.0/FirebaseInAppMessaging-6fae0a778e9d3efa.zip", "11.3.0": "https://dl.google.com/dl/firebase/ios/carthage/11.3.0/FirebaseInAppMessaging-3a1a331c86520356.zip", "11.4.0": "https://dl.google.com/dl/firebase/ios/carthage/11.4.0/FirebaseInAppMessaging-a8054099dd2918b3.zip", diff --git a/ReleaseTooling/CarthageJSON/FirebaseMLModelDownloaderBinary.json b/ReleaseTooling/CarthageJSON/FirebaseMLModelDownloaderBinary.json index f1cd1300ef8..193446fc061 100644 --- a/ReleaseTooling/CarthageJSON/FirebaseMLModelDownloaderBinary.json +++ b/ReleaseTooling/CarthageJSON/FirebaseMLModelDownloaderBinary.json @@ -35,6 +35,7 @@ "11.12.0": "https://dl.google.com/dl/firebase/ios/carthage/11.12.0/FirebaseMLModelDownloader-90a680269b1b7dc1.zip", "11.13.0": "https://dl.google.com/dl/firebase/ios/carthage/11.13.0/FirebaseMLModelDownloader-680180005688845d.zip", "11.14.0": "https://dl.google.com/dl/firebase/ios/carthage/11.14.0/FirebaseMLModelDownloader-a4329595e01513a5.zip", + "11.15.0": "https://dl.google.com/dl/firebase/ios/carthage/11.15.0/FirebaseMLModelDownloader-c053b5792960df37.zip", "11.2.0": "https://dl.google.com/dl/firebase/ios/carthage/11.2.0/FirebaseMLModelDownloader-d8649822e63fbf7f.zip", "11.3.0": "https://dl.google.com/dl/firebase/ios/carthage/11.3.0/FirebaseMLModelDownloader-517f51af92733a7f.zip", "11.4.0": "https://dl.google.com/dl/firebase/ios/carthage/11.4.0/FirebaseMLModelDownloader-069609cbcde7e789.zip", diff --git a/ReleaseTooling/CarthageJSON/FirebaseMessagingBinary.json b/ReleaseTooling/CarthageJSON/FirebaseMessagingBinary.json index 776615f4ea6..b48d93e0ea1 100644 --- a/ReleaseTooling/CarthageJSON/FirebaseMessagingBinary.json +++ b/ReleaseTooling/CarthageJSON/FirebaseMessagingBinary.json @@ -35,6 +35,7 @@ "11.12.0": "https://dl.google.com/dl/firebase/ios/carthage/11.12.0/FirebaseMessaging-c27934ab4d2ac145.zip", "11.13.0": "https://dl.google.com/dl/firebase/ios/carthage/11.13.0/FirebaseMessaging-57ff2659837e66f7.zip", "11.14.0": "https://dl.google.com/dl/firebase/ios/carthage/11.14.0/FirebaseMessaging-a49d55ace7976c99.zip", + "11.15.0": "https://dl.google.com/dl/firebase/ios/carthage/11.15.0/FirebaseMessaging-faace3ba9827c455.zip", "11.2.0": "https://dl.google.com/dl/firebase/ios/carthage/11.2.0/FirebaseMessaging-70e63bb9d9590ded.zip", "11.3.0": "https://dl.google.com/dl/firebase/ios/carthage/11.3.0/FirebaseMessaging-8a39834fead3c581.zip", "11.4.0": "https://dl.google.com/dl/firebase/ios/carthage/11.4.0/FirebaseMessaging-2d09725e8b98d199.zip", diff --git a/ReleaseTooling/CarthageJSON/FirebasePerformanceBinary.json b/ReleaseTooling/CarthageJSON/FirebasePerformanceBinary.json index 19ba1f6da82..1c75aa6bebf 100644 --- a/ReleaseTooling/CarthageJSON/FirebasePerformanceBinary.json +++ b/ReleaseTooling/CarthageJSON/FirebasePerformanceBinary.json @@ -35,6 +35,7 @@ "11.12.0": "https://dl.google.com/dl/firebase/ios/carthage/11.12.0/FirebasePerformance-d8b225f36b8cbf8b.zip", "11.13.0": "https://dl.google.com/dl/firebase/ios/carthage/11.13.0/FirebasePerformance-916f67a44f64a09c.zip", "11.14.0": "https://dl.google.com/dl/firebase/ios/carthage/11.14.0/FirebasePerformance-0a23b7bfbd3f251e.zip", + "11.15.0": "https://dl.google.com/dl/firebase/ios/carthage/11.15.0/FirebasePerformance-1ea9f0b8e5cef2d2.zip", "11.2.0": "https://dl.google.com/dl/firebase/ios/carthage/11.2.0/FirebasePerformance-aa174ee3102722d9.zip", "11.3.0": "https://dl.google.com/dl/firebase/ios/carthage/11.3.0/FirebasePerformance-a489ac7a27d9b53d.zip", "11.4.0": "https://dl.google.com/dl/firebase/ios/carthage/11.4.0/FirebasePerformance-9a6f62e80c2324f4.zip", diff --git a/ReleaseTooling/CarthageJSON/FirebaseRemoteConfigBinary.json b/ReleaseTooling/CarthageJSON/FirebaseRemoteConfigBinary.json index e59f01d63a9..0d5ccc12c74 100644 --- a/ReleaseTooling/CarthageJSON/FirebaseRemoteConfigBinary.json +++ b/ReleaseTooling/CarthageJSON/FirebaseRemoteConfigBinary.json @@ -35,6 +35,7 @@ "11.12.0": "https://dl.google.com/dl/firebase/ios/carthage/11.12.0/FirebaseRemoteConfig-10e4aac268e7dde2.zip", "11.13.0": "https://dl.google.com/dl/firebase/ios/carthage/11.13.0/FirebaseRemoteConfig-cb344560e8a1a69e.zip", "11.14.0": "https://dl.google.com/dl/firebase/ios/carthage/11.14.0/FirebaseRemoteConfig-010bc32e24c1e227.zip", + "11.15.0": "https://dl.google.com/dl/firebase/ios/carthage/11.15.0/FirebaseRemoteConfig-df265f79f252c97e.zip", "11.2.0": "https://dl.google.com/dl/firebase/ios/carthage/11.2.0/FirebaseRemoteConfig-9a298869ce3cc6db.zip", "11.3.0": "https://dl.google.com/dl/firebase/ios/carthage/11.3.0/FirebaseRemoteConfig-940ed38696414882.zip", "11.4.0": "https://dl.google.com/dl/firebase/ios/carthage/11.4.0/FirebaseRemoteConfig-ec432e976582d0eb.zip", diff --git a/ReleaseTooling/CarthageJSON/FirebaseStorageBinary.json b/ReleaseTooling/CarthageJSON/FirebaseStorageBinary.json index 83a8c4af6d0..8868dc94ecc 100644 --- a/ReleaseTooling/CarthageJSON/FirebaseStorageBinary.json +++ b/ReleaseTooling/CarthageJSON/FirebaseStorageBinary.json @@ -35,6 +35,7 @@ "11.12.0": "https://dl.google.com/dl/firebase/ios/carthage/11.12.0/FirebaseStorage-3926226b5e3ec43d.zip", "11.13.0": "https://dl.google.com/dl/firebase/ios/carthage/11.13.0/FirebaseStorage-d276ced3a4fd1b8c.zip", "11.14.0": "https://dl.google.com/dl/firebase/ios/carthage/11.14.0/FirebaseStorage-109dd1d20a0c531e.zip", + "11.15.0": "https://dl.google.com/dl/firebase/ios/carthage/11.15.0/FirebaseStorage-af8b7d731da47f13.zip", "11.2.0": "https://dl.google.com/dl/firebase/ios/carthage/11.2.0/FirebaseStorage-b9b969b0d1254065.zip", "11.3.0": "https://dl.google.com/dl/firebase/ios/carthage/11.3.0/FirebaseStorage-0435eeaa87324cd4.zip", "11.4.0": "https://dl.google.com/dl/firebase/ios/carthage/11.4.0/FirebaseStorage-0b7a2306152984a2.zip", diff --git a/ReleaseTooling/CarthageJSON/FirebaseVertexAIBinary.json b/ReleaseTooling/CarthageJSON/FirebaseVertexAIBinary.json index 14875d530ce..32749d3021b 100644 --- a/ReleaseTooling/CarthageJSON/FirebaseVertexAIBinary.json +++ b/ReleaseTooling/CarthageJSON/FirebaseVertexAIBinary.json @@ -4,6 +4,7 @@ "11.12.0": "https://dl.google.com/dl/firebase/ios/carthage/11.12.0/FirebaseVertexAI-7fabd201dfabab6f.zip", "11.13.0": "https://dl.google.com/dl/firebase/ios/carthage/11.13.0/FirebaseVertexAI-3fc94c339df642e3.zip", "11.14.0": "https://dl.google.com/dl/firebase/ios/carthage/11.14.0/FirebaseVertexAI-4ec0e98c460030e1.zip", + "11.15.0": "https://dl.google.com/dl/firebase/ios/carthage/11.15.0/FirebaseVertexAI-1063ba053684ed1a.zip", "11.5.0": "https://dl.google.com/dl/firebase/ios/carthage/11.5.0/FirebaseVertexAI-d5d0ffd8010245da.zip", "11.6.0": "https://dl.google.com/dl/firebase/ios/carthage/11.6.0/FirebaseVertexAI-6f6520d750ba54c4.zip", "11.7.0": "https://dl.google.com/dl/firebase/ios/carthage/11.7.0/FirebaseVertexAI-bd6d038eb0cf85c6.zip", From dde003cfb5d065c1b0079659c1a9024c5e37e27c Mon Sep 17 00:00:00 2001 From: Paul Beusterien Date: Mon, 23 Jun 2025 17:19:55 -0700 Subject: [PATCH 098/113] Remove deprecated VertexAI (#15027) --- .github/workflows/vertexai.yml | 34 --- FirebaseCore/CHANGELOG.md | 7 + FirebaseVertexAI.podspec | 61 ----- FirebaseVertexAI/CHANGELOG.md | 205 ----------------- FirebaseVertexAI/Sources/VertexAI.swift | 110 --------- .../Tests/Unit/Resources/animals.mp4 | Bin 10881 -> 0 bytes .../Tests/Unit/Resources/blue.png | Bin 69 -> 0 bytes .../Tests/Unit/Resources/gemini-report.pdf | Bin 115898 -> 0 bytes .../Tests/Unit/Resources/hello-world.mp3 | Bin 7344 -> 0 bytes .../Tests/Unit/Snippets/ChatSnippets.swift | 67 ------ .../Snippets/FirebaseAppSnippetsUtil.swift | 57 ----- .../Snippets/FunctionCallingSnippets.swift | 110 --------- .../Unit/Snippets/MultimodalSnippets.swift | 215 ------------------ .../Tests/Unit/Snippets/README.md | 10 - .../Snippets/StructuredOutputSnippets.swift | 96 -------- .../Tests/Unit/Snippets/TextSnippets.swift | 55 ----- .../Unit/TestUtilities/BundleTestUtil.swift | 31 --- .../Tests/Unit/VertexAIAPITests.swift | 213 ----------------- Package.swift | 26 --- .../FirebaseManifest/FirebaseManifest.swift | 1 - 20 files changed, 7 insertions(+), 1291 deletions(-) delete mode 100644 .github/workflows/vertexai.yml delete mode 100644 FirebaseVertexAI.podspec delete mode 100644 FirebaseVertexAI/CHANGELOG.md delete mode 100644 FirebaseVertexAI/Sources/VertexAI.swift delete mode 100644 FirebaseVertexAI/Tests/Unit/Resources/animals.mp4 delete mode 100644 FirebaseVertexAI/Tests/Unit/Resources/blue.png delete mode 100644 FirebaseVertexAI/Tests/Unit/Resources/gemini-report.pdf delete mode 100644 FirebaseVertexAI/Tests/Unit/Resources/hello-world.mp3 delete mode 100644 FirebaseVertexAI/Tests/Unit/Snippets/ChatSnippets.swift delete mode 100644 FirebaseVertexAI/Tests/Unit/Snippets/FirebaseAppSnippetsUtil.swift delete mode 100644 FirebaseVertexAI/Tests/Unit/Snippets/FunctionCallingSnippets.swift delete mode 100644 FirebaseVertexAI/Tests/Unit/Snippets/MultimodalSnippets.swift delete mode 100644 FirebaseVertexAI/Tests/Unit/Snippets/README.md delete mode 100644 FirebaseVertexAI/Tests/Unit/Snippets/StructuredOutputSnippets.swift delete mode 100644 FirebaseVertexAI/Tests/Unit/Snippets/TextSnippets.swift delete mode 100644 FirebaseVertexAI/Tests/Unit/TestUtilities/BundleTestUtil.swift delete mode 100644 FirebaseVertexAI/Tests/Unit/VertexAIAPITests.swift diff --git a/.github/workflows/vertexai.yml b/.github/workflows/vertexai.yml deleted file mode 100644 index c5db31d75df..00000000000 --- a/.github/workflows/vertexai.yml +++ /dev/null @@ -1,34 +0,0 @@ -name: vertexai - -permissions: - contents: read - -on: - pull_request: - paths: - - 'FirebaseAI**' - - 'FirebaseVertexAI**' - - '.github/workflows/vertexai.yml' - - '.github/workflows/common.yml' - - '.github/workflows/common_cocoapods.yml' - - 'Gemfile*' - schedule: - # Run every day at 11pm (PST) - cron uses UTC times - - cron: '0 7 * * *' - workflow_dispatch: - -concurrency: - group: ${{ github.workflow }}-${{ github.head_ref || github.ref }} - cancel-in-progress: true - -jobs: - spm: - uses: ./.github/workflows/common.yml - with: - target: FirebaseVertexAIUnit - - pod_lib_lint: - uses: ./.github/workflows/common_cocoapods.yml - with: - product: FirebaseVertexAI - supports_swift6: true diff --git a/FirebaseCore/CHANGELOG.md b/FirebaseCore/CHANGELOG.md index a30f93d02aa..14adaffc7e1 100644 --- a/FirebaseCore/CHANGELOG.md +++ b/FirebaseCore/CHANGELOG.md @@ -7,6 +7,13 @@ - [removed] **Breaking change**: Removed the following unused API. - `Options.androidClientID` - `Options.trackingID` +- [removed] The deprecated Vertex AI in Firebase SDK (`FirebaseVertexAI`) has + been removed. It has been replaced by the Firebase AI Logic + SDK (`FirebaseAI`) to + accommodate the evolving set of supported features and services. + To start using the new SDK, import the `FirebaseAI` module and use the + top-level `FirebaseAI` class. See details in the [migration guide + ](https://firebase.google.com/docs/ai-logic/migrate-to-latest-sdk). # Firebase 11.15.0 - [fixed] Remove c99 as the required C language standard. (#14950) diff --git a/FirebaseVertexAI.podspec b/FirebaseVertexAI.podspec deleted file mode 100644 index 655bf991e21..00000000000 --- a/FirebaseVertexAI.podspec +++ /dev/null @@ -1,61 +0,0 @@ -Pod::Spec.new do |s| - s.name = 'FirebaseVertexAI' - s.version = '11.15.0' - s.summary = 'Vertex AI in Firebase SDK' - - s.description = <<-DESC -Build AI-powered apps and features with the Gemini API using the Vertex AI in -Firebase SDK. - DESC - - s.homepage = 'https://firebase.google.com' - s.license = { :type => 'Apache-2.0', :file => 'LICENSE' } - s.authors = 'Google, Inc.' - - s.source = { - :git => 'https://github.com/firebase/firebase-ios-sdk.git', - :tag => 'CocoaPods-' + s.version.to_s - } - - s.social_media_url = 'https://twitter.com/Firebase' - - ios_deployment_target = '15.0' - osx_deployment_target = '12.0' - tvos_deployment_target = '15.0' - watchos_deployment_target = '8.0' - - s.ios.deployment_target = ios_deployment_target - s.osx.deployment_target = osx_deployment_target - s.tvos.deployment_target = tvos_deployment_target - s.watchos.deployment_target = watchos_deployment_target - - s.cocoapods_version = '>= 1.12.0' - s.prefix_header_file = false - - s.source_files = [ - 'FirebaseVertexAI/Sources/**/*.swift', - ] - - s.swift_version = '5.9' - - s.framework = 'Foundation' - s.ios.framework = 'UIKit' - s.osx.framework = 'AppKit' - s.tvos.framework = 'UIKit' - s.watchos.framework = 'WatchKit' - - s.dependency 'FirebaseAI', '~> 11.15.0' - - s.test_spec 'unit' do |unit_tests| - unit_tests_dir = 'FirebaseVertexAI/Tests/Unit/' - unit_tests.scheme = { :code_coverage => true } - unit_tests.platforms = { - :ios => ios_deployment_target, - :osx => osx_deployment_target, - :tvos => tvos_deployment_target - } - unit_tests.source_files = [ - unit_tests_dir + '**/*.swift', - ] - end -end diff --git a/FirebaseVertexAI/CHANGELOG.md b/FirebaseVertexAI/CHANGELOG.md deleted file mode 100644 index 8cc4493a468..00000000000 --- a/FirebaseVertexAI/CHANGELOG.md +++ /dev/null @@ -1,205 +0,0 @@ -# 11.13.0 -- [changed] **Renamed:** Vertex AI in Firebase (`FirebaseVertexAI`) has been - renamed and replaced by the new Firebase AI SDK (`FirebaseAI`). Please migrate - to the new `FirebaseAI` module. See the Firebase AI release notes for - migration details and new changes. -

- Note: Existing Vertex AI in Firebase users may continue to use - `import FirebaseVertexAI` and the `VertexAI` top-level class, though these - will be removed in a future release. -- [fixed] Fixed `ModalityTokenCount` decoding when the `tokenCount` field is - omitted; this occurs when the count is 0. (#14745) - -# 11.12.0 -- [added] **Public Preview**: Added support for specifying response modalities - in `GenerationConfig`. This includes **public experimental** support for image - generation using Gemini 2.0 Flash (`gemini-2.0-flash-exp`). (#14658) -

- Note: This feature is in Public Preview and relies on experimental models, - which means that it is not subject to any SLA or deprecation policy and could - change in backwards-incompatible ways. -- [added] Added support for more `Schema` fields: `minItems`/`maxItems` (array - size limits), `title` (schema name), `minimum`/`maximum` (numeric ranges), - `anyOf` (select from sub-schemas), and `propertyOrdering` (JSON key order). (#14647) -- [fixed] Fixed an issue where network requests would fail in the iOS 18.4 - simulator due to a `URLSession` bug introduced in Xcode 16.3. (#14677) - -# 11.11.0 -- [added] Emits a warning when attempting to use an incompatible model with - `GenerativeModel` or `ImagenModel`. (#14610) - -# 11.10.0 -- [feature] The Vertex AI SDK no longer requires `@preconcurrency` when imported in Swift 6. -- [feature] The Vertex AI Sample App now includes an image generation example. -- [changed] The Vertex AI Sample App is now part of the - [quickstart-ios repo](https://github.com/firebase/quickstart-ios/tree/main/vertexai). -- [changed] The `role` in system instructions is now ignored; no code changes - are required. (#14558) - -# 11.9.0 -- [feature] **Public Preview**: Added support for - [generating images](https://firebase.google.com/docs/vertex-ai/generate-images-imagen?platform=ios) - using the Imagen 3 models. -

- Note: This feature is in Public Preview, which means that it is not subject to - any SLA or deprecation policy and could change in backwards-incompatible ways. -- [feature] Added support for modality-based token count. (#14406) - -# 11.6.0 -- [changed] The token counts from `GenerativeModel.countTokens(...)` now include - tokens from the schema for JSON output and function calling; reported token - counts will now be higher if using these features. - -# 11.5.0 -- [fixed] Fixed an issue where `VertexAI.vertexAI(app: app1)` and - `VertexAI.vertexAI(app: app2)` would return the same instance if their - `location` was the same, including the default `us-central1`. (#14007) -- [changed] Removed `format: "double"` in `Schema.double()` since - double-precision accuracy isn't enforced by the model; continue using the - Swift `Double` type when decoding data produced with this schema. (#13990) - -# 11.4.0 -- [feature] Vertex AI in Firebase is now Generally Available (GA) and can be - used in production apps. (#13725) -

- Use the Vertex AI in Firebase library to call the Vertex AI Gemini API - directly from your app. This client library is built specifically for use with - Swift apps, offering security options against unauthorized clients as well as - integrations with other Firebase services. -

- Note: Vertex AI in Firebase is currently only available in Swift Package - Manager and CocoaPods. Stay tuned for the next release for the Zip and - Carthage distributions. -

- - If you're new to this library, visit the - [getting started guide](http://firebase.google.com/docs/vertex-ai/get-started?platform=ios). - - If you used the preview version of the library, visit the - [migration guide](https://firebase.google.com/docs/vertex-ai/migrate-to-ga?platform=ios) - to learn about some important updates. -- [changed] **Breaking Change**: The `HarmCategory` enum is no longer nested - inside the `SafetySetting` struct and the `unspecified` case has been - removed. (#13686) -- [changed] **Breaking Change**: The `BlockThreshold` enum in `SafetySetting` - has been renamed to `HarmBlockThreshold`. (#13696) -- [changed] **Breaking Change**: The `unspecified` case has been removed from - the `FinishReason`, `BlockReason` and `HarmProbability` enums; this scenario - is now handled by the existing `unknown` case. (#13699) -- [changed] **Breaking Change**: The property `citationSources` of - `CitationMetadata` has been renamed to `citations`. (#13702) -- [changed] **Breaking Change**: The initializer for `Schema` is now internal; - use the new type methods `Schema.string(...)`, `Schema.object(...)`, etc., - instead. (#13852) -- [changed] **Breaking Change**: The initializer for `FunctionDeclaration` now - accepts an array of *optional* parameters instead of a list of *required* - parameters; if a parameter is not listed as optional it is assumed to be - required. (#13616) -- [changed] **Breaking Change**: `CountTokensResponse.totalBillableCharacters` - is now optional (`Int?`); it may be `null` in cases such as when a - `GenerateContentRequest` contains only images or other non-text content. - (#13721) -- [changed] **Breaking Change**: The `ImageConversionError` enum is no longer - public; image conversion errors are still reported as - `GenerateContentError.promptImageContentError`. (#13735) -- [changed] **Breaking Change**: The `CountTokensError` enum has been removed; - errors occurring in `GenerativeModel.countTokens(...)` are now thrown directly - instead of being wrapped in a `CountTokensError.internalError`. (#13736) -- [changed] **Breaking Change**: The enum `ModelContent.Part` has been replaced - with a protocol named `Part` to avoid future breaking changes with new part - types. The new types `TextPart` and `FunctionCallPart` may be received when - generating content; additionally the types `InlineDataPart`, `FileDataPart` - and `FunctionResponsePart` may be provided as input. (#13767) -- [changed] **Breaking Change**: All initializers for `ModelContent` now require - the label `parts: `. (#13832) -- [changed] **Breaking Change**: `HarmCategory`, `HarmProbability`, and - `FinishReason` are now structs instead of enums types and the `unknown` cases - have been removed; in a `switch` statement, use the `default:` case to cover - unknown or unhandled values. (#13728, #13854, #13860) -- [changed] **Breaking Change**: The `Tool` initializer is now internal; use the - new type method `functionDeclarations(_:)` to create a `Tool` for function - calling. (#13873) -- [changed] **Breaking Change**: The `FunctionCallingConfig` initializer and - `Mode` enum are now internal; use one of the new type methods `auto()`, - `any(allowedFunctionNames:)`, or `none()` to create a config. (#13873) -- [changed] **Breaking Change**: The `CandidateResponse` type is now named - `Candidate`. (#13897) -- [changed] **Breaking Change**: The minimum deployment target for the SDK is - now macOS 12.0; all other platform minimums remain the same at iOS 15.0, - macCatalyst 15.0, tvOS 15.0, and watchOS 8.0. (#13903) -- [changed] **Breaking Change**: All of the public properties of - `GenerationConfig` are now `internal`; they all remain configurable in the - initializer. (#13904) -- [changed] The default request timeout is now 180 seconds instead of the - platform-default value of 60 seconds for a `URLRequest`; this timeout may - still be customized in `RequestOptions`. (#13722) -- [changed] The response from `GenerativeModel.countTokens(...)` now includes - `systemInstruction`, `tools` and `generationConfig` in the `totalTokens` and - `totalBillableCharacters` counts, where applicable. (#13813) -- [added] Added a new `HarmCategory` `.civicIntegrity` for filtering content - that may be used to harm civic integrity. (#13728) -- [added] Added `probabilityScore`, `severity` and `severityScore` in - `SafetyRating` to provide more fine-grained detail on blocked responses. - (#13875) -- [added] Added a new `HarmBlockThreshold` `.off`, which turns off the safety - filter. (#13863) -- [added] Added an optional `HarmBlockMethod` parameter `method` in - `SafetySetting` that configures whether responses are blocked based on the - `probability` and/or `severity` of content being in a `HarmCategory`. (#13876) -- [added] Added new `FinishReason` values `.blocklist`, `.prohibitedContent`, - `.spii` and `.malformedFunctionCall` that may be reported. (#13860) -- [added] Added new `BlockReason` values `.blocklist` and `.prohibitedContent` - that may be reported when a prompt is blocked. (#13861) -- [added] Added the `PromptFeedback` property `blockReasonMessage` that *may* be - provided alongside the `blockReason`. (#13891) -- [added] Added an optional `publicationDate` property that *may* be provided in - `Citation`. (#13893) -- [added] Added `presencePenalty` and `frequencyPenalty` parameters to - `GenerationConfig`. (#13899) - -# 11.3.0 -- [added] Added `Decodable` conformance for `FunctionResponse`. (#13606) -- [changed] **Breaking Change**: Reverted refactor of `GenerativeModel` and - `Chat` as Swift actors (#13545) introduced in 11.2; The methods - `generateContentStream`, `startChat` and `sendMessageStream` no longer need to - be called with `await`. (#13703) - -# 11.2.0 -- [fixed] Resolved a decoding error for citations without a `uri` and added - support for decoding `title` fields, which were previously ignored. (#13518) -- [changed] **Breaking Change**: The methods for starting streaming requests - (`generateContentStream` and `sendMessageStream`) are now throwing and - asynchronous and must be called with `try await`. (#13545, #13573) -- [changed] **Breaking Change**: Creating a chat instance (`startChat`) is now - asynchronous and must be called with `await`. (#13545) -- [changed] **Breaking Change**: The source image in the - `ImageConversionError.couldNotConvertToJPEG` error case is now an enum value - instead of the `Any` type. (#13575) -- [added] Added support for specifying a JSON `responseSchema` in - `GenerationConfig`; see - [control generated output](https://firebase.google.com/docs/vertex-ai/structured-output?platform=ios) - for more details. (#13576) - -# 10.29.0 -- [feature] Added community support for watchOS. (#13215) - -# 10.28.0 -- [changed] Removed uses of the `gemini-1.5-flash-preview-0514` model in docs - and samples. Developers should now use the auto-updated versions, - `gemini-1.5-pro` or `gemini-1.5-flash`, or a specific stable version; see - [available model names](https://firebase.google.com/docs/vertex-ai/gemini-models#available-model-names) - for more details. (#13099) -- [feature] Added community support for tvOS and visionOS. (#13090, #13092) - -# 10.27.0 -- [changed] Removed uses of the `gemini-1.5-pro-preview-0409` model in docs and - samples. Developers should now use `gemini-1.5-pro-preview-0514` or - `gemini-1.5-flash-preview-0514`; see - [available model names](https://firebase.google.com/docs/vertex-ai/gemini-models#available-model-names) - for more details. (#12979) -- [changed] Logged additional details when required APIs for Vertex AI are - not enabled or response payloads when requests fail. (#13007, #13009) - -# 10.26.0 -- [feature] Initial release of the Vertex AI for Firebase SDK (public preview). - Learn how to - [get started](https://firebase.google.com/docs/vertex-ai/get-started?platform=ios) - with the SDK in your app. diff --git a/FirebaseVertexAI/Sources/VertexAI.swift b/FirebaseVertexAI/Sources/VertexAI.swift deleted file mode 100644 index fc4e5409ab0..00000000000 --- a/FirebaseVertexAI/Sources/VertexAI.swift +++ /dev/null @@ -1,110 +0,0 @@ -// 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. - -@_exported public import FirebaseAI - -import FirebaseCore - -/// The Vertex AI for Firebase SDK provides access to Gemini models directly from your app. -@available(iOS 15.0, macOS 12.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) -public class VertexAI { - // MARK: - Public APIs - - /// Creates an instance of `VertexAI`. - /// - /// - Parameters: - /// - app: A custom `FirebaseApp` used for initialization; if not specified, uses the default - /// ``FirebaseApp``. - /// - location: The region identifier, defaulting to `us-central1`; see - /// [Vertex AI locations] - /// (https://firebase.google.com/docs/vertex-ai/locations?platform=ios#available-locations) - /// for a list of supported locations. - /// - Returns: A `VertexAI` instance, configured with the custom `FirebaseApp`. - public static func vertexAI(app: FirebaseApp? = nil, - location: String = "us-central1") -> VertexAI { - let firebaseAI = FirebaseAI.firebaseAI(app: app, backend: .vertexAI(location: location)) - return VertexAI(firebaseAI: firebaseAI) - } - - /// Initializes a generative model with the given parameters. - /// - /// - Note: Refer to [Gemini models](https://firebase.google.com/docs/vertex-ai/gemini-models) for - /// guidance on choosing an appropriate model for your use case. - /// - /// - Parameters: - /// - modelName: The name of the model to use, for example `"gemini-1.5-flash"`; see - /// [available model names - /// ](https://firebase.google.com/docs/vertex-ai/gemini-models#available-model-names) for a - /// list of supported model names. - /// - generationConfig: The content generation parameters your model should use. - /// - safetySettings: A value describing what types of harmful content your model should allow. - /// - tools: A list of ``Tool`` objects that the model may use to generate the next response. - /// - toolConfig: Tool configuration for any `Tool` specified in the request. - /// - systemInstruction: Instructions that direct the model to behave a certain way; currently - /// only text content is supported. - /// - requestOptions: Configuration parameters for sending requests to the backend. - public func generativeModel(modelName: String, - generationConfig: GenerationConfig? = nil, - safetySettings: [SafetySetting]? = nil, - tools: [Tool]? = nil, - toolConfig: ToolConfig? = nil, - systemInstruction: ModelContent? = nil, - requestOptions: RequestOptions = RequestOptions()) - -> GenerativeModel { - return firebaseAI.generativeModel( - modelName: modelName, - generationConfig: generationConfig, - safetySettings: safetySettings, - tools: tools, - toolConfig: toolConfig, - systemInstruction: systemInstruction, - requestOptions: requestOptions - ) - } - - /// **[Public Preview]** Initializes an ``ImagenModel`` with the given parameters. - /// - /// > Warning: For Vertex AI in Firebase, image generation using Imagen 3 models is in Public - /// Preview, which means that the feature is not subject to any SLA or deprecation policy and - /// could change in backwards-incompatible ways. - /// - /// > Important: Only Imagen 3 models (named `imagen-3.0-*`) are supported. - /// - /// - Parameters: - /// - modelName: The name of the Imagen 3 model to use, for example `"imagen-3.0-generate-002"`; - /// see [model versions](https://firebase.google.com/docs/vertex-ai/models) for a list of - /// supported Imagen 3 models. - /// - generationConfig: Configuration options for generating images with Imagen. - /// - safetySettings: Settings describing what types of potentially harmful content your model - /// should allow. - /// - requestOptions: Configuration parameters for sending requests to the backend. - public func imagenModel(modelName: String, generationConfig: ImagenGenerationConfig? = nil, - safetySettings: ImagenSafetySettings? = nil, - requestOptions: RequestOptions = RequestOptions()) -> ImagenModel { - return firebaseAI.imagenModel( - modelName: modelName, - generationConfig: generationConfig, - safetySettings: safetySettings, - requestOptions: requestOptions - ) - } - - // MARK: - Internal APIs - - let firebaseAI: FirebaseAI - - init(firebaseAI: FirebaseAI) { - self.firebaseAI = firebaseAI - } -} diff --git a/FirebaseVertexAI/Tests/Unit/Resources/animals.mp4 b/FirebaseVertexAI/Tests/Unit/Resources/animals.mp4 deleted file mode 100644 index 8abcffb1ebaadd92d037f3770d65330c547c43c4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 10881 zcmZv>1z6Nw(?7m+mq^#rsKnACU4qgfBDt_jF1brfHxh!R0ullek`jWHbazU3cjs^M ze((2r|IhV5*Pb(TX67?9=gjQ)+5i9mKnsM2qn)Dw9{_*~c%asB2Rr2C1G}2@0sv^S zb`B1%0001H=V}E(QoypXapJ>7>NWrXq6`2E;NkV3@&DN%#s9UJ{*UGVABT#}qZr`~ zwnZup5w?G0qWvf4zuu5>|9kvboPRC6#LSb+Ol0FQi2c%!r zM&LhKR5m+^H5e%e+Cl#7>?kH502n^fx~+e4Tvia6^Is0RxLQM?|MCy?HFEEu1h$93 zpbs`ELw45o7D(o?tKDCx|2J(G$Uiz-h%@xT=3zYO@m-u@z<+p@SUAEAhUB~82>9QE z{38ea{HI{Z-9MPW%>OQa$fGMEcMtPn{NJemNd9}JyuU|^gppq5P#^&O`$Yh~C6X37 zqsyYhFuq}9<03l%*)zxmgPubhy9ot=X|*9&-dT!-(Ym-;Lu{?2k4#w9+iFE~Xa>-j zkN+nEu_GAnh~ytqc$k!M#NSFhs2}#|fQQ>fUJ&wt4;6YC|JoA6A&3Vo07y(pj3glQ z|6tMo+C5b7!5*Ey^e_F#7s}tNBJ)D}G)KxG#=k!Q!67>Wsq_3t^>;4Tc_|8@kji=4rZjt@oq-yvrGPuub3 zBOD$aK81k)f*+CsJamgJ@+|-b@^XuC^8xuld;%a5UJwX`RAO5=Ly--})@g@?Am1z{ zm>Bo>g)<79^=nf~)rp*wz$xaveRn<~0U#I9+`$>?1j#z{^NI)o1w{m*AYM^Xq(+Gw zX~Cnaq40uB04VcX4rvO3nj;l*4vro$s09KU6~xc=5E?18LLeN)czE30+_)e5+W`i) z=XP+m zfR~e(7ia;7BTO9Ow$_dh7XLVKax`(Uuz*7m5?p*hgq1TA0hbT}!W0SIXC{5OWVwH+AokcYKB0_qF{BaM)9Gnk7r*u%u!!OjtkK<>?vmxO%4 zS=%FBAPt?t4>lIgU^^&WLIh}L;^=|ots%%mn3;efU`NDX&deGNe+Xjj3`L%cALs_P zwzNW+A%i(MLhVf~9UPI`e}s-mfGyMm>HFb2|KUuKPaUK!+#G5THFrTs2!I}vbOt|M zs52C9g#WhV+ep10uA#AVEJD8Vido*!)uP39x62n z)%A99D+;s(hxU#!z^1P!eYhIrR?EL_$aZL4&tJbQ|0A({K6!6VxyxkcoS;9wGUUS^ zj!Ld6!h|*oUz~)#4zA5&W4)q?=~Se*?38$kXS{2&bDODf9@(%}pSIm|)~7ardbE_Z z+w!`$B0xW3s%~|3{}m;hDcLxSmVnajaZPc(#Jt%BEH_U=aW8&CjWGIU{48A-RSdR#g?AqD!J*%R|LA4p7BG zN1%xOI&M>KTNI0M(%GFblOyVTDC)KNM?R(=b-hUN)|iVVbNJ=ejjO?A;u&`jK^gls zfB4Y#m_Bck`5SI*yB)IQ*`MT->w9<^EVZ{x=YndPT`8g5nQebo`EM*nt#_pK0EY$3 z;NPbPagiQVdh2ohG~bHQCEGTc10&p;=Be;Qb@WFbZ4hKCwZFAAD%9Cx=9alKjM=t- z1Cp<$e>_`1(!@Pv;?bVuoy2Dd|IQ$uy$&uA=X7+Se2zD18quTZV&LrKTxDP>>^Up& zA>f0ee%k{39waCHd^2;_Nwbe$9Iph6_-QolB^9yy;yT`rE(&V-3#Mz0y-=Hpc7au= za{98RH9es%{FUyg zLjLS(hADCKfg-AE?$7d#UZzm#P92b$P~(6rA;k=AcU^h2Kya##i*E+yZ6oK7U@B|so|F?+nyN^(gby}ffkdAv(G`^jZ-C0i}Y1p8g7T-&z>Klb_FH&%6k zc6Q|7sGEgLOBubHOSF5hcSk){C?q5hfqPb6-rHm_cy*DMJQNnlJE+SDnl~<*Rh2$J z$nlh2L`*~8nbwsyuO@O^+IuYuzTetr8a&GF1L}iLb^8cH$ak0twE498C4@#iCt&h! zW`6bkO@SB`ZJ&06eC5|C6@K`%@{8Z@IFu~hl0H2N*a!yWu64m`Z~folaOhat$>Fpv z=|^8m+xc)^T;-?}eDP9*g}ut>8i#75ln|9^U89C{UD^AH>)YRKCvp|51Zn*`D6b9_ z_9{l0*j_Y|SYGtD#6|S3TUFOcMXDgYvgYr%@2p?O)(c?rABdn;p|D+g`aa$04|rT# zcIBy>y^hY;rpKav;Pj;N3AK&`Wc;+nLG(vpsq^aFtKHw1(-KwL7u_2f+UoeV&NPk= z9`wxAtGDq_FMj$@lMZ$1*7ff)-jS~%WV~X`u}MI0_Ux)@a70dgLuF;jQyr}V zRq^R|vF}V5GDW-KyzHW8C)7&8+6j&|%;3R)Q&onagUar%7gXwN4A4NSNjwL@7I0$D z^P-gbWkmoOga&3DTho{ttexJ8A@YQEr8 zZvW7mX++C`7U3?ry{Z z8@OTk0{w-zv1az7Z(p4G3O6?AhOm10b=utE2vWl0z!)$O^|}g5#344n*<_Q8 z&$&@v`H3}f1S;tSPhRVP5j{;^uagUtNPp`llcWqJ-}4yMuh`Ur;nExAzTC&-C6ki@ z#_wu=6)Rxps?jcz96O%;>M_T-YH?6`aYot@AQB#SIp86meY{YvSIp(#eT7O462E{2 z2B@Gmvn4BFqDi35%GWi%678Qo`DLyWNbRJ4>?(dzbeRH+u6ec7rdQ?i+ek_G+l-5&oTlmb2=t;W?;U5Zmny0Ni&sJm9pQp0_7E1gi74_?k zX(}4J9cKIu!6qq60l-ucY0md!jD`g1jL>9=-+H6T3zd8vK*LR)~;t4s3)Py7$B0CWA zroH3a3t+pP(@mNX)J2Rp>P+p4+#40N;=)vTOWFCzK}qPr;GY0hxmbzuVs&&+K^zu^5^MB{4Xz&vU?rxvBz-kz1PS;3@!71JrnLeBo6rM6WJl;JsuU9Sc? zcrD1N8W~+_Af&WIRom{UPHnojp}lwND9IKUlZ4AaopOk;fv@Mz5y=2%%m4bMahlwB zp&@oL`4jDw<+-vcFb`XQYb@&iV_JBCYnA&n2r3RpVC#5yqqsLMh1aQHgyz>(a>|hD ztr&XxDBQjCVk9p@83T(V{LVP8c;hYGO~0LODJ1%=iZF{WvDxBk>?ev6t)4sKh;NR3 zUC)v7rv+J5!!S7?Hol!)VKoy9s-*?}#V>QNWBDP&Er2P`rZa~8*E;^UC8mCy z@7*O)WKN@Vr#R+ClGQY9gkL3MZP#;eCT(Ba z=EM`{taCO>&C}t2pn79Amt(Ia^2vThEa>WxT>FW1f%&6(6kzD-Y*aTaTdNwZ>Pz5T z$1`JOHQ$TjcnI(8t!uTa=dx&=u$dapaZk_ujGEE*td@bG&sGj(?mf$2L)uUDBq?m* zRlL8J^#u=~a167;AffQuPL1vb2@>Aq)ZffY!xx#pnhm{dZ=?DHIfPg~f~=lQTwM{Q`?|-ZrCMV*Vh~Pl za!=F3DxVk`3-vqvi5!UfG7~(P)Sgjf#*uKKPEnOgJS0F|ShOo+RH{6h>NKkBC&kWN zrUEOzcFS^+dnKe2wE9h|?8w+%F$avGea@FFLX6)bK>6F?rP7PN3(GJTJ1`0dX3>g2 zPPt)=l6>+-ng2Yn-$EVNh3!`4vumTt07Irl6E{w?U8hV>LYWf42-xI@YOu-)Zj_*3 ztccoT>!A(a>lLvL@5?f-&83>LmefT1v_PAvMwEluJ?9b031T0)7?@p^;*MFWkZu8T z>lr6^d~j(yu8*9Ov9VbP?_9AQP@rzDcnr?wtbn$JdQl&dgqC>qn`qG+uo#4}RfC0_ z#8Js>3%*FFdHE6!{iKq!OpXu{d{%>~$MW!gYuj0snHM>~)|d90)?woyH@xwH-k`LL z=LFR)?T^jJa{R4l&ncmA7R046J4W`sols-F^Wr+A9P*0tj-55Mt97LYx__6L9DWG& z6wNPL#o>$++op*Z%BzdE1A#veII<~eM7UA)NUMj&7BIR0#*~n|!s;cvsd;e+yfU0` zT%fG(3)XEJ_$H+z)J?-dAzUr=x`KId#g%q?FTbqnWOhWK!e2BpMh3&EVVigSnUwc| zNCe@SM!rw`1+!W=!}nj^6U3|d&*jL{`e@DPP@kO@K1qlorM3?1^7cJmG1Pt$qAcix z_ED~?bLzm}>OPRr{PpD+@3&&2ZvwS?bJNMs$Y^RD+om_d!V2m3X&dv22-x{hK`d#GLe>(C9o{iH=Af z1;p#H0$xv}YQbC6n~Pgh%)nM(y_r^(=V=SSmR!)mF3pXi96!zPFt(>sPbOLn`Vz9R zzW1w?45Aq(Z4ErBLs{hdz4$2I)MGuRO4pximvfj*==aY}3-;p=Fo;K5YxisMW!5~d zK^$;piTf42AO#h}+fA=bjUNk}*t|#6_2+eW4NSAiO-SEGQ}Fqd-C79`yFUa?`%iV& zh_$^FfX8C8iQn4-xF_0i2(_GdYT%{#&*oNVl1g6H(Su$%2UnS zBbOdb>7Ano`1#nphC$u4;rDv+R<;(odBU@vi{C9}evqY;)!8>Y`qrGkN`(StI&p6> zT*}j}0##@uD4g77Ut=9cy<&1|sr&hrb$lk3g?xCPOa@`M)R*?n&rUO412u&?*DC*I zTUV~ilR%M26x>aB&OOqeoatJy-Lerky-L(NcTHvdwFYVQ>JT+?nPcJ{(KB5aiJ&fdMX=OK6cS&xzu zyM&8d-I(~{{G)_wWu1sMsT^ap5*HMXgjQ^3Z zbW4*!(8_Mi#IyC(o=z;^%)6biuF6m4WP3AG2El?0mO(#aNT=y5DY;aGX$Ct8(V@Li znxr%4?z>s>7eh|p4sv>9It;>z(_V*F$REp>vOu}(loKwXy=cu}@rL}+JSKTtt+}w7 zEY zeg8;9CfbdP*ZpsuN1-Tzk6mB;h-ul!@h(!J)(ny;4r;zEb$a(jm%TWPSj+x2;Bzvk z-VR1jr4?{g{T#ne^%nr=vX1#ioryH`6>LS>0qqR}MF+%dpDtFGKiU-<#=}X$>eM$f z$XhqIfN}Uz6mBO{SIGq=7AMn2+4RekRgtV^iNzGy7UBUi;VLXLt#v)mT-}md52H?)BZbeWsmP-q8L7QFEMEnO#SsN#lHb38Cj9Ywrs!F^`mQ0eK-EM&0q{t951q z^|`Ke@vDi`N7rkJYCMj<>ANJrVVlkR#9swOM7Iv?GW0sWU^!H%wO{IZ%1KPBM11-^ z@-bl86?ITiO?BBH(+_nyimHqtuQ$)#hg`C^ot3Id9G0;;iu_WSl3K&#jhl@phMTDR z2W(hCNuG0yes-KK5kA3775#ew%AozZs97#rG%V_FTC^7;M#%r%4sLHKZ-J3Q^~Hx5 zqK_7&IWQa&}QOlGyQ|Zu>>O~^|Hlg8#+ebmv^^^M5TEO#_Dv8AJTGvsRS`f zegq881<)*k{GQnlzw0~YNOz7slx(0K+X#REX;rsx{@V#5?ah}2j`WVpIYoFF=dSuY zLJ_7e){36<7xTV`4qunFAB!;s)wq7>=3Ejib+6Y=CuKYt^AuCqd?uUF6e@-SH+?LB zB3iLZA&Ot*y5%BG&gL93pO)v@qQUr~11DK5h-R$4$ZG3FYW$}{C5v8w?~*)0x0 z4R^s%oexf)=CW$7V;o`cSHA*2G} zD7vrpoe>5MDUo(e;~0smTa5`&)t3)_e*H&cVZN83Wpm*3pIAGKH$u^Yfh5UKN_ie} z4nLD43f>P?$)Ag2^kg&LBK(4V=)HOrO5;hs0;*5K|OOsDx-!-h=a=7*jV z>Q4{UIKBgBpHDPCm#ox6R4P^K)EC#NHUgXky0{SX9Zhm`3}?T1?cp?~+nac*#d6s? z6>K46siJ(={gz6N^L>S}>baz$j*$5I)#P8e*zJf(kI`J!`|}N)MB>-|qC7OE#6ek@Yfj$5I=0a17O~8^pGLU*C&q_D`xe*FEcR zV)kV(4pUkx5iYI}H~Wo8XgwxqFU*rJ?It6>o1D&Gonxcy>$+3b-SW63s)@X+@YgUI z)s+c=EK&=kVxwdEx?k(Fr}A`g)VGQ2Mb%;yxmc6=!XIb?It8JeTHwd5`OTu_UviAz z7i_;WAPOqjmK$G@$RX5GfUj0Mc4$w(_dzw^DINGi}AT&M3O{01^R`Mm&V(aC1 zN<&Rp>qfe3@URw1wi{Y-hgKUs5$sq4Ef?;PS{6+lI`DgT%bl@K+^p2&tn& zO2hIAYP>O7yND}SHAho%XQO*w1f4XVmT4ncH8;Fi0WYhp*`mbtDz;W(E_-4mo|!w` z3Ho^BYhc|I>=fBe0w2>@;^+$d87h&%R+Fdu$E*&MX8FA4$|JSdh1|pFrobjX|x`#LVkrYkCN7pwZM|Q<{xg?u8QSd6fYL&&fknXX&k-yg<%n2Q%k(& zBZt7J?fA4ah>v#oX6<|&9v=?zt@TBvp-Z~ZyH6FQ_vm);qr|3(21oeN?(@|;-@*lT zZ@IP##yxI(VwXf*-vON2D)bUOR5S~@OyV&Te}6`&jpoHe^l4$RXW+2UpnNa%zQMXp#-_gLIrRk7j(_jlx!mOZ zU7|!u;ALR=UZS-w4u7R~6fGL0Zt;F!+o3PRZs@c~2dHYiUXr^^Z$49BUDh8O>2;Sj zy^1&tJ~dj3{fUv?RNlC}_FX9^P56~g>p~N6MgRh*w$iBNu<}&EGkYw|L^cmkJa6^8 zp8gr?8rLI4ADhe>wOle;Q54ZDEjg7`6*UsO%r>*Yfe+^_GNlglM2`yZh@7GtUsRE) zZQmeF(_-A`vF4|8hHH<O{<75(2s_ z7cvBoKarh3O3I55TJF)v?s3WCl3T+jjAS<_KzVx*y*OlSe(Lc?;cIx2jb?Jfvlo*1 zQu+g8?s1f;vo;tqWAs?030NFwI=s{kl*7>)&j%<2KaNI=A#C%vW+0P$Dlld(se{eZ zK;-Y%=L69Mgf0zy@8u6u+zL2_Y9V9O*LfeMz8Y?t|Ja#EVQM#uPHsz^Q{!SuxEbu` z6A7qHdyO5c`N4ER&fi`t(e08XeBze{-NLYNgP54<4E<#d4tjS0Hlp}~lp=-DU?Fy% z{c`7ZG=H>X5BZCLRjVp57qt&V(#7)!o1>>wDIaV$jv()Z?uCMF#hoVH82+g5O!UU! z!KTtBxh;182+5ZvR#A?-40V#q=eE`@m#rMfRlGFfjr;70KiAW=u`dPtL46hmT4$HY zINtgp4h?61!T@<(CViw$JIqeq+m@l8y(EnFZX95)@wnuh{k?U`JnPh-@7Pltfy*Hk z$0DD8RI@~UvS805yy*QtZvQwFrjYmjDKkEs>seOQ%&#Xn9{#I#uaq+u`dA2oJ3AyJ zu7y3}-;62NoKWo)+`|;4;3e~%*}vC+u)nn&*+9=R?ylV$4kUFPemAFnuocYYPXf4h zOY)dn=zB3c1$Q_+=Xf)$9j+Sx@oR7ftuOn+#3g&8oK*JMF3y!I9;;^*ZB{l({8_%0SmX2duRz6uk@i%WbL2n-TL>OKu+9>?gV0P3E@T z1wLrp4UGc zaJ$>LB4ACsO zW9GpUn`uoF_V#;Y16;Aetqt)xy8EhQ7yj;7(zA=H_wRlElU{2i1^)_Vl#1v-wC%u8 z7$V!&PUgw9tU)(@g&72R*C2qx&VG~t1zud}!9CSqOwYu9|70YsfDwf4Kw1kR(u_ev zK~xAK7F|YxW+5n#suF_Ds+g*qD3niTcyPmh+^PLoX|!Zta=+2wOi9aIpxcWN>m_gb z`N)uoeGakOJJpaq5=W((q_}zIye_{LWKoo^Rhwk$PlJw1S zK#Ws_ysB3B0a19y{CU%{V_`2P{!1pb_Y4#J#a22=A6Wy)TXuEZriZcQ*F&#|K2u4^^>%63OA22d9}@6Pf13TKvaspGO3Ah;{N@i{>il4 zBa+?bc*dOEjX*G0WJIFzPwSJR(#bKWJ*5{xV(F4}{a^POdQR_Ow)vypc)VQV_B*7M zb~0sk`34_{O*gox5SzzdPgB2o=gwTb31V13-1To$%w804TN}-$kRU6`9C!w2T!do) z6P$m)-+zLge2TV1Q}HZa(%|c*J@eR4usgx+8*#&<(V?qJ*4%F@d8sL=E?=%!xg*AW zUB80Kar*dKZ+N*&)@wt^*;nL#=pM@uYD_8?lkiguFN}B;(G!_$KL4pGt-#^K&+K&$ zNTkc9rB34axV95VRSKjXOk^rnti(bzqNF!GG3@&0cYf(r|2)H6qTP0Nch|5Pbw59E za9Rr;{3tGQHpbzp;N!@OH}c`|JRS;i85^}$AM%KwyM&@o%S6@*la_BHWIU-=x~qg; z9tWS)M9{h>d`O!STTDsvIU#P^9 zjhrtq3eJmMlVntm5MrNWia?K^cMa{IqLW-a(PvB&K(kcuw$ZT@0X6MrP<`lFqRz;p zYi;Y)+!H61_Po=sr6k9tf4zpjqCxs-2U{yT%iECQA|?-l8<=M?J4Vf@dCPP0`t6S) z2$m^J*S@fwd@!FcU5P1TzU+0ly+qJkhGDKnk^ZV5Q=n4J;^!MV&3S&(f$&XHhDm4g z^K>eF*E<7#;;bz<+{v|VA0?cC?9dh)`_^qSQvCUovvR0d;uJR;Ul(tBHh7xPCCO9O z^D!djLvkV(YvD7NmN{&O30^Q=8$-Y3FaS<*U_N1}9PC5OL)M)-HX&>!aj53p_lNe< zCHE19R%+5bO=;wLu#c-1>7%P6&gAy1*7VZrR>gPPL0XP1k{-UKW@iU{;~JF8)6jNl zYlbqFebd&wBG%*$+1a92p7@EWZgmXYUp5AWup2cF+uPzLBEuH>dM2V;)TL?MQcf%Z zvRR{qfuSpo>1iSQVoQTDCC-3&u@n$M^hHm9jLI6%FnU86PGX+mopK5IYL|kzI2qNIR}IdOj#VwM~~byhWD)-DKu+5sn5{SPIi# zD)dH|G7&qi^r8&$1+zu!w{92#glD&3xgS3hOQ&v2o2IoK;uHWT9V-q=(PAKq+VjSsp(u4jH{=U2&}!cg0)JKKi5kw3@ij%LOtHJQ9zcAj z#xQ=yOQtc8*WMYp;doU}yE8YPhcq&8HBrYkR)_l1YOWigj%f{Q@AMIWCN&2{A177e z&O@BYQc*nixP|++7*0%vYkArIPJ0dxX)PZw$$;bWd*gRJ9%r_b6&d4M3eey=?uJ1u zj|MSi3~oBj(3{5{R1Y;YV=F=ow)#N(i{-c1$4Qkb@ai@(O3|ZlZI6fE%fKcgZ$eO?mwvnL<Cg7q9fSvItcmV-sbxV*n5I~~} zw6}8v@d4B=fB<2E=@|5KnQ zMgUfLW>EzIv!b1&jgj>~fq4H3Bxz|4dLxZl()x`CaiGbY9O0Sefwtx#3&0!O>_S2S zC(xS|ZQ$K9PW2S*D4NhZjy1=5-#5Sf1j9zKkfbMvfw6CYKRGzah1##!UgQ7rV#q-r zu6}=9wbYk|2WMrlXX%>2fITu)rl~R7dUY`+X?L?fRrWNcezJef%-ywdlD&+2Gq{4T zp=fmdedtTqFU#xW2|I2@JObiP@1MtSFlKeX?(Md$k$t@$ANM!7ZLhC=?KWR;x4L|O zJ*Nl@{pxi8^>d@Ct!v%pX1_1=bmJ^H&HCHmA?iKj%gsgPrtkNQp_FX9#%$Y7?_b#@ zKHhK8rw3cV9(D|}eO|WCzue!GoS#=Vx{`2_2wC54dAOc)E0*JOXZy6WhSsD-!%3v6 zi*gZ|bjZ%6Bywf@w76F{xR7vV|8&2;ToaQLdNsM$x56RzssDgyXADw8@$zvqjGyfh zf4=dw-*!dt5#}(gua&eSn!8T8xu7UFtgRyz7G!bV?s0(XgE_mPP0*-ac|3se;oqd^ z;9CypfFZduT(+=RuDZPNRGv(ZH_7;=KBt}E=VXqOS*zo2Aj>ipUEJ!R*`T6)d0%khkKKgoXjl=Fr<;{@^nMh;G%kBvG6v|J@+M*m|`UbMx#ZxGIB-wl3(dElsva5BKu9>$dxytMDvo>U~y(-s`k@7P;bQ)$9r)A50 z>_20RQD8%6$a`=GMRSg}m~kdH*DRJM>ZR&Kx8+Y_5kxEX*$k8r+OYM_ecDUv15Zhu zQS>B$sU`6_R(T+=G<{I?5|A>vDdgeas>_%4NcuRbDCZ$*W8JruG6`JAtu|ins})F{ z-d4XF#P4Y|i@I91R3ma9sxbowu&+$~^jTjD=^~lmq9rhvu?0(f$4q$7S*|*=!vD*$ zgQ6b2eRjlBjniK$6kqtvYLL!Ke$qAvv(JIB*oVjd2I8cO`OyD-QJ06vXh;_469oRd ztm3|h2wB==<1$*5A#O)5-Y-2>Y-Dsi_B0VlBLEJcgN|k!^%X%U9AMTkpDhd2UqAj30Dn)OcTj?*5#+@er!q=cdAi zP!y*o`fd17L{J86HtsZzOVeBjmxMTrKa^OyQynGm$U4l>)pql}hgzvGKVH2+I_F1j z@B`g?g|J0A_I62;?P7TRLEDcaSvaY4s}$@)wke9SkL@}79MM8S3*G*mc}4WB4SKaD z&^co}cW4SBgmUockGa6Oy;!tQCIka6TTr86p*Q|fX z8D=l(bTR*}9EI4;WzOw{m;;HV*<*X)!N1h8K#d|K5CE1v4JV)lhVeL3veXU*4H_ts z{s5a#7A_s@&M#on4LKhanF9y=^&&_NK-pZ{?zav5%R0^!jV0hI>IQ7HZyKSYDA?G{ z;IN43@Yj%BQm43^8_9}3kvjbc=qA^4#rF*{@6wlm((KzOHg}Qx&|qUX-oi3^lR5A; zXuT`2_%rXcqRy2u49UKZAc?&AxF}Y9t(b_$fw5T-D+U#grnXJyBCrxvfJGg@iHmJhf*IQP*)T*CGwcD> zA$=GssQ5oILA+#x8l3F~3fc@YyzG~pczppMM#Q;g?#|6VcT_02<*Rd z$37~kx_(uNxVxYJfP(+6rk!;aFRYW?*giYuX;H00ns9nL%FU2twL=m?*)3|bZZnZj zt2nMADBTHp2?+u}_9lqYpnliJ9}Q^*mJ}t*W#5>J2xQiySaV`47Bo&8sad@(Rh>EO z1WK0z5Nps31{ob5NNa7YbjuW`I^()MNQxpF0Vut`FRvI8?q1&UTvg_uNa_2F`ByfZ z7(-T9L=WtXyobfuahEq@v4-ZdgWM3vVn(5K>8Dl4J;E-7W=`emURWr(YxK!0KWu4) zyv3kV$kksw-A!wes;=*=;9umLL)=e3?^Xk}FEO>TZ5vOxC!9UXA}pe zH>Iy|1V|(wKDthXaDu?1j<#OwMhmoBj7={W2GpZDDv$kboGWgjvfqdI5bwtH0PZqh zPzlO<@VQ0KE9iKqOzZr>n_zYFw>){%S9Bp2Xb#OQ^-w*>2cffrJBA0XRvf)@p$ww1 z*YnZ%!5yua5qMuv8L1$jB2s%Ueih$dVM4a=E$+tAV!*tam3~jj-4( ziC%rjw<&FQFZ;7#aCTEZq@M!?I!xVV5XDKN$epBObxY{QluslS3{T*j1+l4=lAu-n z!3_SP>d?$1KU5TI(f3RO>k?!F?7n9K3-34A1UPRn@WUa5JRN+Gn){_%1O0SW=sm4X z4kLbGbRno7Z`~2!#cx|xd?(q+2;X*&2{W!Jd`|>DlQqCJ@cF2KmqP(3|AjG~7niZi zM9S3``<|{FkKZ$A9Bq%Ib@lioZUHeR+2z?Z0!IwN2;@A@5M`Z|Ii;d1gQ+%=I7n%A zd_L~WDr4LR^kXeT#&bvdpxQhmadeY;fHG4$#keb0fC{!Hb93Lt2(d+E(D27aLKLFc zGqSnFC`O1%!40qo+$Ps$R?+9Bl3wb&-tbopcE1X5w=nwgc@35CwZK*11sdmV;~NX6AYO@iCyrW z!z}wERJ5YGa*&$s=QkclE_a?rks5bEI`cxB42pvA!`^Bb1&_7G9R?agx{5qC2hI-X zVewhSQZI4H;0W$H)xA}8^w&w!2W2JMT^bwJ_R$NR(>qi4zMC<^(9h`$Ch^$fDZ9sT zM__yWp1j$6l#H1bA{Y>uQO+JAg`#r=nOpLEyS%hcgeMFn(|s6qiet!*I;#{F@Ee3y z$GZ2}6s<*L>L5AHegZ=ruyOqbfg2-`i1w*0T~3_>f-c1}J{PAoYw~9}7__|-OJTC= z4q{xM=R7K1_3-BpMeX6kkYc))-K5kE=45=l4}0Bg^hJo=Gq6#>u4``{02*64+2_lr zN9UC)QCbnkoQ}ZQ1e!366XA;GYJl1>54ttWZ~nuEdc6ILwtB{ zY=)mUZpBDF_NlUDpyW#?dC8uSGNQb~5XO}PSFwSTm z&5{C^=Cq+vzKl=H-*8q&S=$$j7iNlHgkmFbb&akKD?#oo-KMx4Nzxsmql(+h{!q@~ zdu2bp`LXZb%ZH%A%8^Y(0_M5|0>drmR-wjf=T>v3Q@FgcHBSos3`|uEK64Ftz0;q! zv()-#?~3#5XX1Cmuceq55LWQM^6jh+#hx;}ZnLjFf$EifGe)7-M2BLjBo6ENnX-IX zBrx=D-*g0W)B#n{$*}9GEm&|NYj!exUo;{{Byt1tm8CY}`im;W7-)Y!bcou;M~RX- zZC4slL-~}D<3x&wctPBv8QtlA=n>bDt&wc3I5Z_V;e=kbaVuvh3XEutklmX}(sASG z@h#N(^gh{9aFBl%&Eu3bD!Q!Mm}&$20$D1hE5E7Ur>$Sx@mgLi6^}n_uixbO2^6_i z+%j>JnU+H2i^ycJ90w8ltr;2+ZvMEcUBTzfmHpw}Vf>N9Vkr*8w_jPL<1hWFv68AZ z0j;|A_Yf}Zh^`oqh~lJ66AttJkkbngIV$i2t9Ud{iQFyW(Vv8%)!=Go)Isx`>=YS} z4jhx{(!woF`p1xqmnysm6Q=$nk$9u-5Mtb4XPDL9z2`iH2O&p!>nJGEvY#_Qb5Q$Z z+a3D}!L}AaZWJc@r7@J4h`gFLB9jo{MRnZfeZAbjIF>9umD1Nkg$fP{9TRks%MUfj zD#a{%$v}^1#^fUzpZz>VYLZrwKx5cSe5e5)hpS#YAkRk3k`ygi)rQxUt%FUIxhkErarA@gPVva<-}yAK>yL`y9iM_& z`>UI-lWY$RyoL3=gq_}npzULeE$38fm#gXP>w47ftE%o+;QQg}VO@Uu=n(Bd601on z)nJ_Po$to5yj_W71ikT)0Knf!bMl%E4quMw;+xw1{xWN;@jE9ajS1<6z7R^ z1BwY@N2ro)$gt2bO!m%~D%Kz^Oa)_qH0{IbLMJsw*n8csR!BX4%(w8>E>uxiQEXxP zy&yB|6@B+>ierW$nnULUhzt~d>k|U8tj!gOL!~?Sy&0Rw)DVf$;sC8hSe$nBP{3Uo zkcW=Wi0g-}+4^zOT4MMX6?gtR0TE~)&bf%4Uh1@tS_MBZULJqv(khN2#7;R3ktTHd$A@N znyP>XFcM(Dw4Mf+)b zZQH}k<$hVH!%CRvdcYKHN)NdaaGr*qzw7dhBj55;CeK469JJA(<6T;?;m1}xk~%Ya z-9%6g?$!YJCVpXIa&Oo^ZqIufVsS#B8f*p8U0T5xjeRK3h`f&UW9`tMVKw$LlIKI9 z)T>CCysS603_wbpsvNa7ZV!)fKBygq3LP&-IZcwfHkQt3HOcC4@E6L7oc%JXA}?*~ zW;dRc_reu@3%}y6bv7TPi_GQTP33R~Wk|?v2H@?HryB@#`O`1T{;4|Ztwf<*6%A6! z(mImAOn5)mHq55x99HDFcR6{tDbmmteWT+2NW@LtntHvec^v83X7K}GPxBekadoCo zNNm8BPZt6OYS>MDF}Cp?9r`=oo@fQkA5`>JV6^W+@#cJogfmGNU(k~Q>%VdY0D9pu zZN1rfGU@^;8A>xqL!nW4^)}Yr z=#7wfgJuHvQiZ~Za;Sw=TY)0i?A}|cY~MX{_PLhI5K&pJMka7agk8wjkD2FlQ;7pu z@nJtWs#zr_JKYt5J~{B2uoPz)AgaC6zADv!J!zy^V(aZKaYXDiGCK5)dL%I=60J@2 zgBz>N_e1L3J3`4FY5;u!QfD4rhu{Gd-L)AFtfRSbGT6oX~_x z;IW0@XV}xAJoILmXwqFSiSpg6SY}tCRS`??o+q_?kyU}8QTTO zE5Mx4X?nX#IJxsX8@W>EK4G$SdPNej z$G-X|XwST(=w{s>u2$4RUR9!L+Bn4>!v=-9@b+YinxOq@pEHX+0Rv@YkIsj6IRd;d z4D#4_Gq_IxcPk^~Rx3xPWK<2rO{L=2AH!_l$#P{j1BHUEpYf{>9dl|B?RJdFtF~@KBv}7qK^kU!>>eBPQ+KD@K3n04J zUv#jUyOYY-7_KQW)X#co_l{43n>4+@@}!yT%I~@-Y3%YWOqd(gAgOJ`k-Zo={NWFY zVwlokA|G8t#Z6DgjC6zJsH&~;)?!K(h9zXN@(cu(5IT4G$Q zWtc_LQIc58G}x61Q*0eZsZe>nrosN+(6)PPXd|6hS2m`4ZD`9s+54L~R)n1Nwtv^@ zLV(X|=m%{RM;D{>o0`DD;`xvkKyZepfd zK0S-D9XJ=4HF8&NJ+X9)ih9Bt59hre9Q3gGiT*H1=dlm z&VZlNx55d)tEP;Ick+VlW)8Q#{DgK)AZfKYe2 zb&8?5CHWfMa;1&N$5h|t%v?4gna9O#BepudmjGbKJ|Wsr6wLTn&{;H^mg>;V`EG$q zRs5uZ-yG)npc}!l9*-{%>$z_AX#6ilpqbg=#3P{=*fMlW+6#;G)%o?-=5k z$?X;p`7WR9c+)6b3w%;j070m3M0Kd5fH4?kKv0g+1Gg1k0c?= zx$}JGVE16^+R8TFYFPTRl$l9zW^=SUEpsV1_JQLqlJ+@piy$1@7TdAVB>wbL$#HsW zsKq?)XP8Sf_!(n>mDK)$AG>Fc=DQWFX|MO?L6y7@g)~jvgK{k~9cT%3n>y^~wj6^+ zduQ)7kUHUVskXJ@G>JC|qT{B7)HR6AeKE4fz5o>$^>o}6r_T=zBWGkibwxXtY2ZT> zpNUW*a61DGJnkZ+AdI{)4x@46h)yHgjubO>ndKRfE-8I~qVSr!Pn7H_k54@{3nG~z}j!H}?>@Im8VtqG^Ph=Pm_>N63@ z@qvkE{*V-pUaU0uJerq)Yc~Tc6g+{%b|TXzh!Emo56;>Fdq4FD?eO5PmU>0YIO*bYDS89>0t-$6n*^(%43RAw3B2fHy^|GC>PA? z>zaxcqpx8wqAqJM?||#(OyIA^b^5%|9z@@bq&v^t=}U2b$${-n&m&jI z3@YR#s$?@Vu!IIbZFxHUG(7>^v2l`I1P7I4#%jO808Mxmcuma~3uSCZ_7LkIAP+g` zZUP1!$*PYsI)~(;>^oXmiV&dwgd<8E-aYO{%1^)~RAN}kShuq(H>=5@igz3$ct1cs zH-^ zn0TGgv$66vtBV0lGv6L-n|bQAgvM~w`ISU@C_npU!o&=kiz34?u851Bo?8OWbKhJs z`UXfKR^J#k(2=%|gF!&vPf?8>zeK#GW>j&#Zn6kYOEe39^FZDN?XbS17(1`_EiH`P z|3#IZ8ZscNw>@UTsnQ++^aJl)Fn?_`Qqf>)KPWsOFnnK>W_j4oE&%VwlplE9 z{}{v}gO+Il%ZxPK-M=Sct*n;#LKAU6tgJmze0PA+*}-rdDJpWAksa&Ac4e$i`pl+O zBt8`8b`JR^VJ1#8h8trU(V5t8)WqAuhu6h8m#7o$a{!Vm-&m+#JDxD44Ha|u%{uvv zhyo$TNgclTG;L2~==X_8+h+kHh6w6}@ zmxIdhg-i}@He_1VRtAvVZ+#Hd0v7mS4TJsm$<*2}yB5A-M)ZS`>-n-V>u&U>fv0l6 z(?TvQI1R+ZMV*k7{sQUsf%O!)`y4@5NbS^mVHs#DIzz&-?1@-Rl1bbJ2EH`Yv(DJ^ zPIp+@bJw2XvvQ$~2MY?txgHwlBST_pP_=vs<)#mO!%mA*r~;}UBp=P(>6f@Tf4cl?x}^`g0|105}iAKFsXEINX2 zp^YkR&$tnrF(jZLY9Y`~A`2mQGA%h8sO2~VPr4{Y44RjTRy5my88x75HrZaWR*z#5=l+`?2{;R%?k=w2+GG7_CNV!){w9 zDO{BbU5gV=Sdl<)_-(ZXc}hKMHfh;80DkNsy(?!c~f?ieqq6_ z^#?KG&xkkZmooS5t>PXjW-@s;p=zxPU5JKzXtH=U#(pVn1gF^9^WpeI~pz8^5q29DH(}KgoCJsqy^UrD#W5GO7FAkGoBncU@3NqVEmE45_$XM($37M zO}gmhe4@nv3OaG{kUt@hRa?d^!nS-#VS^$caAn`<_fdad6Dm9kucUAprJgoH3|n*L zefoZC>gVjISE;nTYHHaSgoL4;mk%?26ObLT9sMf%dRm-A`W+&X8m)34%FSyKq4nrP z;AhdXARfh;t*v3kAP43}ds`@*Bm|E}R0R_h?jK(!CVG3|(x*E#kqKPL0hEySSW09w z%rA{Tu*JFyPq#fPEOpTe_XXrJ#eKmf;wwhn)P0~e7DXQHOk$^BzyHMTOSptdaJ zbcoYq%ACy}-O15E6784JN#R0El z^-CH2oPl1gphg+?X@=ttM~}}6{1>JpS03;$rY+bU2#~ zijMte(ZP2@2cCK0gmp0TGAC(mz2U5rfgJrOtdA_$8Cs?_7|8%I{+ZZ>J&pktGwNE* z@7Ag2XTGcNF~(nq4Y#jhwc{BNmrp`M^t;c4XE$PbD!^X&WMmG>0bPe8?`^=C)l4^O zbi#?wjz8Wt*LZ|6(VGM~v$w5dGM~GC;C;{<9Ef=8(c->sqIkt7n?!~T<%+F?OGiu9 zB}=g<*kQQ?SC#Br8|ok*^zZ;}47jQK6iplZ;qBewgz??188q?~np`T5AGppkC(B|xlh}GHXQjZ3%3|I+ za+5WL!fydo3nO{uX8wGAk4U{o{jG-L;>8?~#i0bLg=sk-fzDtt4T zZJ{)o5k^(XwQnW^Z{TKeUPc9r$U42F@hfE&-(deF1E|K?D!F7m#Pr+jdU}A*)ZS#D zsd;LXQn5lp%Y|1uC)cXM`bEAXDS3t~ZytktMk`7S`o4|sx50~#xnAF}qs*X?2|Yp{ zl`_+s7J^GeVS9$TW};GaJ>y}`YmsHM5jDl=vlZXxFlQGBv0OzNfubSExM3w_EYqf> z_X81RkB#f(_uZFxTX#uY$SaD;wIE0b84U+Uii*vXo`pZL{B)Ggmf4$KHHwJ7O_5iw zf#R0yuzymXcG&2?xM1g{RkKE&T#I*f$*k>E3GjI^td( zz_kinm~s~!Uu9}xeAUlLbd2-0JCq$HQ4k&dp}vhHD5+q}!18btKM2|xySH%v)oJ%N z>?5za3sF-I4T*xIsEAJH*L0L7*NWiT=nVfxpJ%Mg?|q%1OLGg341R79W2zUl)jUM4 zy~hXZeL143FERb!4aruDcQ>{uu|BRZYsOz6!0usjc!hS(FoNZOb!Vx^Tdn@UV+}!! zeE71XusTU8Hw7!56rd>t!;MhzBXqNa~;p16_xqJFka8?ef9AVy)J0AIVtMnYJVNo~LCVT@Hv2>~FZNeklq@kGD z73MN{sy?kA;6N(bjDm=|J7Nq<-sv`7PYV|1z!)s&(I*!aM>QxmDNv(Cyc(|+_h--# z7tS-Yt7|kUA#SX~#M#0g!z_p>IIxD{wfEL6c`4)p+~=`TarWTEI$fQd&8kmzVR$h@ zR^SVUyJj{&kf%*eW62;hyGzQQXEH*zNv@dZsPM+i`4A@=Ren4rH>8MHDWpA#e*hzH z8b1cq`noxah9NGw8UiTt_XDoF76dmBYFl69+?j4rWiMW}H>b0g4y8;hHZ zqAt$E5~{Pe3Kw(vaD@Bf^%YLy=n$k+!9EkuAkBOhLiU|gcp|BTMO%RGSmE+)0UxNn z{2YcI6{fq}xX=`(+}nB4{Gi=ZV^bq*ejaQ^&d}|is-d{~ynW7~Q?}HBPB!6|O^q}z zZZs7PJJlzro*nz;h7b?+6I1uo@V*R&{|0^kW#pN|wAYZ&iN1621t;!?s*xD-uO+)=hn0qeLqR%MaWAoDt z3Yj)~4>WST?4lj%R zris=UhdOKS@USK-EOW^#<_ZruiPzPJZ-7wC8Lt|<$G@fryXLM{My~C*m7h2MdJ#@9 zVi)_rBnba@6!X6(2wAx}|0O|~scW}492dNGOaEiVukO0nl+9lfa$|P*A`ofW)-XF- z+Y`*h+(nT8-Q5ARtg2i=na~Hq5491q%RZLn^7~16)Jhp)_N)t`zfN8z&wY+1f7Q)5 zKmQ#1;=6g`8_xTz7t!D^X2%N#ID!&*Ou@v+xv&l z*}lz>7j5;=JHB>8FPB}uPh-r&zmA^`Tu6j{9{Ntt&s}`(kLFU^)*cum*X^y{ulupH-B;K9`122e?Do~*B4*oz)MD`KxGV0Uz~hW zi5WkH1u?f>K)E!SrjzzLltdK78e}B>=r|WTN6}PK1s#_iQUIr5hv*A6Oa=!bt zH+ICk^2^bhTK?x`c@W8pD+l=vl+qbvgW1F z?~D?>7yIWZ5@bmZ2-q!en|ETy&ZI-iPrSIb-E1)^1K}OuL3t!Q3Z^w0qSs;@7zE@}E2a_+^XtgsKvI*^cPl0hv!?uj86-yhH2r)DUvpj31B#JxV* zV9c*CY@;+r+b;(RwAsZ70d~gOtql%msfUT^%L;Za8?bDZjIMbpY3lS?U}Ii@7t#b;X3@ z&A9uFg@;Q~I|OF#IE>L}v*TwY`T5DTrz-&)q7qFJkf1Mpf?@I1FMQ;M^s+JlY+Xrw zi~M$6paoGL)JZb(>4^+@k_!EB*-Ydl_yAAP_u1%IOG>KQPUtB=cjl2jG1*Ty>!*vN zn2NXah-kcoj}iHv97jJTuS21*dJoL>ozjs$=D847!|PlST0(PTD+9=4_XXd9aw?Ws zPDe%_IcsEBAasVY1oU%8WJ*MlR@zsr$9eaW4wP(3H|M^X7J{jQI~K=B57xABYs`R8 zs&li!6mp-u=a?O)o6bvjxe_DPVn71K6EZ$+dd$SX{CsMwzpNu#Pm7$PqEb0Z@xikbQ6%tf_ z#`pGbo6@$0@|wG*qR3!>Fq)&W5yKrFjOT?PyvK}Cm3>hKsCYX~Af8hjsdf;| z>L(pCz|oF02Cu?OdB}qNJacw@BI``qKfTsD3Ae>gjOE*SRjJzPbv(8OYbtM%KN2zz zS!8-ku=(t~s()L4vAI~7XVr#y)ejqrB`|74lj?k%_%kurTBLvm0yO zxY}TX_np{WurBN~jh`kE-PFjpbuW;lw?CXm-$pKn+IQtJi<8!yN*Glz%zF9ZC$D;}vI1W) z1ztpFIHHNI_M#=}fqc+6*cB3|K_YZe)6lO;_MaB0dGya&@y50%=Tbfkd#pm8nEM6b zhx9`eX$!PN4u}1<0>S9I?_RACqe3PNQRgZGv8N$7??*ZtAv^diFJpj@x>09nm-|uH zD*X~j4t_j%t(zz-43S<_pyfDEN#Ry`oPf$>KLC@j&UxEx zmGvV#QA}=gs?&Ko$Ss$uUfR^Ac4T;Mp8Db8YtC#67{4k#-aI5z`Ld85@(o4y$4knI zRxf5$Ky*bw2Du!EhTLwx(z>u_+~Fkys~I4W{%LkKS4J{=&kl8lVyj_KPo`TFYV;JY ztuSp<-qnM5SZN8?D2sdUqLD1L4N9<)kDhFbM3k`8q?9z=(RwpLSpwpi57)GNr3#6& zH|RDM+o*~$?EBL}5S)xrv!V$FRsw=hkv8*7z*xr_bo|6e_JVwNv}1PRS`&hf0Xolt zxge$CPRZW)DX~a9t2Ly`l$2qwizqZ5404|!Y50^x$UHexmrF0B*3h}Y`hpaw$0Df? zP+N7g_@7s=3uRB@)Z=wRl$tI~0Z{hGZ6sSA}b3JvFv2on@@&VJC z|4w=8m@;zQv}F~WXpb%4*bM#%Vqqm*(MS+__{U?L)@EQJ3(~W+KU(eyM1pY`g9E}R z2bFSar!b!-=S&3eJ15SFMqD(Dqo&W_3E=BI5*&l=e10;d=H}^#4hpW71eUbBj~+=o z+J}v<>0Ic+S1o>wl9Ln>@Ms|0Smr>~6){GX-^UvGKDKM7w5PzaL+;_%CdUu8yUl_# z0nL`)PPrGuP5?~}J?Yrz*OR_Zerw97N`=Qv<=}t#1-nI)w_bjVWWM6t#E+p7s`y1M zlnXUo{T8>96s6a@`Bvn-XlP!6@0t$$F5ZqU_dbpC8e_3@w+)69-(qmo4|)riAitYt zCzm~a!a%@;E&W-zVYG)|Qf;E4tCEc)|mdMdl zxPn$zP%j&!T(EX-;fl|+c38~gyu2^09U;zIZDkNpewYV--ibu;uA-?jwja^i(>+{( zXz3DoFZe{%;7}H#zeSFV9QMIrW2(_lfk1Y!QG#Var3{N$t3+l?wL<@Hrtsvz>Wq=b zgItqh=@D96evQFTxrx*6@aN~mxH57(OfM?{kQ>mw!>s%Z^0En_sD?l(l9c>IPJMOIij$4_Yz@6*LLcX5A&oJ}nIj9wE zglJ0EK>F&&W$-1K!J-7q4_g|}$kgF;D8|b0^YH+EE-IM{^nsaWfOXq>#e610@}#=V zl)BobKxq2RiZhw_;s?NW;J|su7;UJ#!wJ{J%0xNojYZZeR<64V)fv)=%vYuLyQbaK z_jnDmub;yw;yJC58)P-466r+wkaY~DJWZ0n~i#+6_YXQ%=T5u zAi?!Y!qc2{;m#WPmth22o9Ij%L+&Dl8gTmTy{v3ytyIg(Ee(2JULSZj8(#|=Hl)iaUPU*3?7J4sJnQ)TL=NM|c5n^3b5`VniZ(z$N8UN*Em``xI;Dj`=mR2o1Z-#vesy=NqvebD>pymrGO8R84?qVHRMm zPKTJCHgcK`7oJBle2f0-+5_KRPAN(t{mhWNLo2>^L6#}akGNMSyGR-@H4l_gdUEQ; z!RmbN9E!3$9XeU9U$ZehNAzu4$le>3K} zCZEl8mB)@Hg=aY}x_{{!?IPTDyq-PXha9e6_f)Sf$fyRf?k^+Ox^ zd0jtzO9+W6h|t`rZtVWdCCR-Suiphh=}_h3IJBdbat~GKaKLCa$*nEF@r&iw!WV>q z-uql!xgOJ+$Z3_ZIM`YDL4WW(`8{fqhu1o)deAIMmy~A1(mchUx^uX zKdEz!jk44WArxF&(8JY@fDn_{=5D{6evOq^laOu3oRID1%%I|g=uWO1R=+GH(&m0t z9kTZ?#Y%wneWCmEaw%QS6%3L+FPo|vpXDI9@imYNf)0k2t6<7<9Pv&l+!Hk5EAX(V zUW7jujQogPhNBwSP3`4Sf#b^cLe#coBBBcD!v6?(QIYNoqH0TgBI8b>~$iG{lz;D)W{GIhzhjco=M zS1{6Hb!GOAZRGJtN@q=mN*iyZGliz`Hlf7Cr*0%je)`$HNw1YfAsyFuaCiL3L(qx0 z@~F(h7bS3X+cDf(h+e9$AEDMm$MvN2D&GZJnAK=fzL_Uof>R>mJUzJ5O+0EM;gzX1c2C^txA=9P)>T@oMsXa);svA?j;^%)K!7pj17` ziPj&ULqa1wal>JAvuxz1!tB*uG8t870bk+AS4SL&wg2HNf9bhmaVt@@h2KBLP*MB zNpQ(w%rNxU>210Q8mDUp6v-^IqMHm{lj>@<0CMz6&HbA~&Z;KV!d5NGg9wY|);fQ- zhhZk;(SrurhJdYm`mG`8AM_;af1&5_7x*w+^M(sL;D$h?9FP^eCh|`HRH!oe39?)~ zsq7CwyVU%lH&S*ZSIW)8BS%`i1=JyebBw9i5E463RE6_F3Fum!AyJd38jiEe2fS~54 znO<6u<;x&_p{L%RS5vDb9xu&9%_=+|kY&!X0~TWi!mqFc)?~*i{Zd6S6OD=}6Oey0 zC=t~P6`h(IGuWd}%(^j1(>Q>qrNI;3K(PdITBG5Z$9tXH*G1K!Zbc7eI&#YAhPOi# zEvAK`3ghNxP+s}j7=0XJat+L$0#X@Vjwq1Lskgc+z(i<{k*!ZVxC@4E@sA)>Co3$F zerl^NeM02A0WeQre<4(BJY>;O_m!wN7W>|W#HA4LR|;>z;X^f0KGJe0#3Nde(}1}h*jK?ncAD{Qspu-RV4eYq5P3?*2ZCwrZzR6~GSN}f zkzHR1X_J+u2`ab?)e^W#2T^0XqP``NMoW*ewU$ZCBiT=g?l+CWZdo0Elnu;Qdby*Y z@2W4)pa>QDA=yRLkT1#$%AJk8vA!`zKyuGy^hj4K4v_PyPUQ3E`ohwX)$>EZYsePj z7IATcnD^TQjCN>&c_UdszV=7rNer1x-1w25ubSgudkV6VS8oM6#JNiKzn@CXE+l@G z8ClXMD^cmsVE7Sxy>5a`q8$^{?5|(&Bzc1$QY%*pY}^pucsbh1{)IAgZ-x4wNk_JS zR(7kq+XDg2%0}jI1>LGZCp%|H6QC2|t0yzJ=;{tH~ zb;k|h{_Bnh!1Mb~=l)s2ju0L*G{W%YlI0a*Xo{GYY$tiSR7qou(AS0ea-lkq&Hsm{oqpSp^P6e1!!yfSnmPe=e~U%+ zt+T_Qmp{Jg{mou}o9tg${sGIZrLFTe`eu;;mcN0r{fBA&X`K?*K$|!EfA?9i{d45a zIsvSIS+KG>;Ez4u$N{kYZQs8&Vfgb={WoOdmM(vw`QxGaz4(vqe?NMEoj_*$jrL#o z|2GW(LJr&S^U7~#^+wL0qWCv@{+R!7*#48AKiK*kJ^!JP|4PqaYX42o|4lw@e|vrM zzm(6vdxGDR`)?fmi+ouBa#L~u-9I%4_)}tlKL}C%n;HB8`QPxqH6L;Q-K^xTk%p12 zIe-Re`@0JWfb}nzC_wln{|%KR-#{pr-E2=0MIa;H)UgC)=v=&0-n zGy}c`l)vKPpQ!$0>TP#RCwprn_cwL^*_-Ac$p1&H|FnJfzqy7#yQjR#mV<|z>n$q& zmkuke9Nb(y|MK#$-Q7!FVo~^|vi1J%w8PFdUVk?8<`mQlc@*@22zv|QHkvLCH%`n9 zG21dTTV{-z?ZnK?%*@Qp7&9|7GsSEfW5$>v=Bw}D+TE{e>)xvxjii}Ar~CBG8A((9 zyd6wVA0UY*`6=c+3JzTk()dR(>Nf)HfoRy>5w43y|JcIVSP_hPi|=84fjo?eW#M#z z;gK@QKSZIDJgZNULx1>Pc71eRnr+QGWo7fIxLlNXl+JLwoNm~D`(zFoA8?%{Gr{J?f;kAKQ28);oVr)YOd&b)L>`Cn% z`j^i3f}PHRt)`A<3w-iKB%+r%gM12hhF(XsOwf_3?;jQ=ESK3kSBTLmWL}U_&e#Z0<2D z4vxoA`Q=BX0&7kR#PVCa-a%7R*gO?Itj{q8dp(cv@E+|-x=k1RBQ@N3(b}OU3k2jA zNE$Fu;s=0Y0^)aNn(pAJ^2xIAQ9>oJiNi|w9VO9(URuVJRbb5@3dN750C{p$|F56Lw zg{dJj9~SAzAD&7uuaoF#Mm| zm|`%}9n|nj>x^vh((EB3=i4@-#Dy5oEjB*!`tPVmdzgInx<75#8YQ0^A)p^FHXkuWeA3Y6dDf>tG@!&XBGIfz z#WsR_eqVnRw0{RWC+B}H#(^bNV#aRF|1f9d5jP~kGD`5DR!;=95;-G|7N6kG3=&KY zqc@ctt*_jz9(++=Vjo`AZ+<+S?U+a5=;_3*hRGX|9nLSX?U`GP%RGh$u$v zc4=Ba24z@A!|J7>D=a8(7P=bt$V%mL0kr^E)umq~DM2tuWzWv?j_o82+uS)OCy!zOcHjj3a@trd;mt0J}Fd9F5{SA03N< zp^r_B;8#m(M(Owj;2<^yDj>mr2og>_(f~a)0Zs+6aCT222>(t_jL^zX*0QaP#xw^r zcZsi1fP|g%iY2=~m`Xe8>UB5#F${c9et^Bf*X2^Tx2a{BSK(->*-Gs!0tw^H>oF9J z`CnmSV`5X78!IoY{fKbCjWLRhI;A`Vo?qQMn)X-dv2m12#)5}n(88uUjcCJX}6ciZ+WXlxd4?{^Pwss4?hcjIv zjdL;5GQv}=Q7)IB@-W`ClIfybN&ceTT9{i%Vo!N&y1&cr>82r|Wn3feGFBbH;eVUW zZwFc)Axoh?e&l<(R`l9Bw%P99d3L+nC~3C1D9w}=Kf~l*$QVULC)_9Im9U(qiP{aY zJC0Zw>Xx@s?n?^C;sh(sN>_|T+?QhUdW87bEF6TrWPaZ-R-eAB3X+Zgz#hvHW= z?(@wSXVY_Cs+Bn@NF*#alTWNxGG~t~vyuT<=gxCgRLsQ!MRBtFmOjFf-oF3_ z3XK7PVPrnB*#4-P)li1NFnneGm-d*pgO)hVgdctP>A_OpzXz>{$Jq$MU4#UC)#C%Q z!>sBEZFfzG44_n{YW3Mw`$PE|1#vb%)l(=O#$hqtzK<`c4nns- z9g^1-^j4n`0VRArDsMeTPVktrBSm|nwumk1V?x+i-Z)l6+BrqoxWqof4JNmkkPyonVDYvzfJPxw>Pr!AxsWDxvt(tl%RJ8s%ZU!R))pDC zSe8cV;`=fk3QZif0?jC*>V29xj^67k8#yvzmBF#8Sm^C_EhB6Uh+o z-ARzgKlbO|iMuC6j-1vpk0;%x@Z&;KBCQ5_STY5sbYZc$MN5-thj538v?P->Owr&x z+zIaqZ^XDMH}%o@4{pl1RHo##3BP#3WI<(9Y9{JS{Hai=&@)7-!QRDyQ)ZVyo*y>K zc0XDxUZUkzBXisl{muw^6Gi5w%T+xQITsv35+70@5r*2~8uRL!NWa3y@I2W;!nY|0 zq500#xM4<)$y?%i`DZ6^Jj!@7r(?!brEd#pb|tUO{mW zjo?c~N0WiSi%a5JZ(@ds=Nwi8h338fVlw8}7Gk6sAzhF+?sK={9_-V4hr=8b74=M* zgbIsbdBn~nt;{1fKq%Mv!1Gf_1Nd<)-fAvZm9T-iJ zvtlFIv)70qXhqN^dp?=4!k}k_hI_-d?$DOYBJXfi^%+imgKHUx`Xg!B#)cKOBZhjE z_+(6bF~Z*lhT=LVmgLu^bR{$_Qhiv$T& znW~XQgk1^P_KO&+Jf^4zYj*{>jkQlucSzt4N1kXtL+8j|ayj`xpp)o&N5@^Ofq!3* z)~os=CHTwN2BjEb0;z?LQZyzE6iG@wm_@-j%-Nk6%Q4G>jWys ziKDurQW0vz6DiFmW-_9y8M5YyU`Q}^n;o=ig94(Cx~NB&AqD|G|#FXA*-Hl45 zJIApg(deVL!Hd|jenEtOmw>R`FSCxg@UZ~Q|A zvw>EqUSn#P`3~5%z#m9771(+}qD?yM-lh&{XtY$&QsQTKs*~ zW1Xu4$D}NC`kCko>s9~YE9JVv6-U20Yrk#-k3E-u1HQrJb-RKS z^J}<^LR>l>-zy87f@OO2mN6bdCbXOq#8RmR-V`#Kb;tI4VUOT2?`9Ik&p0)m_eEy2 zD_3DBo*ie0E#I^SxG2*=vi-+5n6AywrXPLlS%3>RyV6NGH55B+dU*_j1bzR?__jr& z`iqlmxb#5}GbrxUuu@J9O4bI}gp^?qn8t<%eV2?K`l*$o>$Q6uQ7CqNv`gDf52Tfq+Co_}FcQLRH_3iB!3&6S*8_9v$X2OkJDHgnij z2m*oZ-L0>Z?_&xi)TRXwb1vZE)cYy}dddv~yT?CYL4AgWtnzPGAV&3HFblKOci09j z{H57C0VJdflhht!m4?FIQ%;5ma$>i0bM&cZCuJd|Z9{y-zl$B$f0>N)DD{Geq(AJs zPh4bv>K=FAKjv}HxxJ`8<6(7V+mEiIKVyjj>^$_$^BdNb{azX)j!iAFvul98Aw?4< zMeh578zK68X7XEEji-H_MfM3PIF3@;K9Vj?cPt5*k}w&)5byy1g1TRDT$Kn22s=@x zB&;5H%y-8X4`j>yV4pZMm2Z~Znjw)}#&6$OYl)ukogixF-k$G8e*OyT0gfz#qt^K+ zYBZ-|99;(N@(DC9vN)|+--ClP>RCwE(bTjwvQ;Mh;l`51`}C0vMpBnzFL8LTSTz_0 zc_d&JCrCdT2@ow5wCV3P@w-0=jTYhO2ZwCJvvsUzkXK&(^KSeiw({vZU=q$Y3BD-% zA-~^U5#G+#B!xQ^TZRW#8gh|>5P^aapMsE={2g#0OoI)XnH+_w$hcOdZJq2`FETN# zOOw_~OQUvos>p~X-LB4bu#0+`;8^sn6R;SHEh$hH@BPzW65!3~(MOI#4oQI`O^z}m z1JI`Su#ejB_ZsSmi22)sDbeDH|^FY#?J(7872MBi-KLjN5#2EwcJf3B}Y*7ap?r{AD5Ml(r#0W&8 zKeK&(7RW!LdMyZ_%E|qOyrg>ffeQ!jG`yF4V+*Ol&!lS}!cBPH7U8(h6=mNaDyrjHI$C zdpmdhu^4H1Yj5k!*7Q_mU=q87j3>;FWB`REG=PjZkb7w*ySU5Nq%kXl_TuP~(b`_e zqjJevWW966;!LIbE2k~wVo0b1gH`%io^38?Rm4p=Fz7<`{?P|}KIix+@AcE;UGzmT z1dIg$))wuT(Cv5O+wXF>_9WAT@R?z=763#;p1cKAYOIpdwjZ)p2bZ2Y@5?W3ud}L}`NV21zAW3Ns2>gR%_C2tT5g zB;LTTPS{4Qo>G9xj;rvu(ng7B8IBPmWoHH8M>kj2!*jiph$!D}w-?A)@gc?;yUUXX{%; z!Y%Hz*0cI>DlO2K&*cK^#2lX^<$n@fkn%URKdfn%~_sZdk_mt%f ztrr`xBO$p+vC91tqWY+)28B{H;hnbPI^{d@9FJ^#-Q=g~fPD&FIJhmy_stp)4*waI zE*mIMnQg0NnTm?!vYiHB$Sal-B;N-xfVVw27t z)O%$GzcOPBzrsObtIn~KW!@>d!Z~d%*$WrVp~L3H$dqM9g*VV>g$^8Ke=f-f`WARW zUjp!IK*6}pN~fID;j=XsM0iA+__j3`t9+iq!#{x|9q)JQm>9l+Ajp}jz&Li#Ukc7B zyPJhi>Op`1Sqk?Ght*Me1oC~8(8%z_XCzay%7@SKG`9Cq*rV;OqC(*g2=Q)o_qG{> z_#kDfNDPqTBv%K>MAfdZc6YjDLXR76TRTn|FWE&z-v8|9JEviRZ#9KV5VsgxoGH3n z9W52TH@CF3FlwxI7}H?8!;fhCT|^EWHb=NS$(^D9Wcn|Ba z=v|WreY4bZg5^19J0nXlr}Vsq@RsWEx@-yCPTY#0MF+un_0JfAo{S-LGER29|$cQVM1ae`x0JW#Z`2f4<=+ZHDP6e)d##}t~%Lw`^1XXnnZ0ovu z##JcizL^epo*2GmL-eHv8^RKhCbxBwKgYqQ! z0%gDlfqEG|Rwch{GJunRX0&$K>g!>Gl1fS!JCXDuo zLkyf--3bYRht#8)=-rYLzTmNZt;3)eCUX5e{P{tIgf{?vXcaEGAU)@s-`B?4@1efu zbjgLmJ|XbQ4SP7mzrWp?jk3TVoO3}J2Kq!uLxkyndO;U~sv7wAKru5w{6G^QJZjHqxylkfO#Q$;0>=d?1RbUOvz$B04uQ^rvgr1#GX{AE@TcljC5H58Lu?SU zgIvoIp3!D`1rQjkrRlM7RTxJ`q%U8A%o#qB;<5&LyPqMLhLj)RGMQt10!_0=1^UIf z;(Ver%=L+kuu2-^Sn!V;;~ZE_>*AOt`r6Hni3|XY`VuTea_3~)q`!;JO^FO37!4&H za7`Nu)v14zP8kvvKsAEG)T6o2MVjE-Ae}%k>X9DjU+4$DA0QY1p}uD-M>_Epx!cgI!Mhj+(W{The`%Ou#Cn@H55%dDckqRZg=ebh&Hhgm^shfIPD zw8IY0nN|1TU2&|g5L|Iq_M{&emv?C&7;XEO&Y5k8mdZ?D=0cpr+Qe* zIjV1rUV}&*X0Kt`6~6W)@-7F2-6*Xqs+&GLZ#Zv#DB*yP`XKVIt@bSPE}+Wf@^@=n zKzGpgj`#zzFVk-#d!QH0nFE3s41Qf~caT?oEMcF|Uv^%9!Ch6?Pmg3UYOeLF#TolLWqO^tM(e(9TM}G-wOfmHK030 z?(Y{bj6dqLTSKPS`gVp07e;o!SzZ&mW2-;EBRw{*Bn;)Po~?$$fLDya_uRv~W2vsp z9`JI92G7}Fb@~Y1gS$hKUqiY>Kl%&L+4(|x8&>Kt@Ik)k!hwHA7gmRKhk>63qFf(n z-vg$tiE;``np$V9(E}B`X6>o_{Men z>D&{$qkaDJdg0a@!g%4n%=POISbgq^EnSsy|H2EBamVNczmw@}y=L=*gSkTVg1h{! z(Si*F#TR_E3h0VD0s#m{5Uf$QFs@*AjlHe}TpRiSe)<5vBY9}>+b#1a+M#$*@QzLc z*?I@6t=f9i>Qg<`Z~jGm0Y&{KsIA9#knQu^ad{x^>BB!4^N!#IMR76yR&&ql_Q&Ar z)9qVv59{`~yF&H?Z0{0#0jM0p`Qwz_)A-{qAs>4eKE?SwO9<{Q2tFq$2tES^-Uf-D?oi&p5JD)?QRc|Us%l=eQ7<@u`r zy<Iem2-yKtag!ZA(+|dj!v45Px+N7OWt6r+2)t{r6+6^zub7@4Z*xt#_vMqjmJ; zqg&wZX!q{p{^a9q!EdefWA6h-ASaS&@cOb!@-^x!iP;z~9JdH0YtKS)?By=Jyigji z`>97qQ^r^7^?YKy*+5dX10cLbvHUWc^dY_`;BKS|BPOTpf?QtB#N=Zh(c+s&YE#Mf zg`x$}!RKD((d_3dC(k|)H|+>M!HNkK^pYr&N`tZ(Vnc>%%1^xH-uCVl_e-6vbl0x> zVvMDw9L-3ZNT3a$d{wuO{%BF@-k@Q*B zJdYaPn_+!rvrgrUhZs%pX;qbW^`AA9?PjayMB10M#ExJSM;%hP-MeRo1`*bZbr6fc z577PUcR!M`gNzaF0ygCVIekb`bo^Ha<}!2!zldcb_oB1b#~z_~m&dZMZ|x0l`_wn0 zZb&)u7ptyMa-8-$ntcMwEi|>n!mPWXcUeCy8(Ly)9ALQ2#H_^FK|b2PVxlpjLryI+ z3A93u4*UV0Y_KQ-=~D;!i87OU0lHiRnHE9po%Fi(XAdWYv=(&>!QMPZTRLJW?jM`7 zQ+RgFF9pEa$B_|>QKJ|m-cidKs=tG5sxeC)71=ct=*n)YZXL8ThAIUY&MJ;V?cf+= zyGV7(!rlVT{h5eyt9~#fVj_vhpmF2Hy4!G*v=QQx>^hs69$U)8dPtLte#TM=H|F6d zNwk6wiDwECM$J$~kFrqFTsrBp*pZ$O7iT5jWgFY+^5*$DkfNtc*~xDyh&KboQ5I1x zkzr)Q=NhBQk-^@W?{*tJ+dONvro`CNR2ZwCi^-2_Vbs1~Jjm~_gnPSZ9}S&5?TxPy ziPCCKK+xS*&}^NO+EVQ(vpFBK8m-mnt$fL9ITRX#8}NG*SEXGi*%=;%4N0JtTCVrF z(!eaBua!(0E-r6S*jC1kEt<&QP(GQ)GU@tNqH;XJV^T;e#RFm64^2*-MjQ*r6>juh zo5!}FM>23@02@hHu23n#I4^QoG|`6=3q#74w5Irc+>k|f*yrXQ`oco-vlRh%VNW+w zFdIh`ea)%mIhrwMMdeFcD(_?tZ|*KU?0_E&JvRJDGqEj&a;hUHj*G44U4NTMaiaVX zw)p%l*Bmeoga4L`CRw`49uqy)_7DIS6Pge7oG!1Zlz#b%wxpt?av~MnaN!==Q)Mmq zbWlkA+8P2K)sM z%8GTSC+&W*-8P7QrkTj-INdZoE z5Y139K@0?6+8^+T$d7{9WJ3BRJqr|(otZK?eKx<7M>ZB_VlB=PG znsX+3YTLNbPhKnwQJHxQzl9XaV!4E5av$?XC-WfA!-ZH*fL+y%t4gu=>-9**`9ca= z%$2H|nub0^KE7tFRsq;B)7Y62oyz2aGw6!4hI@7C{&Hzt4Y{7(2{%bUn?vL1T3QYnhy)C#IWER%u)NY~S z>p*){IPO7tbjq1dNdfNO#XtDp7|AF0HWxTtSLoIie6G(}FnsBJ+#Hi%2g)IC@|Ad~ zKZdJs${GlD_Y*F6Nz#VpwZD8>2*Sq4hBQf{Y?A(_()UV!hAM6;)3Eos{((3ZFqC2( z#@X3Gr!D1b?W8LdlC!8=vvz#{ z!T80Ie*@yVP1TDJ_TWHKc;}vnz}3ih@ts#Bkq~pl>exX9`duu5@0|epi=UxLVQw#V zFN5C1?CtyZb8T{1fDq1)M4vY@PAtIlcT0tH2VwG>qq zjolk%^wLtt=59UNcFnzjK?^GHwTHH}*sK@_iDD7_U1y}7XCcjC4iJd<+FGv|IIDIt zajUYn7a+~R)TlU#pla!%VPO*KKuGJ<*~p4ivA*|U99-<%M2v^bo0H!V@C8O$bTHrR zWKD@9bCUE;1?kI+`1N$$aD50xDXU+CdE zhC&B72+L>A<&f3>d7x{NAmV?b_{bmRJ})DP56ee^p4)X#7&oQ812rJLtidDD*?eh) zehT}VtFvluMW1b#rM9ZvvFxg|?X}T6{ocq>iK0eZ^BKzfQ1}sW#lK-zd3i0+>FxF0 zmF@B~u6{($(c@}=f5Elg7d8pT{w-^w{wLLO3?`AbU!=?^}2z1q56eQhhSvtg@e?!8^7L92b^Tbz03Y+MON2=SgNY>GUID6FV&u?RH#RG@Y5H$@X$$wy;_cLg}RGcxg{Ur4>(hobYG3JxRB^5?={J`JwUHl<~{@ z8KXh8^dP#b)d?yi)R)YDMtaSm($M!HFJ-dj)p?IDUL@7DoxxH!-pIt$K##~cLa7Z_ypJP1svIs0581|0Fp z$qm~$UOKvkKX4KhL6)T&8MXi$WCCK9=`{|&J&Z!FQN*_WY3`yf*Xc+)NA#`92i@Mo z9k|T#q({*{r@5LC-~`rGmX{vek(!bOe}m=5ghPg_maFfOx5l*w62n$1{^{=Y(Vdp> z`C>&QbkY}}&zgDl6h@gdM1IQ$#OZyp(m6NG#z`mTWz@O`dOO6(2s;LQq>}ME5K*T{ zV_1f>iZR-+6{y9Q2L;OPjM6G&`j0(kqL8(JEa~_B-elgc=P2pmpv6t2?__7v&n+g* zZ(dX1RXavqdtLonmdtN6jut%Ty-mtp5~`;k{O?&7RBw$`E7v`9?)hm!w~Ws8&Qx?>V}yflUx~+BhXRBBuY$6NnNx<^ zL*rR?-IJ!r$3Ov9ul%%d6-%@#f3hXnok&%1ey(ln)zkf9!PDYVI-P6ddK1~PA%2CK z$cc&@<-vZ;*3C|#(A+}<3k|CUV9l@2f8+DM->I@kqGxjQTBO!{UL=)K$#N9i*%7>tU+o=U>C+kam0p~pO z(LZ?OiRW0;5Pp3HJO(rHl2~@!LPICv=4-lCbJ-4NNsZGqFniimfetkk^4M;$@;l3I zxI9SOLD{-AKL6c^_a0y*Ap1pR8G?L#TOBAbN(uC8x&{2VRH7CD+~OK3f&DzCHS3~5X_J7~)0pIVoX z{qF*~Cv!xru(oe+5a)k`I#s(moZox&*f)PPw99-<&YSpo9#0%R>OO|yE4(@ICoIbo z$p4{|_^}c-`!Nf&>uHOs)ga`hJ(?Jd4nd zbD5(C59_qqrpc%AIVuN=0ADyTn=!jJ?Ah)#{@#8r9km&go|n^lhGbRVxo0CR9yn^w z|KgQTDpebsMibyasGWsfm$|8Nkl^Sv1pePZl1X)8ant0nU(hxzU5W*VaR-ZWm(3v* z$1D`5bw>djrNP)&hSpWc_(?V16O}iJJ=QoRL^_6Wcxiv`K;XJHksIrmiEw zp{FAOI68#2mq#`T`)ARsGM5U^GPKraQsUbxf6HQbCFK4QaymoiT^)DT5Ls)BfTzU= zXr*cx)hASf`>mH7CRw+dX4eeB)z;l^dqIt_XysSMv4l()-lkM>(rRDO zKl}(;rEWReG)52U6+(uBn9=A(_aPLkn>Hze%AN%efS53D*ptaLnnvKK`u;o${0BlHk?*z+&I35gqa!|Wc{5Ce*gXknw!LJEX-IW%v-i3 z-o>NVTQb!o_u;o=lES1MmSfViw=%aFybFd&G93)2N0;Mw?h;8MlZ5#aW-&_t3~8E>o$TOU;}n!Kb(Hx4 zqgT2sLGxKoL30Iprax$k{_&rqwIREab)xSH2Im|4xSnJ+> zWaBd%J75>1i*T)%W;}|Ib&Q3=#<=r=9>#d6941ILuOlVJ2n8_SE z!Gb|df{EmloMGaR4+|C)gzGM%XG`;-$yNN$k)@fMr=KP)6_phg6_u4EmN}ZG3k$qf zcCDtSqQGi-K?hKSC!%1tO&afHBXs1asG#JhsIj(IvbNUqfTzg|MBUq0BES|wE{pY? zjn=7IPN!oyLATFF2=xR41nl8fDh5u(S=VW z0TK6(grU5f$|v1HmM6g=KIvS&Yr?RyO_op+mjnOYD*3~i?il2!-hGeLW(Lnn@>S%Zur@hjdN9*6hT-nc;~*m%$@U5 zQ+gFm#LKIss@y&!f0~CXFSR^>o@~KoddTch7-9Dn&pVp{)Zkiy3Za*8Y zVDQ=27)Ts^_Q0{eN|0$W^>|7$zS52iXK9maah#&!(XIfQ5!&DwWt*Ba&#+7Z@#vaJ zYDg|1wlu3}RE}!yXTF=JQ(DB-h(D5Fel`iPNNwqB?&F{I;vQ$k{kr}%|J5Y&$@{E$ z-rA()NwE@y5wBv_XE;9f7^ObJwD|4dM^bpPvO~NSQDD+}x}+_v=uiv6&KYsMvt|!j zZURv`wF;cF+>(maAHQD;uU&7}0P&ZI?Oc?~9I9sRf$U*!e2DrUQg3;!>MKF}D9qR+ z3EDQ^pT~LAgBE{=P@ekat0|V<3+mMZ>y!voUeY2Pk!R5}De02ruxYR}jOSO0Zys>h zeg+(vjG+r*dBSM0Kk9wlX$|=tP;nBRUu-P*Ja;@ySE{xyAS&A5He9%My87M7B+6Jb z^<3@BDD+#N!=Hk9TjmT8pHbLdeyb?asWx#a7H0X`S3%sM z+9Z3&a_D$%-$==~nmVjexDoetck$}C_FYVFTTy0m+uE|WW|-*E=QE}*WE&F=F?f?q zZ#nbd_mn^4C+r!*O>3_V>~4;sC;pJ1)Is|h6z^jEMJnD%6gkn7HCHnD(rEx6V<#r! zYDCl=7VSuRAV#BzgsU93DO~avElpDLZ(t#ehg5B}{TiB;&S=~#Do3f_F9a{yJZ*d} ztU`*y(ejQ)RvMIeglxsyB`u$ic&(!v5U<}!KV9ke{OnU-!$BNhTak;>Bj3SzGX~Yx z*u}HaV>$i|;k=7ojwyw|4(@GnY4%9EReFOX5_P@Up5evr2>D9)_4#sbWZ_q*d zj(Bq7NeqJ)4MMEwQK$k_B?4#BL+Pbv@rap6uTSZB&dS$v8=%Qz+~A44dbi?%`Nc|V zBU*Zwn63N5y1VdYckgR7WrP#(e0iipfe#y&o$hc8ZRuW4_zFO~gQ@xE_YezE$>oS*|AE4*az?T>6 zSOG$p$CC(;8_#%ql*H|zJE?AWsReuTjiCKUVs5Di`Hd7U?oD;n`pg4s{!9w3=L6$g z5wqM{$$fk8rJm~^1Rs1KFK_5Drem#R-s7a89xd<1NAjGBkDw4`agyBearSp~c``3J zsJZaJl>LXYZep|x`fjSI^LFAh#oTOE@x>G6%5|{ig2!-Kg5hRYP^n+u==-e`b1tLI z-03F%{-M~A^x68l?|R_mM0kDjDxWuVc@sfUqhO5bE#>LknW>j{A z+C4E+W!v-QDhOo=yaywaAV%;mO5!D*) z2wmjJJZ(H6bh}bb39;s{IOH-MF6x6w`BJ_ojjbdZrFH41j!lQR6g37S)Te2nTO5%< z+to@^t*>JT(7-0gZOOZ}bI9*cEN|(w*WoF@U3}x`H2Pc}C)HJa8eXr1wmG#sxRDWU z?onQgks_g;Z}Oqsz21LSfF-qpmrNV-w;=4M@9p@2t{x=Q_ml|p5UKt0fw@QyB8d96 zDbYYJ;4pz{5HGO?fhOQ4d>XSJy#&unu37Gsv{_E4bmF^QzR=qzK`r8@#d=t+!CB2X!a#MoX~Vb8HluNypO12VFS5Fvhl~U&W~-%UE(7 zeJeZZz}=p$YoKl0vC)-TRk9+rQfU=!CD%KuQ=*sk5%@BtuxocpdF$l9_DZSC?icwu zRcgPXZ5(R&Fko{LROS)y!MAIggznZ(m)th2n(#g!B1Q5$4!LJ@l+fE|3RQK&qd1Q)67}X z;?fa9>{;Zf#Y56n9wY92wwAyjN{N4oqUdbkRT77YI8WH*Z|I47rnlsEOX+|9 z@Xe>cOK+WU4$e#fdrg1+>iv4csUWCrZVj7ogZQ4~AMGgozUFhX9VZ&NwOYE~!IV^} zvofQ>WrC~YbSn3%7vr7B_J8#kfd85m>c6KWC@R>)Kbu%tSQxok*qFgw zsgkpajVdu0CnFa(GY2a>7<)Icmo%|3Gj}HDWZ_^0GIOzW!!t>NxmpV&AzL$R6JoG> z!auDM{*UYe0|y5iBRe}YCl@gTkd=**lbMql2xiQgnZbNGxMHw1kP9rx@Q(!;VKreT z{tx5&Fa8|(fB5r%%Kn$d|3*ywpDqD|=fVa~CjS)pzkw^c7&`xlFcy&#{inn~9S80O z@F!(E2`N!I1ADL@g)umM3ull2Y*zAc0tf%!D6pc5nT3>P|N?5sdGVlE(% zkr~|CEIP#OK(GlbDBu1FuOW{fk@V|gQqg`&s6zCCQBMZh0{%;t7&u1ZCj+fST`R8oSa9Cs+?-VH zXeK`8F%R0_ZS7Wlw?bK4{jA$MFt5;s9Q5D8Q>JXg9obqkV3_z=EDsMVXBn7kjI{p^ z{=u|W{rdgx7AaP?s}qpTK_;j@c{nEO)cOEJ$($>bdejvb5OLGoZ1)FJ`{y6!NBypc zvlC4YzsTC9&uU{3#V3aVtaaDln!wMKMais38Y(I(Gktd-4_~BO)_?i5A|Dvc0BKUD z65tEI(zFqWKqW@T7x;%KqtU2HIg7&^6{({Yi=ruts-Rb(=OxTT4qlY+N{k%kD2oY^ z=O`)`2Oo#Phc>D6k+(^nkT#4uF9n}p0}|(pEfv0**)p}d`~{_6ToB;IZGY0LXBWbE zfB(w6KHVInw`o?q@qaHP|3^vTzcTB866K!^0cZ37drFDf8rd2DlL7yeI1G~ieHAe_ z0B1Bf&A>_k|4Cu6ssNL+or~7!;uF_W>WkVe;9_ufcxA)-2jQIwo4t@<{!(- z2n?L0w*3cdF8~?`I|$)^M^l5u+$fADWlY}~t+>$te)KW*B9J$G>+5@YX z;D4fjYc_d^_L%&-=dup*66CMT>2=tITPx^Sghb5n33@7*-zl?OnFvbqi+>mB7K_R2 zc(!HS|1bA9EImHI=O!55%ZAU+*#5nW6%Hk@)P9oH-j&8Y_R%HP69o`nD3BKUuh%za|N`f zLLuQHUgvK#vU(lRzTs}L;|(gm)}4e+s^mJYE%iB(cN`8(TFWU_t85>?^2oP+1igMv zz4(e<^=6=SM32eC5%vt82X=tA0Sn!Eep8X=+v|z4J1(|jr+k69M$tL?Q<{KKZ94qwbmO2~j1$l-0br8NhRJYujuzfj&-PzRaO z%?!Sd7=Av~he+LZwATM~PYr}*=R!ErN2JupV;mr*H!^8Ld5_CG>CLR)?#cdW%~O1D zXL=)1%X{YAx)rHK6Nk%#&xCmT&JO)hm#a<;3B%Rd(Mi$0U3n^Iy( zQH{IDZJu^b(rKC0*lT>?7I5u3_T2D^dclgD_F8l+_Y>7u)K`3{%HD=iyLqQeA28Ke z{E{B^0^|ySa5J@sM^H7hhd3%^4vONRkQ@u32%4<>gcB&19%RvmQ^<^##DWp^E1Ek! zP6k!j?@mbXPJ}2~A6NW(<4HXlToU+{>9T@sz-MZRmHOLIc90bDHO?mF7eXO3%tAfv z?OgOz8*0?t3--OA?Gsw?_rRXxC1pDhg1$9A-s^$5riSc4r< zZwM3*pDrs-8AH!vQMMkDz9CS(cI>0QA*e|q8kSCF;xOWp@gO1^hDR$aNg2b)a;S#= z%j!}ETc~EZS`;CIz7#ZDhR0UdP|)S4VIkGqGwc%yzX#Rrbue1sk+5M;ot{K^_45A! zu|Q70ydJm9>BzF%RI9~oG8*(cMV3T?5){@%Ml^+zv8JRLi=2685xb8}3ngRIdSo;u zL(@XZ5vP|)hMIV>(CH-;(?ZD$e^D}#E}1x0lBl67R23D5Y9gWJp5c*DicA?-7YQYA z9v-O=B|A7iisNfJZXO<~4~L5iL!lba?BSs#X$sXOM=YJax~6G(Q6brEGz^Ojn`tO2 z#AbtWSY(*7s1QkaWWi?Q9!xkw-8BO@Q|Qb^g*8cEWOz-|8yU`ekQAad(`F>cj;pH~ z?hl9Siwcuu*!0K+NkoPwt#Mui!}w#8^01`B9}}9xMuQten+w}l-;`2uK~vl`BQj%J zLtRpsR?nVciznTY;Ys)9M?62@78NG#!|GP{r22)`HJ&*kcDs7@%20B{xVoOyFoX5= zo}$8{!X%B3Xj(lYnV5FdnMH-Q6G9DjNxGuGE=g9@7ZrxsNZ6>-a7H=ZtJ)Kfi zxLLKOCw8;Nnn6tFp2*BoG>-A&467Y~YGw)RQRJ*-qA3}g9!g?-T_j1P6%5R*!0PE0 z{xG}hNl{^Ka>ls2nmI}Ru%^}OK$g$yC#9$w39bGHNzxSQ`26&oX_*{3s(u58GCn!Q zYDqG!8&AgL$$|pLBFeC&%tkPn-}f&nT$-Yh$O1K#qHOvwwk}Dg)ekK86cvWUY=Lh~ zC2&DeVK~_`t}cBa!Ug_TB#PtpN!r9H?cEgTBt~iJrktwY6bTm_n?wM8#wG)$KjMh$^vU;`QG+OQW%mdHLB-27kOsorsh9xnnE-6HlLNukdSFmrr zKbe?V$0!r)eqzFOR_6A!g8mF%UteF(xU;BmL}WzM>eVA6p%JT_R!>W5Ef+*WYGn0x z`V4($^@5tFZpKMzZ8!RpBW|iss!g-Wz@oy<6hk*h$f|Lh6J*tdDRtXbAhc>?T`MJY zSkusYHj#AL#JZlV$3>#P2$0&~mD=Ew9)?$p!2@U?0ounb?V6)~%;+qop8`l_zQ9I2 zLFV8I?7%bR7(Cd7?bwRv;l^mSctRDpq0z%*e$MjKzH1OwQ4kpaF-(Yf+AKa0wQW7OhUZMY~OV5P!yY z;d!kSM))ut)3HbULV81c2SsSW9k>gJ$Zh&3k-)iV!FJ(KScJQUMv-W$%zK^T`} z4@8W@9@0+ZIOivO=Of}FR|>JKUpNynosX-g1?STtLScVqd zg;s3CHl*-3yhTjXG3`O^7`!ONSy+y(_!nsxx;n4vs%D!$Jm`%|oQ3)LJD$Tn5+VPf z^Cgp1A|<5Dwf%6QA12{kJdCaQkbFz8rdQMD!n5KCZ73{Qfm_*Z4K9Pu#Scrv$NSI6_SCA{n)#PS!KiNngAzR5lvX8t^J|SO`Z^%gs3Mx}S z4bxnjOCxjuV_oPIC3gP*^Ff71jz*3h#+Naj&RJ zB~ppBPFgQ*lpd3wk&ekG<##&hUi$HY&VtT&yU?|&Yh71s*H-O4IN^m40R&NnahQf_ zn2Tjthd*NzUL_{tAwE(-29tBhI5L&YB@4+i@;h=Jxtsi%_x&&AX|jjBPQIj|W*Xpq z?nC?2p>zx#L(iu(=|Z}e-bT051M~+$5sZRWa0&&&NTE@fDJ&K)6V?ey;U(dq@V;kR8LNy_8kIH5 zHf6uA3EQv}PvWmV?MQN1xJIZEp2RJ*RP@q+(SM-`Q!zsrMXLe2k*uOuk*zdOS|$&o zgUDzc6Jzvt`Yc^fPtZZaC{jx%U@q;KZcTQGj{>L?ccMdln$D#E5}w2|*+j0UU&+ z5+|d{qgaWFq=bAYXb|XVY(=^70j|YG^bK_2Qmn!s$P957Zb2!z5+C6qdaux1xPrd@F0kD$XqfB zcj0c_jXTi_5z8rP)^fJBK0pW;*e1;AkGDXbP> z#{^VsH)*fIiC)OXUAO>e;|S*A3mnCnLOV*kM$^sO2w?#(lMZ2=_OKQt2F%tj#uz+} zKPwWZDRFd&N%9J|;R?*8gNK_}wGDKOBWtMF+>VKns1(_By6h)_pPSJCc9(o<1 zJFSYM$ciE;iU3(KDvAP85fllMB$ee0S*di&CU zY+tX}OL{$TpG~H$6ZHxdy)H|&{6_n%wy{V1X0rumla=w5(F&^>FrQY%U^Ezwve6(y zFRBKk5wbxt=-FePHZ{YFr!E;_VLKCWiek1{VKJ+mWCQDx<+Lg$qtR%RjYbIuQ8k*3 zP>izC2!m1YaoB&!%u2dnRU#KPk*~9cDn<1o0F5=aM}R-X;rLNi`A-FtuidK%WAbkZ_!!JFj>sm zUe|B5&w8i!Xg@2+3DJ=SQ z@9e-Siqq+a)8XYLKfF#BJnVVdY^u#>u-O%;ir;Rt!Kmu(R#>dou;2S%wC{3x;Bxpf z?fYDS>-6^RHoMJW?{41?qm8w1wW`rz;FrQ^NcYZ}!P({Y`r&nFv-X`qWP1VcX;mD~ zET_ZZbSlVFf=;IsCcD9DgUx0y$O~my@ziAk+(>`BDS~9w;L{}vrjDYOJOmm!$Cga6eSo8BN)hI?fat03j)E@s`z|vpU>j+ z8Q?a=d_EtnZnMt~x7%IPJN8Rqv7~z!$l&Y>hw~5)=5tbS;1s2#WB^L~4CJIUFt7wDIju@TL9C#_Sx{g@%vN1c zPylbtSrA2DG&*7A;0!CCy4+xaTmJ2)l$TebymSaB)nG_DP<~pKK79)M^zroRV@KRR zvQM8r2o$*c^hQB`uZB@I8CE=X`G8WSzulBG&KQa_D$eAjTAXp>N=y5cmio&| z9Vm8;DlIKVu#c~_2t`FjGbYylQdj~&1=8Pc%CKQ)V%Qm@IcWk$4+DmsR;8k%q@p6b zyuyVN*Tjm73WQ4n75&h!U%%~`DD>JA^91)jE%e4=p*N_|yEUF2+%Dt`*{y?uiIfo8 zVt1BUhZG4R5EOG55<-|Sgs@2nVTZuZZl(%3AW(%IEEjUnBIIC`kb@mU4)zH-Y~v7e zI5i~XV7`!p^+FB~Gm4Nc1X@Eubx6M8#d5(53ajA8mx3Fb;D&&p;6}0F#u&kkse&78 z1UJ?TZpgeG%bEXE+2w*8I|Mh5aY{mPx87EoND1!N8+o#2?!_hic3S$jp^@KiIk!HY zjvALvho6-$HZWbRUs*c4&(L(5Uzkqq(UKOH8q6i_LtKIj`vey#76>j7x(il95X1(- ziKO5J7354#La=Yii0vhK^f0RFVXXft-9ZmyFFlMe>0!w9Fg;8U(L?lI z`Yx>WAd2ZhRMUf)N)KZFPxuac5MR=RQ0PH=5Gs9##ojn%cr|?ol)gjXflA*7p>NZ- zVWn?@(6{JYT04EUwY;)qJ4fQh86+6ZAZ~vKvAarA^p)1{dk41*F(JS>>M0=?gHbBv zwnqB}Q-Y_pYECdkKiCqA2R97qOZOv5_cK$Q?uSbEBSiOOEZvVLx*rSZe#mH|2e5!1 zKnp#9we$cs&;v-)1B}al%29vH3DMmM(U%bViPD!IK!P5?Sb6|Dy00}952one*4WVC z5EuOyeGYB}=^pw#PhX2CULYfcbDjPzN6J_nUP3za^HV){== z^dDRD>_KgajqU(JknTV+-GOSl17qk8Or<-phVFn&chKC{8A1CHBYg_HbwH4|;uD@e zg!^?!%nc@D!_F#6gcyhoJfkEL8hA#@`q26qO~lsSRgwrX5WD5Jl0=As*mXCRBti_t zF2ANE5n>>A@zRn+h=JIQxh07Z1F;4o=3+U`#g{Y}GVjipGz^OQnJ#YP9V^asdJMaxJLygy z7z)#HB3liparI1LO@LT)$e0{0hnB;|tU9|*XG;NYTf(1@{MT2)Y#I^w8M!wdqct@^A{y#kwKB;DrJzSU#Xx( zM{zciSwbzXoiLQtCflc@_JUCI#DqwS7{*OWN|B)?X|F}?#G%QGcx_72#wW|;wMk{{ zd3Bo!xurf?5l_-pDT0Z0DWb8g6@GT+wH<`mR^04oX|EMG*Vn`2T3YR?why*dju`$M zpeY06KVP2H@a*Ke+6i^ZN3-jbB@EHB>uZz0XNO|j$yel9&G7By-z=%G+b#?yU)79f z`NH7g_4TzWGMSe{i2S=|_;$otQeU@SmxB;1hmbBOUGDC5xhVOHmCIvEecg7w9#LK{ zs@L;!B4On=H|Nz1-<+4n%eX^m=4G1Qp`K-SM{9;}jz)PIR||IYGP_+ZtW0t+FA@mU z4Bwm+;6;cJ0bV3Pe7wlypNkY{irjFj$PN5S0{OX2AYI0MxVwz`@bLQj_oX^fv8D^A&t~bgnaTRd%;CxDk>R1u zgBpH=+`!0#BEvVMp=M&;=7z+~;jM!bgK8qvhSzTyIkv3)v}fIL>RDxDf1|Ontg$lo ztdZrvK`v+Hk?dLJ>{;dPStAo8`Ln=zd~Drj9fsBqYe=VCsL@~_R@dYY*AI263kGxM z9TfIl?Qau7Ho_RMPnse_ljg`!PAVEwG=z~vaFT_c8fQqJs|SVsZDeDHq(+7&ZIPjf zFJ98T1fH5X!_$Aw&CSh=mozV4!X`WovtCorDVx?IhfAYA4}= zQ~Lp4xV4k;!K?iMKYZE`2ymDUzxD%i5YWCyki!tNweJx|Q2U;}@uhu_2twL-$U|8B z4pHQ4-yw!v?OWs{qJ4{A$kV<>Z^X23QNUpw`PvB-qL+38MI81)fp!ALh-)X%7e(3$ z^h1&M4NA~Q`v#>b*1ka*`fA6~pThy@ryWN*O10ytK$-S6Dmfg8{@T|V#9ot{uZDjL^QsXb#6Nv<^(>@LY`6I#7o(+UKapSnYF6!C0*W=V6@oIT|oQ`y7p!sC|y}Ih=|~ z+Gl9OWbHFd!@1gLxB%yBpJF=dwNEhvQ?ySp6X$84;zBfNpI{b;v(c!1f;l)}`xtZ4 zqVS#oOS7V`e1j{*WL9=!Q*I==B z1i!-)jh(M7)jq&=9In8n+WWX3%e42g5|?T3V-+sf-p38NLVFLZai#ViZp2mE`?v{L zY471?T&=x_Td-Vv4{LCZ_8!*a8tpJ{#qYGkxDD58hw*z{ryauW9NvKy+99mNO6?H- zfK}RI+=*4%A>4%E!d#Fg{`<>dlOIM0qqTJ<7sU_UcukASMe(TroDpw_`CKBUc(OU6&ygj_A*}Q@C`hp zy^J@pQ+pY2VVCwY-sbQf{8M`w2l1@-GTy~=+CCiO@GxG`_ToM4*7o9kyr}KP2OJ*3 zOWIx>#U5=hKE%JYz4!?Gw144a4nM)m+Q0BAUeWg8GrX$p!RH)yV86BpU*LfD628Ri z+Dkab;lJ^Q_7c9ro7zkG8gFSY;W&ri;2rHnoWMctMSP2QwHNUn-qm*FdmPes;|Cnp zcH<=8({|%W4miU&`p5r4 zr+@S-o&Mo}q0^6?(&>v%)9D}l2c7-_*XbYpN~gcib^7}~bo%>Tr@zm2`uja}`g_09 z>4&*aKg@Od;s1d;{muU$>Gb{otJD8ir~i-B>HpL1^#8d!{Xg01|EtsgSEv8BPJjOY z4|F=^Kfq%z{|M}rldvspi-v7s0ueukg!Ug35>6r{wzJSP`(@%v?16x2!b7WIpjA^b zAIq@`;sy|G5bwLw6IV|(Hg=%8qhH_B{-w^gJ$v@Bx`zOIQfh|*n-U=*VYZcBBrd0G z=v_MTagpdDOH|NH#6-z%15#Rh!Vr#>^#x%kxGC-MR#l~wkkUR)*sNAM2?3LdPJ+d3 z=DEibUaM7}1l43>&}^0`!Do^ZW^0+m+On{=BodMm5|zBhHc~}az!M*>9%)<{kEB+4_UY+=d_lp;cR}8)~_?MBp zr?Rn4(moQy(nH80lQ&cLYWQ{#tvz98y(0mOA;;+q*i-bWgwZOBIRUeUK=GusPq(t6 zaD<;&UszJC4W`I#n{VVS5$`zOalAu4!6v!mcw-f+J31SW@PRhk zDvKM{4)w@NU7xsgmAVTyJDdE9ii!%durVI5&nkDhN=pXxFN;NTWhFl=>HtBE9yDt9S)+cT{_oiNt+(O^%{Og$OZfz&J#Wx>+zLT`5t8d(O|J|))s$KNo zk9RF?=sNN8bGNo0X20;<4v_1`80Y_ByOhuT4G_R30oWo5sP-wv92Tp6)mggP`X+UiuvUFRdRA^%kEuqTR8J<; zvFdDNQvKTWwfSp{UNnhj(IOZPdPx*bW{XZ%6q8;Ob+SnzKuY^AVdb(CQcMm-F;PKa zc}|umghZ1=6ixaZNz&!Wf}ElY5_;%NpCl-uw2c@+h%sR|g)mbQ#*Y>EiibpDtw_Wa zAqnGHQ@e7=B&;LXQZN0r*KQtA_rU#0F^*~i0EKB>0K%9ZM_U6x(DR!Zr#Utdz2G)|~Z=8T(Cw^g(X zI;BlJ258?g9;qjb7?-dsLP|+Q2n$(ZA(k&I0xf-+)*XDT^Pc%o^L~fu|YWraX zdAe&jokG@azx3uCnciCmh@VJpupt`-Bx^fF?Ra9O(I`(6#SxLokqaZu`s?)a9N!XY zfxg*zt#qwX&UfhrPkup;D_gJ6vgZ^O^zMy7b`B*pn3H3J&J&YOOlQd{?ZZSV6Li_m zq+FKS%*#5~y3E&Fb}&AWCq`qY0IOj#uyQ8G7fx2n+AS(}^s3FB?93rC$bzxT-v zimBqF5#ulG$Mouj+DFn-=~ZOo)hDOZx!IJYw2!y4IYCPMI5CxBA(WV>V*wUtx8S<$ zwYXb)O!%{TyRg;#oOvIPWPhD)v)Hq3+1WyY+{;!F2n9!)Cp*q{PWH~0F3P^bexv_o=s%fGw+bXK|4yH`TZjwG|c<(`Ul>p zwBMH}|3NN!&si8>iT5$(`@GM2SoN;BO~reIAtkE$KDDTM8=*5 zeU1@2g^em(wU;Rqg|kD3keM2MW>NqDfXz&U&PxwG!)K#7qcx5?ekA@&{_5Aa)E0Jz zGvE8gydUos;y=D7Tqm_X(N+C;m-z`chK+!@LTZB^Hz(qJ3~Ll}Y8cQde+~PMeIUe9>R7vjUtC~rV6n>5F)#CEJ8R())NxTkLHC0Aw)y@ zO;n&M?Fb(U-!<4sXi9sFuK?dQ{H#7*)RIr~vtuCxF>v$8;Ehc`?-UD;QX5ZX#-nyt z+3c04%!_yxzh`o8vsbbWci3f#;bO!e@CCd9K{mzIs52If>7rsR67`s~!*E%%!o+5G zWQCOMFmk16m;{XOFmc%2VUnW{hmj|Q!{8@~Bpz3*)T&eGfd$tvMMC;VZKrX)%dPaG zkz83;WT(R}mX-`Cw+ZLad271%ZFr+={njmH?Az-Jxh=LSe8IN)E1tPDT(OeSTdzJg zm{vbdIu9>u-cHVc;{a*iIxBU1-vuqB#$7jN)%sms-?dCDCpHlF3vzOe)CK`BJ;}I+ zGJ|kS#Tnc%+)`SWPK)}c(_X#PX(XCXvvbm^$CoxF3(RU+NLnjxk^~_{fHl~FB*bDQ zFcyb!43a&BHCPLQ7dLYD^JLia^KQ2MqMI#GB-HfY%-QmO@j!hKO+BokuC)b(G}bR% zRMpwoJ(0{jWlUIV+wlzB%s}}5RUoxN!n}luP*KQ{pbN2Wnm(McDpdHd#rj0ITzuCp z7xFK65B0;wv^=Lf5q7S7hQ1=T{qXe@Anf<~vQ=t>N{@6~!aD6lTKIGpvyF4^7h4%3 zrL->+y%=V)GqPkg33?E!(;F?&>8Zgev;G=Y)< z$=%b>n+0KGIbM7`&Qxf1RaJU0jp@7CkaBSPNz2*jb^jOqOx^rvbWf&y^U^!ne=OwLb?>`moS+0 zhET$^+(?XVbTTZ&*eZo+iWn1mD?!M*KqYF5PX231YLZ$cK}yk$TWo{sJ#nvkyzzKr zm8Y{RZ7&{gtn!_@InoGEb#+yh+T-I>JGd3O@+xjbuDohjzrOg{So|AI+DYiN1EAUg zZY$O%O%rO9y~a(c+YYn#-DZn{f2%-a5K;Yv$kxYC@`_HQe%w3L){^vR-1OJPxE zddlk;Eo{WXM$%YcUup{zmwP}t3ELtz5+SxbNgg?`uglw?OeNA&U6VI;)k$q9zq<9z zvG)i+{xCv(@nnDT@W~J;rfVNb2c`Y6z>nRDu|6wts1AqU?e~kKDmsjAqhEZ)z0LBh zMR2=4ej3V7*v4dyaVLCrQl0)>b&_pr))eq|KVfZhbH+ zZQC#_aUmKT8y9A&2$zUXS)9U&Y`XiPd-nk{JrbjuDzs;__q+_@4JqIvj6xYc1mq9 z!-LjD;Y`~_4qB_$I?hwibBIP$j@4p;+mp5q>@gj;qjhRVqBHxY&KL5LkdOF0=KoKP zhF{w}-k!=aV_Pq5Ok3Bd%!VpvG_cK&8PV<>>U7X>*k%iJe>OiB3ExY5-!|&v+v>mQ zdZB9-x#H=28_(%?UDpj#o5enJ+q|c`Iy)a1$W6-|u63H3UDTj`Bz`8nioVpD$e%7u z7n_B}q8QEZFH{DG31=ziWY+|T=Z(mpAk-@j+2{7UAtUN;i$Mq=Gaem4@~ zQ;;s4MxxzFtQ*N^d)Ekt^)kouXr7QC9bhes43E|nPYF$qOp0D?oNKDsY~*jqt^?ojW?KATW?lZMmW4%cX=@OO<^j%f z|GCaxJoy4%9JLriQ7L-+rm4#=CXBJM@)yFT?&518Htu(!0 z`riC~+*V#@A);EGSLQAWJ3Lc+&+kop2Z}A#mNl037R@59w`{U}X%Q?YrX4J7k(rEG zxOc9q@+1q7%2{L9oJd*U%JxdSp^{X(S>J}R7Tr-#ZgJiYd9O@^a3m=JBcXS?M z4oG+Tg=s;pPNc5=lT735&AfZA(R@tIBMjXC2| zP+YHlEC!iMl0VwqD}8#Md5t)AW}6E${nTpSwTzevo}Qs0F zvC@UoTiM@;Kd2_vX%S@#e?V4@ne(X8lQEc2@a^8n z_I1)CNo zy1x3`(-+aQNw+S2{Lf34J}$L&ezRuGn%&J^Uv?e%6Ir)o(v5pw-1qDr5RBD67COYi z@R2EL?tS0w8^d8}E^MmSxK9kPuHO!@Rgt^iZ(*kpg`61Jj z`fY|MO(vJ=dea9~u;fm)&bKbN3RaS$k0vhb%YDu!EWlc9z+oJN9#$*+1$=iO16E?q zv*@^f%JqXF&lnF90>Xl~Y=IJdbATA_-CTZsl%Na5;L>E|!o zl`(i47j~qDzj0CKAK~yrkBa(^MaSbEi@Ku>w#s6)@rc@Zgzr^^clM)XasA!Iw%gn>gQh!JPz`1myVZ38PU>2Pr&D2kKGzHp& z`=!^i4tkGf9d&%^{>*!nOP(tjjQg0l*7}(2Dt&04xsPig?QgE7HRchHvjXQDCYxuO zkIEmpejvv!Dsc)HqiTgeU{q`{I0J&wQ%VrES);1D&qh>R!q#MKv5CP1F2ids5+L+I2WHWBFuo<^?dxRecrIfu#w>e&vus9VI+&X+?8 z^V2gDj`2-YIKQp%i|wCueMubeyhbeK$BzxIE2iJn`4$~#s+fGkm5-3g?gzG#AQ6a( z^y+%I>w7h{sckm7M<=YMq6!Bx>l=j14xf%9= z$NMyCLl`HB0iJmLM7)O>#N$=!@hY{dL+$8jWZqj9i*j{T+R~v>hia4cima2Vtm^H4 z*kr4p#7Vs1nrldWVIvlm+9Lf+`!FsMr^I?*Jt^zU3yM~zoKOP@V$G5 zyKh=}QQ3%d?SC?iXu9C0A1?&O(5`X9r{ZAbpn%LzG#QPOqtF<2oMWtU$ogz=cA+um zD2!AZ2RP0)j&Mv?>Ws6EKN!AoTKYr^^9M%;=bw|mws1qCG9WylcXiZ-;fS^^jGwia~3&b&OT8a*46}*xFiiS!>n+YbkvY zZsoeo>WvpJ4m0%@AKgQ}9q&+oq2W4@oM30pM>5CGN2;qbL5qcMx67S2AoJx&E=}t> zcmGlw_m5&(J(S&rn~WvH7GJf>VG8%fo{I|;ez&XynNez$koV?x2p?K@uD`Rq>S!>Mt$`1)Qm(sLZsbi0Z*d0nq z+k>E7EGaiRM>|K3?Ga7kZ)0>;F_)r;g~+qnfo0kptR$I(3yW+~q88cYCuW`1Pr%L} zu0gypPU59$E79e0+9Ec-jIz_Va_iOYOaD^4b;(6zZ?2NsI={ND@xecKPNny)ykf#F zS9LxG%KrB&sp2OG3ic$<*AHML7^7dS-=I(G+x3U^$Mg#HLHz=Ki++73>#$za8-jWQ zqKH(`%fi(JvLuTJS&2#z*NYp(q}VPV7Ug#Fm`EXp#C_snQ54g*GMyxznm3Wpn`mH9 z6}e^;yEU80jBqw*A`>D5n?rH5?w7N-sEWVJQdOOPRl&yJRUnOv7RLDt3${|*s;yhM zil6P>d(tV!PQJzXaupza$IcDuw1i(y+Ys_(d5T`Jn!lD#$b!E6Q2RLdE)3m>z8evk z!_MEpnIv3lpmsTw6)w}Iv}0TB`DJ?MjM($b>=Mri^NhrG_WUwg6eUqE*N+sXs9a>I zGh8YxF}x*wAS(~aBqGO@sIF43&{vzsnCr!QxlXCqUnO29-KBq4enmVWACW&%zLme% zIqe36BnTpvWks*o84QwMr;94GLs4Ww6r+;CAxQ>Z){A0*9Hv znYmU^g8J(Os`r>}Wr#N}tnb&C1+)_eePMQ`UYDI+C9|{a>`FPM?Qae7WOFzj&aUUN z?1jkudQjHdTf>z?N^5U*vEA&PC)R`Td4U31Bfcf0OeF17vmG)Zp|LajQ!mDXRY?#&sr_JhgM6kb=vOGWsHur zXd|!%>?N)xcm)kc8uoWbxcsa=7ieiDO7?*;UzY~K z7}rwMKUj%BFnafNA|QIy5kU?M|y-NdW5v% z@y5>4H8Y2QxNs4ekyu@w7Gj&b=SjN73jdRyZ5 zV$TigzLJOLF8xFB>fQG~x+T&uc){&k>t>vD%|J1B$LOgS)U|Ee)|pTLbn(=IcRbkn z2im%9+1R^p?R>M_w)jvS3>Ud7ktGRo7Tu_()DMJ@vW^KSvSg8|+$y8F>@tO*#Ah&^Kg5@!)*&AwsxY3iDvVqRjJdo7n_+HM7`atp zOljYz7u0CTM4e6~xH>d)!^KE6BQcKlFro7?3&V5FLl<~9c#@uWkLVF-snf+}^Tbx0 zEptfyn}&tq7lwtchhZURB(XhV|D~Za+O3}G891-%tUAt(jni^jFuqEyV)jOL$IsS= zOSb6^I)h>mWHn}!Eq-D(*fWdFUUXQZp&pyvJ z!*eNd>Sf7%o-k3GXgJSwu`pAbX}H*Aa0f)i7BCted46u=`#BpZr(VESc+esf@ahgR zawK!2c#OMVnNvrOv?sFiqGf#*0!39qilFp6hclvb5{H z&OM*~j^q&YOE13k@;_hP4T_arbHuPX7ghI*SK*(J`B z?4j8ULTf|1f$o9+v)yO=>viXu8r%*3xw?x?bJTh6i~Q}OR~-jE2Ys*R9B~}UIULeL zu80^{3z?U&0Vy zP6K-@(a09k;K|(o&~4D2dP^Z4E;cY;i}3dq7L%+}T5691za1Iw4hX9~0>bKP0pSzB z3<&cB8)8ofgo7i?J>;~AaCboXm*HR@54KhIj0R_QD^-`%L7C&0Zxec~-pU6D-Zp#H zzPU>dT`^@%AKODqmp%6I;^xg=bELnm9yjhL?al|fPTqLVz|NDxgL`(p_}YuRUuU{> z1wfw_2g8OJ5`&7fh$@nZSSAh=Cx{n{i$z&))9H13bCykShM*%xKKU@{d#%+GU2Z6g zWYJvPfA*D5Sry+UY&}$(%vt`ly({f5$vw=;(e{zMe&sG5Q5%mhVsEUm*B` z3o9-B#fZj5q_KPVNyjJ@*=bvG|KK^*=bb-z=+HsuJ95O>eGAVV_;CKn>ZV1V``Ij1 zYaa`n#lh$+xD!{1xsKd{`m^=J^Csuc%)L^7i~hR2hq4|kd`2+q-9C@IZ*AcLx8$dj zC{;^{!PB5?&^H(wj18s+^IY9r{anLb<6P5R^VZnbd@DPk%-{1J`LFyXVdI}QxVgL zdfe6fu-l#cFp9?1SlcIr1nf`5(u=w3?%&-D6})}4AX?f#tM|;GHC|dhSClUZQ4*e zBvUuV9oliHLo<@vx4IZ8p3&Y)n!P){eY@{_-+RxOUZ~BtvE7#RB8gHr4DS*QSfbIw zx=O}CN0J#Bnasebq;OG^fLvr-qurz%n9w$qXdo-0a+!vd$rnWjZU8!s+KWsZ7fYRs+v6EQ z*ML3Fz%{wZo$`sB?4Qm#P|5Rsy0g6HYJbtsIF4gF&dgma{9vNvZ245KveSqyIF2(g zvqc0G0X0Kt91e5&jPZt@_S(;DZVg5|^I_96Bc>#0jZ6yBf|A0)^OO{Bj%HG*CDfWi z*;YeW7qApAv{NQKffSl=&I60y$YKU3br#2|?sLOK&3hnv!g`}s{+xNMU zdpss`KLn>VaER~OK5}1A?uldj2Nz$^@!0AIURfVLsNX$2vMCnpO6`30skOt$9{Ba| z@x|#|@4ET2i(3=9?&V`EmToJ|cb09xC2`G$Yx-K#^CGORxOim4`lqjb9@c4F{hy>G zxF5yQ?~Wh_X^eUBu&2Dmt@+Yu5+ke|3`;0xQin4+mXFR!R!+xtMZKI}euHwS zGOB!22_Pk-Jfj>`rj)l7S)>v9`9!lqixfx~5dp9U^7lJ_hS7h7c7XK(kQv@MH!&cm&zN z;y1-hBom31INWW~ik6%RZc`&M9Y>CE@^FZGnp80uRS6L3GZA@8e?o zj?W?Cc+{sneSR%2T$?x`VFTn*kK?I0j<2wV=LsO#{>UbG+RxYr?YbSX^&Fiu926s( zp>NUmX@H(H9CXfb`1~FdtR9?S*b6F9FctI~U6K5Z^9eNC=izRDRYZXX`Wu!*EFwE# zh74{HSy5#*s7kUK&{N1z!zl!Sx1(bWm0@Z4aiaEoPq-M4#>Il@g}yW}^3L_o4Vv1x z7QTJesz)yx|IYZb+Xj2?CXZJSKXU%kRja?To7CN9aOBLoAZWAO%*@Qp%*@Qp%*<_O zW@ct?Lz|(@+-7EGZm+)+GxyxNcVc$;*T$AAQYlrHq)bU!QiSq(J1i6kVZU5ev)~Vq z1}#2**z#5omjN`*DJ7Q($@|$Ae;cN|+;w=}d3I=m*+8~uWnDlSr@(c=K6#K_%x9$1 zSI#C#e@+_Fz~MA;GCO8jxyV4FW$8$R?9STOg&42mcJu6BQqs~E${HC(p2H{x9c4y) z|6y)PsU5Z%PxuvQKZG;hz%6?%qI0X>B-ayfZ`O4~f9GZu-=yOg;g4}y9N&06*L;D- zTG`#VB`9D)G0Sry@&L>eZLUQjB9tb`q%P>SJPMIGYB}3%Tv||$MV7x>C=|0(P6A|t zA8utTc~M9R^CAmGkr4Hg0v7xWf(o4?cb~jFj%O5a@ta60V?KOj5>sQ)FDAVB**6omY zOS$bEjYs-TUH$UTAteD|cVj~V53R+KCZ4kdsgbsfLmdst-4npMn22Z?l~VRbd2-O` z6FQl$EB6$j3RUkS+j}bgR9@1rWaS&too%Rva$$B)J20(G9~EWpS}PD?DMWU9Csf_> zmkZ=lVgY*ZVka6$P^WlrIQs}kR_0oNWv#fI26&A!m>r83^nZBkiVq3KAZeLi|MbL_ z0BTBUS4txjD@C1PhJzrL+TVc1f;ie>WQ(C>VwK{^oP@GCVsec^W(l`MC89>!&j^am zp%-)0Gft64PLvy*bsK`9v!&y3KhYX-NI8X%S97$UPu2hw7j>K~Go&QCCtMH?SbBMi z_Kn`znm}I;#dxjdSo27_Bl)xo~Zl;%}lc$Fr|};iV+3Zr4A(5AAzW zGR-UrZmscZ%#7$!;b2@Nw04wLT-rK2wGEf*ukn>biVRqx;~F9D8{?uDA^Z`l#B=Fx zZu^>T=4-w(xrOO=KsM%%i&K-X?k#QJ953JgxpdP+qrzI`zWaPgaNslue+m3O>(LE~y-Zi=iMD^B zRNk)B086MC849*ox%#A}=B0Mmmi@z7kGO(mfF_M*=vdRA1U6JGYwWf#l0muk1D{yC z-S^^W4n9j>)GeFK*o(+36M;p4<6c~UD(|pQvNwieYk%C@^6VKaRobFb6<~j??Qyca zoUTuZ7Kak{pZJeXb=gJ}#*)(FB#Al0MQOtw(}UjfCQ5Q9NRqJ&rkudi*;ezZ{%msd zXv~cLBzcEoG^VlTaGH5yy{0|ZNYy{nyT_c+_415wQWMhB=P*u#f3+yrpNrP-kcD?~ z9)15P4-jK3%jrH}Bb=I_i|DlmJIhE<-OED zdsYoku3l^K%shX-AX%-j4?~Z6w{-R+YI)nIamH+wpF_1$L4mb%*Eadw2B9Q2RmhL{ zGS*Vxz+syLC%Ojc=1u#dX!@_&ts{TMlD*GmNpkMBFQfi?cZc2F*qZWX8bM}g+hVP+ zeu3iV*HUAm&v>ncfk1<)CEEobct}Y*s2A!0B=2BV0*9*cu00KWV=M=s^{~uKk~z|; z=TuiyXK70ys%84AaXQ`THxICQ=sLR*xRStj=KX7aBgTQ4qcZ!%-8cSME`JPx>ho;; zEv*#U60d#%_o7-rL2opgCS9_*N~EhceeL4*lQtbjG7J?7wF#GO5he<(SpLCCLGc)K z*PI{(CIqx(pQCV$DkFi08X4tp*}C9z(m)ofv8EvEL|BQMqF6Zq!cj zhujT)fp&#lA%9ZzlY@OG9USq|HP``ZoQ={~&2k+^jCE>(TW&ez;h)s!p-YkW0yBz8 zd?LrtnFZxCY&O^%15a1)P_vbk|D<&){kujgi6pv8NwUTqGGTnR^yU-J`J-PzR-sI{ zYD5`B1ol*M1I;jESQk0Ab12TQsS(wuVPkE6VLl{v%UDJw$oK2YtySohW+{KO(GKPB z`hF6%KyRz}r~8{-$ZP;`{?8nQ{|v;HS%@4pLyEF6UYVFVJg ze4~EKTm%%g#Y0h z{-^o><_7-*8vK?B|3MJ{?GFAYRPg_WIr#6D=>6~X!GA2o|8Z*kAN4_&|Dq30*atHr ziaq~@X2=#ZH6cWRA|fM|q-nBIY_~w5UQpl`SY5 zL72XM%XR)oL);(Jp+1NlCTbI}Zdl^-?^|EGJswWD50T(g5DO zdmt*(qrM+!{XShrsXn8^VfwQVh~07gF3091gHj*oc^S43ysVZ6jy;31ozH< z;*PPq|x2+N5UZs?~>607lKVyXYiD7qznjG}5$8nmL&i{h&y)1R@D} znA9tTc0Fubb~@f$k+&$LjP%NBof>kt8>ciY(}Y-@|Gzg^|J&B;A4>CofSv!%A^fkW?*CJV@SmpQzc_^d91j1vHR1gC z;qgBmLRK!0e{j_Q)6v4r{*8M6FAiZ3l&^}~8^>S1t!g(X^jD%DO;E;CN=J7_(Rsx(SNVVFR!glu^XguvdymD~$lkJ&?;! zANzTb{mJ*|=hxpK+fG|tR(bauE_ps}$6PaB(=PV*LO_yWJ3&MwchPBn>_&)!#z5HO z2)MdD4|P`Cz*sgw=bI?zG5M(uk9gn}FnypXbvZNw7k=jsft9ecG2OPy2UrY`Jsbpx zGvFch-QxLqpNq5h;dzR~A%8GS@n)_DP4gLmX$?bqj( zdP#GFAu<5HM%}WIdx@tV0Jne>rcY(9a%zl^NC&Dmd}z6lPXRa?J$Vx5Au#`f1O}s{ zsw0X4LxLpu+`v)a5Q-{Fj*VId<`0w$1A#-bQD)Xm1|a_+d^+z&R73XH{#s~F%5sM2 z=d+FyOyAD9cN^rC8TQbQSD*4aD4w)M7nqsRzFl~W`wq%%3+uK?=D2~}1On1BKwXGQ znCCg!6EsmFN23@VR!(~(SEG^8b&ku`AuSH(Jn|jE>6lTO_K9Q)Y1s&TM`S>qomm!J zaOoB(X^$j`^hOh;4-yJ@G9fVx*0d1Admk5eSgZrxra`{V;=;^~?2aWdnE7GU3p41p z{4O>A@3_TJ=EBRuXZ@E^r8f$pAEL6&Rd zJFTZ4W|J_n)3oRPkD4ib4~(m|~a4obTY2P`kY^S=UT7A2P|5HJ$Hxa$#c!XbX#|;xkA<=1QTY;;1se$^ynbxx7~e6vg*a z678jl$I&XrrV^`zon2@83UEnG!j>QoPcA`&-JDzWh9Rq8pwT$sV3)x`I=Py3FSD2x z!Px7LLmhdlwR_A>7qI4h6GW z&MsBOS37-YmeP)dHbN;A75D;7+^(8-kAez>is{)XWNIis)5Vc+5nDslkX0*}MA_7o zlxoHE0N%mt2XI_GY4p)j9W6w*IhZ+|{786kI%=1D z3od*c^VTb>nR@hkzcl0Ou+)9L?F0LNackJi+smhz!&+-{Q(|NNzS!8v$wIpOvqsrd zTE{MJUpXH>cG?nl>%7>*8nwFu_Wcmb7N}$rUe}$~cxfOSg|H zl#S9&w`BV`->eZcNs z2sA+Ew@3;r*!pi?7BgRBv1B4Y$S`KEQ}k9!tnE;V!Cgytb`+#W>MA3?lXCs%$*E3e z@!)=~B-~=#7seKL>5-MkX^+DrFp!x3_F>`B6umO z*>Z5g-QEOuG`3Jx;+nb^PZsSW&BcAfXS%OkMjo-ISm+O}#l>F{Yq7Y@PnAEhyx0a& z(DKqFMkbVEYT(Aylwzu4ow1bYNy;uLO}4oeSecvB4r6LQwSMeNMNY8%;DhR}tE-EX zvap{n*eM7rm4O656q3P7i;Jg{ONTI{>Treei{o#1Rd*9f-x*3-Ugwnz z;jjQ54ulhGGW`?wLyOs1_7WW`Aw8zXt}H~I4YtArRH|BhId7WJO?vSVM3_c7M7<+) zG+`io2P8!S_>cwNLtc&FK$xGEcMLK0(N$`i!ugFS4Av&0VQ5qy(r9E}L2s$yNeH;nk z6T4iq5&Oj~2hgvCCi|)D@+bhNhvoS?h<$2*K=Fec!@qqG-J9mzH!7#Z^G@nryF&zN z)m12X{Y4XK^}^H#(&O1cMs=*33n6A_C$=m{f~-cYY^1^bTY4sFiBthYr=6$Pp#LQNt97&)DB-&!5bML1{SN4CM{>nM=c6WfW zIP&BTJr9Wk#u%NMGKK3XqQ`R&`2Uge_=`VJCAo9`r{s3cT>_3EZ$Mv=d`SY58zejA z?zJrJj;E(NxPNOzrHEmMoi`$S?BVlw^6 zGODA{=wEVT>0I3~wg+$jxjy7K*7e%cO^ga9HXv=(+Mw>K>?zM##T3P1UFi3CK)~I^ z1MgnsB6SRyKAJ{96yZz&;po081{q|;-)Dl;Fd@Sq_P!ty-y^n9l6y;p8DnIQlO<^$ zUpf$XX3-MES6lzfx+?yZ&_1?;x+vOXoqcbqz#Rx*C~`vPikvH_G23Mc!zUQ9Cpz7y z#R-`{l{>iPlHAd`!L}hy59k5-_2C`GxlnW_=M0>C3FME2zc2>C3&iD*3Je7R0;prq z^pW_NPuN&kqgk1zwukkN1)M54Wot0fqqB!U*C1?1?*D{XO#i8EcY^7(wnw=t81{ws zi|q~5jTscRXRHM~(QXQvrl4ch>(E{ZeSmQg z{sIex{_E9pzkWjchTRUOVH0xz@zy#LVGg1VpMcQ;!av#b)1y;F^nhT*r#p{RipMVo zM;i8E##f*a9ry~EcWR3KzA;iA^bKXrj8vAMRKbu*Jc;-Yv^=mFqX@ioL!tv};dI?{ zR88~ec5>v0=|+&TGavtO{)vcgnqw%r&ORZ-Lgk0DH3eP4$374p#c2pik|RsyvAR`n z*|j15)15c&LEc{bT+f4*J!60>rhJ(p#E}V-ISq_ctm4FPDe_>F;>7;;U3=Xbv|Hef zSn!PC#<5ZJj@c;8HWyggn+|N1#E@u5aD9+tF^IW(lDFVCvX3TYpSHg8o1ktJINQ2tGF^8Hm_NU$O%{zlUoRaj25OX~PgkIX6PJQc z$Dyvl%n{k4HX$OIWxQoCk@zYp6HH+1Hx-nI-I(G$1Y{21KJp+bw{GTy+*wXkS0k&xv;&rK*l_vO;KmOLN<{ZvBO_MVy-Ug0fXADmbx;272r*v9 z6o({_T=!li&=+x9@~(!E3uXM>e&dZ2FOX<0?(K-6$QRu=F#FvgY3(@IUL=m& zK%GC}a0r^7gngiV{&G5has2gma8i@M%GYnU{~3U80>tjoV-CD+VLLzS9rl}MN6dnp zwWfAeztHKEW$do@*H$7b=j-PLfOrk@<5X?&S`#SXItaE zyd!>e_Wf|S?eXrsE&Aoj>#50$@2Q_t@gtx<3n?h3-J)QAcs5=dDj+aK}4*&-G%pu1lP~V8yX(YdD|xR#}$=O ze>j|v2bwkfnZiq)spX=j&zbV@#ytEHcW+GGZ;5OH;WS)RaQ#ol0=w!wd(B_2E&26^ z^tN4_H3&GnV!H=KK2e1E;D%X*1O)*>vQMD>6G+WZmfl?d!1_~2#8b!zP{{{BbHj>+ z-P8v^#W#LG0%SjgkY0)H;Lu(e;qB6EYMztcqxricI%?!;1;W2EV0#awh&s+nF}E>RCIQL-K)W%a^;xyrvOvk?3~ zMQdO>l}2R|G$)Sc6iAs#}@|a5n$UULb-GR}R0%)nkbO zP(P%CF2XqsqB*^>at6VI8GG6G*VOL-x_DszzwlmNzatd8!xpYH#o3QK|H8xmm0QN9 z@UZ@dbE1B+4C22QGqd!f;3*nC#u`AX>ZY$GYEHP=<)9>bwb^dj+RZIWQkeRTCT0pD z?6IMSnuzsdv%7|pm<92dyU{;ib$v}0L&^-A9kTk@D8uPrql82;B(JftB22%N%m>+k z(}YveD~Cdj!a)7dA3e|_r)oQ=Y8Sx-UdwIo+0D(LOuxRX9Pq@^np9?2V#R6Y9l|O{ zEXR>h7FtsIlT}YRYoKIYCd;>kN;s=6sVP6SGE!7~x`Q^pLvq1>z9o*8EvXFA3P31# zS|UYWnurOg{>=mKe)>zD)io$Qy6k!m(2XKLY;igBR=Uabr3^0zCQ~FLl5)jzs<_ z{2OoY-%S0&8IfQSRyeQ;HOoS)v2v@55-UuJg@(YgU7IY3*tMK`DQkQ-9U9$Ts)r?(5fUljvcG$EwV~;Aqz_@~`qVSodY!;-oo0lt=Y+AKr(^iz}TBMjt>5$FK&!n&)9dk1u!MdYl zQiQMt!pcQuocN2}>%x{}Fa@oPc*qNml)1cpMH$5(21i6gcYu&vmkP`e0xh*V$jPY( zi%WO2DmWkZ*5E=mlrZREBuj>Dq76g5Pv633Ts5<5bm5XaE$5h1fCu(ER8Al{(YoL7M@fiLQ?j@3_hO{RNuu#&w zM6V-wE%WA-IevqysjiMpoTJ7wy?Z_j(m^!-=hIpQ=HlR*$Kg};;Zx=@ju`q}F}GG7 zS8me^S1j&a=}{E%_Clr}@13v**VGZJVx>|mS3vo~#dHOJ2N8)#sg(VIeX6;KGfHvf zlZsUL)>#mauYPJs$F7=G_fTz848K@XK4E8T_JMjUd0bA>?TD4EogQmhTacUEt^p1? z+>h|_5q>w6k*2}SFvG`^Fhe(yhc=q>jv~2qz+D)WTck?1;$SICS%c?CiKU+7eBVjP zj-Z!Fe&ZLZ5ADPi3T_9mNwvhXJtj^jYeT0(iGrKsN8hj5V^}&WzT!Hau5)UvHw9=M z05pw}TdvBRLX(Wv6IV^0vbqLU^?A-1m$javnXly~1RcbpT5RknPNk4Tb(P%>*ck+= zO!Hgiz&gdwul@x*XO*D)0kPjNmt(f++))T#_`%pO>X5bl3~0srS#j{sP-&cokqk(rDD06>YaC zMIy+I9^s}xtHzQlZp%uHERIvJQBMya;SM=wPhzyXpeC8SaKyZ|Y2f$pJD!#?jBL!v zj@b7IL$bfXPP*!YpxNLvb{RBUiaG8>LI;Z@NkQxgVSwYg304n6*DgijK1qQ;Db(WoprkMgR^x)=u?0wx_SfZvfVv-oB_)>R1fswn zg6TR^3J`(IAA)U2D*69}v_GWqRLg*lzeDl8p%xgZ7sjdt#Q*54|A=56`_2ff`wMb| z01(Cmv+h8JB~^MQ$bSN!Pl8+zeN2f;eB*7=!V)WSCE&d&M-!_Dcui?W6XP44alyyb z;))SF0UngXd3ShGiS@qW$f%T~vnruIiWRsbR8grWlp>LLbO5zKIDDxNa}uFwC#Am8 zy_9ObVge~t+eOHS0FH=)_B*(@;_q%c5Cy`o5NZ{Qf8&Bqsz30SPRc*6}ZEOu*$t7q13oPT~g|qP>-n%OfaWadIucQ;`&|z z8kmvTrFg}RnpUHhX!;>AsqTx$5qD%~jH<85CXA|9qr;eGzLAZXg}#yAF{-^oWYoCf zN`URzz&XG+BR&RIz+h>II@TFI%U2Q zHg?JklU``LN%tL>`Hu1-i*67Uz#^k^Kr5rdH)=Jb#5am7qsBK%9Bq0S^$=xpQ1uW+ zH_{3~(E+`X67R%TMnkZVJ*mh)(%K>Xin&sG<2|YR?VL?2^N+w~)Z+Gops^P!as3R< zsK)J&%_wIycuWOIbZCXP?@%8yqVHONC;QlkjA=XChu{8~8{k_(J5NP$!a1S|Z-l-7 z&hgkQ@(KE z4dh0tZ=k@Q2LRF&)r01GU!g<73nAX9^zK_ndj|M;>V_)p=pXX&M!u&!-=JP;Yz=aw z@y9}@JU8GYP+t>8g@5OO5vZ<GEi^CQKYsvfGSWq>}u7hYz?@0YJ0)VnDjUU z@gS+e?||DX{*A&=>wuX87~CSWQ@`IbYo~nviIoHRcmJIFPNFQnCxbJZ2#Y|M}EFU-;w`~x&&l%2I2v5JY_;1_PGw>x`U5XId16P zsU3Fs(0b!BQaEma^;Ng}gf5izM~TqdcFoMbK{9(Y2Karn@0{{3Qg_wG@aUi7i(v{+ zxz%We+h2Fs{3^T0o+4gw20L6O z4mWXk)V;%9fNIXNf$N*zJLtH5&_gue_+S9d3ovBr<_l7I%H|7{9l$=PFZ?@EHGYKNr3y6#PTw1?FoP zj&r_ezJ1RmQTz7GU~>I6mrlbK7EZ&zJCgj5EWuyl^7cyZ9=WAcyWc{&f2Y5Qa(lmi zbANunIm#CT&fVV}zQHmYo_}V1zw^%@(*J_Ga{sx{JJ1i-pXg@cEr2}q3f$+CM?sji zME(uG5LHw$XDI}(RE*Y&Ew~t=?e|PoD?M$)ngXqgGs+b!J_C5!CYTn_{4y5`nJbXF z8Fq|fFy<9RMe#*y<<3=K3|g=h%at!T%bAZ1Q#p*lRyq((+-J=R+5|-BP@aGZani*8 zjYlAsCFgt3tpvi{_uci%6Bx$emoGOFs)j6|i-gG4hddF@op!ClMOW>O(DU6D6B-3@ z;{5Y7ZB5!RFaz1049|Oz8Jm4zZ95EuhwpAE7C;ndtq?s*2q$jdxreG;v^Uyx`_YlR zKhsvCAe0vKQpLYUA@N9~6K};ppGcPIdr$U&x%GZBKm^ZO&f@f2!Eq<|TLQsy2k)X9 zxN_IZkDh;vCWo@xx$-N+>CHszznT?~erwGRTC+87lUV}6aJI?9U<+{$rw_f&4r2&; za2wQY9#$ND^XGS=yV!K~C~!qrwqs9UXugf>Q!xz0hTz-77$UrVhLShKrp(!L;xMe< z$^FJn89>Q%rcL?OqXit8tPp%N=blmyjF_z6LiHxN+%U21AJAFbo{W9F2^oh}AnrG^ zmzJWjBbW$`*eL9k%R@&2!dilYy(2>|DPln6P0Xibo6)J^2{0VjzMoXE9;X zdv~`9XaggyC;8UKEP|!GKY#RqaZV6BOm*TwQ7@w;bWDUS8Ls&5+>E7 z?^U^CU;Qs(VvliJba_N@7_OfCN^T0+8^ zjQq_oT&zAqL-<^YXCNuri*Y*-u6s60(J(z1o_tr9@pCS(;8DW!`>&0DqMlBUg_vgj;C+UzU}Cj*)dB?#$4Z-;-B{AGAa%DHeRqv$Mb zCST{J_h3%Aa3m{tOE+oNvQzJ=jb>oa?gzXWH|D^t{{0=uAT{>GE3?xU1O#!Fxt8PX zG0rn^Fws%2ti+R-YFhQ=f(rgO1sk}elee;PIl$=;o|JdE$l|J)K-ZGx0#6No^`mV} z;l9S~$A}1XQ?r@5mv$hm<&=4!B|CQREl@d&k%CtbfBp(y;M}eogdZ@&j@x_p>gFM5 zE`0gIf$P~LydQVhQjV!Bw@Naeg$Zo#@1I8;_{s_C7^Z3EV5UN&X`so&rp}|F8&@HG zhtH58{tnzR^1pdV60RUWwgLs}yKvjrPu;UO?R&N=5gK*qNJLJSyNk{fh*Y!tUPX!uxwz&=icic}6gRl4S^0Z8bHBk*KGrb%^P3#fcXsu@}w1JCS?&! z2lu|CMVXtIgPsOWKIoSNZoPc@qZyV=?=qZK{P^>yOr#!7fAM|qFu#A55#(f(C;ajU zt{@bwI}hP1nN%F)nDam$U~+PL8un-)DU0gZ;@BJ{^K><{r)whdP*p3dt#Q%y!~mi~3oCtvEDkhM@?I@*bPPw`xBV0cmPVs+-)|2@c+=Mb=P$Xr6+e zascxE3|1%TuZi(7$%(NB3sX&6t2AeK8|N%Ok^}}w5R1Y&tbbM7EGQeB+2q{=kQ!t2 zVPE2&qv(p1_53*P~(3yF273RVynoF)OD4&SshW zDw?gU{?$y2eLq64e-${2@oCT6+zTRb zx8e0OaQ)gHV-z$h8s*%5yB8GVfsO~`s=IfX4Rrbv=7El2_IdBhIV$=-Dw>aMSSs$L zq!Nx}O?8)B0nn%jPAt<)VJ6XsxLyL(Zj-AJ}VNd`7`P^M?sq3qx#gH=3$x>s*)!8htTXwE!17MUT)$C<_ODcnP zcwh~)YDjoKR^#1C(IXuL^S5tLCYSTK-${k-wWURm();4p+}38{u-ESE{PX~b#u8iN zZVBfE##6B-{X_DG;-C1B2VnswrDy{Atz8QBo?(Qp=0bvyaj8^P#k)k55VZ!(!ucq;iaOqVueAB?o&&`g}6NxK!i^ z1_yeNvw+gL#D zib~vz)wEk4k#riO{&s6XQi z`7cz0_oL)Oj?4W4<@>&sI40z;j7%&{MBJsOB=c4V<~#hM0W6pK$LGh05jnac99Rt# zuWvmKEnc;NyQp=20=4359dr|F`oX}@y}aQ#(%6jEYK_w)J`o0L>g(alRhIX**`1VI zjNk%+$T=%l2+jjhW%D^LTs&C_73rS^_D1MGlwY*kS>PN?^xwc=8IkMRily+K9J?9(Ps(4dLqB?mT;_>2AeauU4BS{BD2VQPE*M z1r0{f?W6=xNgcA5;l_+f9sWN4aj5Qc&IQneN&-Wa?h~5vgLuP=OdRC^{ur^*GpZEk zUZx-RYS0{mS*d18Uko3FXLrFjnA6H8_I*`BUPvlVQShp62*z7ZRKlV3@v{-Ve!3M- znlW`gGX_{tUt=Ll8BMNe8JSW^vSXi8VrpUE4es9LeK>j|P_Jvn^Ww1nraje+9xgH> z^P4wjt{l@yL=6@ij7rgjCM`}BN?X=DsASe*b&fiSrIN_5w0()54>K)=V=sk6FQs#) zs@IZD$4t}IXNTdQ+bLRlg26p5SM?HK8|5A;gMF68D90iH!{8ySV0EJ_Qa`V2)v?^9 z=~CaJ?7jL(&sV@@=sB}@Wp7_hkNhJI_2h?ZQrwyPOKq&7%ug;vTB9%6pT?mMD|SwW z4(V|#Gw|&cSyE>f#rRc~f&c*E?Cc^bwzA4JTcjwsQ1$fG98z(Ooe95h>GzX3^CjSWo_X;ZEUJ6f#zjD_1Zk;IbWo>aa zHselgsET>9nt8E?`FpR%mN2@z-HIN@uTzT3qPK;ONE8VYHX$NaBp6$gp&g(Pm5*FF zYI5f(?msp!wIZjcPCFZ$og4F=4F(mc6(jjPovCTdDzrRobKE_L-yh$tJa%n;J#cl6 zHukCkbyHph#$QN}B~4Rj>biHCr$k03EmaX4h`A<}V42;KLGhCp$&2sYH|plE&{~PV z#?&14Vs2tHDfcW;y_3we%xwP-@8=tHu%N3ob+kZ2(O=UmoHPG6U668zrMu3o zqA_jVxdG`z^O~zus@J9}!-fULIkG%e#V<3~CU=u(CasmJV&0EPZufs1dTZ%D zdtM{l`;zyr`=a-)Z8n$fYi+Ci?g1BEXYBSIye8%N<20qx{8INAhm@kFaN38Iu7J6S z_44!<>?!+tp7C=xn;!c(#oG0WOkd@gzfSvzG>sz>HYn%7i@Obo){7k6&%hz$+^fV7>>z32A6 zfwqlbHzU3K$NWzlBqo06%a8RL4f|oa1P1J%9tgCp*M7&*ZmkNo@B2x&p@f*Vz5^66 zJc#6OP$O8%x=8GQ=^1{YEH%uDN+i}4Y?(4?`+EC*v*m|=TKYs2sH|9eRAB5{#sdt| zL?dG2_yCJF3kCl7K6QO9s#clHw!4ofj8Y7{!})1Pq<7}OkBGA4W!4MCCpQ4yxYKP^kEY+&)&$ z1HI5?k)@lK7zkJ>Vh~8OFtPTx+bn+lZxTls1_`DttRv`h*}rHj$!>-hG_LdfSBG#k zT>ag5v_dxyemOWjjGPn5dq?Q=1q{S;Y|}cdv2}XwbwJ+v2K1Up9DC#kHnCvoBWtgY z(?E%NuUf~d#8k(`;~20*V>n`DTpe-Y6l!C#ecyA#<@_j~GhLgymBJl$Ay+Jp#OSPb zrFq8?GnErX$P1r~*!1QXXYdh6d`MIci0qX?IopRxj`A(7Q+&guip?03)NT;9g?>QQ z(4<762&Sq8Q!QdXr0mMv6fprLPF>*t8pkD>SWNuOj9aIHw#!tePhFxws)isvN*$-6 zIWZwMP;+!F!$XHIV+5?UU1O{a&%O?jV=@aEQq-L;Jxp`)wYCPQDXPPNR5P(5ks668 z-1x)VvVjSeinGvtI3j7^S!H()vMi{eY)j`3R-2PLn~KM=02%PS7fqM@4WvqRPEpJR zwA>p37JRtNf-7tS1Yb~mOBMP+M5hHRGKapCJ@E1`o!kNxzMGX-6TQy5gE z1;rM%MqIJ8$zmp^c&2YHp7>VT)SR(LTO&3fe zY3zxv`0qu>^&O7RGF_LYR{ZF7!L=(d%fS(k2jb<%cL;z*p{$b9_Df$=wfh8s>DzNT zcRlX9*GH_L2YWkHwOzv<)it6!A=;{`r11GG-H^fvQkS1%51>q2u#(ov44ZXX@A0(wyhS?BNZKMJbL8ssaHpu_ZY? z-4Jyua?i3W;?>}p@ria%d=7LEXi`gAMYI?>4l!3%RP%&|slXzh7)uFu4m8u$q6yEc z7*9DMdLLmDpQl37)5w;JNfERClQKtH8I$sZRH{f>mg^0+S+WF;%X@^2fGVC;gL{sW>g(Ls5qMpQtXIwLQneLA$w!qY3ZCJ;E&fqzm9;;vyjAT0uO!8 z{isA;*AtX~h?jQ%&QE`X9)ZHb`*)7?wrxS{vB!g3ixqy4yWls9Gh>9!F8}Wf;8cZI zR3pfoA4P%0(<|sCyuG|-9y#tjc;7c^FfXja2>DY73s_j7nPxp&t&@Z3Z5Adqt*%%k zuu3d+^mR5Oqi#x0o5cO4JTWmFg=r^>VgpV95P^km3w2qZ^&Rq>4~xYx%U{?L}jskOBy^L|$){-&5e380I zn{?=leh45UPwJ&z{gDqN9?#$)htFkKg42E;K`%}rQQ}xkMhqzfO$&xTE=e=ey;fc21Tyse}-zh5;uO9Ari&lC-liw)Df(31F&;1L}wJZMb`+2d2Z-MjNEIIvw z-(ff+)MjO~V~1%v+3mW8?HXU(W%at**`0p1EHD9YBA<+;e8YF411j2qzY-yX zjCR9_OqT3q#uUUQRu(DsDawHs4{R3M)rt$)6^u%hW=Xt^566ti{2|r_NCsD(<8rpW zMQ_w`bqvyK>fx`VWtQ`|@Txn7dP?Q_bw43zQctHlvHppUiDZio3dnl5nP)ne?IWGk zj}D*g_vizKgZ-u+hdYt+^Q6u#EfhA^0~i&*WqYkA@tVb7#NFqvFmaK}@2BTV>C_^hw#o+SntpF{ zd1RTg!QUw*y>y$_lAUEl1u@EV_LO$I@8=8BefSe`Puuh#-=qizdWYXvYrh5V7P}r& zC64tsKVBa13CKxGZ0b7<``4Re>gEfz!YSN49n%>)DIpRIn zy7<#%F@s-cKa-anf4K@;WI`^icp!Y?f6kuO?mf6G=6L z0ZlTwRmBx<9@#$hq3Nc`Jls{4*)o)yISW3u46|syeZ)a-JIk#*k>l2Ux?ly0*MT*& z6mrBW#dj~bm#$~Dmb;e3{?yGM`ySr1KOzgh=#@*fU{B-V7 zE)NFGZAU}kq9`1Rby2U8iM5U=OgWlPYVoAfbVxO7)r7D6MYJG1)O$C^@rcUpI5L_dqpw+Wy|m!osXS`>Z(R z&5xg^r7mG)ER9i4_LWq5vaDxhq>T674HmC-u4$f)x}Hr+7M_)aMOd7nYp}w?Rh%3H zUfj&}xa7@r35}TIgK$)huZS3mU`&CII(a{W{0eQZIxpePF~70So&k~vqC>FEO;h6)6F>6k~W*)@`WvQve`NFuF|oz0ip6wyA?=onzYo0rsDgvmMQL_ zDQYIUA^K4n`|i;qnkE_VIG^>}Kx>A3rv7N+qJv7UxlR=uTk6E}LxZ`G*%w#YoD>F^ zc)2W6S-HMN*Hl|n*GxB{EA1n(uJ!MdtpxIh@^?4TOqS+OiO#AImv5R99dXO#8H+1E zenpCC;`PUP2x9v-R#K~|jcM&%*$a70Y<|}wg8gqrZhe7{iKu4oeF?h9$#Zo0WUisg z-C(QJ7K=!_o{k8QD5A2X3X<^=RJ`pw-R z(&eiUng!2c$GP`3^bok!DqOvnJkFF=ROeLGlGgL7KdtB9du1N{PmuYx1)}sp>IKN0 zL&4QnM7^Exm8z8j)Fy3|b?q^h8uE#p9Rf+uYk?~) z7%v*5Lre0cDp*!CZCyx}Sm4aTqLBY)PbxCrAimy?GjS|V*>&Hn@jP$LcLt?wzgikS z?raVT>QqW zwdhBj1!(2UE9`8PEVnY5P9$d%kHPW;d6h@D=jK=Vsr7}6lWrh#FuP`M!((tf9@N)9 zFC8sq8w769&@&SM=Yfds%Yi{>cIdKOZmNP?)^ej(3;K=&l6K+XWn#lx_#yG>6-3J( zD03=Y$}hOzMVm+>8|ir&A-TUTdwXa8EMx^}zsDCa&po^a*uHCD1t$|MSdJ<#Uu~Up z(}VWI9;z5cHy~gQ;XC;x@xreqNYT%&MaIe~Nc0_*VBILWIRk3oLM(ImSuk#_Tth;b zS?0~+k}Gpo3x4s(Rq!ckY==oo^YcR;)M~sB*2VYv`e1jY0D1w{r|nSj7-g4It#+#OB zNCaC=3Y|(e-42WONY`$FyN=vVudH-$cK$LW!Ft=W7QTY6MbQ1_bwoF#heoL*dy>n6 zdnrMaPmE{hg591Vv&AontwTO~MW3<6>iK6%B&}v^^;KlyMcEj<-#w5PRl9$8Nlw<9 z(xujc_PqMn9}e{Nq5X}Yo*N`I_>e4nPE`!}T^mm6zHL&}iJ@o%-a-4OAhe^{qW#At zKMOfSiV$}4lL8e6C22uphH zpK_w&-s*x(;pxdkhL>v$kpQI(%R8MP}(sa zBoJE`bEm@IJ?y52=6p7pg%eYz5i>AokqjENWJUHbaF0#7V^0x&6+Qja>ry|ea5(B< zdrz|Dt|`n_V(nZs6xK@LR&Vi{x}Z`oFLwb0Ad3{Z96jFJ(Y0q!0*e+soHheq3*NjM z&lj;XS41|tHud$^-9hh1rqZ_0Ey1!RHDDpTvek*x5%DrKbSr1x7H2-z-lsEj219gv zTYEz^kJpaZCtPsZ1ZPFFBAO!%Xn8xoXQ93G9u5$0F2;k~BBs$PcTFLT0sXNf&Nwog zmM|%nC`>bZs%%@0b7_6cSbnX)Qc`-cV=ETUTfQsWOKX+_>ZgAB5}=4& z3U$@t77TzwjomVP#$`>oW76U=q)eE=Can60s0FIqu{W(03tE&oTFzMYU*jA7Ki@JLZ(j{0I1>Lr7+qP}nwr$(C?bWtzWA$p=_G(S)y|xL(=excAdoD6TksR4wktQ*B)N z{O)wWdr@-ybSyq?-zo#KVF`-4HxLWcR?LEUQ5vEnzo#Pi5A?90WAv~=@~68MIzCb0 zxYW4?_R!V*US04YZ@^eli%^kx7ti39$-CFZ64vaRD!uQjP(mPXkBb3@;#gB?G~#mL zLap2ZnA*5=SS;6TsmRFpB{SE3DFeD^5qZDU^NEQx=D38+P(p^DBNCoET7ru;w9=c*KLwx}&O{U7ImQ35fI+iFIN zfd+>H(_j`YAywo+H7ux#(Cbp-Ltv3{aT!P#t!37)D@Fr4YJ0|SV}piIIK4#MnSYfV z(>=gD$r}Ndi)4%NX#Gna6YqZR)tU3mdFBR9?=Z`7oN3(|{Y%fR9*mM#1wd^(D$_k7 zYWKjR5U&iD0Ght^yztwUbSibHc*(46mW|lZAy_04DpoC+P$B-12+m`LYlkI66slC4 z(w7?2yCh)bW7){ESy`7_8xn=i1l7bQ4n}NOEKMOE00A>LFD@`33pWugVK9ogpaHEj zNfRl>#QBM#VTF(dA{)6}iCO1!sdI$#x-07MomWKMNX4(Hw|CLUEf1+`Y8LWQtvoqO zU!Ci@-ubvzcY1vNOwHu{N&3PRI|6B*1XMT*=p?R<#1dZ?@vdmvDfy@$s4=gMG*14^ z20l8@3Gi}h>}cN9QK>4*cAA>uj66tm*veUd%FvzbCLUP@kaT;dA_cUbmkJv8qL(B` zM<*$NBsqwvZ*hM7JF8XrG|cXv$NlJceJCINsxJ3(uLpG9fLu{v- zb72ac2rCQ=8>SgX7HlwoZc>!DpM4pZq;IZp4;g%)?hWCazl8SSz{}iL@^?KlnCdCB zbrK5OSvD=5{#X^xl~PO2(tFf`c41PCTDihC6m&YL3QK#VC>Dn5#Aq^ZCU~+Xv4}%U zg|4i$LcZQcjuL$-YM(+Hb~N9b5oAi#S*gRKwduk*`|7BOlQpg^E!qrR*#Gx@t=)vB za(UfvEt#5;Re}b-`sm`?E;%=-T5_~|Xg{oB_FM}i?pDaj@v4s)P!dT= zNxbs0p$DXV69+7wkAvBnWAvGvrL%hlPSzhq8Gk>f-8xijOLURqg5w?Igk#O(MKo_C z=S7inWXzE*U+@HCf(S7)bs&SlO;eWW!Lg|jJ#%Y7O#kveHY$b|Q1z)jTS>Btbl9VU zQ`WV_qsy)1&eqO1{TR<@w2AcTsp$#{NR($IrE=A(GGw1fL)wBOBMj06^6Uu;^U*~5 z
    )TYIfnL}|w>-lOjAV|I;er>JWJ=6=^XH@?@u!g;1FeLSPj#c!u0Jq2M-%;;73 zWb96tZileBaZR^?Gl_YEi#Kvrf>jb-8lC(Ota#3dZRjlO#>s}T_FR2I3UVvE{=LO+ zUDkx%u}kKAX=aZ8#g4L^-WXDU>hf=UTdDVZv7J{Y;x9W*-{nLRV8Cith2&Jd4GQZZ8efmX)S$lWr^7NpVcKEHy11O4s0Z1}4lVKU@uMlzMIlBgTX&Ln&j!djXEGX#4H9V(vbfN#eR39?#$q^E7_0g70Jc^|SOOd4})gF7Z#t zD&?!XM#yj}HLnt9JugOpj87(>$eiX@y~!iXNW;T=kFng8elX`_G&=pwmzxfs&Gi;$ zfBiKSA047L)j3uSpPruRZk1i9>#{$fo4d0uzMWLp{#gVV3tUYOo_jD<>Yu^#upX(b zuWQkJ6&H#QPf3@zT|8GteR5@+^Uj&P3>5I~kM)jrTT$hF)w0^VL*HcnyqWZKdnq|C z0%VfJfH5J~Ar3Jv3KSy-ni4Javlam>4t;=<=(~19D`@I|sTL4OM8z0RX|o=M#sXdg z1aFXN%A_S_IS{k+SIe_Z#Gh|ZKM%7TUT$V@vtKQ}8}B_k?A{PWy{n2CDl*C#eg>FY zr()7>BDy-B?AW0dVC0nqn~)DM^~rG}!%1^fhdWSphyJJ`4@QC*O?Aq_zs7I8s(z_g z=8udI-94gn?P+(OB9{>wzyNtRiarXjBNTVvPrmgX*uTqM)5}mcfotp{i_@%?EiApd zd;AGc51c!YB|DpXOMKMu%WMthtaM}&5M%eMjYh3;QmN0ZSTiHyg=fcc9vnWB7WZX1 z&)yZb?G^2X!#`4ncvN6mFk+E^bXZBy(4aK>g@tt1oqdue)39a|Wl7JL`J+FHU=5+a z-7c)mivW`fV69?#&dBVGBS~SoY-l$%qQiaidHXGB7wdJrALvf!MQ_BJ(DS`OsPvX- z(b@SspTycDs*zvQ56295qjRw2Z?I!RcoaE`_CxRhBPu(a^!b_eDQZJ!Wo1F!5gZO% zVQ7F-Rkmvo!zXMUwtQ$A_G}X8Cze+52#T>Jd8EkiLn@>Jz$02%5xoT_AR~hkPBNp- zF#`-z7}11a01_QfRX}(cvca1Z=K+AHRzmVz?yfyVjB!GNa;8>ZAo`%#ia_i!i=|}t z7XZp&H|3of&N9F(#jai^{Lyph8FrgS9ER_^zE=qjT=Gk=&XU*OtqHw=)Iu(o-+*Ij z;C|WJ07c%%wcnE%mQ6D%uXj>%Hs^JO609?Ku%>2A;Yig7vew1_g;r#kx$_CQy~VHO zg{jj<|A5wXGKkNOMyoIP!p)Bq?+E~4huH-Fx>qje$**Ad$UOB)sbF6+?e&epFo|It zcP|gThP5F{m4bXv(XRNc6n zBa6Ya-#TL2SQ$B!HQPd-=XC^Sh9Tm}BM*^O6V1Vye*He9Y|Z@rbNgE701oW6*n>VB zY@2(jryBtjMo1BY=AK!cNB{CkTkqFS3TWYPYc0KBmg8AyE3ndQu*wOZed!A@x?mA^ zlQ2hXtg;9mc!UujWtJEL@PFJC@X7ik37||k5Iy!pb^*ZTHc?0VeF)}Z@wcCYs>Oo? z9Wx8~lOe&FzV3+4;J=CVp%<1f_KocfdV>lQLa^4>_P(#_5+!PWvUI%FtGy1k2Nic< zZLXKeSlzKaWHX551iGkyat%6~&KIG^!4c1g&z9WA;SONj&`0)NAZwo5p$CosJi+E^ zX@EIOK@aMisDC_L&~RvkJXi8Jr-ahK?_XWo{xaRE-nF5Ahif`9T1uApK`rK+0%_9! z{@kNGUpoFjc*0ftJ*~MsCBa66*$807N>gK?N;Pp>O*8vi zZI#j3wIJQ~A+NE=0Dc=CG^`R+fdC##S-AuI7dC)YjYJP=D2w|B!}rSS8Y8yF7RGoy z!yRczkE!@<$i%p!z7U89`$*$9<4ipfO}nF4MiItGXtY0#%@(G^8*Li+E%g zL~eN4Lx0`ILDFbg(c$b{&z`h7I_h!_IZ?aT-ooBEtDL9v?%H4RT1=gGUwhexR}ri) z+nUQ~eOJ4GSm|ZwLAxHG>U|HkLz%(1xL(rCr=qX3neNr$WAs_Kl~N68=(gR~QERWh zp2M?qu}7cv{f-BL)nUTKsfN6c+OrmHnYHTLfeCI6u1R8zb#&0@_jq72HKQ3_ry;^D zqg=!kNR+VZVD&NeP&9uWc@He#*nw(ab?_x0t<17g-!;&aJLnYc<_(`VP;a9A@$jpm z!0&q>TYucw?o$mCbV!j*tlCkmeilnO=N7iW%pn}Qzu>-l>8`(|njk_3X~0G8HBvts zf{~U<#jTRLNdC;!Nt(n;eera=)CEB2Q|=DhRR)GYnuFkvS{H!Ll{cecwFI~o8}BbJ zD>;UE5$M3P56F3dEh7E~(Ixh31cq)OnxogbD4O)3RqJPlUI@T`RQ zXL(G1gp?E-61b}fyJ?5>P^B5=jBkRxbkO6H+>9t&k|j}&QHPRgqX)YpH5IE>)aS0i z@N`vB(-PEl!(W{e`abTe~1^?#`ATTe9pcc z;}7TebeSN-uWNfZc1N!x>;gzd2CU zfcG~@Tp+W+xVr(J&saTJOU5MfrwSGj!f=TQh!6l{A&`86u$ehaW-`Ig7r2J@mjK|z zI>_N1sUqh@eu(1B)a(o?o7pc;jC@ySm1ykpRMuo_U`Eu=UU%!mXCt98sfkq!OJh%u zj!4w~F5cA5y88x6%l?m}pdQB+qqd?uAAcR5{n7k8o>TcnTfwe#dyh+JUgo?(_zZ6N z0HOqt`fpp?y5LVt-Sk6718 z?qx5~n6)}2ub^E=;u!JW<3Q%z=G6B#^g-niB%MTyAPLgc%?Q$T>G-24|9uZD;3~z8 zRS?rM9$br3PR&k5zSQ?Q+0#@F*ON+h*)&$%havD9N;&*BGEGfecL5GtfgQJC=7Qle zJYYSDsxUO1WQE%F&qn2W@TXhE+vGmZ8f@m2RNi6aPMKs$Y!*qp8V-#@PX0La&>GL3dq(Y2f>LwG;kbHtkd$MnQ(ppi zv47wB5n_nZN55isd)f2i=kney{L=DSVkS=Z_x@_i?`<&ZXpZMK+7&%-1EMmV3{Lp` zEpgoEd+YnR`|D?q$844}`I(Uy#cdD~$3z1$!KJ8j1xqqonM70N+q95j>#+A$Cl?dI zSg!T0qGASv<&1pB!)gZs?>r6?1_qv495fuXJc~J49psL|HdZ%bcaH8gZ}{w+>uzwC z(FU>)$918Pp>0pEq3u1Q8c=D7;PleE z4du@@^}cC8;97oP5LJ)6lJ?KQ>{U~^;>i2mN^A9Ai1I&kt^*Jy1u)c2`KEm<#o8~M zK=~fGRoblp5$|^eaL2+1!XuQeAQhliK)^t928z3uZ|0NHQ1~iTsj~v|0dTu_6)<8+ zqTNChS{fmGDfK)oBS4PDptU(;g;yM~6ptJv1lMta!O0-gvLVD1PXJ&zG-QC{iVG+P zi51;RB1fef4g#)xc;DK1G)?yg>y$=r5?Y}s)~+YB$Zjkiv-lpk*MOwEI4FVqi5%&t z#9$Z)yc-qld8_jIat8@LiOcsTFzhpSXJFJ0G;>61=+g)c8nhtD42msQs4~sv1N&OV zHFd3Y>j8l9*~D5i(bRCQ_M4}W+ijQUnS}$vb(ns;08dMeyC;nCo5U8xj_vfiM=YpjtW?jJ(alg zaaNqMaTc;#(PEY&M$H6y+O;Y3Es%M8X>t}KZI*!|Pm4%3+eioR6>UxBPdAqB(|6A8 zQhOeG7+#y9q<;iEw?B5*WNx38}y(73IhHQzl zsVZGvqZ0&GH(C%txrkbz2p6E_{yOa#($V$Qbv+9 zLMGZ$?l$OAVy>uHMWPt1Bhz*fC{#r*lR!gX{1p`y1o>8T4ND0n2) zuZ!4D(X$G@rNtW~v>#Or-qqNavMP>s-ence%Nh1{9}M5CdzZp>?C5nID(gKqGkD(# z25_FAF%o3wAXIaq-JraF22@JvZ$8_QqCl{lN2-{v!GQn;P68}-9$K#89x-lGj5nyw z*)&um0mUJ~Or1m~ESHjiJo{-TnpA2TW`-T2$bxK6k6a${+cXYaTK5yeOp~9hKFHZ0eav z#)7k%SITWe>Yg>2gm@e7zVCAO*sC=?;qb~0f7`cJmz*Wzs`Fijtjku3u=r<%YODtc zSkI|+B#$X866{uPce^h9zPAh8LKQy8#q%P3j?jH1Q!7H6;GBjs=-x+DH$0z*rc34* zCU3f4IPRt?rY42Mx=WaDx*K2sHU!U4A9P_9l)_$C7&l6X2`+bjgMu!1?w&^u$6vY2 z84yj0oRjmk(~8G1!lD_XGT_O^77z~jkm>^m)QF-twYAcAAobumfEB-5zfVYQ^_Rsr zx}2~68vATxQj`PJ3$@wclJnwlO4x1*U;B5%*%!{qvc2!v}btnuhkK>^G^ zIugztx;wQgln?6rEG9X{B!^E9AN|WFKY|IL@uX<{xY#s^9|e`7s)l3Qt3i4|u$2a5 zek9njov)WNZod^*<=_I=VxGk4A=x6f--X1eNrDu%vSy6kiU6q%k<|<#V3xwfCKl*n z_5XmFFo(Ay%=O^h^81#@nZ-;g$~F^X5ZMuJhUK?;Q1#O!mqOX|u80mYKNtO> z&*=i%hcsTyj*~6@?&e~f<9X5Va_c`e)#|W?Q~4PFpRr5NHe0Ec0{r?8p9$n_=6NC; z>Gb)xOJhv=C_Z)cr-l9CH*P#IBVO~+UTt5TPv~=)=Q-h}4U@JhDTldSn+5of_zx!^ zE-7s)Q|4iqaE*MT!+nZ~56Jve@;-Et9@)rF{ejTnNMvuaFayNnS zdTi7V;ra6mSHXsz$StBiDij0&DMb!|?6qGe1 zi)KCqUA8f6Z5KehVwk}+lx#F2M0yVyXWI4J2z3CNo&XL6Jx#?qT&J^ZFwa92hV#Oa zr^&#z;`bc}}Xr6Q~zMAbXG|2HoF>^5I~EHZZH4R`7KZW_?7eKW zS77mZ__On~au;>4*Q>?zWA%nQf4lD(aCI9oe2s^R=JQ=6qqMCs;*`;MJL}Rd_#E1=pSR@ z+7B4dGG1nu_tP*N)=EfSH&p@L7DJuBJaJbqJI!4G!)oko9)KVxa9(!S5%N~K#(Pnhg^ zSRD5|H^WXE(eZk{B#wbvJioVJ_`Ghm_>CxWa&x6|i^G9%LkxQ!B0`WVCjB|B#M~!s zlG`ZfaWwS1D>Ed$k_yZA_wx1%CG#W;vw7G<|3q;|!8hP%>euW4Op$o;t5A`5Q>u{1 z3;ra`TG0I!`C9(&xS8rlFN~H5ZZ-lPLMm@m%Sa2bs%`-|sK#1m6}MjEV(H8PKpZi7 zW&skh=n)7J3xJ3PK*VA!0g<}hYgpBx0NqB>9geBb%HDvbA!rriVvDDZt$FbHtZnX=|lC^y8+E%{YM zzTkXX%0i9N-47i#hJYe)r$9smC{pOe3;(uQ0q&(xdG{T6>FwL&&n1R0JcK0rh#Nl$ zd%eyl_vPWdyp0d?^7FX9KGLoR4li3Z{{eh@Q=tgBm7YmNr+n zQ^`Z5oxgSDq58ayLbN{E&s)IxX^ah7NEu-fTyTLuIiGSG#axQ{D07m>FONY!hkPda zgi`lN7Zt0FW#sS5SXp%KV$Ho~s`OOaD3=jGnm-x8-kZr2GB8^-{p6ggP2HyASGJSB z=>ReVM z0jYzpf%UFHzzR@e|6uHJY?^ zz@sp<$Q?JZ;zu0-Bn~jh4V+6c=0=Bxs(YQeIfrXKl-i#Bz)b~Jvqm-5xTUK5HOg70 z0xAiGU7vKC&N8kkODN7RJpySi?(NUYpDaZItoKjN z7J9-t?nNT@2zowvW;DE75Z1uJ54%2{zB+oS2ge#-M2=o}uRiD8i554?S6L3sh9$9T z+>*Wr8eqw1w{>kvQ*J%v<@=5MOruqF>@LbLrzqN0BEkX{he8P*G0+1>)L1~IR+G^j_YpNhJTy?fv! zyc^=bi$DNv|J2p$HaL0eevG~6Sz)rZpEpRl_c3mrrle2na?YJpLvDQ^Co7*^cfI$M z-$vbjj5LMoD;~$gV>MZQRB%%hM=ns?J?k?+WQ8?4B#OtZz-eDZ zdp?SduCn9*9hb|^8#%de&UP+r&L3^31>OO=j$b?V;i2Q2F#OVyyv*2%^J+L%O%UNM zr^g*xgr|?h&gy6-OPzV!k8yK1F@KP(L4ai_1=P~pzB9Tfk}yog7O7;D+<)I=f}CAp z-}RGiUCSeoFCJ`*w!D7y|seU%legz>_-IV<%fB#ebVl}&M$nxD&-Gi~QGDQ25& z&g=M*F8>9VueJ0R(xZpjSUgx<7RT8FD~0PGLqIz+x@!_0I1x|k3G{Cmc#*tN8+t-U zv2#o-Bwx?SkhJ!$xWIyCiAaq;YB8zX%srBL_6lxyt8mOwsLV@I7*mK5Qb`3(og@;! zas@1TAbm?5e(uXn<#m3@qSVjitW9_os3Rk&<;daz3P-A(D6KckK^zY7nWGb^sR7(u zI2ZChopxazSoLD?%9c&6FT%YOgW%hYS0)cNAK=U5*2tTHorv%O@%^=3=Q|({YPIM9 z#Ls?mwIHVkK^wq03Wm5dX{NXm66jnAM(pGfI8Z$$te^k%BH=rYUFYH4kz%1)qOe3# z83?YV-@gvVzJ|X*D$Yu6*&=Y}#y}U4KoAumMs)e`iK7HuCOm1#p-=*3VquPywjFWW z#2I0(Tr%Lm7`GS>Arue$mCly&Z>_j+VN4b?UFQA&dT{M16{D-ODDBX84qP7d;Gg}h zq{u5d?v$qm;h(E}doy-`=)ZrV-qf~ml=*J2$Ki>o72Mzw;lGx?E}IUVOh=^>m-(BS z^v@V+V8a{60fJ?nIPx_kA5&4|dw3q*iY(M42kYy&!?^Q80YQRhTxbm$kYb`_G5C5w z1e&Grbg^<>5wnAF!ROzx_b1_!2%5Qi68H4+wYU(Re6seIo%z?C=zO3Cv*BJ?&lH*q7$tW;2VY$PBuVc@J(5XmE1Tn~z9=m)||iP%66^%3%A zl8S?{+w|(8O2wL?*n{lS>So1J4d*boSkC_(^dh`&fi3*TZ zsZgy-)eP2EgL#AP0se9Og1nUcaQXuD654yY`sl6Vueh&_PZ18u{N*pBJkvR7!^n{x z4KnRqS4*$qlH}S<{Z>N76$@kxp0P1b+PZxPxg!eDNyk#|mxiT)mXx6V`lw+msAirT z3d|#;!3-IF;#n3n4C>f$m<0q&C;=Ya>tUb#X{}@q?E|ILr-Ro%>rYr_R41CK1RYK> z1W~;tQ$==|TJE*(U_i5GZuZekVk@gh+u(!Z9K$TguqKQ!Wl_yI>Z(!-Dtikpp+j25 zL&gVIdP)Gn*%Hs01l3RU!CM5MrsbusLp{X3-Gn5pPiv zw_?h;d87W&(H=0e9C=5Q+(26p^0ExO*AF?5A7%i~F%sxtwruH3rjs|>ZcHfc`P+Kc zTJIdD@$;LY$Ej*N0{<0*KZ~0Vc!Oi}yS$~N$>e9^n3j<0uEThvy~2BSdTpgAioRJodf)nCt0Q=$1MoF!W5A$! z?6YJ$`lWY{?1tHC%q>EZ3kvK6vxUUC;27?TNx9&U3}BAhtwBZK6H=#aRExw6t{R0% zzK4xaPbn3}?;Ky-xoBCJtLR^LHC;w)t2S%a^w00ax_O>|+wbT)X`A+XJ}qWLhb)d} zqrm}&`yRzU*>&MuUdy|2@2wP!EJ^AkR7D7^hKbj#kW3Vlt_cdavLIU)1GJ~P2@|sF zK104Bzf=Ay*M^@Ndbhu@2s-;z5*#6RODX&c7A{e}MU4E#_^VXAL(MYlFUcl>U4mP& z-JAPj*ZKQj!*k+2;3MVF5DT;r>7+nQ3qMhFN4v|C;(g*+Pzk`I2n{8L@N^NPL~@@w zL(QlIP{78T{&^Hq%d9#osAU$>bOM9~BE?3!Myy2k;(FNblenR}-S<4XmT5~0VE`BX#53+E|S*=;*)yrF7JGgqCu|CFriY}F3MJXcZ z?@>xlmAOSyw)Z~Xl2YU=7~3c`w33i=?QIF2sR3mq;wsRFwXw4Dz_W0Qs0zU^=J|gg zoIi(F?r{C5`M~h`oIE6+rBxuCcH*!cOs_&~a^84xHnL=aA*33SEBh9Y2q3=6`^2I| zq>D+YaOP#yjCkWJMM=fuj@P6L$Pjsu9&g~mT)K$`xfrnvakVh4UdilW%c*KB|EMK8 zp@<7>H9H9?jbY27$>i^|Q2vw$Eq;fq`3RkgE^A`KonpKytaIfWDWM1?n>y~X= zZklc#`3iWBYnazP)U>cg&`bQf_=V|Rqr9(Q<4=M4sZEVeM^{6UFAf!MVcYK3CuSMA z{p%(O!pwe8Ah>Lz(=dyu04Qw?nO$^>MO1bbhLbKbjU*CJ1~Xm52M}R(sDkXn3?sBl zaY=6GAR}%imW*2|`7Gnq>p>PdbL)0e7mEgzScvEg8IzWr3O+&G#40E!IdK#A*QR2z zU@bPQYiJSm$t&_eK;8guWsslJ)y3Kz9{jG{e0i|nCkrQ#9}WkK8p;lPX=M7cRiocC zn|oDq7Wd~*@`g9;ct^6pWNwJBYi#Pfjk>TDjjcrGR!1^-4`uOkEv)Ux7ZY7y_?en~ z=#-Nsfyj3^bZ|CIdg`{duHF{MAGS$MO79D8air43;S=3;&>uS zqAsS#l^g1{I$_89uUo6s+T@1xQB8TW?y0f~v z+V>{(@yc#CRGZ0dtiz{0V5B&T$B!99b~)Q$jTT3QFWRmwZbL1ZT)%CaZ?N(}ylqWv z6{hsR3#l8N*mUI*8K$2~6HcWI3GR@NC~1SQGwCFNb^QHD}$C{9LM=r3a+<{kO4) zuMN2M8Phq>SE>d_g?!hj7t436@KocvZdcQ~X?Vp$G(7Eg?u<~g_e6L!Aiy{D$YF)d ze-H%;xo3uFHX$^Rsb{jVqfPtfT98)59{ z@P0@!c6K_BAFPP^r_9XCLdVI$!150RiGhHFgOiStje+qWND?C_105$LJ108<^Z!7& z{;l*sxAU(W|7!c6CEcH<2$(qjWpWYxXU6QOZ~Y50`w71GKe@60M49Olu(17m^?xB_ z9RECxe>MFdb+dop-9J^be;o`b3o{)D3p*Rz|Emfb!9M}C|KOqhyA8*|N}&DE>!3@( z!T!HR*K`Ruf1>%%0Q_7V_MeLX4AM{Z7+8M7$G}3zz`)GO_`l=RSQvkL$NveR#>DvV z9F}gJ-(>I8vg5jf#gN&&mSVu#u1b0mY!gmOZJcAjMbk zCx5`alk5Br%6gEm8_eEDULAeC2GaWazw|T(xydA}Q;1~yT5o&s0-9D^tAFTe_H>P& zsy=gY7D$=~SgckVI@SGct>8)yv!0UCRaI3<0W06VC%;{Opjw z0*SIpGkCZ~7`KWdQaxcNm~G}3oT>3N8Ml~nOe5zes=Hncgg0Gso|(*z_uiO)$TZ!l z2WS-d0@MFK{{BCphyNU5{u`P0zm7%!hh*A+jeY+!nf6~@;NOQwrhj#b|3RiPakBj< zGL4awk%jHw`^aUtr;m#0Gy6wvr}xd)*<+fE9eb`znw*3L7dFTuA!HCH0fbSISWr+9 zHe@xm$tJ?4!w#sc0C-NJBuchz%sX3Ldodg_9EBaGA|m_Zi|iI0WA7|a{?0>p{!9GJ z=XB4RvlVxFm0T`YdDV3fAfN#;0K81Dp3ct~PZM4NBmm8GHW`~t%BLETCbIySZF!zw zIdFVLn?Unz06gBujiiD3W4w=i20SnlO|$15?;lr-ALW2|QUV+=mz>eu2H`*m$kj)e z4|H7CH0$XgR_=g`8y_7f`WSzWEQu4IxdjqW=CYaHf1czi0nUIF82!JxIpa{J-~{A= z6L`NrNYQ%{TCRZGxd9tbyF<-qHGK|H=>e934c6YA=`IsI{V)ZX072+7oWHtbpsCpa zgCGge-Dq^WMX39`04fdNaHEf1eSG)F=n77i`@g^d;Fu_22(rN7WY}z9!C2c7i70F+ zMkfMZk$tg%C^$~j)22MWvZDbO+YeEeH*S~Y`E_lUl>JQ?F=ny62O=|Q!g4?|-A}0z0H+i3Btz6ksrf5ChfBi=Zgzx7O^N%KzkTjw z=Jk6_8b>Wf4Ib`|`t&t_5q@!Nkf9HQ8QgLGj>nHt?o;+n*5i!-4oMGV&^ZL%p_&1? z?GD@_TqBkl?4t8p{c0y9+eIfSv%*b0SRJC2}#yt4r>qW&O+V z1V;d$+yG#1gotLuh_+8dBlv}IM8EkJ0U)Iqgrq_cfSD2R3Gq?(1#sSg5ItWw#Hqog zaUcPr5dQF}mKy@ff&I_`68-d>hh|l~4d!R>#Kx}7MlA=Ut1+0mx~iIZwA8q&N<57f z3`z<4>DaRqaIp|z%QXIGVRILbU5mMva9uN2jM*_@qG=+5ClrE)#uh@}1bBAw4}0^& zk)kwsS;!ILCos|$@!-cG`^bK}WOx>9(V%|1Ol;%`{1@M9Olee@*i@1>fmq8Zs9;#a zfv?rDg#tm-S*u7;!@ukyTEO;wy*wK6^s2*WU<+3b>MIx!EFP!rA%-Qr3mEwf*FRWe zuV6((O{y0Z@T>C8DX50kf*bf$>}jY(HgV5?OKl!R;1yhtE@)GlI4c?&Z=zdS#CQwC z)_^+Fl{?OEdOS3zjfTY-)VEYH$equ@K7&BBNU!BkjrR2U^9}!TzoF zyX&|!1lGJ+T*g`0`6Oo*>EyV%k?S(CoqHL;w$c#`XyX6%BRNayI0d6?wmbb4`|p$|ehsqn1?emz8Z~a4MsJt9 zzQnUaNZ^U3EW$BUmSQ;Y%Ve3&YBh~tRkuUte=eOh zSqKpFYV)tmUp`D-mG)Glk5z;Y zvp=gC9cF)P(yrJD9A;wD?4&Gw-(Oc(i6FQWD!=i>$neF;3UGP8r0M428hOIbP5|!8 z{esom@kY8x;z8zx{erOh5$G{PC3o+5Icx;^?Shei&@V>+MRW1&*VWnBzI&*ZY8Y%nwSA>ti_E5K2eMs zPl!0AJW)w{egwhnh-!PXN5_dHo!tH2vl!IWlF~9?5KS-uUH4+pVvq7NBC%Rva41vmh!~7@(94|qIpPC zq1b=@fAJQ4Vv>b0LK!oHGCP9R^(%Wo>K|ZtDrrYXX2czN#Jx%egh=9fhI^esbq0AO z6Dx+ZGi-F=;)jUnH`jaLT#B>WNiBlEi~1*#M%a)_l+@sOFpr9s06u^ei* zhJVP#C;MzB$5si zp{faxMG>-O<#9_BypEh2BKBnN3Eo4&d-Hpo3*gjK2&_U^7p`34lLhKCDlcB&7(Oxg z`Seq67y7H>9Y;I5VbONQO%gjacPe+lwF%liH3xMkc1L!{?Dn;G_736Aavgm72RpuK z{Ym}loe}=Bf4t);=52aI7J@h!pF%hc2!!ivTJmNkgALS%cs7g)ET3*tB z)vgILO9EaccGbCo=wrr+u%e0UeTViIDxqu)3)0LXH_f zW&xWkd2=MdM;5oS0@ttOmGw_M3y+z9w0q- z^VY%f>EDx0u=2{yC%rwF{U$950=XHd#uEiUfq#dL*i63%7M{!q&Qmue+zvH;-m-^V zLt?m3%EKw|0~?Qsm_Rk+_%Xr}gMXJ<9}NF+0C=U~1nAH2FHpT4B@r;g#1llC5s!Qe z%Qx!%J68Phw`B$d@V!D57mG34@jg?{psbcomwJ~_mxOkNx!qR>6EW_(*>zh%Wh zvYS*VH3*PQVRVPv^c8=6tEq6BIQ_;UtyO^SZ>*GLTsRNWwb6s<0TZr>UPg+;3wgE29nITOLHvB0~vI5VM|OeQZxut$oEPiB8q z+Y~*qtZqM=c({f7idaH8NSB1|G+5XBwPlgAeiqCiv->l3YNP)Bv#tk>CX%RTJQjhp z0XvK^NfC(@61^l2$t;B=5=dmaNHE2qiINgd_`_Odss2NHDdATX&#oeAKZ^)a!$sQ% zDWX|ZU@kb^$sGK_TzL`-MHCJ8V+A4@D3nP*j|kCJ63s*7wD7)cBaJYErzX=RQjM8$ z)PciSjc+vk8j7Hz$9T7-B1%MK0YyyTjFprl&TM{5{O6uW zUkpQLOc>#pSO$jw1wy2e0!)+v!>xix^ngJ?1q9eg4MqLNi~+g*&@1$JWS?ikKekW) zhjbLi5&juF$)9$1AczkjaniFf(W2K)R#v9rsxwuYa{3lbSTIGCB?A=evt`J}#THDO zv0^3U+Zxoc!tT%wjj9Z>Mt7j9SBzR=@7pvDOh1;wC1lK!*GV#GfMkTS)@{P3jntA6 z@!EnN8Q~7-OSR1LMt9)4w#;Ogiq9N=YmfuHAVjWPwPu-Cs|IOGwQ1EVOgFCNn6VKL zotRV^;f?B>&EVqn4EU7}oVom7dNPy}?*x|P0JuSjT(N7>M(xrKQ+-~)a>J;N+RCzP z8O+}^!lCWkw-1KBw8!{_Js=v7Rw$mblzz0N#?B&=bS>vzp1o-Yya+4UwgD^MIgxuU?_NZ} z-mkL28PgXTX{^8vHZ~GpQzN6Vu(pm6lsRrRIEPE*_`b>4Hgdu|U^{vD=2PE6%jZ6S zH99U4(Xz-I(}&6T+W+OCV@DMv$jYpJk{@h?D)<^Wju1(|lz!G^W|pT6q0()RDiq_cw74~{Uz|PLCQBbXk2-TQ4^$L#*Kun#1I_(4! ztY)Ga9Xvp=*n}hKPcjw1kQyojl{xgf@kkCfj~*U;kQ5&jw5gCtSEooZDGG?aIZ2o# zK!E^N5-P+7VzZz?0pd+gk_6 z(JYIe7BjPj7RzF^7%XOHOR_X#W(HeiF*7r>G-76E95FL9Klz@0=X`JPjg5`{V<%=R zvv9gPsxqp(x_@b3^LdIijwF&WkEp}`%Hhi4$K#{fpk(RL#Ka%Qf%r`23|4SiDivnc zQKEhULMZA_&pnrRG~%M7hl5kiPqTJq@l8DsEzB{Bk+U!i@hagdDZ@3~Z9G(273l0i;L3j_#1g{k@RK#w_WC96 zgN=-gV8ce~Xo&=BU<=cy2UV(Vaeat~7boNMF_k;anY~{YOM;s}%k=kF<4*Yd45LbF zs%okxYpL!EC!gn)lzcTzELP2@N(k>>S&}V_@9TLm$$?k>>C+jcqC`e1S4PYudOq$b zQ#>FN24##AtrA}TSsROhhXX@3xg0PMA!@B^YbolW%5}pIE51l!OOWl~N#<#G(uY#h z|I(UZxTYlC{mC!EFhlm(+nc zRiDwwP$#_wVZly43<3UkeDl&eIon1^AFEXcYN?srG%o8ZXg%xS$#D4 zx^pIUv{N3;T!m+33hL>00EWmjaz6EZL>3|i2u*}pipSSJY`R?(N(yMB7|e32t@5SB zE7UyBV%>mk7-+);9sk(_S~K6vuexZyy^B-DLXS0nu3Zd~9kfu?qjAdA4@h&yz2&wP zEO*8Y4>J414CVyVFYpKH%ZRkyVNqraJ>$rUHFR>zR3NFwfm4VUF4^FNg)_O zpKLr?PzMu|EGUr^u4Cqji7*z(KiY{|jzV>8OPK=XPxCd?BG$5vxueix)_F#+b#(n| zY^t}#Hagobh%YzQ-g(HK7LI+2P?xLvOyIyI{Y+r8p>pbwR@~EMI>SG}n^xf!QOl(L zjA(Lf%MSv|FJZu+DyR9e0_E)(_RKSDOmIMjoW$34@^)b3)BJtk)5;0I!|Yl7nGA*k zeWB~-0#Rv%IRNFWAotBOe-GEf>Qy@&-JiZg40Nq7gpP^u2ekQRbOSZIk7c?1vu~ zNL(X4{v+^X_=twCTM%z@6Y56N)shHvKO>fkFMs?YQJ{4Xm@A0Todq%zAqWp;bNdis#k z4XsBxwkxeiLD_J&A|~o31PNS3A;16P0eUU|YN_*D3~B*-x#GH5_zaLWsy~17>GcAw zSHs?)crS6g`L|H}y~X zK9*!w54m?l8J(1;eB@P{9w^I~MR!Eb8;Vwp&Rg;z-IMN2VB2DN;~m3WP7hVJss~Qn z!TegE^1;+v-;Aq_2hPL>^C=;3s1=CE6E*{tOD#PXS1>t4UeyTjHMuDrv(+n_n6Z;dDfe!GOum|E*ibyf3#u-W7~MQSbY zak*%{gI?=H0O2o&Cf0qsAkv**>wI?A^dKbOz&dq$A@rHk9pG;*Iqec~eE6a}bN5r= z&eY=qO?TmLBhyvb0|~~_71hSPaud*+-xer;5pnk!`S3!ywe%G!Q@`@=n`gv*o%$uz z+JbIh;)9?Eme)he-PgAOFHq?N{QIPCpT1{NTS(<)_MN(?-z!M(lAeEBw+oG6Qn$;6 zn>WM{MEgKQY*D!Zm`ki@%19Q>SeKZ!DSev% z4!ZHNn29{#cnz|iiG1lV@F`usvGD=SbWB-2eQTC|7i&1wJLY(`SS|1=U%shyN`1Sv zv3%11h~|Gp9aG=pt!Fx>t)A3B%1V8dJ>+<$T`jnOT_|`bUb=yJkFFl)OyQk*tZ4~z)cQB*t;sb5l9yKmw(X3Y7+DAG^GR(|`TGO9` z`mFjb<1iY{JObuQ--bj!&i*U zwmG&Xtyx7Dp*4I4tpfY4pa=N6`4;(v!YLY&R_&94<3m=Tgu<48Ei@ucHX?1HZgBiW zXaLhgD!9;MyjO@cFqjkgcm>QB<#*>WA0+-gYIEbCssInzN;?#x&hKYm%C?Do`}rV| zj~ih=x`P_$5#^D!TmU*kTzSlrH=?&3 zyJv7xc~B2>YL;%6&M6j*98(7U*xzA*+}yLnA%Tq7?$Y^1SG1D60(Bw0JHD~kUDm)l z4*%&N&dZ1;w+H!NqvQky|hPeXiuWdX$ zm5x07yS%IUC011X5L514dXWbD^w*9&(>DegM6vmG&fgkvm7Dsqg6yQ-S2Cspc$&c5 zXao2%5XB~^%9EsA9L{DZP218!k%p`pVn?Q-w)bnAXXaefhm8(H%6umi4~ZzrpD4Xj zk-mBKhz?XDZmGjut}AIA=X)r{`nGpnyfw=_F~b_qcxi|WK zR52@<JH{+)J9VT1IfWQEgO52y{khD&jS9yckin4=swNkN_c zSAjf$hdhviG{phu7X76g_NfgL%$?>#|M?RV-0?#Ruo7&p2Rj5o=UL3qSVBw#kt7y4 zNOV%=^k)W4Xe_z=-oP|ZiKFKJiUpcGltJ_NUuAzqhg`LfpxQHxAuy9+efYH4!&*?o z1KJ;G@*x~!_#nDLtR!WBMQ-c~9_oAsnEol=$rHK`E@m5q!7(AK_W7?xcPG#qSoJM( zP`QhsWgE9uWreQvROw7VOfNPusP;S_S)yv5Mxp1$RyNAuqBC-5z!ZV>Y8Dd{7(ZZM-$E4YV~ zCtm&0gOcU!B}L%^W<~b>g^w0#rSNZ`G0C(-3>QFmC@GC>GB_%;?Iua*% zzTX$k`3PAt=tX%H#_*BK_kjb&@tZ4l=DurHr_v1|!U_cpLv{Gw0n$zQ+Y#G?P5ua8O<1G)> zP)gvg3NhX5v{#EM2gz2=Rb->;&sL&89nK7uP7W2Q<$yoBM_xsFiA(;Wb%q1P76}xq+(? zI`AFI-Iku_1yC{Pf(qAiyo-rcIutPC981rk(0LEl^hPA3l9~OQOAoxA3bhKI7w|OP ziWa$pwh;v?tVcD=*J{)2qSCC6bdDr$19SXkh}0|9ujl66u~v_Ee?zVkNGrF@qB}`W z2{~1}=WvVjNm`9aPL8b}nH@3A%hbhSH@l^R(rUHR^C%_c8r;9jeYe?yyd`BX*ejX) zts~Q3Bz0L%2kImLHLY?QV6H+xD9J=9(8MBiQVo7sRj0f8rJO7NYTanAUVZ%I>jBlo!hE#771lyCM8nkv>?~d3nHlnkyNsm zYphd_VkF*Ak25Z=Vn75pppZi$Jt!J2x!E!E>s>)RqfcGn+*igcq=dlegd*_ zSc)?Um(wrrUcy!xzz%L}RznU+#v>@x(&89?)M@DotI}n#WIEn;?H;yT#W%HF{0w_w zWdEzpJ-LkwSIwBmOsKJ1--5F&5gtkcfmT%OJ6N0kBR83C3N==VPht(R!itmcOyCW|mUr`i2(AHTZ? z;K-iGmW~M|xVAbS;Y$qFig$nVHC_fQV>=sL<(GESS=2@Dqhz1hSHuw_Ec3+>lg}n~ zmR^(`mDwIDmMQ>KIbjQVD_QB)$|Eg46?N&c4t=$rBw$su`SF{qGvP>uk<(mt^O1%Q zuv)9Fq901;JXO1X7;x5ZhNO;>furCycamq&;oAJYSO6dD3aA#ddI*~zVv~zmUAd5zq zsf|XL*-C9hP0~DU0EDkKg-Ptj8@_#0R~|B*H0i#KuSFJ)@OcnjjSxXpBJZs(Aqk9> zyjk}Lqhh_P#`N}eBEyPoB7j0?{LaqN&852Ct6;=KY^UmVBqn3)3Ui!x(yoC~BW2Rv zRw% z-P0@&Nuo2FRH&qwCHn$985d&mPej>De0ay#CJoQuBYeVQ@~A0Ht>}=zGk1PQJ&^xa z#||Lhb&h7jM5iKhC9Th8e`Qy;6gQ{5U&yL2=;(JYE9fv*k(?x|+lM?A0w)>(|8ZWO z^eYo>!($0&j&McII-^S12j_N0!!f>U*j0tod`DD>Z5(3{FA;7ej1)2=NX(B84wBb| zmvn?+=hv8mWf8k=AY>D{@dkLw+bWzm`pq5DOrZOGMt%ERz4z?=$Db2`d z=ru*G;j}0P4o2K73UX57MEbv$rA`E1qF%m2C6_iskwl_1avBayn_(fcSq6lBlIrXk z$!r_NNH*Y^=4c`Y#y*S1$1VBYX)g|N4+)pKumXi!MGpd?z*f*LnkQ|;H}z{IL3zBE zZr|M$qfJ2CI_2%jM@x5)6_4$;s!b_sp;%G@Zs_Uc9A7a;QD`eC6MIeKO~%frPDknd~7yqjKRX&&Kg8>#Zgr>QI7`kd<= z?1{~vNz+fhmH5|XmxsqS>o}*92a0uCmzLQ^qEbv*J2VYTefX$5skco^X!qI-w@B=G zmAfhgj;u3SI6vkpk0?nTv|U&4oESdWFAtH|M6Yz5-c1}Cr)A1e#>)47DB{%F@^ind z7DilSClLgS!^gZ=YR4M*wvFDPCWt18&WSRAWGZHAo@XAm{plF14PH;832py$)ho3w z(!QpAUVcBclwoO8AL$VAnEb+?;lX+~*1FI^;}EOo+-Y+S^OE~A@}mB<@U(t8;!TN_ z$jWzA$Pqg?vBsEZnP;%kX5!U&Kz2v zl4v#OYgxHxEjQned28?uZ6|BOC#izh5y%PhD$i?~M$} zw~2VawGqoD{Yc<-_YH*|%Cw;vhS9c==X$(x+y4>scsP>z{y3V!dKAI-Cpjatgm7yl zAp8PDn@+DDQYJn^Y=Hb+XYZNbg>$We8rdU-%oK&I!X9=bcq6%vhR3EvZ`?P@6SoINcib8a$<$F zpKTL30dnKXB&h(o79AkgvT1esJjY!Bl7=FFDeag!@Ir0b+w7d^TX0kGa-kMFIj%!e zVyupbpn=98`i+e-cLyFWu;QjAuBP+BE}HsW_g|Wnsr=6MxmIXi)Oe=Hbvz~NaAaf& zBbF2B9=996!oGe_oEvMV0PNN6QJX)Tf6U#yB|m2a6p)^QbD%31YtKMC zpS4rctGCi37#y@x17S@4w*nP4@xIpKqoUrO@|}3`J`G*2(9>{s7>8T~U8Zj-k>Kru zgRGdTB?>gNDdSySjzlgAOnUsw7c?e(isUM4uqFzax=OHcg7)AsMHilesOi2W!+}W? z0^?aI#S_HrI|>mPZuRG(nj*pQyz(R;+ZM#=j&h?#=&ObUzB=+7Mfr3@a< za}p@RG35oubF~u%lq&!!6=rcXeTOm{>$Ek@i4=}fBOXrrCHm_?LM`+dXUoz-bycMC z##v7!=q3^z@-DUrj0~B#{8FD~(V_iATqT{0t7}918u3LtOC+S5bCX)r2xkdS9ajwg zR*Y18U=64V1VnZTVWhUPv%%}wjw7I$h%*^?*=tFFmyR!m(v*r_Ib&Gi^9G1u(ISIOC@hd(tZoQ0cw0Jl^lH?--y{ z?1}FsPzqdFY1~cHGFIr-2OFokKd{=9C5tkUG?er3@#{~;XHxk{dB5$R%9z+d`Ezw6 zFJ>7SmC?x$vZifh3{0@XL7kc3i>Q}cv`ZH`s~eULH%d3IQWxD3fT!#YR)Y*}&ai`- z`py)?6z5AdwA7;@eJO-K*YSYEE=pO>CS)z#L5d;WC6p^tE`zuu#T+X&X7rRxD^(}w zB|+1^`PPXeU6h#T+F4!I!oo@WT#ztmI+zju&hTn&3?^O3+%PyJJeQInLv&`GK-{B&Te*x8UNHl8 zRKAv7i9}y4r^0tHFhFqhXP;H?o(>Bid<%YyRzLQ)b>KO2MWqj7`mztB#d09=lZ`

    sJBc zWFy``9sV7QwY?2vHDh`BNs($mGJ?Fm_nKf~J2;@~Q>_(ojpReVD&6=IL8+Wq=5R2vOeD~$<{ zTTdnQ3atl}YR`Y>)lZCt;wP5L>cdLO!cD&4L4~u z=g>EuUCPI#5}mGkzvB1G4a3Ktm!`I4ygkh5Sn(X2_20h+YnEn`nshueC-Znr4=}1{ zxGYWC#0XINWMHm>b-!&RyU8qqAtN}YAJT-2L2)#F=i-i-<6c#SWzN<-K)*xq{rYh~ zrCa~^Ir?Hsq@PUFJuK>gw{6>~bM=(*M6=tE&PeXHOHsdNf6(Xpy~7`v!6J)WkK8d- zCl6-eu+Q=WIqHjG7`MG)VhnVD!U-nO7_y!E;zp+wg@4{86~#>6-6L)-60?YlA^jeW zR#c2ef{9~9;;qC*G-La~T$FqfL3sS7WXYL2zQ0eikDD-q@F+l?iWo`DgD4)KiCE$E zqGgo6>9$MJ)8feZ9&weiiTWD%uJO3?Q@7%WX``?1fL`_w6AkHn>}_6mWS@GL^{O!4 zUTLJdU>k)L#KOTsYI^7)0Cl~{p(%e!81t+ac|?k_7{aneA<%QU)uvuVjpr zXlOC!h9yCKs*%I&;IB35&?$m=K*CBMCFU37r*Y6Y%hIG21usT8-ieadr}!+Hd+KWYnE054PXLZ1Mc#}`s|imGEtpsRcvj{*?pFMCxvkts zoCiT~<^7)=hOD0QkEI}^$Lm=MOVP5>u8{^i>{>IU;#vj@ntKm`Q@ka0 ztgdgKUsc|Rg1zet+%DTM_*Jz5;FiNDkKI|+d07o19rb1tK-tw;L}nJpBHCJYH95Xx zS8+X1cH9w+B7O5u(*o&j&41XUN@HkaT4I-DX$Ons>#g~!&V#A$W*Y9+m!=5u(pyQ~ zT&~)8zJD0>cYxAN9YEk^w3Yr^NC1|{k&7;JH>lfr-x9wB@ku_Oi-c3u)aJL<)d77b0sKjw@^nI=`lcK9CyzdwhNVg<*6Vti&tObjEg<;Z9 ztb#a%-TJe*J2x*mubk%)wx6^p=iz0VYE)@}YBaTxpc4o`0yzR%O1_NQGP703ZH1Kp ze+)ODpAc$k^EnLXD~@~OW2IunrS2&XR-!VqCjAV(G`+f(HIUa3jSj4K$c!VktiZ8$ zIX>3dA;x*%oyv(D4VJ|&nLfdB5W9Y7EMUpFV6TD2ej(JZT78AJN?Lmkjr6yIWKf{* zVNX7X!EADegzQ27uN10;PL?4HL!5+|19_!rc+YjC$>xtD_~Q->BXt z&A&B3KcDXw7&e3nT&l!&wpx7Yv{`V$3N^?!$oFSNONmF$m)0zmAVo7po=}9V*>Zk< zhzCbQ&!aX*&HqFL=Aq~-dYYD>>^#ZPoNzTudoPf3;oH*==G!5$_d{}9L03C*M}iw%P9Fgp11WTvkr)vvbH8V9 z?#D&-(PjAj*rDCZDZM&6C_Aa!nOZkfz?_>1A{1^kwyya_k$>Y#oI;d2h?00Z-gAd~ z+9Xi8;5?ofX+6~+$3GE~F==f;d)On;MJ96_Ai6XvKyJxl$#lBo;h!EjAj^0)EaC01 zUja83g`nTyEr1 z8*OEw2~GyLC+T&Y~;;WBsm zcs!jRjL+%Y!`n~s7$0;;nSyh;Rw>+dnhd<%OI^6yQmiqFaWZja<;B)(6@8o!sXel} zc(C#C#v;N8LyZSo-wwJ@084BhzTW&Q2GwE%PjEZ~A+QvM;_A>=&cQt|jZM>{J=231>z}2Wy)p-{x)Fx*;!d?q|^A z6I)COp&@O3y9BwCw(>G@ut-FmDDqJPO^nj2g7ikZ1dNkj+)Ot~^ zC2!DK(H>p>Y~GnAz?-BYCnqeKe*DlLrl)E1hazG)Y@&GbcBxDgcQ>y{^Ngxm39)yy zo7PVFf-^-*V_4eGzF2Cn?2GU+vGYXh{@%X#LTi;7G*{c!^~rET;5vK4QrJx<*?BwA z=@w(C*Gc`Ap>~>9K55cxtn4_I#Q{8d=JNpgx^0}hy+!{h9g@271VrE0Q{^|cRaWDz z_ETF^fnG7ZQd(BI!K{enEtwvf1sQpZz55uA@kr)KN!kh1ozziTvv9lyDHj^(*Z>7^ zVvi^i2{{gIGqGGOXcvV$rwTUSz7 za)Uug)lBKCC5s?4Z7QB$I^9E$lc22*r>?E;L2So+0yU~CY)dQn^EYoJNh&_=pZ3*7T z%uEw%)5NE>uL~&;R1=rdK8rh3@>Yn8D6633P6^|vPUYwn89y#p$Sn|$03_Z zN$R84EIZNjYrdx6W71DC0Cu~O&7^0Y+&0W2-d0_kN&y^gqO{nLj(1Uq9@n-8nG1^y8pvrcgaD0)x(^2 zh=QdW^}Kx6xePFK&aim#hl)r8CWQM`nLm*jhKglKcv*kOJ4lvEZ9RX*s(tk?=%Px$ zux2LhVyGroCXXrz15vq_h}j0C;Zc{V)zp2UYT?H3rfn(BY)mH7=ppxzIh4;_)`#U4 z=*Xb65Ll)~sJ#L_gmd>AH3V{|(4S(PUvk2FTUJtAPm1qztk(CezXEw5KW|1IDsS8en3t^*sNP3oV!NPM z=CdoVZIfMloN?arg21TQkaO>i%hWrxWRVy~au+@4QxW^MKHB4B9M+aiumh^@RNF6T zwB;L;V8m5WC*_`r;!%%Od~B;mg>rvJtR-u^jU@r+zMNP~=H#{EDbb&o1aUyON2pCkCXWT*GN?LV(q zRFZ@Y#Vz8Eyq3Pq>a)0nHG@{zLr|hnk?bh)!V>J5mE@0`l*`M<=hKoOS;@-#_O*Pf z-lO(#0Spe|L$tJ(EZ-Vau0F$~q&}?%;>+|JvL%N@Q94xg?aDE-q^>Zm#f}+wZa*PT zVyzl1#ODo|N^Q3K&O*ZO=3Nwhcu}D~#B1Kpq-XNW)pEeA!3|033_pw+pvB(7@8L&b z%jQBYh1_Xj{ zUYVv`<7hjh70151u`(8oO0rfScg4riY5>5d7mD_Z7|3#Uk~d6R3{)ixv@KZx|OiWlq&EWUR z0d{~XyrSn5#*c-dlLM^@ca+l$g1gB|-d+fk#rTTUazSTDFK(_hx#_kuP}~L&jwp1b zwnZ4HO#)j2oTP3O!cXFYsAzAVqJL9^SyQM;bDhN-v z71F$ls>*%ecEaGPXsUjvSu@d zp?Enz-|e>U@&>7$;?Bc%g|<>;%Y&7_Jkj%`2>;9VGl>S$MeXhNjm=U|nirq3M|pdG z^QbmvJSTo4<=$75U~NSC&$=qQ%&j&|GW#Gd^90^u$V*JOWNJ%g{+;Isz>7-`lV}QQ zCWUUl-oSd#I_(Pm8vQCgzRKDcv48sbXu`zQ25sPpS~{*x}QXHC<+S{v_Qb!xx4dcn|+dC75Q~fZOjsP^rOSAa=VU z2gH$d-@fH?aLV~H3Ls{zSA6Q_d9)j(0MwJ|9ft##kbu6_Dbu2fG{d61MO2^7v%>9j z3%?k`+x9)q#NWMCyf{7jpb{r=q!8f{f9t!x-#MRXAnD-j;PTOVi+v>C3w>nPGp^(4 z;OdZ`z|13Ie0&+Ta>UQeI^%O4GH%#6HZ%@&K!VJf!**T-)DAD78fK?2VmN*uJsN?1 zX8lOPF^;*DiAm1FAR2-D z?toaRgWkw1Q)2C2Ns~?!fjvYMMUxgo=J6Phf`cap`-8RYu-ZI<)p6MD%>u!xCE(y; zcJ5oR7tqU+HjR7gODO3meYAuYQ~GJ-$`ixT>2#s}*`&&wky<6m3b4&&RhMP6YbJp| zX0D_ zz{kE&LxJQFOia<|vb#{*E(dm3b`iPFP&&0-OO?*mHxJ)?{}!@mTjGWNB`O^MnTPWe zuFX2n-))^bDldO{&o>0@Y+TpkmXI<&c1BS!Y}K;!lyS`b7iv7q3QxLNe(Z(kGIn9$ z>@i zJnqW08*r#HAgv3%j<)4bzSU!+yl-7>zCrv!nRz^`=@7q*E*{5dywh%wL#~IZHfPbK zz-JpNU}cR@?m9GD7=aA28?YOp_Guf12x`Hb2&5P~zmC{m5-eXhW_|I7DU#3=txHcV zd>ANrnD9ZG;cg1v^9V7s>87EUPvl8=fSXk+y6P+Yc(d&#^&A zz0XVV^Vzyw7=#Y(iO(Y7uE?vvYHG0~IXjn;-{)qM5rtH68P$N2%R#_0|Gt{URUfP+ zWVMqe{0RLVVhu)>6rR6HslR16C(PmM2i^!&>r~0En;@wl7jrmd$0Ru~HR_joO}?Tn zqa)*6qg$Q$B5%XVJN0r3{Z^Ow0uaBlsp@S5@^O6)@16r_47os!yD zk36rV?B1x+_2jyeLi~FwHQeP{D-cF-rW!(QSW6R!Spv(#0(J*&7gdRJKY0_yT8yb= zy~=gkAhf@$h~!YP2u-N>>3F{Y~gliMZ z=x^->RW>g!1W6dH!TWngNVNZOkp(=Dp5CdCWFC9R0r0q@k&#fjUFm7Fgerx(o{ikD56DhvQCl)~Zz(tqi)kGbRcZV9xT)i)>v%4sle6zjOPe$3QhVQ&#Kg06Nz23RTIMLU zI*JVE#5@4;!)Ysu#_5gnN|fvHC2EO}yXT?`{=mIv64og$LNYt8dRb7-nPw;7Nv}T+ zEul=bXVzCjC(u87E2}nvb)4(k?{2dKCX&g2b7S|%s*+h)wZtkXYh~4!2OA;fM%amEfexb zbB#_Un_cD4yFZ5Dp2@vGrg9Wx{Dg-HhLkL>7<6PpT;Ezl&K435%ihf*P9k3B=+Erv zq)1&zIIBCKL}V3u=WwcHB?5@vTPPxrFr8W~c)K*n0sNfyjrhGxxEiCzD?}5E&j8r! z*dkdOi8#BHYQN{js$x$>wI=#L^lR@yrBIGlNlcn#X?jHoqcbusN@=%PGkQ02+?$*h zE|L$L*#L1Ffp{V=F}>U(!{y$e?;>&Y-rMM0@Rzq*s{}SGM8Fi7v>rjDKvkjMC6%U}DcU{R?C z?Mj3@tImn~b&y+UbyRYBg`;Wn>*c!F-IhUW;}gKjO230H(UEg6ea5o}vL0HS%$7~w zw1*SAQ`1RtI7SNSn5O+m(p_$*get(c4Uvo^nhWd> z;S&?-mxz2R3Gx_fSX>Bk;)t~TbY)tl3=WF?X+;<`(FK4vGu60L&;g}1DJN|-L9#UN z)o1G`z2EhHS3~r$B}GaYIafn(5|mOn>Xg%NTs}(z36b1v;Q*dn8hW`ox}v4BS|F<% zNY*~y4i)97PL?n()UfQ^9rV0`;j(&^p0k}~{fBL1RG$}`btfxPSX9l=d0T#-yh{_`9U+B=tqX&(s z#k$KVMf#%Xs1#H37NNh;7wo{9qVuSl3bS4y)~9FESc;?$iaEztNv=@a2rmzDIJZ>k ztWahOnGBlU)!B;i((8Rs9CW*DwUy*$)DvGAqV@vf_w={X=|mS>IkM?axO>bxneo zQmt0SlG|(m$DE1f82D{mj0JJ&`*L7K@aa7k(f$icl5DP#szNGUT#(ESYT1@L!DS9j z%`fjl^G#ofy)MU~2Jekg!(Rr-rHAYTwtzwuBbXrzx~erX6f?ABek^U@QGR4|@=_~W zxbnhrYWmNMI(k7JGWOy@H=lyRrg0;;lbs6=dQZLGJTM!C0k^@uyqvK+IO}1-ys8)u z?VPPMfwW^CqPD~Wkoy~K0y$Mg{9>d(Qd0dXJwVy`L;*;xrh9!^0`zJfY z6g|4*sxkYHIL>PR)6A6F!aL=gQ3(CK=;;vg_dAzCVeSXXqdgXUS?NZv3$_|ISyC5p`H1KHdX1?3{D-buAoWedE5ncvDIw4RmjzjCG_^?9W0nwsJ7@<6{Ja6@bD)9bKEyc__xV12g+(fUy$xSPliT20;J z1sM)d#2kb=J`YtpCPU?p+bM+atV|p^e?vPriV0R3{?ghSRb44Gy~bQ_4B8sgx!w~w zH`nyGiNgixz8oU)#_4&BliJF;72&_)w3K<&|94my+h5q;e**}L7&!p!&1@ZQ?Ei%l zl+(8|B4HHy2P~2PyN#uxtjb5WrM`&+2{Q{kqmTo@$lCFP)T2gnVFb6l6+%kXW;z6|9vD%I_g`R z0fekgER9H*{&fuBzuUNyXw!4Bd}HAHV0dwn(6fHyU|{25<76XYVPg6K12Qo)F|e@z zrNjNJhM1Y95eo_1Uk2DenP6=HQ;+{u<3If-`L7f6e;^b8$L{}|YWDv(H<9(97(FHu zwr^|<%q+}ITz|=V|H%3mj}hx=WKZ&UQaKul7y)byjo=yo1+M#GT(bWYNv9JtV*PJdjQ`gn1W+Z+C=JR-Z!^1iHh`Y+dHf;5L}N)Moc(u=i$F0p_-XhY(ca-6 z)+8-rKl+zqj<1%OF6_<`RW-#RBV;Cy`b>!oyd@GS9;mi*MjY%$Dn>RbBo@J~Yb$efwL#h6lk{izItaxS`r> zA)?Y8#t~8$oOEy?%idfV(Ggqjj!Lf;Gceiqe_W9&1(K7&{dN@lZsaTVd)QE!pVUYK zYnmoThAbbvSj0Uf&NdGo&cQf|m5VfAf+`O{XK|hRs^(CsOEk$+G6M;qcqv{K?j3o%f0NCVLwzjvJZT9}u zZB*X--|gaG?&yCriy!98$-vRg_QMwbH;Cc?XdV9Fk_`Wvr2iYq@b9Sjr`7rgRq=n5 z44FBZ*gx#<|I?uPu!(H{2kr9I6V6pdwE0fkN$!04P_A-mT$0=DdvmNHdd*Ln&oLyZ zJ#sQp3I2p&aO5Oe;1Q%DMNHPYx!tg&47r5!&^VKd;zFocgf6yW_^3jV-(-$D3b{!} z)1L*d^=*cJVxgskS)zg<9j&5fqbMcdOd&7Gq5anAMjov$PdnBjXX7d9b82aJKD2HXvIM z0)*hGIis>MUDC_&ec=;Cn*ewket}#X*ZYlC{=lb+&w?HLM|lOoFlt^ckR;NdFlE!Z zi-)+iUGYc&V1_d3OWf}<4R!j0)R2R-c(s&lND5D@5R(?~vfjs|1&?Fjp%Q-@Bu+5_*43!2Kt!p`3J^ZNSNbmcG8-V2 zG|#a1V*ikoMnlt{6sITi>Fe7cwjdVI|H@eZGiR|oqR8mRP9?Y#RVxI$8cJGZL;n+Z zn4(Fh=_gwXWXD3du*KE%0;cW9v$|h+xKruao1*JybyV)WkBDP#3jKA362=StF*3 z0rp;2G5|xX#bYeM*E?y-t8Rt~N_i?I;S6B2Db9%!%Y@dHLU?g`?oJ*8<_dO4(b=xF zU14^D53I1je&%`Q`9;6F?&^xoQw^S4MRYs`9UPPt1l5SuumwfXZ_gX1YRIZpg?fC! zl<{R^$~deG-E}goBMS#@(VI8;I0#CM^WyVe4sz)tAvqZ3gF-OZB17xfmvAp(=%`Y` zX#cNaoobu-t>Pl?)%~Sr`dpKpztpP|b%)#i2^lZ}sDVG}=C>6syG95k`|ch2|ey>H$3 z&+FBzS9i_s-n*)I)v%af?HUpcV!C?{h;A$DvH&f=14HsE$UoM6I;N1VZJnK?Bdn^Hk8-qQ3QMA@}A(NJ}AlpZtY9jhs>Z2L>2sDmnp=V#h9 z4~HpQzoxw)FE!Gbep{EeYns)5n^L!d)P$E@CmVODfogIEYc5())F1nRL3`zajV!@z z6^8u^gLoJ2rNjr8EPa{&UQ@oHL3Y(RE>mjHpwF_*wGraae&YEWMOSLSV3+zp92UW~ ztY@(KcBsfS802ckAK@J zoA(8PV~}_qA3s>Oour-IDAqxNR5r$fq^9$oN8VZZS?yVp-$+x-kPZ~$qLmO!$ zAHOQiM1Ab2)%fUcZ8G!IHPEiXuG%inu4>P{vCM1p3dLUaKx8x&KC-4HOzzh{yXyH? zY64#cg|5p@&-#<7^m~`fQtYa-@;$qpHy|aeV!boyAoJ08VmfAaM`FEVg+*q`L$zwG zk@$^GJmHLC3fon_Lts@xZKQp~9orr+)V&Q;_}N2=joYSdkFYmM2Ro(5Bg9;2lZ^!p zJEdP@7)0zgVB8ia^66!8wb=yHwCz?V;OR%)-DI&AC_7d)%{d?w$b-6k3tDAT=3ujC z)mIf9Wo)PW25mmpjaRkm)qJVcok#NOU05H53&?8g-U|+uQ5pvN1P037)JQW4Q5FJX zwlPf9VC$?$X15v6RMgWD9bob$opWUh7BGCcJ*eGz)!K#)T`)VixFL2J&h#n3P&KQQ z%_!SK%Fl*eaK*D)(jx`)uvREbUv|$Fk?{cbt(+o@cm^bE%r`rK^1w3~X)dx^|In-{ zWYj>T7bBN2&yh>Khh{JsSM?nO-Ip*^v169-XX8t5qIW1*jK9zk_+zIm<2l^{&fOAu z#H0(58UtpWjy-zGp1l*$liCh zJL%wFDuVf4>XNFe#_D+DYQ9X?#Xf^sDaJxFW z-ldmH(b1HK`#QPxTIbY>7TBtjKWYKrDW4{_GIDXT=RZU&6l*CZf*vDAZyyzMqsx@^ z3dHil|HJuRRLNHCOSDwpACn@4lqwNf7<4K)pL?UjLP_FxsGpCs1q_i zHq{0zN8hJ5d}WZ7m^|^0Br?7q_xe!n>_XmFk~>goL0MCe5^-pkXt}-hUAus**7`j1 zeehw7p;-1R57|izQZcAf2*X3uwTrZm*VlqcPYw_o5n1Cbeji_c^C%z|IJ>xj zbGKGkDMqky#~ODA*2Y9cEbStRh)a{!^0u!mMR{>bUFx9lhK95fO2-M9j2P2RwnYQ5Iv6$PB$a+n7Qj(L2)n9L z+zZ|=_Q~tKYAwzrt*D^fs-P4vG%Pk;n6jNsQ`=ZuK4CTAY19}E?)PGhaD!XKf3ePk z_E(vQAf7ct9-GN^J>$yiBQX)aIzV~gs$t0#bO$)v@D>(aMa38+8)hQqTLpK-2Q3!A zpPxq!4`jJ}tglH86%_%p1@gK%U)hOP*!lZOto&HRxa{{|iy25aw(0X|Wjar>hsS=E zPX_CNGbu*_vyRs4E?*);i^heLj)!nRsvX-OC8USdhx83G_l(=8+*(^#JE4A*lN57B zP37cYr`DXA6C1?v3~a;6h10VcsvOVpDh9kgjxp3V35~4_?T<}i&9AO6o=r;1yf2?!Rf+)f3n9#`!K`d+ zvu@u$qCZ#$7z_|P+D=(Gtc!$Ng>7$E`F5@1;AlJR4?5EH;6XiUZ0A3QAr>Het7o7d zQ79Qrm=mlkZXn_QH%VxG-YO16>V86p5w;X2U!0UoyrPgyJKwYlL1%5%b3-!bLI=kj zSgB_Jxl)0Cwmwr>qLQxm<2CDQ?0(2J##$}%@u&CxL;#!+Iy%BzVFvWjIQDv1t{NBa znlD7mWYjf0Nf(p~uaHEDy-0?H3q}%0lT(^=PpRw!&g`%3g8gu3<9xfk%Nm-ogqRsHvic>7Ay}nX(31V{PI>uH!(xeLmtWME$ty<;7zEb7=&Mc&go?`Z}fj|dj7d7^U!2KJ+I7(&@&V^>|LBJuSY;Geb^uC!U5jYE}tyZ&)1t) zt^dI^-;dtK8;kDF-#p=E2yN5M$SM-hj+#)RQZ*0)98 zC&m#!;7#0H!RMskoePVrDiXVUQ@~s7$NNG|IfJ8Pd-iy9@i|10uBl+%Nqmp|)j6}G z$U(9LX5nk;@y&gDf%A*J+;-~3euc~l8U*S>-u3!gAC(K*&&{W0>c!%=J^dN`va!?& zwRWsgDs%9-bbH2C$CJV!F}XI#X0ts0@+!~G&kyDdD=Tx}7|y`AKdCLL@#C5|vU8t{ zOtU!cO|$4a0G`+i8@PhzULgF_EGqcluxYqP??zIrLq9|$7l#BoXdl?5wteM#0jcxd z`AS6jIAQsqcZGs#s>6?_dU`=n$w|TQ9zURkg;ri9;E|-q!SF4Xi z9|N^b1Sx$n=7q&vge7~(QqilwmgvDhzK_0~Znw|Y6V<6#8Mm}0A48v4gcmkQ^vl>d_gl?N3!n9{$=FB${udBWokLsRD z3UiU;ADd-#!B*Ywpzsm4HEm{Nvki9jLuNs3CH1-*pZ69e>RBY?kBPzlI`J$3Td%%C z7S9}Uv8KxJ4qujdg&Ou)!sc%$m^vs}Dz+>>uTS1_6M9`uO>;UpZu-R|r_q4BL0^sn zY*#X{76@tERO&tD@IRMw^%gzw7^Jhi)!MTXfOvD-;Dq7(#VMzege300h2km}4htJw z`+60N*N++u{}U-!c6MgSblRY+IXgRh$6gKFMWmG2?b(oR6=hkg5-u{fTRG$7nnLk5 z#fm;hQrjf0_ym!6WaCKf=0s)H-o0ab^eCz8T%tW>dw5XB%uI?6Ea7No#x}Qwo4O^i z#_GQ#z|K2Dx5vpzNhOArIeRmNaSdjtWk7 zZNDFJbq5=X1QCCK4PTPEBXW;I9t=a8dwe&0(lIcKO?W{WaZsHVhe>}y*+--CuG3dN z>sECZ19Qj~=G{j~`FzHtt8kZIr2JVXvcur|i4xCc< zr?ioABQ4UncvJ2V*QO{!kRtlQ;?I2cv%@pKbkPi`4XR|{VMSuLH-!5{`O;kEMbpZ& za+@vY;;kX|G@WVu@!V)q7zUvx45+FVK(H?ofR*<|B$P_C+N6OLfdp6q{b@Uhpwf=G zBB4frUZ{}}R+T+(;EDo)87&}$Y9e5?A<;Ga{zv3P?hYb1(i1>GH1~GLlv?zX2PCv6 z4-gfHe8>dof-d7hS9sHC<(Rom!bXF=+yE;O6$y+BDiUC*PmE#%%qOM~FwoLX3e|XE z^vZ;){Pn99B~Wz*Fk^)PR8;{aS(%<}z$2N`dEZqo$=!f zVrO8CPlV_D;g(JW&4vlq#T|U!1fPJAhDe_PYazoZT_nDKnAs_W+(__(CJGq#(FFJ9 z3z2ep4(pzM-jt6kSc4|J4RI^#`a|L!%I`%UW-QYNpwJVghoovFpD zz!lpUo#@i5RquTwMJj`RB9mxzmfVpVmvrDt=?0Rg(~NUnhjw$F_m}86O~M>_lB12h~5Ze?+yJD5E{Eeh-4NGxR?s_ApTiHcxVn)U5Z6Yi^gD2 zhlMXQo-)n|*>zf-iVGUu^QKQf$|E|?uW#gX8YgY$V`iP+_gp0 zUXoFx&&blJL_F@LPm4^&a3N`tZQ7^z4SNLLZh1d2!LB5noxc6K&GCs_C58vdNM-#Y zdFC7Y6wJLqLXR#`5x5u1j_E2~>cBCq$Ie@1!cDEzNBWSlnho-gLw~jFE zkZm@K*&}_oOASgZ^yPG!`g6zWGGO72wkcyMalXJh$ zEuU%JdhVa$P#R!9nyUAYW+Bb;>#A;Nu@Q;8KpkF1->GL-=KFaSWB2Qif(wz zTL`|t^w*1X`_8Q=S1C)!39vC$CzYGM8(jF!jxXxQ;UBv_%-7!;b$fUVTL|7d1i7*u z-m-UA@w-6x1cty{`yf}!XvsBP$cKL8*atTD(@|xy2l9`Ln@LDUx1WBt+WyccZ$nJH zxdM0X*U{yeui?P>CS89uI9naj+40Mmm#U2K`jtZmvVLL}><8Jf%p%QRJQWMzrZgd$$#kEH;EiKAS zyeebxy=P ziJ`Sf;a$0hReMHy*y6YgkWy?aNw4bla7nE#>!PjSr-B7{wQBG5-Q_QD66jF|H z7U?hpJXGc_vNvI2=~PggGT*!#ABIQJC3K>zX%HHqa4@c{o;8>f_r0C*o8$6O)F3YR zhpR-7qce5u+7tWfN z{LqDFBE~oc-WL*hn63}!xZzp{aBQzlVwblBG(LFe5|*V3*U71_9Nf(p6&>qbjfcyY z)=t&t@rwd6dSd4&$CXL4pX10)QAq6~JGPz3XD|JQ50Hwup)K%YOCpP*&zQkaaUlv) z{wbYh>onR*$?niy1*0%Q#Z##;6jql|Y4cYGi!$R#)%Rvl-8%Ft8>RdO@ZtT&POnt0 zo#S_+@n!^{wxbhb(pp#+U#yofUd03%ysQ{96HJ9+@yDA64VwuFzp<+RY*z+u<(}@I zHk+Q9lF^GcwNXwWRhGcDVNZR_m-S&6z~n<;Y`brxb5BcqRL#geah)sS!=z)WOs@@s zJM~a^=efD1)a^qO_^iRZis427C-X{ow_;=GFJ`t)j$WmL{G2CSy8bllyO`1R~eVPOnxWDZX9%(b-X*#+ZKDro|0E-m=uBv8Z6swMtZfade zTN_dLBU<8N?{C-aXdLVSsOrp&xO|8Zec*qZ{48q0EpyI(5 zilhltUGTiYY3E#w=nYwFzr1w(I#oa3^_<8c?me6b4J zw^d1s+whtXxh8dutHbYd^EADb;c@-_F6z3eRv)Jy$lwuQcHQk-t7TZsTd{tolYN9A zM?t6J`Qntk_E}L2qpgi+mNDGjy?>7)_(Eq+#M`(vG3>Js+o0~@fT=6i$yVdD&uX0V z!gvb(ZkWp)CGMPb8>P-gQft)m$$8R;luA#>%Q#cn$I*u&ZyY znUXeD%`}hLxECulEd8A^6EHMqbHG7tyc*-cr?scRY{~O90FOB!4uD@H8b4~n3Bv03 z43aG71aRUjH8IunQ7p;}i>C+&;j79p)oc*GGITHkx9x5`0H3!Tbf#ce2y=ZJ63O3R z(R;Tpyj74b3`x-~NI74 zH;M=^EXqjzZ2mEBc{=5+alu2kl*epNK6$?tYEjX$6r1v4rVKjUb!+G=@_93EJcXe6 zHs{+ib z57TvI)T*|Tb5x;N65gZ)QrJFX4w5F-3R(CZ-_D9&u`$vpq3k)V6ilReJf4(QQ-x`c z9RaRzvbiD$>Zj|qrBgn>LuT9{ny?{=z+5hv@UMaKXr3n@;%a06sY z>!dGPwG-Oxt;!xAFh*a*Goy89hSeBS-IsmPg@I%t6$Iexgk>J?6ErV*4&AUK7B)VO z+$3HUAH$_bJZcdW!dDhMZ=ih>U5sS``8#7}KF4<_ZhP4(h=t{l7eC)jRkn1iqwiEC zEv`)>^3TsNM7`-MF1m{s_oi#z;fw^P0)P3P1s8YtneGlc!>bHx_Q19dRw9g<1MuXq zahxH5dclJ+9|f>=_8wQts>G@9kl|LdXy|gqNfsczn69>o#_vX8%Eo7?2MW8)8P6{= zep5_Juo4M+!;&cqJ|T`10w*OUW#kmyFP5(11QV|w=j$f#h&}PlIF29gzeg91uFm~B zpCL!0Cj&#ZJ}R5!5_kSXx!4nf^SgFrKx6++YOa{c% zTia)P%AaMiVP$3-fOjJ!NXUn_#G0H*eOkC{Ds3*e<%LDI79^dFJTAuw-6DKBKbe-1Kh7uB7Xe@3T_6 zmAM4s#q)YO!+Um7JY%q`hQ_BwD!Ow9;?{>pHf1Cw;<}S2C}`o%{xki$HNna3ZM{XF z_e@xIBd`YJJ=rLciabB6tV#Gy>7pw{0vPAR3MCpa3JE-)H8KxtXD&N!XF)XY8ZpFd z4Q*+bDmp8`&}-+Ck8SQvrPFMY|D`$$hb8q3?G~g$>6OZq+G1TYV&bX8cg$f$YFMX&Sr;6V#=eRWq$K7I5oFIj? z#EVrUOh*C{*(^+s`b^5vqqPp9+e6gIQ!jws`Zz~%W=8>5zIm~V=(iZ}{*mcTg}2O6 zE*jY`W;#*cKOQU(?S%6n?64OM)7+sqErTU0#4Qz!#1S~FNX?vW0d2w@Zw`@~gii`> zc}}at5Bxk%N(6Sc-Bi*S&3+CQd%m7Li9sB(o$RL-dhV4Mrp5j&+ZV3$?TyM136a#< zIHi{Bw$*dn$kwv&(#di7^x{6XN@xWT2TZv)UcndsGHSNk@J8p*`p{gGI$PHm_falJ z-yJ9XQC(Y2UbXbHS+7v9=817zaXs>JgMPD8`KiZb?b&-8#H7dSuV@k_s7Ir(gzi5$ zJYmgNS=N#Au1ny9P1od;Jn(JfhpYRXP}oeenZLYyR&H{l$zbDnG*?JN7z-{Ge(XDs zP8uorUcnZtCv3ONe{p~K1%x=&$LvwJ4@j~IWvVuT*6|AhfbVMv_w=hrRB7we6`Cqcz8xa2(^U{vHZOFlZ{k<}=& zWD@)g$22AS#;>OG)p9knkd&44L2**BCU{X|o9v`9zR1_+MZelUCe0*AZz7-Nx?{Z+ z&|7Xqs(}?Ow#v3g;k08I&a*Y$Hj@xHd>Vf2W2z$G5d{iji*Ib^&22P!iqu?Xh31yT(I8x`Iu4tD9I|!>$~|73 zP(ZVZhI${{Nu3IdNA;Cy(|ED*rEqo4hxXxlAJnX?Tp#4}$%arXiS4<8~_7DwNqh!h6=j}od1gmAz z@Z5)RmsbfC?4&NU>do-{^~*r}jnc`v^cK^BU8rP=exudPG?45dBiyp3jo2~yh6XwTP}V+ z5I6W2<^7BIhH&#kKmz;>5D1uCKtMj8^X771z<{ ze?zVR53l^6#{bJg>u9^n=r9QI{uM!npr8FOYyaP9Qa&)`ZwRuQGWwTw($7a63sqvE z>{8n_K)jsEveA=jJ3s&SvG@-XM1q-$wQT?6L89QFnd*P=R)0(@&-Y_aLfI8`|V-k4*@A~#7Hsx4(sl^N#_%TkH z_cR@@EroTfqttG|gJH>K35)ZY>3Tb<>^3(m7ORR&uf~+!tYzzuIF?@&Kgac2^`_#dY7zo+CMDDnR=hyS-Q@vr`VgNc8=-@ka5htnG~JTwo_i-*pe_}9iD zC?LQuz+lGkZy6AcAphDJ?EWPK3i9!x(?$L! z-`k-xC;k{SP!IzCqaB#{SCRR@_Y3}S`Tz@}1pc%s7%2GX^LWwW^Y?rCdH;AH z=&Xw0?8gfPgFt`S1GkH9>+`7F+oMyn{t+6`30HPz g_6%ra{3A>_yBImS{3A#J(W(O>c&x0ls&aV$1wGo=`Tzg` diff --git a/FirebaseVertexAI/Tests/Unit/Resources/hello-world.mp3 b/FirebaseVertexAI/Tests/Unit/Resources/hello-world.mp3 deleted file mode 100644 index be617e65a5a34d1ae2384cf15f3574864a1316c3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7344 zcmciGXEa>hy8!SrW{kmLbdrz>B6yJ@dLky#dv6h)Ac$xYEk^G(dL3OtbU{RoC?U}W zAxK28(d)V9y~h$yp8M&?w}On4{={drnLlPceKT!j9S>M` z!IOE=CK}vLH_YMzAdV$?iqDSDEtO4~WQuAHZo*<6vE3ZP1dsRs&kvh>Bt@obgu59D zdxF>aqQ>DHGKo2B=3o+v_re`dGKDSY(z$^JN{%_5i^qGEDTV1r{e*ql!BMHBU4{-l19bUrFHRI zz0lGUyW7lkb%@|;_&@mph;RTbr)srtDNFXDeIxDfq`Jp@vWgk{Jsri7-if!Df~N=55@xA$D!OXw0tQy^h!Z)hPJkE z8j{ndYQVz1zji9ym$PV5pgU-Ivq4Ml#^l$S?grLt8_1*|WO_e+)SYv%bZ z^fWmOMI4Kqn;O7t1Bd3ESyLVpedn}f-!aMR(!S<7yRtBd2{qGz%oAChXnaK-6D8~P zfxEc(?E#;k>|_odfwA*r1Gaxh-oQQ(5j>xXP5fi)BcC^49Mlnj}g!`@U zlv9NhFl^IruE}w2O4UWVtsq^9**x>>8KvXn;$tMdn5m<00zv`PKsX9L6=vl??B&~6 zvE+B}sqvx(0*j$oP9lrwP!_XZRXvr-%f11IYE9&ZIa6FZbG-uvS4Fz)bY( z#Wl{;jY53D5vM41#>-kmao76w(FKTS@@A@Gk zn+B08AKMhA*neHA#6WBgxFxu?Tz>KKUg1<_+FoB7X06i7cwaPD@6@6wVbsqtqbm6n zZAqdN(m6@3*Y62Q%)2}xt~H{%Zd;2OcO>T&PKM#5=*)?T6(qa|12-~phAa4ufGs4_ zPyvct&kmDD%FSwi#!q2lXMHt4`DcnMEgI!%1i7k`5V^yNW*N+gn^DD&l0 zb0KqdXrLSY-5#u1QzsH%grvlZ7YQMNhh%tcoVs7}+Dn#uE2d9bWnR2gxXxHE=JE%7 zztJ+-BTE=8jwMN2KAkxrCV0XC(&!ts_o{HD=4|F;ffSxzS*MoDe}Klkuc4~T%V9xg zv%FULp2xS;7A)-sEAP|aPPXQA-Cz4*+m^fJ>S8#k@$$*d05bkF`m<8|3;GVCq+{qU zr;|@T>eEu6{72XvJ*QD+q(dLouEQwxwm;JvwCmdLA-F*h1AJTJY7no8< zB;cwD9#QNUlqXi*>@tkzRF7>iT2aE#SZq=1u9*3`n{nI?AmwC4<-3T5P0I4&k0Few2 zkIXMUvq@Lz@6!Rda+9Z%b!L8uyqXA}UtmI|e*M9pKe4ka_K=pU>ddEpXa4&e!K5iDPB`ca?5`)^eOrCS~=b?V7%=31XFjX`MHSWcz=E5^&R_I4P{tGbgA0n>rHPYjH;jAA{QeN=2kOqX`}n z96Zz48DB7unuy)-*-Juazv&uOfv6e=MW;9U!_4W@x?V3RZ3I8IX!B!+Pjicz)|>iq zR#sr7{=8RMDmj0Ht-NQIUiSt3X{{-~F>7JLYr_6`9*4v=Gi!*?rNG zQs;$171|td*5pMXEf3eARl+z93oNn`1>Ji#ni!!;Sp zA2Hy;g8;;_uWyE`_HZ$f*yarEl0*#(L?gmz^ zu+m~Ox90QBfZP0J5Zl;j0cz`J1*dsOt{_8>=nKC5vq$pxhgr@@sQqfT;tLd8!C4uU zos+@k+_k*(ApETAJ9uaICf@ifGu#lf-4?^^nge4p!YJyqVjpHxH>ht;Pl%81-#DDA zCc&ctz$=@L%C4yy^oDQV6D@lR&Jow?R6gi!*=oM}i@~w;NFo292o3#j_q>Ca_AF1X z|1Ox#AJ>sVTecb=)6kRBV~GN9*5jzBr5x& zM9m+@(_npeQM`+|rR8Idu!Zpf&=YQQ1(%TW%q#>a-$}eC`yGPE5GNPqZc|jLjOvSZ zxU8WnD-tZPP9~J`kTwPTo$I%kQ+z1a@bw=wA7T$uXbyWI{p~>;VAHRNWm#O_Ze!nX zU6tVM(qU!{a-(T0o*i^J+fhD>5E4Jsx$euXZ|m9~Ha9ccK`W?31VH7U4?TbNE`uzH zwP%j>eCJqW3(kGlj^q4$UD6Dj+N0fYg2xh&d){bQ!lVU!qjVG&4Idl=8_gA4*J$rL z{dCc7i3wDA4%h;$YgP(P4TTej$`Hfc(jz2-RLv7BIa+K+=){dJ3yZmJ9@qgehxpIHjeLkA$t$t1dSN#k% z)dInjv6i3P{rAnN2%Kw$Kemu(zN^BekmM zULQTauKUKRP;Z{nVC%@-OQ5R_@dqV08%0L1o@UOf9vU3<%EXsE1d%5JKv z5kkbBn#d_hbm?Nlge@4Mb|FdX*tbng34)!g%pm}L0l)z-x7bU7epY6J#|;N>khjlm zmTnuSbgZ?>tUOd<4&*G*Wh)ZMp;V@cx&#d>Y#wGxV_jdQmS z&Z;Km&l#X$Di6c`KyXR(2B7?b?VWYAu2;~bS2ZblbtG?JYxVel2yo0oZoc>6q8Lrf zZ(818z2hhf9y13*c06fJL9p2|2vDcO!g1|E!!+t@rif z#+#l@RvhlZ_3d&&f+rAw7igQ~TW$d3l)TFyg(4bkH7)fJ5&%H3&$&8m zp*D5gW%X%6+wq}p3f$DF*(L3&%XzVT?S-z$ubHo|Eyd}E>so~%cy3_s2!p09XTX5^ zlTFyK1o;LLwZPZUXhq{n(K?<25sQ1ee0Ag=6Ho@f@v-f2D?(oIO(~vPddvcvmkrU>pwe5NR zPwUu$eM%3d;f3AE85t&sOD+-`Z zt@-8lxvBYN#V|+ciAqTl_|HrlczhGAbqQ@|L!o{UJP82&%-gBxp0dX8h|*d~j77eJ z&&aqhwu((9qJLbMZmrbnIopU_rH65Q?)w&ej$WV``I^X;#xGi};6ETFmKY#Xlk1ZK zj4JzLt|tzg=jaFMP1cop(qtXTiZLyW$$BDkOdB}AzUr-`F-wFqfG4d=k9n#A1kvV{ zx%e9c=GBCsHE+_Ms$$drt)Ei>5_FAS(Y->A-DF<(5YjwoW#Ugyd(r@{^&x{A($vmb z4F_Z$$-^EHypRd2e1Xo&?wmkVENQ&38tA4PAvbV8buq(HHjebIS?9kxhq4p7SrO++ z?R9im$F<$Q+{jm4_91ejoPU*YB+_$RB&}oOn=E#=m4ewfPP=uf_I>}zmA|1&uvBHE z&LQL{4JXg!Y+7J0t?`wtOvnLkabL$I2VCDzWI_~BGicmc2f=}qI4pyp%VIhXxS(d| zS&N+yGfKFY0Cg4d?pZ%k%|1f1uC|;@$Br3+=d*DdF}MuZBuN|J%O!X*@D?hb5I~Iq z%)p=8IHE_d5$kp}g<)$(Q`4YLK#${Lx_^^$+Q)(Wcf>Dz!U&#RKyJ{<7(XW+Hw0hZ zAbj#&A|LIJ^@#Gy^#Mz9+Yq6Jw}@{~>nZB^n{C zaVWIuw8xocHu=A1W}1W5l!~ic7#?4dbbY9!t01=W6y^tBjDEs0MXmf>kCosM1>JT< z3!Cv|DVuK7JT!Mg+wSrH6AKx10Ryb$CqHnKyjjYpC*oX(GgAmfap!#hbM6ODOWyO*7#4iVs`db%sRa?x>7&P7C&LGW(5D?`k=%|12rbYC5b~1;D6|bY7uV^aj+o1Y_9DVk4o|Hf z3bQ}$5(%o*-gnG+a79s3ZxiPc@PxJf%Kde?rbk!QYWX+EAc&3i@BVJ!Kb%X z33s{=AC<*0X5l#Lf-(r6EF8(8hx_ICYkMQv@p=85c>A&_#CVrhFWsN z-x5680D`H{wYW^@`QdB(o1s~@T6D~<&BPPwCdpq|(>K09MhTsioG7x%%TF7zv7UG2 zkLVWlrR73xHO1VZwtFWYg>JfzQWxP#_^1#eMF0U#W&%4~(0WQrP0u-7c( zJW42eyCuk986(q^)zW3iMA6gM@`bfl@KD%S85(YjGn@zh34-9s1V|ElokBCK#SYT` zF%QieVmb(LYrp!>c5$AJo8j7WWk|(4*5ti1M>pa(Ch})XP8}eOj_TH`_R#4lbDf-b z#G`mDfIkTI$H`Z3c?u$u<96oAXygXtD!BHkGcx%~m6up~SO#oFf0v#xq6Gb1%>4st zenA1!R~3MCyhutFy`e|$8Irg?CodksRre$mtB2(lz(WW z@9Q4_Bf_cFBw!(|)GN+{O->Gh1~~sHGDHcueJhs^as=|eEZ-x&F$eUX1=^iR@1Fj? zpQ5-CdHzVXvX^Yj^W)m^`&59|4JSf_&AI0rtMLfoAS{Iw39`~cx0U+6Or|nD&wkuj zVcRC5dC(&CuLmcO_OO=E5{#RmbP#6DHG@@kXd2UF&|K&*m;X4cme1#44;tzf_;4tX zHy8dpUSwk&**Sx7%KBU5C)G{&Es85CEu!zb^ZJr!DO#X9v^#Wb{FNwo0yJ#&Np@lx zjh_n}C5_<}(r%vwM&~jyKmjV7w@0F(&UfXdkk69J5*)b%YF2wMTh%dtf+r6LcQf`V zPAkU@BG&c}iU9vC>FPvoW!m*RNiR?FW*X_twrruN>Eg!2t#Vf;tBGH@j)wXtR9$_* zF0I!I07U0L%4kW_PEU&pn4>|`lVMU)((Z4G@vZYpADj#q<9Q~pXBXCqVuHX3lj&%H zhwoEgpv;q~dV0P0_Z`7f2b%C0P>7-aj$}6=6)@s>}8#&xnvK z?@uNCzyr)@(zNldaZB(;G)>_D{5Il7_xmrp6;(3L(LBzU{O{SNN@yJ-SR2dNH*m!}bGd+DG>+YKG zJ2R2>@pNW(Y?ND)h`v;LMs`y+aegh8}lU#9TNdM&sL!d@YF=lOG>R(i8X22G z-rP>JD}O~Lsdl7HSHC1|5%M#DgQp5e@m6+W``|o+l^FPmGrm-y-qeIt4q&RWFy{}O zS0+{y8QZclnpT32tgc4AE-GLPxHEI^%b@pdJz{flAv+i~<9Fg$C!D-;v#Ki%3s6jE z2bev6JoAo&BA=^QJt-$Woh~i_zC;mRzqbA~&Pdr}k(x{k`A(dx@ry)2d;vKbPWuGS zKtu3M0?24)P4Pe+FvGwNt;GXG;?pF_)Zc{5M|+!eAWZyvdy4OcJsx7JbX>ybpDi8O z3es062v6|57ai86Qv!&~Cv`0?%U33CN{_;}SPi*YBg0pl^|bQKSJw<1HTI1Yv>R+f z&I>HeqpM%`X`a3Je}uS!hKR1;^S1b5*7xwm#aVgpeVfM5(eM84FM4qB&U$5Jfjn-M z{;jn@*mk^u@(rJhucg9g`?nXn9>;%)a&l%XVUfAH0fDgr!b%c~GwND)Lc6_>Q?QQiu$=|^RSUL9xLa>Z9ZNW;?QIg zt&?jnm)%z8xai0G{VwWYOpxfTxi)tyvZ7K-lKXu$KSaKY$ET$@ Note: This is typically called in a snippet test's set up; overriding - /// > `setUpWithError() throws` works well since it supports throwing errors. - static func configureDefaultAppForSnippets() throws { - guard let plistPath = BundleTestUtil.bundle().path( - forResource: "GoogleService-Info", - ofType: "plist" - ) else { - throw XCTSkip("No GoogleService-Info.plist found in FirebaseVertexAI/Tests/Unit/Resources.") - } - - let options = try XCTUnwrap(FirebaseOptions(contentsOfFile: plistPath)) - FirebaseApp.configure(options: options) - - guard FirebaseApp.isDefaultAppConfigured() else { - XCTFail("Default Firebase app not configured.") - return - } - } - - /// Deletes the default `FirebaseApp` if configured. - /// - /// > Note: This is typically called in a snippet test's tear down; overriding - /// > `tearDown() async throws` works well since deletion is asynchronous. - static func deleteDefaultAppForSnippets() async { - // Checking if `isDefaultAppConfigured()` before calling `FirebaseApp.app()` suppresses a log - // message that "The default Firebase app has not yet been configured." during `tearDown` when - // the tests are skipped. This reduces extraneous noise in the test logs. - if FirebaseApp.isDefaultAppConfigured(), let app = FirebaseApp.app() { - await app.delete() - } - } -} diff --git a/FirebaseVertexAI/Tests/Unit/Snippets/FunctionCallingSnippets.swift b/FirebaseVertexAI/Tests/Unit/Snippets/FunctionCallingSnippets.swift deleted file mode 100644 index 492574dc11d..00000000000 --- a/FirebaseVertexAI/Tests/Unit/Snippets/FunctionCallingSnippets.swift +++ /dev/null @@ -1,110 +0,0 @@ -// 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 FirebaseCore -import FirebaseVertexAI -import XCTest - -// These snippet tests are intentionally skipped in CI jobs; see the README file in this directory -// for instructions on running them manually. - -@available(iOS 15.0, macOS 12.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) -final class FunctionCallingSnippets: XCTestCase { - override func setUpWithError() throws { - try FirebaseApp.configureDefaultAppForSnippets() - } - - override func tearDown() async throws { - await FirebaseApp.deleteDefaultAppForSnippets() - } - - func testFunctionCalling() async throws { - // This function calls a hypothetical external API that returns - // a collection of weather information for a given location on a given date. - func fetchWeather(city: String, state: String, date: String) -> JSONObject { - // TODO(developer): Write a standard function that would call an external weather API. - - // For demo purposes, this hypothetical response is hardcoded here in the expected format. - return [ - "temperature": .number(38), - "chancePrecipitation": .string("56%"), - "cloudConditions": .string("partlyCloudy"), - ] - } - - let fetchWeatherTool = FunctionDeclaration( - name: "fetchWeather", - description: "Get the weather conditions for a specific city on a specific date.", - parameters: [ - "location": .object( - properties: [ - "city": .string(description: "The city of the location."), - "state": .string(description: "The US state of the location."), - ], - description: """ - The name of the city and its state for which to get the weather. Only cities in the - USA are supported. - """ - ), - "date": .string( - description: """ - The date for which to get the weather. Date must be in the format: YYYY-MM-DD. - """ - ), - ] - ) - - // Initialize the Vertex AI service and the generative model. - // Use a model that supports function calling, like a Gemini 1.5 model. - let model = VertexAI.vertexAI().generativeModel( - modelName: "gemini-1.5-flash", - // Provide the function declaration to the model. - tools: [.functionDeclarations([fetchWeatherTool])] - ) - - let chat = model.startChat() - let prompt = "What was the weather in Boston on October 17, 2024?" - - // Send the user's question (the prompt) to the model using multi-turn chat. - let response = try await chat.sendMessage(prompt) - - var functionResponses = [FunctionResponsePart]() - - // When the model responds with one or more function calls, invoke the function(s). - for functionCall in response.functionCalls { - if functionCall.name == "fetchWeather" { - // TODO(developer): Handle invalid arguments. - guard case let .object(location) = functionCall.args["location"] else { fatalError() } - guard case let .string(city) = location["city"] else { fatalError() } - guard case let .string(state) = location["state"] else { fatalError() } - guard case let .string(date) = functionCall.args["date"] else { fatalError() } - - functionResponses.append(FunctionResponsePart( - name: functionCall.name, - response: fetchWeather(city: city, state: state, date: date) - )) - } - // TODO(developer): Handle other potential function calls, if any. - } - - // Send the response(s) from the function back to the model so that the model can use it - // to generate its final response. - let finalResponse = try await chat.sendMessage( - [ModelContent(role: "function", parts: functionResponses)] - ) - - // Log the text response. - print(finalResponse.text ?? "No text in response.") - } -} diff --git a/FirebaseVertexAI/Tests/Unit/Snippets/MultimodalSnippets.swift b/FirebaseVertexAI/Tests/Unit/Snippets/MultimodalSnippets.swift deleted file mode 100644 index 9e4683d8c64..00000000000 --- a/FirebaseVertexAI/Tests/Unit/Snippets/MultimodalSnippets.swift +++ /dev/null @@ -1,215 +0,0 @@ -// 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 FirebaseCore -import FirebaseVertexAI -import XCTest - -#if canImport(UIKit) - import UIKit -#endif // canImport(UIKit) - -// These snippet tests are intentionally skipped in CI jobs; see the README file in this directory -// for instructions on running them manually. - -@available(iOS 15.0, macOS 12.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) -final class MultimodalSnippets: XCTestCase { - let bundle = BundleTestUtil.bundle() - lazy var model = VertexAI.vertexAI().generativeModel(modelName: "gemini-2.0-flash") - lazy var videoURL = { - guard let url = bundle.url(forResource: "animals", withExtension: "mp4") else { - fatalError("Video file animals.mp4 not found in Resources.") - } - return url - }() - - lazy var audioURL = { - guard let url = bundle.url(forResource: "hello-world", withExtension: "mp3") else { - fatalError("Audio file hello-world.mp3 not found in Resources.") - } - return url - }() - - lazy var pdfURL = { - guard let url = bundle.url(forResource: "gemini-report", withExtension: "pdf") else { - fatalError("PDF file gemini-report.pdf not found in Resources.") - } - return url - }() - - override func setUpWithError() throws { - try FirebaseApp.configureDefaultAppForSnippets() - } - - override func tearDown() async throws { - await FirebaseApp.deleteDefaultAppForSnippets() - } - - // MARK: - Image Input - - #if canImport(UIKit) - func testMultimodalOneImageNonStreaming() async throws { - guard let image = UIImage(systemName: "bicycle") else { fatalError() } - - // Provide a text prompt to include with the image - let prompt = "What's in this picture?" - - // To generate text output, call generateContent and pass in the prompt - let response = try await model.generateContent(image, prompt) - print(response.text ?? "No text in response.") - } - - func testMultimodalOneImageStreaming() async throws { - guard let image = UIImage(systemName: "bicycle") else { fatalError() } - - // Provide a text prompt to include with the image - let prompt = "What's in this picture?" - - // To stream generated text output, call generateContentStream and pass in the prompt - let contentStream = try model.generateContentStream(image, prompt) - for try await chunk in contentStream { - if let text = chunk.text { - print(text) - } - } - } - - func testMultimodalMultiImagesNonStreaming() async throws { - guard let image1 = UIImage(systemName: "car") else { fatalError() } - guard let image2 = UIImage(systemName: "car.2") else { fatalError() } - - // Provide a text prompt to include with the images - let prompt = "What's different between these pictures?" - - // To generate text output, call generateContent and pass in the prompt - let response = try await model.generateContent(image1, image2, prompt) - print(response.text ?? "No text in response.") - } - - func testMultimodalMultiImagesStreaming() async throws { - guard let image1 = UIImage(systemName: "car") else { fatalError() } - guard let image2 = UIImage(systemName: "car.2") else { fatalError() } - - // Provide a text prompt to include with the images - let prompt = "What's different between these pictures?" - - // To stream generated text output, call generateContentStream and pass in the prompt - let contentStream = try model.generateContentStream(image1, image2, prompt) - for try await chunk in contentStream { - if let text = chunk.text { - print(text) - } - } - } - #endif // canImport(UIKit) - - // MARK: - Video Input - - func testMultimodalVideoNonStreaming() async throws { - // Provide the video as `Data` with the appropriate MIME type - let video = try InlineDataPart(data: Data(contentsOf: videoURL), mimeType: "video/mp4") - - // Provide a text prompt to include with the video - let prompt = "What is in the video?" - - // To generate text output, call generateContent with the text and video - let response = try await model.generateContent(video, prompt) - print(response.text ?? "No text in response.") - } - - func testMultimodalVideoStreaming() async throws { - // Provide the video as `Data` with the appropriate MIME type - let video = try InlineDataPart(data: Data(contentsOf: videoURL), mimeType: "video/mp4") - - // Provide a text prompt to include with the video - let prompt = "What is in the video?" - - // To stream generated text output, call generateContentStream with the text and video - let contentStream = try model.generateContentStream(video, prompt) - for try await chunk in contentStream { - if let text = chunk.text { - print(text) - } - } - } - - // MARK: - Audio Input - - func testMultiModalAudioNonStreaming() async throws { - // Provide the audio as `Data` with the appropriate MIME type - let audio = try InlineDataPart(data: Data(contentsOf: audioURL), mimeType: "audio/mpeg") - - // Provide a text prompt to include with the audio - let prompt = "Transcribe what's said in this audio recording." - - // To generate text output, call `generateContent` with the audio and text prompt - let response = try await model.generateContent(audio, prompt) - - // Print the generated text, handling the case where it might be nil - print(response.text ?? "No text in response.") - } - - func testMultiModalAudioStreaming() async throws { - // Provide the audio as `Data` with the appropriate MIME type - let audio = try InlineDataPart(data: Data(contentsOf: audioURL), mimeType: "audio/mpeg") - - // Provide a text prompt to include with the audio - let prompt = "Transcribe what's said in this audio recording." - - // To stream generated text output, call `generateContentStream` with the audio and text prompt - let contentStream = try model.generateContentStream(audio, prompt) - - // Print the generated text, handling the case where it might be nil - for try await chunk in contentStream { - if let text = chunk.text { - print(text) - } - } - } - - // MARK: - Document Input - - func testMultiModalPDFStreaming() async throws { - // Provide the PDF as `Data` with the appropriate MIME type - let pdf = try InlineDataPart(data: Data(contentsOf: pdfURL), mimeType: "application/pdf") - - // Provide a text prompt to include with the PDF file - let prompt = "Summarize the important results in this report." - - // To stream generated text output, call `generateContentStream` with the PDF file and text - // prompt - let contentStream = try model.generateContentStream(pdf, prompt) - - // Print the generated text, handling the case where it might be nil - for try await chunk in contentStream { - if let text = chunk.text { - print(text) - } - } - } - - func testMultiModalPDFNonStreaming() async throws { - // Provide the PDF as `Data` with the appropriate MIME type - let pdf = try InlineDataPart(data: Data(contentsOf: pdfURL), mimeType: "application/pdf") - - // Provide a text prompt to include with the PDF file - let prompt = "Summarize the important results in this report." - - // To generate text output, call `generateContent` with the PDF file and text prompt - let response = try await model.generateContent(pdf, prompt) - - // Print the generated text, handling the case where it might be nil - print(response.text ?? "No text in response.") - } -} diff --git a/FirebaseVertexAI/Tests/Unit/Snippets/README.md b/FirebaseVertexAI/Tests/Unit/Snippets/README.md deleted file mode 100644 index 8d03458c456..00000000000 --- a/FirebaseVertexAI/Tests/Unit/Snippets/README.md +++ /dev/null @@ -1,10 +0,0 @@ -# Vertex AI in Firebase Code Snippet Tests - -These "tests" are for verifying that the code snippets provided in our -documentation continue to compile. They are intentionally skipped in CI but can -be manually run to verify expected behavior / outputs. - -To run the tests, place a valid `GoogleService-Info.plist` file in the -[`FirebaseVertexAI/Tests/Unit/Resources`](https://github.com/firebase/firebase-ios-sdk/tree/main/FirebaseVertexAI/Tests/Unit/Resources) -folder. They may then be invoked individually or alongside the rest of the unit -tests in Xcode. diff --git a/FirebaseVertexAI/Tests/Unit/Snippets/StructuredOutputSnippets.swift b/FirebaseVertexAI/Tests/Unit/Snippets/StructuredOutputSnippets.swift deleted file mode 100644 index 1ad137188c5..00000000000 --- a/FirebaseVertexAI/Tests/Unit/Snippets/StructuredOutputSnippets.swift +++ /dev/null @@ -1,96 +0,0 @@ -// 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 FirebaseCore -import FirebaseVertexAI -import XCTest - -// These snippet tests are intentionally skipped in CI jobs; see the README file in this directory -// for instructions on running them manually. - -@available(iOS 15.0, macOS 12.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) -final class StructuredOutputSnippets: XCTestCase { - override func setUpWithError() throws { - try FirebaseApp.configureDefaultAppForSnippets() - } - - override func tearDown() async throws { - await FirebaseApp.deleteDefaultAppForSnippets() - } - - func testStructuredOutputJSONBasic() async throws { - // Provide a JSON schema object using a standard format. - // Later, pass this schema object into `responseSchema` in the generation config. - let jsonSchema = Schema.object( - properties: [ - "characters": Schema.array( - items: .object( - properties: [ - "name": .string(), - "age": .integer(), - "species": .string(), - "accessory": .enumeration(values: ["hat", "belt", "shoes"]), - ], - optionalProperties: ["accessory"] - ) - ), - ] - ) - - // Initialize the Vertex AI service and the generative model. - // Use a model that supports `responseSchema`, like one of the Gemini 1.5 models. - let model = VertexAI.vertexAI().generativeModel( - modelName: "gemini-1.5-flash", - // In the generation config, set the `responseMimeType` to `application/json` - // and pass the JSON schema object into `responseSchema`. - generationConfig: GenerationConfig( - responseMIMEType: "application/json", - responseSchema: jsonSchema - ) - ) - - let prompt = "For use in a children's card game, generate 10 animal-based characters." - - let response = try await model.generateContent(prompt) - print(response.text ?? "No text in response.") - } - - func testStructuredOutputEnumBasic() async throws { - // Provide an enum schema object using a standard format. - // Later, pass this schema object into `responseSchema` in the generation config. - let enumSchema = Schema.enumeration(values: ["drama", "comedy", "documentary"]) - - // Initialize the Vertex AI service and the generative model. - // Use a model that supports `responseSchema`, like one of the Gemini 1.5 models. - let model = VertexAI.vertexAI().generativeModel( - modelName: "gemini-1.5-flash", - // In the generation config, set the `responseMimeType` to `text/x.enum` - // and pass the enum schema object into `responseSchema`. - generationConfig: GenerationConfig( - responseMIMEType: "text/x.enum", - responseSchema: enumSchema - ) - ) - - let prompt = """ - The film aims to educate and inform viewers about real-life subjects, events, or people. - It offers a factual record of a particular topic by combining interviews, historical footage, - and narration. The primary purpose of a film is to present information and provide insights - into various aspects of reality. - """ - - let response = try await model.generateContent(prompt) - print(response.text ?? "No text in response.") - } -} diff --git a/FirebaseVertexAI/Tests/Unit/Snippets/TextSnippets.swift b/FirebaseVertexAI/Tests/Unit/Snippets/TextSnippets.swift deleted file mode 100644 index bd7c70fa06b..00000000000 --- a/FirebaseVertexAI/Tests/Unit/Snippets/TextSnippets.swift +++ /dev/null @@ -1,55 +0,0 @@ -// 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 FirebaseCore -import FirebaseVertexAI -import XCTest - -// These snippet tests are intentionally skipped in CI jobs; see the README file in this directory -// for instructions on running them manually. - -@available(iOS 15.0, macOS 12.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) -final class TextSnippets: XCTestCase { - lazy var model = VertexAI.vertexAI().generativeModel(modelName: "gemini-1.5-flash") - - override func setUpWithError() throws { - try FirebaseApp.configureDefaultAppForSnippets() - } - - override func tearDown() async throws { - await FirebaseApp.deleteDefaultAppForSnippets() - } - - func testTextOnlyNonStreaming() async throws { - // Provide a prompt that contains text - let prompt = "Write a story about a magic backpack." - - // To generate text output, call generateContent with the text input - let response = try await model.generateContent(prompt) - print(response.text ?? "No text in response.") - } - - func testTextOnlyStreaming() async throws { - // Provide a prompt that contains text - let prompt = "Write a story about a magic backpack." - - // To stream generated text output, call generateContentStream with the text input - let contentStream = try model.generateContentStream(prompt) - for try await chunk in contentStream { - if let text = chunk.text { - print(text) - } - } - } -} diff --git a/FirebaseVertexAI/Tests/Unit/TestUtilities/BundleTestUtil.swift b/FirebaseVertexAI/Tests/Unit/TestUtilities/BundleTestUtil.swift deleted file mode 100644 index 272be41c1e4..00000000000 --- a/FirebaseVertexAI/Tests/Unit/TestUtilities/BundleTestUtil.swift +++ /dev/null @@ -1,31 +0,0 @@ -// 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 Foundation - -/// `Bundle` test utilities. -final class BundleTestUtil { - /// Returns the `Bundle` for the test module or target containing the file. - /// - /// This abstracts away the `Bundle` differences between SPM and CocoaPods tests. - static func bundle() -> Bundle { - #if SWIFT_PACKAGE - return Bundle.module - #else // SWIFT_PACKAGE - return Bundle(for: Self.self) - #endif // SWIFT_PACKAGE - } - - private init() {} -} diff --git a/FirebaseVertexAI/Tests/Unit/VertexAIAPITests.swift b/FirebaseVertexAI/Tests/Unit/VertexAIAPITests.swift deleted file mode 100644 index 8514d76b543..00000000000 --- a/FirebaseVertexAI/Tests/Unit/VertexAIAPITests.swift +++ /dev/null @@ -1,213 +0,0 @@ -// 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 FirebaseCore -import FirebaseVertexAI -import XCTest -#if canImport(AppKit) - import AppKit // For NSImage extensions. -#elseif canImport(UIKit) - import UIKit // For UIImage extensions. -#endif - -@available(iOS 15.0, macOS 12.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) -final class VertexAIAPITests: XCTestCase { - func codeSamples() async throws { - let app = FirebaseApp.app() - let config = GenerationConfig(temperature: 0.2, - topP: 0.1, - topK: 16, - candidateCount: 4, - maxOutputTokens: 256, - stopSequences: ["..."], - responseMIMEType: "text/plain") - let filters = [SafetySetting(harmCategory: .dangerousContent, threshold: .blockOnlyHigh)] - let systemInstruction = ModelContent( - role: "system", - parts: TextPart("Talk like a pirate.") - ) - - let requestOptions = RequestOptions() - let _ = RequestOptions(timeout: 30.0) - - // Instantiate Vertex AI SDK - Default App - let vertexAI = VertexAI.vertexAI() - let _ = VertexAI.vertexAI(location: "my-location") - - // Instantiate Vertex AI SDK - Custom App - let _ = VertexAI.vertexAI(app: app!) - let _ = VertexAI.vertexAI(app: app!, location: "my-location") - - // Permutations without optional arguments. - - let _ = vertexAI.generativeModel(modelName: "gemini-1.0-pro") - - let _ = vertexAI.generativeModel( - modelName: "gemini-1.0-pro", - safetySettings: filters - ) - - let _ = vertexAI.generativeModel( - modelName: "gemini-1.0-pro", - generationConfig: config - ) - - let _ = vertexAI.generativeModel( - modelName: "gemini-1.0-pro", - systemInstruction: systemInstruction - ) - - // All arguments passed. - let genAI = vertexAI.generativeModel( - modelName: "gemini-1.0-pro", - generationConfig: config, // Optional - safetySettings: filters, // Optional - systemInstruction: systemInstruction, // Optional - requestOptions: requestOptions // Optional - ) - - // Full Typed Usage - let pngData = Data() // .... - let contents = [ModelContent( - role: "user", - parts: [ - TextPart("Is it a cat?"), - InlineDataPart(data: pngData, mimeType: "image/png"), - ] - )] - - do { - let response = try await genAI.generateContent(contents) - print(response.text ?? "Couldn't get text... check status") - } catch { - print("Error generating content: \(error)") - } - - // Content input combinations. - let _ = try await genAI.generateContent("Constant String") - let str = "String Variable" - let _ = try await genAI.generateContent(str) - let _ = try await genAI.generateContent([str]) - let _ = try await genAI.generateContent(str, "abc", "def") - let _ = try await genAI.generateContent( - str, - FileDataPart(uri: "gs://test-bucket/image.jpg", mimeType: "image/jpeg") - ) - #if canImport(UIKit) - _ = try await genAI.generateContent(UIImage()) - _ = try await genAI.generateContent([UIImage()]) - _ = try await genAI.generateContent([str, UIImage(), TextPart(str)]) - _ = try await genAI.generateContent(str, UIImage(), "def", UIImage()) - _ = try await genAI.generateContent([str, UIImage(), "def", UIImage()]) - _ = try await genAI.generateContent([ModelContent(parts: "def", UIImage()), - ModelContent(parts: "def", UIImage())]) - #elseif canImport(AppKit) - _ = try await genAI.generateContent(NSImage()) - _ = try await genAI.generateContent([NSImage()]) - _ = try await genAI.generateContent(str, NSImage(), "def", NSImage()) - _ = try await genAI.generateContent([str, NSImage(), "def", NSImage()]) - #endif - - // PartsRepresentable combinations. - let _ = ModelContent(parts: [TextPart(str)]) - let _ = ModelContent(role: "model", parts: [TextPart(str)]) - let _ = ModelContent(parts: "Constant String") - let _ = ModelContent(parts: str) - let _ = ModelContent(parts: [str]) - let _ = ModelContent(parts: [str, InlineDataPart(data: Data(), mimeType: "foo")]) - #if canImport(UIKit) - _ = ModelContent(role: "user", parts: UIImage()) - _ = ModelContent(role: "user", parts: [UIImage()]) - _ = ModelContent(parts: [str, UIImage()]) - // Note: without explicitly specifying`: [any PartsRepresentable]` this will fail to compile - // below with "Cannot convert value of type `[Any]` to expected type `[any Part]`. - let representable2: [any PartsRepresentable] = [str, UIImage()] - _ = ModelContent(parts: representable2) - _ = ModelContent(parts: [str, UIImage(), TextPart(str)]) - #elseif canImport(AppKit) - _ = ModelContent(role: "user", parts: NSImage()) - _ = ModelContent(role: "user", parts: [NSImage()]) - _ = ModelContent(parts: [str, NSImage()]) - // Note: without explicitly specifying`: [any PartsRepresentable]` this will fail to compile - // below with "Cannot convert value of type `[Any]` to expected type `[any Part]`. - let representable2: [any PartsRepresentable] = [str, NSImage()] - _ = ModelContent(parts: representable2) - _ = ModelContent(parts: [str, NSImage(), TextPart(str)]) - #endif - - // countTokens API - let _: CountTokensResponse = try await genAI.countTokens("What color is the Sky?") - #if canImport(UIKit) - let _: CountTokensResponse = try await genAI.countTokens("What color is the Sky?", - UIImage()) - let _: CountTokensResponse = try await genAI.countTokens([ - ModelContent(parts: "What color is the Sky?", UIImage()), - ModelContent(parts: UIImage(), "What color is the Sky?", UIImage()), - ]) - #endif - - // Chat - _ = genAI.startChat() - _ = genAI.startChat(history: [ModelContent(parts: "abc")]) - } - - // Public API tests for GenerateContentResponse. - func generateContentResponseAPI() { - let response = GenerateContentResponse(candidates: []) - - let _: [Candidate] = response.candidates - let _: PromptFeedback? = response.promptFeedback - - // Usage Metadata - guard let usageMetadata = response.usageMetadata else { fatalError() } - let _: Int = usageMetadata.promptTokenCount - let _: Int = usageMetadata.candidatesTokenCount - let _: Int = usageMetadata.totalTokenCount - - // Computed Properties - let _: String? = response.text - let _: [FunctionCallPart] = response.functionCalls - } - - // Result builder alternative - - /* - let pngData = Data() // .... - let contents = [GenAIContent(role: "user", - parts: [ - .text("Is it a cat?"), - .png(pngData) - ])] - - // Turns into... - - let contents = GenAIContent { - Role("user") { - Text("Is this a cat?") - Image(png: pngData) - } - } - - GenAIContent { - ForEach(myInput) { input in - Role(input.role) { - input.contents - } - } - } - - // Thoughts: this looks great from a code demo, but since I assume most content will be - // user generated, the result builder may not be the best API. - */ -} diff --git a/Package.swift b/Package.swift index ec21d0b86d1..db6fe329c2c 100644 --- a/Package.swift +++ b/Package.swift @@ -29,14 +29,6 @@ let package = Package( name: "FirebaseAI", targets: ["FirebaseAI"] ), - // Backwards-compatibility library for existing "Vertex AI in Firebase" users. - .library( - name: "FirebaseVertexAI", - targets: [ - "FirebaseAI", - "FirebaseVertexAI", - ] - ), .library( name: "FirebaseAnalytics", targets: ["FirebaseAnalyticsTarget"] @@ -226,24 +218,6 @@ let package = Package( .headerSearchPath("../../../"), ] ), - // Backwards-compatibility targets for existing "Vertex AI in Firebase" users. - .target( - name: "FirebaseVertexAI", - dependencies: [ - "FirebaseAI", - ], - path: "FirebaseVertexAI/Sources" - ), - .testTarget( - name: "FirebaseVertexAIUnit", - dependencies: [ - "FirebaseVertexAI", - ], - path: "FirebaseVertexAI/Tests/Unit", - resources: [ - .process("Resources"), - ] - ), // MARK: - Firebase Core diff --git a/ReleaseTooling/Sources/FirebaseManifest/FirebaseManifest.swift b/ReleaseTooling/Sources/FirebaseManifest/FirebaseManifest.swift index d807ec0e69e..20cd0ebfc8a 100755 --- a/ReleaseTooling/Sources/FirebaseManifest/FirebaseManifest.swift +++ b/ReleaseTooling/Sources/FirebaseManifest/FirebaseManifest.swift @@ -53,7 +53,6 @@ public let shared = Manifest( Pod("FirebasePerformance", platforms: ["ios", "tvos"], zip: true), Pod("FirebaseStorage", zip: true), Pod("FirebaseMLModelDownloader", isBeta: true, zip: true), - Pod("FirebaseVertexAI", zip: true), Pod("Firebase", allowWarnings: true, platforms: ["ios", "tvos", "macos"], zip: true), Pod("FirebaseCombineSwift", releasing: false, zip: false), ] From d6c8c213548b9354d4bdce952794dc8039123318 Mon Sep 17 00:00:00 2001 From: Paul Beusterien Date: Mon, 23 Jun 2025 17:58:09 -0700 Subject: [PATCH 099/113] Version 12.0.0 (#15025) --- Firebase.podspec | 46 +++++++++---------- FirebaseABTesting.podspec | 4 +- FirebaseAI.podspec | 10 ++-- FirebaseAnalytics.podspec | 16 +++---- FirebaseAnalyticsOnDeviceConversion.podspec | 4 +- FirebaseAppCheck.podspec | 6 +-- FirebaseAppCheckInterop.podspec | 2 +- FirebaseAppDistribution.podspec | 6 +-- FirebaseAuth.podspec | 10 ++-- FirebaseAuthInterop.podspec | 2 +- FirebaseAuthTestingSupport.podspec | 4 +- FirebaseCombineSwift.podspec | 14 +++--- FirebaseCore.podspec | 4 +- FirebaseCoreExtension.podspec | 4 +- FirebaseCoreInternal.podspec | 2 +- FirebaseCrashlytics.podspec | 12 ++--- FirebaseDatabase.podspec | 10 ++-- FirebaseFirestore.podspec | 10 ++-- FirebaseFirestoreInternal.podspec | 6 +-- FirebaseFirestoreTestingSupport.podspec | 4 +- FirebaseFunctions.podspec | 14 +++--- FirebaseInAppMessaging.podspec | 8 ++-- FirebaseInstallations.podspec | 4 +- FirebaseMLModelDownloader.podspec | 10 ++-- FirebaseMessaging.podspec | 8 ++-- FirebaseMessagingInterop.podspec | 2 +- FirebasePerformance.podspec | 12 ++--- FirebaseRemoteConfig.podspec | 12 ++--- FirebaseRemoteConfigInterop.podspec | 2 +- FirebaseSessions.podspec | 10 ++-- FirebaseSharedSwift.podspec | 2 +- FirebaseStorage.podspec | 14 +++--- GoogleAppMeasurement.podspec | 12 ++--- ...leAppMeasurementOnDeviceConversion.podspec | 2 +- Package.swift | 4 +- .../FirebaseManifest/FirebaseManifest.swift | 2 +- 36 files changed, 147 insertions(+), 147 deletions(-) diff --git a/Firebase.podspec b/Firebase.podspec index 007b7ebfe9c..2bf5ee849f6 100644 --- a/Firebase.podspec +++ b/Firebase.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'Firebase' - s.version = '11.15.0' + s.version = '12.0.0' s.summary = 'Firebase' s.description = <<-DESC @@ -36,14 +36,14 @@ Simplify your app development, grow your user base, and monetize more effectivel ss.ios.deployment_target = '12.0' ss.osx.deployment_target = '10.15' ss.tvos.deployment_target = '13.0' - ss.ios.dependency 'FirebaseAnalytics', '~> 11.15.0' - ss.osx.dependency 'FirebaseAnalytics', '~> 11.15.0' - ss.tvos.dependency 'FirebaseAnalytics', '~> 11.15.0' + ss.ios.dependency 'FirebaseAnalytics', '~> 12.0.0' + ss.osx.dependency 'FirebaseAnalytics', '~> 12.0.0' + ss.tvos.dependency 'FirebaseAnalytics', '~> 12.0.0' ss.dependency 'Firebase/CoreOnly' end s.subspec 'CoreOnly' do |ss| - ss.dependency 'FirebaseCore', '~> 11.15.0' + ss.dependency 'FirebaseCore', '~> 12.0.0' ss.source_files = 'CoreOnly/Sources/Firebase.h' ss.preserve_paths = 'CoreOnly/Sources/module.modulemap' if ENV['FIREBASE_POD_REPO_FOR_DEV_POD'] then @@ -79,13 +79,13 @@ Simplify your app development, grow your user base, and monetize more effectivel ss.ios.deployment_target = '12.0' ss.osx.deployment_target = '10.15' ss.tvos.deployment_target = '13.0' - ss.dependency 'FirebaseAnalytics/WithoutAdIdSupport', '~> 11.15.0' + ss.dependency 'FirebaseAnalytics/WithoutAdIdSupport', '~> 12.0.0' ss.dependency 'Firebase/CoreOnly' end s.subspec 'ABTesting' do |ss| ss.dependency 'Firebase/CoreOnly' - ss.dependency 'FirebaseABTesting', '~> 11.15.0' + ss.dependency 'FirebaseABTesting', '~> 12.0.0' # Standard platforms PLUS watchOS. ss.ios.deployment_target = '13.0' ss.osx.deployment_target = '10.15' @@ -95,13 +95,13 @@ Simplify your app development, grow your user base, and monetize more effectivel s.subspec 'AppDistribution' do |ss| ss.dependency 'Firebase/CoreOnly' - ss.ios.dependency 'FirebaseAppDistribution', '~> 11.15.0-beta' + ss.ios.dependency 'FirebaseAppDistribution', '~> 12.0.0-beta' ss.ios.deployment_target = '13.0' end s.subspec 'AppCheck' do |ss| ss.dependency 'Firebase/CoreOnly' - ss.dependency 'FirebaseAppCheck', '~> 11.15.0' + ss.dependency 'FirebaseAppCheck', '~> 12.0.0' ss.ios.deployment_target = '13.0' ss.osx.deployment_target = '10.15' ss.tvos.deployment_target = '13.0' @@ -110,7 +110,7 @@ Simplify your app development, grow your user base, and monetize more effectivel s.subspec 'Auth' do |ss| ss.dependency 'Firebase/CoreOnly' - ss.dependency 'FirebaseAuth', '~> 11.15.0' + ss.dependency 'FirebaseAuth', '~> 12.0.0' # Standard platforms PLUS watchOS. ss.ios.deployment_target = '13.0' ss.osx.deployment_target = '10.15' @@ -120,7 +120,7 @@ Simplify your app development, grow your user base, and monetize more effectivel s.subspec 'Crashlytics' do |ss| ss.dependency 'Firebase/CoreOnly' - ss.dependency 'FirebaseCrashlytics', '~> 11.15.0' + ss.dependency 'FirebaseCrashlytics', '~> 12.0.0' # Standard platforms PLUS watchOS. ss.ios.deployment_target = '12.0' ss.osx.deployment_target = '10.15' @@ -130,7 +130,7 @@ Simplify your app development, grow your user base, and monetize more effectivel s.subspec 'Database' do |ss| ss.dependency 'Firebase/CoreOnly' - ss.dependency 'FirebaseDatabase', '~> 11.15.0' + ss.dependency 'FirebaseDatabase', '~> 12.0.0' # Standard platforms PLUS watchOS 7. ss.ios.deployment_target = '13.0' ss.osx.deployment_target = '10.15' @@ -140,7 +140,7 @@ Simplify your app development, grow your user base, and monetize more effectivel s.subspec 'Firestore' do |ss| ss.dependency 'Firebase/CoreOnly' - ss.dependency 'FirebaseFirestore', '~> 11.15.0' + ss.dependency 'FirebaseFirestore', '~> 12.0.0' ss.ios.deployment_target = '13.0' ss.osx.deployment_target = '10.15' ss.tvos.deployment_target = '13.0' @@ -148,7 +148,7 @@ Simplify your app development, grow your user base, and monetize more effectivel s.subspec 'Functions' do |ss| ss.dependency 'Firebase/CoreOnly' - ss.dependency 'FirebaseFunctions', '~> 11.15.0' + ss.dependency 'FirebaseFunctions', '~> 12.0.0' # Standard platforms PLUS watchOS. ss.ios.deployment_target = '13.0' ss.osx.deployment_target = '10.15' @@ -158,20 +158,20 @@ Simplify your app development, grow your user base, and monetize more effectivel s.subspec 'InAppMessaging' do |ss| ss.dependency 'Firebase/CoreOnly' - ss.ios.dependency 'FirebaseInAppMessaging', '~> 11.15.0-beta' - ss.tvos.dependency 'FirebaseInAppMessaging', '~> 11.15.0-beta' + ss.ios.dependency 'FirebaseInAppMessaging', '~> 12.0.0-beta' + ss.tvos.dependency 'FirebaseInAppMessaging', '~> 12.0.0-beta' ss.ios.deployment_target = '13.0' ss.tvos.deployment_target = '13.0' end s.subspec 'Installations' do |ss| ss.dependency 'Firebase/CoreOnly' - ss.dependency 'FirebaseInstallations', '~> 11.15.0' + ss.dependency 'FirebaseInstallations', '~> 12.0.0' end s.subspec 'Messaging' do |ss| ss.dependency 'Firebase/CoreOnly' - ss.dependency 'FirebaseMessaging', '~> 11.15.0' + ss.dependency 'FirebaseMessaging', '~> 12.0.0' # Standard platforms PLUS watchOS. ss.ios.deployment_target = '13.0' ss.osx.deployment_target = '10.15' @@ -181,7 +181,7 @@ Simplify your app development, grow your user base, and monetize more effectivel s.subspec 'MLModelDownloader' do |ss| ss.dependency 'Firebase/CoreOnly' - ss.dependency 'FirebaseMLModelDownloader', '~> 11.15.0-beta' + ss.dependency 'FirebaseMLModelDownloader', '~> 12.0.0-beta' # Standard platforms PLUS watchOS. ss.ios.deployment_target = '13.0' ss.osx.deployment_target = '10.15' @@ -191,15 +191,15 @@ Simplify your app development, grow your user base, and monetize more effectivel s.subspec 'Performance' do |ss| ss.dependency 'Firebase/CoreOnly' - ss.ios.dependency 'FirebasePerformance', '~> 11.15.0' - ss.tvos.dependency 'FirebasePerformance', '~> 11.15.0' + ss.ios.dependency 'FirebasePerformance', '~> 12.0.0' + ss.tvos.dependency 'FirebasePerformance', '~> 12.0.0' ss.ios.deployment_target = '13.0' ss.tvos.deployment_target = '13.0' end s.subspec 'RemoteConfig' do |ss| ss.dependency 'Firebase/CoreOnly' - ss.dependency 'FirebaseRemoteConfig', '~> 11.15.0' + ss.dependency 'FirebaseRemoteConfig', '~> 12.0.0' # Standard platforms PLUS watchOS. ss.ios.deployment_target = '13.0' ss.osx.deployment_target = '10.15' @@ -209,7 +209,7 @@ Simplify your app development, grow your user base, and monetize more effectivel s.subspec 'Storage' do |ss| ss.dependency 'Firebase/CoreOnly' - ss.dependency 'FirebaseStorage', '~> 11.15.0' + ss.dependency 'FirebaseStorage', '~> 12.0.0' # Standard platforms PLUS watchOS. ss.ios.deployment_target = '13.0' ss.osx.deployment_target = '10.15' diff --git a/FirebaseABTesting.podspec b/FirebaseABTesting.podspec index 82ec4457133..aebfa4555eb 100644 --- a/FirebaseABTesting.podspec +++ b/FirebaseABTesting.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseABTesting' - s.version = '11.15.0' + s.version = '12.0.0' s.summary = 'Firebase ABTesting' s.description = <<-DESC @@ -51,7 +51,7 @@ Firebase Cloud Messaging and Firebase Remote Config in your app. s.pod_target_xcconfig = { 'HEADER_SEARCH_PATHS' => '"${PODS_TARGET_SRCROOT}"' } - s.dependency 'FirebaseCore', '~> 11.15.0' + s.dependency 'FirebaseCore', '~> 12.0.0' s.test_spec 'unit' do |unit_tests| unit_tests.scheme = { :code_coverage => true } diff --git a/FirebaseAI.podspec b/FirebaseAI.podspec index faa8db5f0c0..5d8febaa078 100644 --- a/FirebaseAI.podspec +++ b/FirebaseAI.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseAI' - s.version = '11.15.0' + s.version = '12.0.0' s.summary = 'Firebase AI SDK' s.description = <<-DESC @@ -43,10 +43,10 @@ Build AI-powered apps and features with the Gemini API using the Firebase AI SDK s.tvos.framework = 'UIKit' s.watchos.framework = 'WatchKit' - s.dependency 'FirebaseAppCheckInterop', '~> 11.4' - s.dependency 'FirebaseAuthInterop', '~> 11.4' - s.dependency 'FirebaseCore', '~> 11.15.0' - s.dependency 'FirebaseCoreExtension', '~> 11.15.0' + s.dependency 'FirebaseAppCheckInterop', '~> 12.0' + s.dependency 'FirebaseAuthInterop', '~> 12.0' + s.dependency 'FirebaseCore', '~> 12.0.0' + s.dependency 'FirebaseCoreExtension', '~> 12.0.0' s.test_spec 'unit' do |unit_tests| unit_tests_dir = 'FirebaseAI/Tests/Unit/' diff --git a/FirebaseAnalytics.podspec b/FirebaseAnalytics.podspec index c3d5abf2ad5..f5200294ad1 100644 --- a/FirebaseAnalytics.podspec +++ b/FirebaseAnalytics.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseAnalytics' - s.version = '11.15.0' + s.version = '12.0.0' s.summary = 'Firebase Analytics for iOS' s.description = <<-DESC @@ -26,8 +26,8 @@ Pod::Spec.new do |s| s.libraries = 'c++', 'sqlite3', 'z' s.frameworks = 'StoreKit' - s.dependency 'FirebaseCore', '~> 11.15.0' - s.dependency 'FirebaseInstallations', '~> 11.0' + s.dependency 'FirebaseCore', '~> 12.0.0' + s.dependency 'FirebaseInstallations', '~> 12.0' s.dependency 'GoogleUtilities/AppDelegateSwizzler', '~> 8.1' s.dependency 'GoogleUtilities/MethodSwizzler', '~> 8.1' s.dependency 'GoogleUtilities/NSData+zlib', '~> 8.1' @@ -37,29 +37,29 @@ Pod::Spec.new do |s| s.default_subspecs = 'Default' s.subspec 'Default' do |ss| - ss.dependency 'GoogleAppMeasurement/Default', '11.15.0' + ss.dependency 'GoogleAppMeasurement/Default', '12.0.0' ss.vendored_frameworks = 'Frameworks/FirebaseAnalytics.xcframework' end s.subspec 'Core' do |ss| - ss.dependency 'GoogleAppMeasurement/Core', '11.15.0' + ss.dependency 'GoogleAppMeasurement/Core', '12.0.0' ss.vendored_frameworks = 'Frameworks/FirebaseAnalytics.xcframework' end s.subspec 'IdentitySupport' do |ss| - ss.dependency 'GoogleAppMeasurement/IdentitySupport', '11.15.0' + ss.dependency 'GoogleAppMeasurement/IdentitySupport', '12.0.0' ss.vendored_frameworks = 'Frameworks/FirebaseAnalytics.xcframework' end # Deprecated. Use IdentitySupport subspec instead. s.subspec 'AdIdSupport' do |ss| - ss.dependency 'GoogleAppMeasurement/AdIdSupport', '11.15.0' + ss.dependency 'GoogleAppMeasurement/AdIdSupport', '12.0.0' ss.vendored_frameworks = 'Frameworks/FirebaseAnalytics.xcframework' end # Deprecated. Use Core subspec instead. s.subspec 'WithoutAdIdSupport' do |ss| - ss.dependency 'GoogleAppMeasurement/WithoutAdIdSupport', '11.15.0' + ss.dependency 'GoogleAppMeasurement/WithoutAdIdSupport', '12.0.0' ss.vendored_frameworks = 'Frameworks/FirebaseAnalytics.xcframework' end diff --git a/FirebaseAnalyticsOnDeviceConversion.podspec b/FirebaseAnalyticsOnDeviceConversion.podspec index 7eb70670266..ce1cc7aacef 100644 --- a/FirebaseAnalyticsOnDeviceConversion.podspec +++ b/FirebaseAnalyticsOnDeviceConversion.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseAnalyticsOnDeviceConversion' - s.version = '11.15.0' + s.version = '12.0.0' s.summary = 'On device conversion measurement plugin for FirebaseAnalytics. Not intended for direct use.' s.description = <<-DESC @@ -18,7 +18,7 @@ Pod::Spec.new do |s| s.cocoapods_version = '>= 1.12.0' - s.dependency 'GoogleAppMeasurementOnDeviceConversion', '11.15.0' + s.dependency 'GoogleAppMeasurementOnDeviceConversion', '12.0.0' s.static_framework = true diff --git a/FirebaseAppCheck.podspec b/FirebaseAppCheck.podspec index 417e5d63576..cd02bcd48f4 100644 --- a/FirebaseAppCheck.podspec +++ b/FirebaseAppCheck.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseAppCheck' - s.version = '11.15.0' + s.version = '12.0.0' s.summary = 'Firebase App Check SDK.' s.description = <<-DESC @@ -45,8 +45,8 @@ Pod::Spec.new do |s| s.tvos.weak_framework = 'DeviceCheck' s.dependency 'AppCheckCore', '~> 11.0' - s.dependency 'FirebaseAppCheckInterop', '~> 11.0' - s.dependency 'FirebaseCore', '~> 11.15.0' + s.dependency 'FirebaseAppCheckInterop', '~> 12.0' + s.dependency 'FirebaseCore', '~> 12.0.0' s.dependency 'GoogleUtilities/Environment', '~> 8.1' s.dependency 'GoogleUtilities/UserDefaults', '~> 8.1' diff --git a/FirebaseAppCheckInterop.podspec b/FirebaseAppCheckInterop.podspec index 68f2a2871dc..17fbbf51206 100644 --- a/FirebaseAppCheckInterop.podspec +++ b/FirebaseAppCheckInterop.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseAppCheckInterop' - s.version = '11.15.0' + s.version = '12.0.0' s.summary = 'Interfaces that allow other Firebase SDKs to use AppCheck functionality.' s.description = <<-DESC diff --git a/FirebaseAppDistribution.podspec b/FirebaseAppDistribution.podspec index 42214d76505..dce9b720536 100644 --- a/FirebaseAppDistribution.podspec +++ b/FirebaseAppDistribution.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseAppDistribution' - s.version = '11.15.0-beta' + s.version = '12.0.0-beta' s.summary = 'App Distribution for Firebase iOS SDK.' s.description = <<-DESC @@ -30,10 +30,10 @@ iOS SDK for App Distribution for Firebase. ] s.public_header_files = base_dir + 'Public/FirebaseAppDistribution/*.h' - s.dependency 'FirebaseCore', '~> 11.15.0' + s.dependency 'FirebaseCore', '~> 12.0.0' s.dependency 'GoogleUtilities/AppDelegateSwizzler', '~> 8.1' s.dependency 'GoogleUtilities/UserDefaults', '~> 8.1' - s.dependency 'FirebaseInstallations', '~> 11.0' + s.dependency 'FirebaseInstallations', '~> 12.0' s.pod_target_xcconfig = { 'HEADER_SEARCH_PATHS' => '"${PODS_TARGET_SRCROOT}"' diff --git a/FirebaseAuth.podspec b/FirebaseAuth.podspec index 5ca2eb61f2a..72b0414bc90 100644 --- a/FirebaseAuth.podspec +++ b/FirebaseAuth.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseAuth' - s.version = '11.15.0' + s.version = '12.0.0' s.summary = 'Apple platform client for Firebase Authentication' s.description = <<-DESC @@ -55,10 +55,10 @@ supports email and password accounts, as well as several 3rd party authenticatio } s.framework = 'Security' s.ios.framework = 'SafariServices' - s.dependency 'FirebaseAuthInterop', '~> 11.0' - s.dependency 'FirebaseAppCheckInterop', '~> 11.0' - s.dependency 'FirebaseCore', '~> 11.15.0' - s.dependency 'FirebaseCoreExtension', '~> 11.15.0' + s.dependency 'FirebaseAuthInterop', '~> 12.0' + s.dependency 'FirebaseAppCheckInterop', '~> 12.0' + s.dependency 'FirebaseCore', '~> 12.0.0' + s.dependency 'FirebaseCoreExtension', '~> 12.0.0' s.dependency 'GoogleUtilities/AppDelegateSwizzler', '~> 8.1' s.dependency 'GoogleUtilities/Environment', '~> 8.1' s.dependency 'GTMSessionFetcher/Core', '>= 3.4', '< 5.0' diff --git a/FirebaseAuthInterop.podspec b/FirebaseAuthInterop.podspec index d08a9e2024d..461ec711984 100644 --- a/FirebaseAuthInterop.podspec +++ b/FirebaseAuthInterop.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseAuthInterop' - s.version = '11.15.0' + s.version = '12.0.0' s.summary = 'Interfaces that allow other Firebase SDKs to use Auth functionality.' s.description = <<-DESC diff --git a/FirebaseAuthTestingSupport.podspec b/FirebaseAuthTestingSupport.podspec index 3cf9b5128b5..b30e2510a74 100644 --- a/FirebaseAuthTestingSupport.podspec +++ b/FirebaseAuthTestingSupport.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseAuthTestingSupport' - s.version = '2.0.0' + s.version = '3.0.0' s.summary = 'Firebase SDKs testing support types and utilities.' s.description = <<-DESC @@ -39,7 +39,7 @@ Pod::Spec.new do |s| base_dir + 'Sources/**/*.swift', ] - s.dependency 'FirebaseAuth', '~> 11.0' + s.dependency 'FirebaseAuth', '> 12.0' s.test_spec 'unit' do |unit_tests| unit_tests.scheme = { :code_coverage => true } diff --git a/FirebaseCombineSwift.podspec b/FirebaseCombineSwift.podspec index b027ae2edd3..9d9ccf0c52c 100644 --- a/FirebaseCombineSwift.podspec +++ b/FirebaseCombineSwift.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseCombineSwift' - s.version = '11.15.0' + s.version = '12.0.0' s.summary = 'Swift extensions with Combine support for Firebase' s.description = <<-DESC @@ -51,11 +51,11 @@ for internal testing only. It should not be published. s.osx.framework = 'AppKit' s.tvos.framework = 'UIKit' - s.dependency 'FirebaseCore', '~> 11.15.0' - s.dependency 'FirebaseAuth', '~> 11.0' - s.dependency 'FirebaseFunctions', '~> 11.0' - s.dependency 'FirebaseFirestore', '~> 11.0' - s.dependency 'FirebaseStorage', '~> 11.0' + s.dependency 'FirebaseCore', '~> 12.0.0' + s.dependency 'FirebaseAuth', '~> 12.0' + s.dependency 'FirebaseFunctions', '~> 12.0' + s.dependency 'FirebaseFirestore', '~> 12.0' + s.dependency 'FirebaseStorage', '~> 12.0' s.pod_target_xcconfig = { 'HEADER_SEARCH_PATHS' => '"${PODS_TARGET_SRCROOT}"', @@ -104,6 +104,6 @@ for internal testing only. It should not be published. int_tests.resources = 'FirebaseStorage/Tests/Integration/Resources/1mb.dat', 'FirebaseStorage/Tests/Integration/Resources/GoogleService-Info.plist', 'FirebaseStorage/Tests/Integration/Resources/HomeImprovement.numbers' - int_tests.dependency 'FirebaseAuth', '~> 11.0' + int_tests.dependency 'FirebaseAuth', '~> 12.0' end end diff --git a/FirebaseCore.podspec b/FirebaseCore.podspec index 12180f591b8..49606f63792 100644 --- a/FirebaseCore.podspec +++ b/FirebaseCore.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseCore' - s.version = '11.15.0' + s.version = '12.0.0' s.summary = 'Firebase Core' s.description = <<-DESC @@ -53,7 +53,7 @@ Firebase Core includes FIRApp and FIROptions which provide central configuration # Remember to also update version in `cmake/external/GoogleUtilities.cmake` s.dependency 'GoogleUtilities/Environment', '~> 8.1' s.dependency 'GoogleUtilities/Logger', '~> 8.1' - s.dependency 'FirebaseCoreInternal', '~> 11.15.0' + s.dependency 'FirebaseCoreInternal', '~> 12.0.0' s.pod_target_xcconfig = { 'GCC_PREPROCESSOR_DEFINITIONS' => 'Firebase_VERSION=' + s.version.to_s, diff --git a/FirebaseCoreExtension.podspec b/FirebaseCoreExtension.podspec index 2741cd941bf..cd3aab0e1b0 100644 --- a/FirebaseCoreExtension.podspec +++ b/FirebaseCoreExtension.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseCoreExtension' - s.version = '11.15.0' + s.version = '12.0.0' s.summary = 'Extended FirebaseCore APIs for Firebase product SDKs' s.description = <<-DESC @@ -34,5 +34,5 @@ Pod::Spec.new do |s| "#{s.module_name}_Privacy" => 'FirebaseCore/Extension/Resources/PrivacyInfo.xcprivacy' } - s.dependency 'FirebaseCore', '~> 11.15.0' + s.dependency 'FirebaseCore', '~> 12.0.0' end diff --git a/FirebaseCoreInternal.podspec b/FirebaseCoreInternal.podspec index 77bf1d633d6..b15c77ff498 100644 --- a/FirebaseCoreInternal.podspec +++ b/FirebaseCoreInternal.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseCoreInternal' - s.version = '11.15.0' + s.version = '12.0.0' s.summary = 'APIs for internal FirebaseCore usage.' s.description = <<-DESC diff --git a/FirebaseCrashlytics.podspec b/FirebaseCrashlytics.podspec index 3ebb6837ffa..461cd2e379f 100644 --- a/FirebaseCrashlytics.podspec +++ b/FirebaseCrashlytics.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseCrashlytics' - s.version = '11.15.0' + s.version = '12.0.0' s.summary = 'Best and lightest-weight crash reporting for mobile, desktop and tvOS.' s.description = 'Firebase Crashlytics helps you track, prioritize, and fix stability issues that erode app quality.' s.homepage = 'https://firebase.google.com/' @@ -59,12 +59,12 @@ Pod::Spec.new do |s| cp -f ./Crashlytics/CrashlyticsInputFiles.xcfilelist ./CrashlyticsInputFiles.xcfilelist PREPARE_COMMAND_END - s.dependency 'FirebaseCore', '~> 11.15.0' - s.dependency 'FirebaseInstallations', '~> 11.0' - s.dependency 'FirebaseSessions', '~> 11.0' - s.dependency 'FirebaseRemoteConfigInterop', '~> 11.0' + s.dependency 'FirebaseCore', '~> 12.0.0' + s.dependency 'FirebaseInstallations', '~> 12.0' + s.dependency 'FirebaseSessions', '~> 12.0' + s.dependency 'FirebaseRemoteConfigInterop', '~> 12.0' s.dependency 'PromisesObjC', '~> 2.4' - s.dependency 'GoogleDataTransport', '~> 10.0' + s.dependency 'GoogleDataTransport', '~> 10.1' s.dependency 'GoogleUtilities/Environment', '~> 8.1' s.dependency 'nanopb', '~> 3.30910.0' diff --git a/FirebaseDatabase.podspec b/FirebaseDatabase.podspec index 09768d48252..892a9c766e9 100644 --- a/FirebaseDatabase.podspec +++ b/FirebaseDatabase.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseDatabase' - s.version = '11.15.0' + s.version = '12.0.0' s.summary = 'Firebase Realtime Database' s.description = <<-DESC @@ -48,9 +48,9 @@ Simplify your iOS development, grow your user base, and monetize more effectivel s.macos.frameworks = 'CFNetwork', 'Security', 'SystemConfiguration' s.watchos.frameworks = 'CFNetwork', 'Security', 'WatchKit' s.dependency 'leveldb-library', '~> 1.22' - s.dependency 'FirebaseCore', '~> 11.15.0' - s.dependency 'FirebaseAppCheckInterop', '~> 11.0' - s.dependency 'FirebaseSharedSwift', '~> 11.0' + s.dependency 'FirebaseCore', '~> 12.0.0' + s.dependency 'FirebaseAppCheckInterop', '~> 12.0' + s.dependency 'FirebaseSharedSwift', '~> 12.0' s.dependency 'GoogleUtilities/UserDefaults', '~> 8.1' s.pod_target_xcconfig = { 'HEADER_SEARCH_PATHS' => '"${PODS_TARGET_SRCROOT}"' @@ -72,7 +72,7 @@ Simplify your iOS development, grow your user base, and monetize more effectivel 'SharedTestUtilities/FIRComponentTestUtilities.[mh]', 'SharedTestUtilities/FIROptionsMock.[mh]', ] - unit_tests.dependency 'FirebaseAppCheckInterop', '~> 11.0' + unit_tests.dependency 'FirebaseAppCheckInterop', '~> 12.0' unit_tests.dependency 'OCMock' unit_tests.resources = 'FirebaseDatabase/Tests/Resources/syncPointSpec.json', 'FirebaseDatabase/Tests/Resources/GoogleService-Info.plist' diff --git a/FirebaseFirestore.podspec b/FirebaseFirestore.podspec index d82d3525034..1dc29d19fd8 100644 --- a/FirebaseFirestore.podspec +++ b/FirebaseFirestore.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseFirestore' - s.version = '11.15.0' + s.version = '12.0.0' s.summary = 'Google Cloud Firestore' s.description = <<-DESC Google Cloud Firestore is a NoSQL document database built for automatic scaling, high performance, and ease of application development. @@ -35,9 +35,9 @@ Google Cloud Firestore is a NoSQL document database built for automatic scaling, "#{s.module_name}_Privacy" => 'Firestore/Swift/Source/Resources/PrivacyInfo.xcprivacy' } - s.dependency 'FirebaseCore', '~> 11.15.0' - s.dependency 'FirebaseCoreExtension', '~> 11.15.0' - s.dependency 'FirebaseFirestoreInternal', '11.15.0' - s.dependency 'FirebaseSharedSwift', '~> 11.0' + s.dependency 'FirebaseCore', '~> 12.0.0' + s.dependency 'FirebaseCoreExtension', '~> 12.0.0' + s.dependency 'FirebaseFirestoreInternal', '12.0.0' + s.dependency 'FirebaseSharedSwift', '~> 12.0' end diff --git a/FirebaseFirestoreInternal.podspec b/FirebaseFirestoreInternal.podspec index ef81b8da45b..11df66fdaea 100644 --- a/FirebaseFirestoreInternal.podspec +++ b/FirebaseFirestoreInternal.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseFirestoreInternal' - s.version = '11.15.0' + s.version = '12.0.0' s.summary = 'Google Cloud Firestore' s.description = <<-DESC @@ -92,8 +92,8 @@ Google Cloud Firestore is a NoSQL document database built for automatic scaling, "#{s.module_name}_Privacy" => 'Firestore/Source/Resources/PrivacyInfo.xcprivacy' } - s.dependency 'FirebaseAppCheckInterop', '~> 11.0' - s.dependency 'FirebaseCore', '~> 11.15.0' + s.dependency 'FirebaseAppCheckInterop', '~> 12.0' + s.dependency 'FirebaseCore', '~> 12.0.0' abseil_version = '~> 1.20240722.0' s.dependency 'abseil/algorithm', abseil_version diff --git a/FirebaseFirestoreTestingSupport.podspec b/FirebaseFirestoreTestingSupport.podspec index 97ab0f834a6..11509cde08a 100644 --- a/FirebaseFirestoreTestingSupport.podspec +++ b/FirebaseFirestoreTestingSupport.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseFirestoreTestingSupport' - s.version = '1.0.0' + s.version = '2.0.0' s.summary = 'Firebase SDKs testing support types and utilities.' s.description = <<-DESC @@ -42,7 +42,7 @@ Pod::Spec.new do |s| s.public_header_files = base_dir + '**/*.h' - s.dependency 'FirebaseFirestore', '~> 11.0' + s.dependency 'FirebaseFirestore', '> 12.0' s.pod_target_xcconfig = { 'OTHER_CFLAGS' => '-fno-autolink', diff --git a/FirebaseFunctions.podspec b/FirebaseFunctions.podspec index 7fd85e241d1..55f2bac00f5 100644 --- a/FirebaseFunctions.podspec +++ b/FirebaseFunctions.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseFunctions' - s.version = '11.15.0' + s.version = '12.0.0' s.summary = 'Cloud Functions for Firebase' s.description = <<-DESC @@ -35,12 +35,12 @@ Cloud Functions for Firebase. 'FirebaseFunctions/Sources/**/*.swift', ] - s.dependency 'FirebaseCore', '~> 11.15.0' - s.dependency 'FirebaseCoreExtension', '~> 11.15.0' - s.dependency 'FirebaseAppCheckInterop', '~> 11.0' - s.dependency 'FirebaseAuthInterop', '~> 11.0' - s.dependency 'FirebaseMessagingInterop', '~> 11.0' - s.dependency 'FirebaseSharedSwift', '~> 11.0' + s.dependency 'FirebaseCore', '~> 12.0.0' + s.dependency 'FirebaseCoreExtension', '~> 12.0.0' + s.dependency 'FirebaseAppCheckInterop', '~> 12.0' + s.dependency 'FirebaseAuthInterop', '~> 12.0' + s.dependency 'FirebaseMessagingInterop', '~> 12.0' + s.dependency 'FirebaseSharedSwift', '~> 12.0' s.dependency 'GTMSessionFetcher/Core', '>= 3.4', '< 5.0' s.test_spec 'objc' do |objc_tests| diff --git a/FirebaseInAppMessaging.podspec b/FirebaseInAppMessaging.podspec index c6e0e263968..318a70686bf 100644 --- a/FirebaseInAppMessaging.podspec +++ b/FirebaseInAppMessaging.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseInAppMessaging' - s.version = '11.15.0-beta' + s.version = '12.0.0-beta' s.summary = 'Firebase In-App Messaging for iOS' s.description = <<-DESC @@ -80,9 +80,9 @@ See more product details at https://firebase.google.com/products/in-app-messagin s.framework = 'UIKit' - s.dependency 'FirebaseCore', '~> 11.15.0' - s.dependency 'FirebaseInstallations', '~> 11.0' - s.dependency 'FirebaseABTesting', '~> 11.0' + s.dependency 'FirebaseCore', '~> 12.0.0' + s.dependency 'FirebaseInstallations', '~> 12.0' + s.dependency 'FirebaseABTesting', '~> 12.0' s.dependency 'GoogleUtilities/Environment', '~> 8.1' s.dependency 'GoogleUtilities/UserDefaults', '~> 8.1' s.dependency 'nanopb', '~> 3.30910.0' diff --git a/FirebaseInstallations.podspec b/FirebaseInstallations.podspec index 45c40ca732d..579cf3711a7 100644 --- a/FirebaseInstallations.podspec +++ b/FirebaseInstallations.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseInstallations' - s.version = '11.15.0' + s.version = '12.0.0' s.summary = 'Firebase Installations' s.description = <<-DESC @@ -45,7 +45,7 @@ Pod::Spec.new do |s| } s.framework = 'Security' - s.dependency 'FirebaseCore', '~> 11.15.0' + s.dependency 'FirebaseCore', '~> 12.0.0' s.dependency 'PromisesObjC', '~> 2.4' s.dependency 'GoogleUtilities/Environment', '~> 8.1' s.dependency 'GoogleUtilities/UserDefaults', '~> 8.1' diff --git a/FirebaseMLModelDownloader.podspec b/FirebaseMLModelDownloader.podspec index 2590eead306..a825ba390b1 100644 --- a/FirebaseMLModelDownloader.podspec +++ b/FirebaseMLModelDownloader.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseMLModelDownloader' - s.version = '11.15.0-beta' + s.version = '12.0.0-beta' s.summary = 'Firebase ML Model Downloader' s.description = <<-DESC @@ -36,10 +36,10 @@ Pod::Spec.new do |s| ] s.framework = 'Foundation' - s.dependency 'FirebaseCore', '~> 11.15.0' - s.dependency 'FirebaseCoreExtension', '~> 11.15.0' - s.dependency 'FirebaseInstallations', '~> 11.0' - s.dependency 'GoogleDataTransport', '~> 10.0' + s.dependency 'FirebaseCore', '~> 12.0.0' + s.dependency 'FirebaseCoreExtension', '~> 12.0.0' + s.dependency 'FirebaseInstallations', '~> 12.0' + s.dependency 'GoogleDataTransport', '~> 10.1' s.dependency 'GoogleUtilities/UserDefaults', '~> 8.1' s.dependency 'SwiftProtobuf', '~> 1.19' diff --git a/FirebaseMessaging.podspec b/FirebaseMessaging.podspec index 8cf729a8fca..58c29368a43 100644 --- a/FirebaseMessaging.podspec +++ b/FirebaseMessaging.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseMessaging' - s.version = '11.15.0' + s.version = '12.0.0' s.summary = 'Firebase Messaging' s.description = <<-DESC @@ -60,13 +60,13 @@ device, and it is completely free. s.tvos.framework = 'SystemConfiguration' s.osx.framework = 'SystemConfiguration' s.weak_framework = 'UserNotifications' - s.dependency 'FirebaseInstallations', '~> 11.0' - s.dependency 'FirebaseCore', '~> 11.15.0' + s.dependency 'FirebaseInstallations', '~> 12.0' + s.dependency 'FirebaseCore', '~> 12.0.0' s.dependency 'GoogleUtilities/AppDelegateSwizzler', '~> 8.1' s.dependency 'GoogleUtilities/Reachability', '~> 8.1' s.dependency 'GoogleUtilities/Environment', '~> 8.1' s.dependency 'GoogleUtilities/UserDefaults', '~> 8.1' - s.dependency 'GoogleDataTransport', '~> 10.0' + s.dependency 'GoogleDataTransport', '~> 10.1' s.dependency 'nanopb', '~> 3.30910.0' s.test_spec 'unit' do |unit_tests| diff --git a/FirebaseMessagingInterop.podspec b/FirebaseMessagingInterop.podspec index c79f294d70e..11b34ae4326 100644 --- a/FirebaseMessagingInterop.podspec +++ b/FirebaseMessagingInterop.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseMessagingInterop' - s.version = '11.15.0' + s.version = '12.0.0' s.summary = 'Interfaces that allow other Firebase SDKs to use Messaging functionality.' s.description = <<-DESC diff --git a/FirebasePerformance.podspec b/FirebasePerformance.podspec index d2124aa25c3..4ea778a1992 100644 --- a/FirebasePerformance.podspec +++ b/FirebasePerformance.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebasePerformance' - s.version = '11.15.0' + s.version = '12.0.0' s.summary = 'Firebase Performance' s.description = <<-DESC @@ -58,11 +58,11 @@ Firebase Performance library to measure performance of Mobile and Web Apps. s.ios.framework = 'CoreTelephony' s.framework = 'QuartzCore' s.framework = 'SystemConfiguration' - s.dependency 'FirebaseCore', '~> 11.15.0' - s.dependency 'FirebaseInstallations', '~> 11.0' - s.dependency 'FirebaseRemoteConfig', '~> 11.0' - s.dependency 'FirebaseSessions', '~> 11.0' - s.dependency 'GoogleDataTransport', '~> 10.0' + s.dependency 'FirebaseCore', '~> 12.0.0' + s.dependency 'FirebaseInstallations', '~> 12.0' + s.dependency 'FirebaseRemoteConfig', '~> 12.0' + s.dependency 'FirebaseSessions', '~> 12.0' + s.dependency 'GoogleDataTransport', '~> 10.1' s.dependency 'GoogleUtilities/Environment', '~> 8.1' s.dependency 'GoogleUtilities/MethodSwizzler', '~> 8.1' s.dependency 'GoogleUtilities/UserDefaults', '~> 8.1' diff --git a/FirebaseRemoteConfig.podspec b/FirebaseRemoteConfig.podspec index ea7760ffc21..d2a6118c78a 100644 --- a/FirebaseRemoteConfig.podspec +++ b/FirebaseRemoteConfig.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseRemoteConfig' - s.version = '11.15.0' + s.version = '12.0.0' s.summary = 'Firebase Remote Config' s.description = <<-DESC @@ -49,13 +49,13 @@ app update. s.pod_target_xcconfig = { 'HEADER_SEARCH_PATHS' => '"${PODS_TARGET_SRCROOT}"' } - s.dependency 'FirebaseABTesting', '~> 11.0' - s.dependency 'FirebaseSharedSwift', '~> 11.0' - s.dependency 'FirebaseCore', '~> 11.15.0' - s.dependency 'FirebaseInstallations', '~> 11.0' + s.dependency 'FirebaseABTesting', '~> 12.0' + s.dependency 'FirebaseSharedSwift', '~> 12.0' + s.dependency 'FirebaseCore', '~> 12.0.0' + s.dependency 'FirebaseInstallations', '~> 12.0' s.dependency 'GoogleUtilities/Environment', '~> 8.1' s.dependency 'GoogleUtilities/NSData+zlib', '~> 8.1' - s.dependency 'FirebaseRemoteConfigInterop', '~> 11.0' + s.dependency 'FirebaseRemoteConfigInterop', '~> 12.0' s.test_spec 'unit' do |unit_tests| unit_tests.scheme = { :code_coverage => true } diff --git a/FirebaseRemoteConfigInterop.podspec b/FirebaseRemoteConfigInterop.podspec index 49a101bf6bf..21a39effd3d 100644 --- a/FirebaseRemoteConfigInterop.podspec +++ b/FirebaseRemoteConfigInterop.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseRemoteConfigInterop' - s.version = '11.15.0' + s.version = '12.0.0' s.summary = 'Interfaces that allow other Firebase SDKs to use Remote Config functionality.' s.description = <<-DESC diff --git a/FirebaseSessions.podspec b/FirebaseSessions.podspec index 9bb2e6988da..308da8c87e3 100644 --- a/FirebaseSessions.podspec +++ b/FirebaseSessions.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseSessions' - s.version = '11.15.0' + s.version = '12.0.0' s.summary = 'Firebase Sessions' s.description = <<-DESC @@ -39,10 +39,10 @@ Pod::Spec.new do |s| base_dir + 'SourcesObjC/**/*.{c,h,m,mm}', ] - s.dependency 'FirebaseCore', '~> 11.15.0' - s.dependency 'FirebaseCoreExtension', '~> 11.15.0' - s.dependency 'FirebaseInstallations', '~> 11.0' - s.dependency 'GoogleDataTransport', '~> 10.0' + s.dependency 'FirebaseCore', '~> 12.0.0' + s.dependency 'FirebaseCoreExtension', '~> 12.0.0' + s.dependency 'FirebaseInstallations', '~> 12.0' + s.dependency 'GoogleDataTransport', '~> 10.1' s.dependency 'GoogleUtilities/Environment', '~> 8.1' s.dependency 'GoogleUtilities/UserDefaults', '~> 8.1' s.dependency 'nanopb', '~> 3.30910.0' diff --git a/FirebaseSharedSwift.podspec b/FirebaseSharedSwift.podspec index 8ead4e75ddc..8f91286b6b6 100644 --- a/FirebaseSharedSwift.podspec +++ b/FirebaseSharedSwift.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseSharedSwift' - s.version = '11.15.0' + s.version = '12.0.0' s.summary = 'Shared Swift Extensions for Firebase' s.description = <<-DESC diff --git a/FirebaseStorage.podspec b/FirebaseStorage.podspec index 07954bf0b9b..c42929db4a7 100644 --- a/FirebaseStorage.podspec +++ b/FirebaseStorage.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseStorage' - s.version = '11.15.0' + s.version = '12.0.0' s.summary = 'Firebase Storage' s.description = <<-DESC @@ -37,10 +37,10 @@ Firebase Storage provides robust, secure file uploads and downloads from Firebas 'FirebaseStorage/Typedefs/*.h', ] - s.dependency 'FirebaseAppCheckInterop', '~> 11.0' - s.dependency 'FirebaseAuthInterop', '~> 11.0' - s.dependency 'FirebaseCore', '~> 11.15.0' - s.dependency 'FirebaseCoreExtension', '~> 11.15.0' + s.dependency 'FirebaseAppCheckInterop', '~> 12.0' + s.dependency 'FirebaseAuthInterop', '~> 12.0' + s.dependency 'FirebaseCore', '~> 12.0.0' + s.dependency 'FirebaseCoreExtension', '~> 12.0.0' s.dependency 'GTMSessionFetcher/Core', '>= 3.4', '< 5.0' s.dependency 'GoogleUtilities/Environment', '~> 8.1' @@ -57,7 +57,7 @@ Firebase Storage provides robust, secure file uploads and downloads from Firebas objc_tests.requires_app_host = true objc_tests.resources = 'FirebaseStorage/Tests/Integration/Resources/1mb.dat', 'FirebaseStorage/Tests/Integration/Resources/GoogleService-Info.plist' - objc_tests.dependency 'FirebaseAuth', '~> 11.0' + objc_tests.dependency 'FirebaseAuth', '~> 12.0' objc_tests.pod_target_xcconfig = { 'HEADER_SEARCH_PATHS' => '"${PODS_TARGET_SRCROOT}"' } @@ -86,6 +86,6 @@ Firebase Storage provides robust, secure file uploads and downloads from Firebas int_tests.resources = 'FirebaseStorage/Tests/Integration/Resources/1mb.dat', 'FirebaseStorage/Tests/Integration/Resources/GoogleService-Info.plist', 'FirebaseStorage/Tests/Integration/Resources/HomeImprovement.numbers' - int_tests.dependency 'FirebaseAuth', '~> 11.0' + int_tests.dependency 'FirebaseAuth', '~> 12.0' end end diff --git a/GoogleAppMeasurement.podspec b/GoogleAppMeasurement.podspec index bbfca9bbefc..f8586fd5532 100644 --- a/GoogleAppMeasurement.podspec +++ b/GoogleAppMeasurement.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'GoogleAppMeasurement' - s.version = '11.15.0' + s.version = '12.0.0' s.summary = 'Shared measurement methods for Google libraries. Not intended for direct use.' s.description = <<-DESC @@ -37,8 +37,8 @@ Pod::Spec.new do |s| s.default_subspecs = 'Default' s.subspec 'Default' do |ss| - ss.dependency 'GoogleAppMeasurement/Core', '11.15.0' - ss.dependency 'GoogleAppMeasurement/IdentitySupport', '11.15.0' + ss.dependency 'GoogleAppMeasurement/Core', '12.0.0' + ss.dependency 'GoogleAppMeasurement/IdentitySupport', '12.0.0' ss.ios.dependency 'GoogleAdsOnDeviceConversion', '2.1.0' end @@ -47,17 +47,17 @@ Pod::Spec.new do |s| end s.subspec 'IdentitySupport' do |ss| - ss.dependency 'GoogleAppMeasurement/Core', '11.15.0' + ss.dependency 'GoogleAppMeasurement/Core', '12.0.0' ss.vendored_frameworks = 'Frameworks/GoogleAppMeasurementIdentitySupport.xcframework' end # Deprecated. Use IdentitySupport subspec instead. s.subspec 'AdIdSupport' do |ss| - ss.dependency 'GoogleAppMeasurement/IdentitySupport', '11.15.0' + ss.dependency 'GoogleAppMeasurement/IdentitySupport', '12.0.0' end # Deprecated. Use Core subspec instead. s.subspec 'WithoutAdIdSupport' do |ss| - ss.dependency 'GoogleAppMeasurement/Core', '11.15.0' + ss.dependency 'GoogleAppMeasurement/Core', '12.0.0' end end diff --git a/GoogleAppMeasurementOnDeviceConversion.podspec b/GoogleAppMeasurementOnDeviceConversion.podspec index fb9b864a069..24b3db89042 100644 --- a/GoogleAppMeasurementOnDeviceConversion.podspec +++ b/GoogleAppMeasurementOnDeviceConversion.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'GoogleAppMeasurementOnDeviceConversion' - s.version = '11.15.0' + s.version = '12.0.0' s.summary = <<-SUMMARY On device conversion measurement plugin for Google App Measurement. Not intended for direct use. diff --git a/Package.swift b/Package.swift index db6fe329c2c..ca900df3f4b 100644 --- a/Package.swift +++ b/Package.swift @@ -19,7 +19,7 @@ import class Foundation.ProcessInfo import PackageDescription -let firebaseVersion = "11.15.0" +let firebaseVersion = "12.0.0" let package = Package( name: "Firebase", @@ -149,7 +149,7 @@ let package = Package( googleAppMeasurementDependency(), .package( url: "https://github.com/google/GoogleDataTransport.git", - "10.0.0" ..< "11.0.0" + "10.1.0" ..< "11.0.0" ), .package( url: "https://github.com/google/GoogleUtilities.git", diff --git a/ReleaseTooling/Sources/FirebaseManifest/FirebaseManifest.swift b/ReleaseTooling/Sources/FirebaseManifest/FirebaseManifest.swift index 20cd0ebfc8a..f02eb0c579b 100755 --- a/ReleaseTooling/Sources/FirebaseManifest/FirebaseManifest.swift +++ b/ReleaseTooling/Sources/FirebaseManifest/FirebaseManifest.swift @@ -21,7 +21,7 @@ import Foundation /// The version and releasing fields of the non-Firebase pods should be reviewed every release. /// The array should be ordered so that any pod's dependencies precede it in the list. public let shared = Manifest( - version: "11.15.0", + version: "12.0.0", pods: [ Pod("FirebaseSharedSwift"), Pod("FirebaseCoreInternal"), From ca966a2a4685a02c5a07eace0015eeba4d5bd6ec Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 24 Jun 2025 06:26:13 -0700 Subject: [PATCH 100/113] NOTICES Change (#15030) Co-authored-by: Anka --- CoreOnly/NOTICES | 1 - 1 file changed, 1 deletion(-) diff --git a/CoreOnly/NOTICES b/CoreOnly/NOTICES index 01a6bf30bda..397d023f616 100644 --- a/CoreOnly/NOTICES +++ b/CoreOnly/NOTICES @@ -21,7 +21,6 @@ FirebaseRemoteConfig FirebaseRemoteConfigInterop FirebaseSessions FirebaseStorage -FirebaseVertexAI GTMSessionFetcher GoogleDataTransport PromisesObjC From 8f785fcfcf7410368df30cca27a86bed8bcf53d6 Mon Sep 17 00:00:00 2001 From: Nick Cooke <36927374+ncooke3@users.noreply.github.com> Date: Tue, 24 Jun 2025 11:57:42 -0400 Subject: [PATCH 101/113] [Infra] Stop including AdMob in zip builds (#15024) --- FirebaseCore/CHANGELOG.md | 7 +++++++ ReleaseTooling/Sources/ZipBuilder/CarthageUtils.swift | 2 -- ReleaseTooling/Sources/ZipBuilder/ZipBuilder.swift | 8 ++------ 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/FirebaseCore/CHANGELOG.md b/FirebaseCore/CHANGELOG.md index 14adaffc7e1..f6e677e74b3 100644 --- a/FirebaseCore/CHANGELOG.md +++ b/FirebaseCore/CHANGELOG.md @@ -7,6 +7,13 @@ - [removed] **Breaking change**: Removed the following unused API. - `Options.androidClientID` - `Options.trackingID` +- [removed] **Breaking change**: Firebase's zip and Carthage distributions of + the Google Mobile Ads SDK has been removed. Instead, the Google + Mobile Ads SDK binary distribution should be accessed from + https://developers.google.com/admob/ios/download. Note that _any existing + versions of the Firebase zip or Carthage distributions will + continue to be available and functional_. Learn more about this change + in our FAQ: https://firebase.google.com/support/faq/#admob-which-sdk. (#14408) - [removed] The deprecated Vertex AI in Firebase SDK (`FirebaseVertexAI`) has been removed. It has been replaced by the Firebase AI Logic SDK (`FirebaseAI`) to diff --git a/ReleaseTooling/Sources/ZipBuilder/CarthageUtils.swift b/ReleaseTooling/Sources/ZipBuilder/CarthageUtils.swift index 5b87998bb37..a326684ff05 100644 --- a/ReleaseTooling/Sources/ZipBuilder/CarthageUtils.swift +++ b/ReleaseTooling/Sources/ZipBuilder/CarthageUtils.swift @@ -319,8 +319,6 @@ extension CarthageUtils { var jsonFileName: String if product == "GoogleSignIn" { jsonFileName = "FirebaseGoogleSignIn" - } else if product == "Google-Mobile-Ads-SDK" { - jsonFileName = "FirebaseAdMob" } else { jsonFileName = product } diff --git a/ReleaseTooling/Sources/ZipBuilder/ZipBuilder.swift b/ReleaseTooling/Sources/ZipBuilder/ZipBuilder.swift index d19cd4c32e5..99eb31071db 100644 --- a/ReleaseTooling/Sources/ZipBuilder/ZipBuilder.swift +++ b/ReleaseTooling/Sources/ZipBuilder/ZipBuilder.swift @@ -369,11 +369,8 @@ struct ZipBuilder { guard !podsToInstall.isEmpty else { fatalError("Failed to find versions for Firebase release") } - // We don't release Google-Mobile-Ads-SDK and GoogleSignIn, but we include their latest + // We don't release GoogleSignIn, but we include its latest // version for convenience in the Zip and Carthage builds. - podsToInstall.append(CocoaPodUtils.VersionedPod(name: "Google-Mobile-Ads-SDK", - version: nil, - platforms: ["ios"])) podsToInstall.append(CocoaPodUtils.VersionedPod(name: "GoogleSignIn", version: nil, platforms: ["ios"])) @@ -486,8 +483,7 @@ struct ZipBuilder { // Skip Analytics and the pods bundled with it. let remainingPods = installedPods.filter { - $0.key == "Google-Mobile-Ads-SDK" || - $0.key == "GoogleSignIn" || + $0.key == "GoogleSignIn" || (firebaseZipPods.contains($0.key) && $0.key != "FirebaseAnalytics" && $0.key != "Firebase" && From 3fe56e9fc1c2a8cf41ded084b4d524053c73751c Mon Sep 17 00:00:00 2001 From: Andrew Heard Date: Tue, 24 Jun 2025 12:21:19 -0400 Subject: [PATCH 102/113] [Firebase AI] Cleanup Vertex AI in Firebase references (#15033) --- .github/workflows/spm.yml | 4 +- Carthage.md | 1 - Dangerfile | 5 +- FirebaseAI/README.md | 2 +- README.md | 10 +-- scripts/README.md | 2 +- scripts/make_release_notes.py | 1 - .../FirebaseVertexAIUnit.xcscheme | 77 ------------------- 8 files changed, 10 insertions(+), 92 deletions(-) delete mode 100644 scripts/spm_test_schemes/FirebaseVertexAIUnit.xcscheme diff --git a/.github/workflows/spm.yml b/.github/workflows/spm.yml index 4c7faad3814..97a897e2695 100644 --- a/.github/workflows/spm.yml +++ b/.github/workflows/spm.yml @@ -71,7 +71,7 @@ jobs: with: path: .build key: ${{needs.spm-package-resolved.outputs.cache_key}} - - name: Clone mock responses for Vertex AI unit tests + - name: Clone mock responses for Firebase AI Logic unit tests run: scripts/update_vertexai_responses.sh - name: Xcode run: sudo xcode-select -s /Applications/${{ matrix.xcode }}.app/Contents/Developer @@ -106,7 +106,7 @@ jobs: with: path: .build key: ${{needs.spm-package-resolved.outputs.cache_key}} - - name: Clone mock responses for Vertex AI unit tests + - name: Clone mock responses for Firebase AI Logic unit tests run: scripts/update_vertexai_responses.sh - name: Xcode run: sudo xcode-select -s /Applications/${{ matrix.xcode }}.app/Contents/Developer diff --git a/Carthage.md b/Carthage.md index 7e8bbfc90a6..8bf4b21c65c 100644 --- a/Carthage.md +++ b/Carthage.md @@ -48,7 +48,6 @@ binary "https://dl.google.com/dl/firebase/ios/carthage/FirebaseMessagingBinary.j binary "https://dl.google.com/dl/firebase/ios/carthage/FirebasePerformanceBinary.json" binary "https://dl.google.com/dl/firebase/ios/carthage/FirebaseRemoteConfigBinary.json" binary "https://dl.google.com/dl/firebase/ios/carthage/FirebaseStorageBinary.json" -binary "https://dl.google.com/dl/firebase/ios/carthage/FirebaseVertexAIBinary.json" ``` - Run `carthage update` - Use Finder to open `Carthage/Build`. diff --git a/Dangerfile b/Dangerfile index 6e6cb1ce057..99868088875 100644 --- a/Dangerfile +++ b/Dangerfile @@ -130,10 +130,7 @@ has_license_changes = didModify(["LICENSE"]) @has_crashlytics_api_changes = hasChangesIn("Crashlytics/Crashlytics/Public/") @has_database_changes = hasChangesIn("FirebaseDatabase") @has_database_api_changes = hasChangesIn("FirebaseDatabase/Sources/Public/") -@has_firebaseai_changes = hasChangesIn([ - "FirebaseAI", - "FirebaseVertexAI" -]) +@has_firebaseai_changes = hasChangesIn("FirebaseAI") @has_firestore_changes = hasChangesIn(["Firestore/", "FirebaseFirestore.podspec"]) @has_firestore_api_changes = hasChangesIn("Firestore/Source/Public/") @has_functions_changes = hasChangesIn(["FirebaseFunctions"]) diff --git a/FirebaseAI/README.md b/FirebaseAI/README.md index 9f9c4b0cabb..48c84867f19 100644 --- a/FirebaseAI/README.md +++ b/FirebaseAI/README.md @@ -1,6 +1,6 @@ # Firebase AI SDK -- For developer documentation, please visit https://firebase.google.com/docs/vertex-ai. +- For developer documentation, please visit https://firebase.google.com/docs/ai-logic. - Try out the [sample app](https://github.com/firebase/quickstart-ios/tree/main/firebaseai) to get started. ## Development diff --git a/README.md b/README.md index 8c98212b4d9..6c5168f8bbe 100644 --- a/README.md +++ b/README.md @@ -181,6 +181,11 @@ For coverage report generation instructions, see [scripts/code_coverage_report/R ## Specific Component Instructions See the sections below for any special instructions for those components. +### Firebase AI Logic + +See the [Firebase AI Logic README](FirebaseAI#development) for instructions +about building and testing the SDK. + ### Firebase Auth For specific Firebase Auth development, refer to the [Auth Sample README](FirebaseAuth/Tests/Sample/README.md) for instructions about @@ -235,11 +240,6 @@ at **Project Settings > Cloud Messaging > [Your Firebase App]**. 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. -### Vertex AI for Firebase - -See the [Vertex AI for Firebase README](FirebaseVertexAI#development) for -instructions about building and testing the SDK. - ## Building with Firebase on Apple platforms Firebase provides official beta support for macOS, Catalyst, and tvOS. visionOS and watchOS diff --git a/scripts/README.md b/scripts/README.md index 3bc7065685a..0eff2ec781f 100644 --- a/scripts/README.md +++ b/scripts/README.md @@ -185,7 +185,7 @@ Script to add a file to an Xcode target. ### [update_vertexai_responses.sh](https://github.com/firebase/firebase-ios-sdk/blob/main/scripts/update_vertexai_responses.sh) -Downloads mock response files for Vertex AI unit tests. +Downloads mock response files for the Firebase AI Logic unit tests. ### [xcresult_logs.py](https://github.com/firebase/firebase-ios-sdk/blob/main/scripts/xcresult_logs.py) diff --git a/scripts/make_release_notes.py b/scripts/make_release_notes.py index a372940e4bd..f79a739717a 100755 --- a/scripts/make_release_notes.py +++ b/scripts/make_release_notes.py @@ -43,7 +43,6 @@ 'FirebaseFunctions/CHANGELOG.md': '{{cloud_functions}}', 'FirebaseRemoteConfig/CHANGELOG.md': '{{remote_config}}', 'FirebasePerformance/CHANGELOG.md': '{{perfmon}}', - 'FirebaseVertexAI/CHANGELOG.md': '{{vertex_ai_in_firebase}}', # Assumes firebase-ios-sdk and data-connect-ios-sdk are cloned to the same # directory. diff --git a/scripts/spm_test_schemes/FirebaseVertexAIUnit.xcscheme b/scripts/spm_test_schemes/FirebaseVertexAIUnit.xcscheme deleted file mode 100644 index cb4b5adae36..00000000000 --- a/scripts/spm_test_schemes/FirebaseVertexAIUnit.xcscheme +++ /dev/null @@ -1,77 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - From 4238fd89b500e209d1e50d36ea1084c32b6bd8d6 Mon Sep 17 00:00:00 2001 From: Nick Cooke <36927374+ncooke3@users.noreply.github.com> Date: Tue, 24 Jun 2025 13:22:47 -0400 Subject: [PATCH 103/113] [Infra] Bump podspec min. versions (#15015) --- .../FirebasePodTest.xcodeproj/project.pbxproj | 4 +- CoreOnly/Tests/FirebasePodTest/Podfile | 2 +- .../CombineSample.xcodeproj/project.pbxproj | 8 +- Example/tvOSSample/Podfile | 2 +- .../tvOSSample.xcodeproj/project.pbxproj | 4 +- .../SampleWatchApp.xcodeproj/project.pbxproj | 12 +-- Firebase.podspec | 78 +++++++++---------- FirebaseABTesting.podspec | 4 +- .../ABTQA.xcodeproj/project.pbxproj | 8 +- FirebaseAnalytics.podspec | 4 +- FirebaseAnalyticsOnDeviceConversion.podspec | 2 +- FirebaseAppCheck.podspec | 4 +- .../project.pbxproj | 4 +- .../Apps/AppCheckCustomProvideApp/Podfile | 2 +- .../project.pbxproj | 4 +- .../Apps/FIRAppCheckTestApp/Podfile | 2 +- FirebaseAppCheckInterop.podspec | 4 +- FirebaseAppDistribution.podspec | 2 +- FirebaseAuth.podspec | 4 +- FirebaseAuth/Tests/SampleSwift/Podfile | 2 +- FirebaseAuthInterop.podspec | 4 +- FirebaseAuthTestingSupport.podspec | 4 +- FirebaseCombineSwift.podspec | 4 +- FirebaseCore.podspec | 4 +- FirebaseCore/CHANGELOG.md | 8 ++ FirebaseCoreExtension.podspec | 4 +- FirebaseCoreInternal.podspec | 10 +-- FirebaseCrashlytics.podspec | 4 +- FirebaseDatabase.podspec | 4 +- .../third_party/SocketRocket/FSRWebSocket.m | 3 + FirebaseFirestore.podspec | 4 +- FirebaseFirestoreInternal.podspec | 4 +- FirebaseFirestoreTestingSupport.podspec | 4 +- FirebaseFunctions.podspec | 4 +- FirebaseInAppMessaging.podspec | 4 +- .../FIAMSwiftUI.xcodeproj/project.pbxproj | 4 +- .../Tests/Integration/FIAMSwiftUI/Podfile | 2 +- .../project.pbxproj | 4 +- .../Integration/DefaultUITestApp/Podfile | 2 +- .../project.pbxproj | 8 +- .../Integration/FunctionalTestApp/Podfile | 2 +- FirebaseInstallations.podspec | 4 +- FirebaseMLModelDownloader.podspec | 4 +- .../project.pbxproj | 8 +- FirebaseMLModelDownloader/Apps/Sample/Podfile | 2 +- FirebaseMessaging.podspec | 4 +- .../AdvancedSample.xcodeproj/project.pbxproj | 4 +- FirebaseMessaging/Apps/AdvancedSample/Podfile | 6 +- FirebaseMessaging/Apps/Sample/Podfile | 2 +- .../Sample/Sample.xcodeproj/project.pbxproj | 4 +- .../SwiftUISample.xcodeproj/project.pbxproj | 4 +- FirebaseMessagingInterop.podspec | 4 +- FirebasePerformance.podspec | 4 +- .../FIRPerfE2E.xcodeproj/project.pbxproj | 16 ++-- FirebasePerformance/Tests/FIRPerfE2E/Podfile | 2 +- .../PerfTestRigApp.xcodeproj/project.pbxproj | 4 +- FirebasePerformance/Tests/TestApp/Podfile | 2 +- FirebaseRemoteConfig.podspec | 4 +- .../Tests/FeatureRolloutsTestApp/Podfile | 10 +-- FirebaseRemoteConfig/Tests/Sample/Podfile | 2 +- .../project.pbxproj | 4 +- FirebaseRemoteConfigInterop.podspec | 4 +- .../Apps/SwiftUISample/Podfile | 2 +- FirebaseSessions.podspec | 4 +- FirebaseSessions/Tests/TestApp/Podfile | 10 +-- FirebaseSharedSwift.podspec | 4 +- FirebaseStorage.podspec | 4 +- .../Sources/Internal/StorageUtils.swift | 33 +++++--- .../Firestore.xcodeproj/project.pbxproj | 8 +- Firestore/Example/GoogleBenchmark.podspec | 4 +- Firestore/Example/GoogleTest.podspec | 4 +- Firestore/Example/LibFuzzer.podspec | 4 +- Firestore/Example/Podfile | 6 +- Firestore/Example/ProtobufCpp.podspec | 4 +- .../FrameworkMaker.xcodeproj/project.pbxproj | 8 +- Firestore/Protos/Podfile | 2 +- GoogleAppMeasurement.podspec | 4 +- ...leAppMeasurementOnDeviceConversion.podspec | 2 +- .../ClientApp.xcodeproj/project.pbxproj | 20 ++--- IntegrationTesting/ClientApp/Podfile | 2 +- .../project.pbxproj | 4 +- .../Podfile | 3 +- .../FrameworkMaker.xcodeproj/project.pbxproj | 4 +- SymbolCollisionTest/Podfile | 3 +- .../project.pbxproj | 4 +- 85 files changed, 255 insertions(+), 233 deletions(-) diff --git a/CoreOnly/Tests/FirebasePodTest/FirebasePodTest.xcodeproj/project.pbxproj b/CoreOnly/Tests/FirebasePodTest/FirebasePodTest.xcodeproj/project.pbxproj index f883b4cc112..13dc15654bf 100644 --- a/CoreOnly/Tests/FirebasePodTest/FirebasePodTest.xcodeproj/project.pbxproj +++ b/CoreOnly/Tests/FirebasePodTest/FirebasePodTest.xcodeproj/project.pbxproj @@ -224,7 +224,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 13.0; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; ONLY_ACTIVE_ARCH = YES; @@ -278,7 +278,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 13.0; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; MTL_ENABLE_DEBUG_INFO = NO; MTL_FAST_MATH = YES; SDKROOT = iphoneos; diff --git a/CoreOnly/Tests/FirebasePodTest/Podfile b/CoreOnly/Tests/FirebasePodTest/Podfile index 238756b7569..9bbbf9f1a9b 100644 --- a/CoreOnly/Tests/FirebasePodTest/Podfile +++ b/CoreOnly/Tests/FirebasePodTest/Podfile @@ -1,5 +1,5 @@ # Uncomment the next line to define a global platform for your project -platform :ios, '13.0' +platform :ios, '15.0' source 'https://github.com/firebase/SpecsDev.git' source 'https://github.com/firebase/SpecsStaging.git' diff --git a/Example/CombineSample/CombineSample.xcodeproj/project.pbxproj b/Example/CombineSample/CombineSample.xcodeproj/project.pbxproj index dc24216be10..ef3abbd5772 100644 --- a/Example/CombineSample/CombineSample.xcodeproj/project.pbxproj +++ b/Example/CombineSample/CombineSample.xcodeproj/project.pbxproj @@ -290,7 +290,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 14.5; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; ONLY_ACTIVE_ARCH = YES; @@ -345,7 +345,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 14.5; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; MTL_ENABLE_DEBUG_INFO = NO; MTL_FAST_MATH = YES; SDKROOT = iphoneos; @@ -365,7 +365,7 @@ DEVELOPMENT_TEAM = YGAZHQXHH4; ENABLE_PREVIEWS = YES; INFOPLIST_FILE = CombineSample/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 14.0; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -387,7 +387,7 @@ DEVELOPMENT_TEAM = YGAZHQXHH4; ENABLE_PREVIEWS = YES; INFOPLIST_FILE = CombineSample/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 14.0; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", diff --git a/Example/tvOSSample/Podfile b/Example/tvOSSample/Podfile index 9b66a8128af..1fcc85e48b0 100644 --- a/Example/tvOSSample/Podfile +++ b/Example/tvOSSample/Podfile @@ -1,6 +1,6 @@ target 'tvOSSample' do - platform :tvos, '12.0' + platform :tvos, '15.0' # Comment the next line if you're not using Swift and don't want to use dynamic frameworks use_frameworks! diff --git a/Example/tvOSSample/tvOSSample.xcodeproj/project.pbxproj b/Example/tvOSSample/tvOSSample.xcodeproj/project.pbxproj index fbbaeb5a0d8..b038668b281 100644 --- a/Example/tvOSSample/tvOSSample.xcodeproj/project.pbxproj +++ b/Example/tvOSSample/tvOSSample.xcodeproj/project.pbxproj @@ -308,7 +308,7 @@ SDKROOT = appletvos; SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - TVOS_DEPLOYMENT_TARGET = 12.0; + TVOS_DEPLOYMENT_TARGET = 15.0; }; name = Debug; }; @@ -356,7 +356,7 @@ MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = appletvos; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; - TVOS_DEPLOYMENT_TARGET = 12.0; + TVOS_DEPLOYMENT_TARGET = 15.0; VALIDATE_PRODUCT = YES; }; name = Release; diff --git a/Example/watchOSSample/SampleWatchApp.xcodeproj/project.pbxproj b/Example/watchOSSample/SampleWatchApp.xcodeproj/project.pbxproj index 1bd805fb6ca..25f8acb524d 100644 --- a/Example/watchOSSample/SampleWatchApp.xcodeproj/project.pbxproj +++ b/Example/watchOSSample/SampleWatchApp.xcodeproj/project.pbxproj @@ -627,7 +627,7 @@ SKIP_INSTALL = YES; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = 4; - WATCHOS_DEPLOYMENT_TARGET = 6.1; + WATCHOS_DEPLOYMENT_TARGET = 7.0; }; name = Debug; }; @@ -653,7 +653,7 @@ SKIP_INSTALL = YES; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = 4; - WATCHOS_DEPLOYMENT_TARGET = 6.1; + WATCHOS_DEPLOYMENT_TARGET = 7.0; }; name = Release; }; @@ -674,7 +674,7 @@ SKIP_INSTALL = YES; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = 4; - WATCHOS_DEPLOYMENT_TARGET = 6.1; + WATCHOS_DEPLOYMENT_TARGET = 7.0; }; name = Debug; }; @@ -695,7 +695,7 @@ SKIP_INSTALL = YES; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = 4; - WATCHOS_DEPLOYMENT_TARGET = 6.1; + WATCHOS_DEPLOYMENT_TARGET = 7.0; }; name = Release; }; @@ -750,7 +750,7 @@ SKIP_INSTALL = YES; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = 4; - WATCHOS_DEPLOYMENT_TARGET = 6.1; + WATCHOS_DEPLOYMENT_TARGET = 7.0; }; name = Debug; }; @@ -775,7 +775,7 @@ SKIP_INSTALL = YES; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = 4; - WATCHOS_DEPLOYMENT_TARGET = 6.1; + WATCHOS_DEPLOYMENT_TARGET = 7.0; }; name = Release; }; diff --git a/Firebase.podspec b/Firebase.podspec index 2bf5ee849f6..625be989545 100644 --- a/Firebase.podspec +++ b/Firebase.podspec @@ -22,9 +22,9 @@ Simplify your app development, grow your user base, and monetize more effectivel "CoreOnly/README.md" ] s.social_media_url = 'https://twitter.com/Firebase' - s.ios.deployment_target = '12.0' + s.ios.deployment_target = '15.0' s.osx.deployment_target = '10.15' - s.tvos.deployment_target = '13.0' + s.tvos.deployment_target = '15.0' s.cocoapods_version = '>= 1.12.0' @@ -33,9 +33,9 @@ Simplify your app development, grow your user base, and monetize more effectivel s.default_subspec = 'Core' s.subspec 'Core' do |ss| - ss.ios.deployment_target = '12.0' + ss.ios.deployment_target = '15.0' ss.osx.deployment_target = '10.15' - ss.tvos.deployment_target = '13.0' + ss.tvos.deployment_target = '15.0' ss.ios.dependency 'FirebaseAnalytics', '~> 12.0.0' ss.osx.dependency 'FirebaseAnalytics', '~> 12.0.0' ss.tvos.dependency 'FirebaseAnalytics', '~> 12.0.0' @@ -55,30 +55,30 @@ Simplify your app development, grow your user base, and monetize more effectivel 'HEADER_SEARCH_PATHS' => "$(inherited) ${PODS_ROOT}/Firebase/CoreOnly/Sources" } end - ss.ios.deployment_target = '12.0' + ss.ios.deployment_target = '15.0' ss.osx.deployment_target = '10.15' - ss.tvos.deployment_target = '13.0' + ss.tvos.deployment_target = '15.0' ss.watchos.deployment_target = '7.0' end s.subspec 'Analytics' do |ss| - ss.ios.deployment_target = '12.0' + ss.ios.deployment_target = '15.0' ss.osx.deployment_target = '10.15' - ss.tvos.deployment_target = '13.0' + ss.tvos.deployment_target = '15.0' ss.dependency 'Firebase/Core' end s.subspec 'AnalyticsWithAdIdSupport' do |ss| - ss.ios.deployment_target = '12.0' + ss.ios.deployment_target = '15.0' ss.osx.deployment_target = '10.15' - ss.tvos.deployment_target = '13.0' + ss.tvos.deployment_target = '15.0' ss.dependency 'Firebase/Core' end s.subspec 'AnalyticsWithoutAdIdSupport' do |ss| - ss.ios.deployment_target = '12.0' + ss.ios.deployment_target = '15.0' ss.osx.deployment_target = '10.15' - ss.tvos.deployment_target = '13.0' + ss.tvos.deployment_target = '15.0' ss.dependency 'FirebaseAnalytics/WithoutAdIdSupport', '~> 12.0.0' ss.dependency 'Firebase/CoreOnly' end @@ -87,24 +87,24 @@ Simplify your app development, grow your user base, and monetize more effectivel ss.dependency 'Firebase/CoreOnly' ss.dependency 'FirebaseABTesting', '~> 12.0.0' # Standard platforms PLUS watchOS. - ss.ios.deployment_target = '13.0' + ss.ios.deployment_target = '15.0' ss.osx.deployment_target = '10.15' - ss.tvos.deployment_target = '13.0' + ss.tvos.deployment_target = '15.0' ss.watchos.deployment_target = '7.0' end s.subspec 'AppDistribution' do |ss| ss.dependency 'Firebase/CoreOnly' ss.ios.dependency 'FirebaseAppDistribution', '~> 12.0.0-beta' - ss.ios.deployment_target = '13.0' + ss.ios.deployment_target = '15.0' end s.subspec 'AppCheck' do |ss| ss.dependency 'Firebase/CoreOnly' ss.dependency 'FirebaseAppCheck', '~> 12.0.0' - ss.ios.deployment_target = '13.0' + ss.ios.deployment_target = '15.0' ss.osx.deployment_target = '10.15' - ss.tvos.deployment_target = '13.0' + ss.tvos.deployment_target = '15.0' ss.watchos.deployment_target = '7.0' end @@ -112,9 +112,9 @@ Simplify your app development, grow your user base, and monetize more effectivel ss.dependency 'Firebase/CoreOnly' ss.dependency 'FirebaseAuth', '~> 12.0.0' # Standard platforms PLUS watchOS. - ss.ios.deployment_target = '13.0' + ss.ios.deployment_target = '15.0' ss.osx.deployment_target = '10.15' - ss.tvos.deployment_target = '13.0' + ss.tvos.deployment_target = '15.0' ss.watchos.deployment_target = '7.0' end @@ -122,9 +122,9 @@ Simplify your app development, grow your user base, and monetize more effectivel ss.dependency 'Firebase/CoreOnly' ss.dependency 'FirebaseCrashlytics', '~> 12.0.0' # Standard platforms PLUS watchOS. - ss.ios.deployment_target = '12.0' + ss.ios.deployment_target = '15.0' ss.osx.deployment_target = '10.15' - ss.tvos.deployment_target = '13.0' + ss.tvos.deployment_target = '15.0' ss.watchos.deployment_target = '7.0' end @@ -132,27 +132,27 @@ Simplify your app development, grow your user base, and monetize more effectivel ss.dependency 'Firebase/CoreOnly' ss.dependency 'FirebaseDatabase', '~> 12.0.0' # Standard platforms PLUS watchOS 7. - ss.ios.deployment_target = '13.0' + ss.ios.deployment_target = '15.0' ss.osx.deployment_target = '10.15' - ss.tvos.deployment_target = '13.0' + ss.tvos.deployment_target = '15.0' ss.watchos.deployment_target = '7.0' end s.subspec 'Firestore' do |ss| ss.dependency 'Firebase/CoreOnly' ss.dependency 'FirebaseFirestore', '~> 12.0.0' - ss.ios.deployment_target = '13.0' + ss.ios.deployment_target = '15.0' ss.osx.deployment_target = '10.15' - ss.tvos.deployment_target = '13.0' + ss.ios.deployment_target = '15.0' end s.subspec 'Functions' do |ss| ss.dependency 'Firebase/CoreOnly' ss.dependency 'FirebaseFunctions', '~> 12.0.0' # Standard platforms PLUS watchOS. - ss.ios.deployment_target = '13.0' + ss.ios.deployment_target = '15.0' ss.osx.deployment_target = '10.15' - ss.tvos.deployment_target = '13.0' + ss.tvos.deployment_target = '15.0' ss.watchos.deployment_target = '7.0' end @@ -160,8 +160,8 @@ Simplify your app development, grow your user base, and monetize more effectivel ss.dependency 'Firebase/CoreOnly' ss.ios.dependency 'FirebaseInAppMessaging', '~> 12.0.0-beta' ss.tvos.dependency 'FirebaseInAppMessaging', '~> 12.0.0-beta' - ss.ios.deployment_target = '13.0' - ss.tvos.deployment_target = '13.0' + ss.ios.deployment_target = '15.0' + ss.tvos.deployment_target = '15.0' end s.subspec 'Installations' do |ss| @@ -173,9 +173,9 @@ Simplify your app development, grow your user base, and monetize more effectivel ss.dependency 'Firebase/CoreOnly' ss.dependency 'FirebaseMessaging', '~> 12.0.0' # Standard platforms PLUS watchOS. - ss.ios.deployment_target = '13.0' + ss.ios.deployment_target = '15.0' ss.osx.deployment_target = '10.15' - ss.tvos.deployment_target = '13.0' + ss.tvos.deployment_target = '15.0' ss.watchos.deployment_target = '7.0' end @@ -183,9 +183,9 @@ Simplify your app development, grow your user base, and monetize more effectivel ss.dependency 'Firebase/CoreOnly' ss.dependency 'FirebaseMLModelDownloader', '~> 12.0.0-beta' # Standard platforms PLUS watchOS. - ss.ios.deployment_target = '13.0' + ss.ios.deployment_target = '15.0' ss.osx.deployment_target = '10.15' - ss.tvos.deployment_target = '13.0' + ss.tvos.deployment_target = '15.0' ss.watchos.deployment_target = '7.0' end @@ -193,17 +193,17 @@ Simplify your app development, grow your user base, and monetize more effectivel ss.dependency 'Firebase/CoreOnly' ss.ios.dependency 'FirebasePerformance', '~> 12.0.0' ss.tvos.dependency 'FirebasePerformance', '~> 12.0.0' - ss.ios.deployment_target = '13.0' - ss.tvos.deployment_target = '13.0' + ss.ios.deployment_target = '15.0' + ss.tvos.deployment_target = '15.0' end s.subspec 'RemoteConfig' do |ss| ss.dependency 'Firebase/CoreOnly' ss.dependency 'FirebaseRemoteConfig', '~> 12.0.0' # Standard platforms PLUS watchOS. - ss.ios.deployment_target = '13.0' + ss.ios.deployment_target = '15.0' ss.osx.deployment_target = '10.15' - ss.tvos.deployment_target = '13.0' + ss.tvos.deployment_target = '15.0' ss.watchos.deployment_target = '7.0' end @@ -211,9 +211,9 @@ Simplify your app development, grow your user base, and monetize more effectivel ss.dependency 'Firebase/CoreOnly' ss.dependency 'FirebaseStorage', '~> 12.0.0' # Standard platforms PLUS watchOS. - ss.ios.deployment_target = '13.0' + ss.ios.deployment_target = '15.0' ss.osx.deployment_target = '10.15' - ss.tvos.deployment_target = '13.0' + ss.tvos.deployment_target = '15.0' ss.watchos.deployment_target = '7.0' end diff --git a/FirebaseABTesting.podspec b/FirebaseABTesting.podspec index aebfa4555eb..d1ce2aaa4b9 100644 --- a/FirebaseABTesting.podspec +++ b/FirebaseABTesting.podspec @@ -22,9 +22,9 @@ Firebase Cloud Messaging and Firebase Remote Config in your app. s.social_media_url = 'https://twitter.com/Firebase' - ios_deployment_target = '13.0' + ios_deployment_target = '15.0' osx_deployment_target = '10.15' - tvos_deployment_target = '13.0' + tvos_deployment_target = '15.0' watchos_deployment_target = '7.0' s.ios.deployment_target = ios_deployment_target diff --git a/FirebaseABTesting/Tests/Integration/ABTQA.xcodeproj/project.pbxproj b/FirebaseABTesting/Tests/Integration/ABTQA.xcodeproj/project.pbxproj index c9f65d6a2f2..6bd8177e07b 100644 --- a/FirebaseABTesting/Tests/Integration/ABTQA.xcodeproj/project.pbxproj +++ b/FirebaseABTesting/Tests/Integration/ABTQA.xcodeproj/project.pbxproj @@ -410,7 +410,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 13.4; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; ONLY_ACTIVE_ARCH = YES; @@ -464,7 +464,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 13.4; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; MTL_ENABLE_DEBUG_INFO = NO; MTL_FAST_MATH = YES; SDKROOT = iphoneos; @@ -522,7 +522,7 @@ CODE_SIGN_STYLE = Automatic; DEVELOPMENT_TEAM = 965RJH2QM8; INFOPLIST_FILE = ABTQATests/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 13.4; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -544,7 +544,7 @@ CODE_SIGN_STYLE = Automatic; DEVELOPMENT_TEAM = 965RJH2QM8; INFOPLIST_FILE = ABTQATests/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 13.4; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", diff --git a/FirebaseAnalytics.podspec b/FirebaseAnalytics.podspec index f5200294ad1..ca418cbbb51 100644 --- a/FirebaseAnalytics.podspec +++ b/FirebaseAnalytics.podspec @@ -19,9 +19,9 @@ Pod::Spec.new do |s| s.cocoapods_version = '>= 1.12.0' s.swift_version = '5.9' - s.ios.deployment_target = '12.0' + s.ios.deployment_target = '15.0' s.osx.deployment_target = '10.15' - s.tvos.deployment_target = '13.0' + s.tvos.deployment_target = '15.0' s.libraries = 'c++', 'sqlite3', 'z' s.frameworks = 'StoreKit' diff --git a/FirebaseAnalyticsOnDeviceConversion.podspec b/FirebaseAnalyticsOnDeviceConversion.podspec index ce1cc7aacef..ee8c9e823f3 100644 --- a/FirebaseAnalyticsOnDeviceConversion.podspec +++ b/FirebaseAnalyticsOnDeviceConversion.podspec @@ -22,7 +22,7 @@ Pod::Spec.new do |s| s.static_framework = true - s.ios.deployment_target = '12.0' + s.ios.deployment_target = '15.0' s.source_files = 'FirebaseAnalyticsOnDeviceConversionWrapper/*' end diff --git a/FirebaseAppCheck.podspec b/FirebaseAppCheck.podspec index cd02bcd48f4..09fbfbd27bc 100644 --- a/FirebaseAppCheck.podspec +++ b/FirebaseAppCheck.podspec @@ -17,9 +17,9 @@ Pod::Spec.new do |s| } s.social_media_url = 'https://twitter.com/Firebase' - ios_deployment_target = '13.0' + ios_deployment_target = '15.0' osx_deployment_target = '10.15' - tvos_deployment_target = '13.0' + tvos_deployment_target = '15.0' watchos_deployment_target = '7.0' s.swift_version = '5.9' diff --git a/FirebaseAppCheck/Apps/AppCheckCustomProvideApp/AppCheckCustomProvideApp.xcodeproj/project.pbxproj b/FirebaseAppCheck/Apps/AppCheckCustomProvideApp/AppCheckCustomProvideApp.xcodeproj/project.pbxproj index 68e82d73f8b..b5d447f5252 100644 --- a/FirebaseAppCheck/Apps/AppCheckCustomProvideApp/AppCheckCustomProvideApp.xcodeproj/project.pbxproj +++ b/FirebaseAppCheck/Apps/AppCheckCustomProvideApp/AppCheckCustomProvideApp.xcodeproj/project.pbxproj @@ -292,7 +292,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 14.3; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; ONLY_ACTIVE_ARCH = YES; @@ -347,7 +347,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 14.3; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; MTL_ENABLE_DEBUG_INFO = NO; MTL_FAST_MATH = YES; SDKROOT = iphoneos; diff --git a/FirebaseAppCheck/Apps/AppCheckCustomProvideApp/Podfile b/FirebaseAppCheck/Apps/AppCheckCustomProvideApp/Podfile index b49c3b0b11a..bff36702c84 100644 --- a/FirebaseAppCheck/Apps/AppCheckCustomProvideApp/Podfile +++ b/FirebaseAppCheck/Apps/AppCheckCustomProvideApp/Podfile @@ -1,5 +1,5 @@ # Uncomment the next line to define a global platform for your project -# platform :ios, '9.0' +# platform :ios, '15.0' target 'AppCheckCustomProvideApp' do # Comment the next line if you don't want to use dynamic frameworks diff --git a/FirebaseAppCheck/Apps/FIRAppCheckTestApp/FIRAppCheckTestApp.xcodeproj/project.pbxproj b/FirebaseAppCheck/Apps/FIRAppCheckTestApp/FIRAppCheckTestApp.xcodeproj/project.pbxproj index 1545b5ffa0b..4e71530ef0d 100644 --- a/FirebaseAppCheck/Apps/FIRAppCheckTestApp/FIRAppCheckTestApp.xcodeproj/project.pbxproj +++ b/FirebaseAppCheck/Apps/FIRAppCheckTestApp/FIRAppCheckTestApp.xcodeproj/project.pbxproj @@ -217,7 +217,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 14.0; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; ONLY_ACTIVE_ARCH = YES; @@ -272,7 +272,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 14.0; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; MTL_ENABLE_DEBUG_INFO = NO; MTL_FAST_MATH = YES; SDKROOT = iphoneos; diff --git a/FirebaseAppCheck/Apps/FIRAppCheckTestApp/Podfile b/FirebaseAppCheck/Apps/FIRAppCheckTestApp/Podfile index 519f03ce334..4ba2cf4fe4c 100644 --- a/FirebaseAppCheck/Apps/FIRAppCheckTestApp/Podfile +++ b/FirebaseAppCheck/Apps/FIRAppCheckTestApp/Podfile @@ -1,7 +1,7 @@ source 'https://github.com/firebase/SpecsStaging.git' source 'https://cdn.cocoapods.org/' -platform :ios, '13.0' +platform :ios, '15.0' target 'FIRAppCheckTestApp' do # Comment the next line if you don't want to use dynamic frameworks diff --git a/FirebaseAppCheckInterop.podspec b/FirebaseAppCheckInterop.podspec index 17fbbf51206..427530ab4fc 100644 --- a/FirebaseAppCheckInterop.podspec +++ b/FirebaseAppCheckInterop.podspec @@ -21,9 +21,9 @@ Pod::Spec.new do |s| } s.social_media_url = 'https://twitter.com/Firebase' - ios_deployment_target = '13.0' + ios_deployment_target = '15.0' osx_deployment_target = '10.15' - tvos_deployment_target = '13.0' + tvos_deployment_target = '15.0' watchos_deployment_target = '7.0' s.ios.deployment_target = ios_deployment_target diff --git a/FirebaseAppDistribution.podspec b/FirebaseAppDistribution.podspec index dce9b720536..015ab401ee1 100644 --- a/FirebaseAppDistribution.podspec +++ b/FirebaseAppDistribution.podspec @@ -15,7 +15,7 @@ iOS SDK for App Distribution for Firebase. :tag => 'CocoaPods-' + s.version.to_s } - s.ios.deployment_target = '13.0' + s.ios.deployment_target = '15.0' s.swift_version = '5.9' diff --git a/FirebaseAuth.podspec b/FirebaseAuth.podspec index 72b0414bc90..7d578d4a4b6 100644 --- a/FirebaseAuth.podspec +++ b/FirebaseAuth.podspec @@ -19,9 +19,9 @@ supports email and password accounts, as well as several 3rd party authenticatio s.social_media_url = 'https://twitter.com/Firebase' - ios_deployment_target = '13.0' + ios_deployment_target = '15.0' osx_deployment_target = '10.15' - tvos_deployment_target = '13.0' + tvos_deployment_target = '15.0' watchos_deployment_target = '7.0' s.swift_version = '5.9' diff --git a/FirebaseAuth/Tests/SampleSwift/Podfile b/FirebaseAuth/Tests/SampleSwift/Podfile index 382c7b4d981..e29d330b133 100644 --- a/FirebaseAuth/Tests/SampleSwift/Podfile +++ b/FirebaseAuth/Tests/SampleSwift/Podfile @@ -1,5 +1,5 @@ # Uncomment the next line to define a global platform for your project -platform :ios, '13.0' +platform :ios, '15.0' target 'AuthenticationExample' do # Comment the next line if you don't want to use dynamic frameworks diff --git a/FirebaseAuthInterop.podspec b/FirebaseAuthInterop.podspec index 461ec711984..c1f9df6ed18 100644 --- a/FirebaseAuthInterop.podspec +++ b/FirebaseAuthInterop.podspec @@ -20,9 +20,9 @@ Pod::Spec.new do |s| :tag => 'CocoaPods-' + s.version.to_s } s.social_media_url = 'https://twitter.com/Firebase' - s.ios.deployment_target = '13.0' + s.ios.deployment_target = '15.0' s.osx.deployment_target = '10.15' - s.tvos.deployment_target = '13.0' + s.tvos.deployment_target = '15.0' s.watchos.deployment_target = '7.0' s.source_files = 'FirebaseAuth/Interop/**/*.[hm]' diff --git a/FirebaseAuthTestingSupport.podspec b/FirebaseAuthTestingSupport.podspec index b30e2510a74..7ca58339e13 100644 --- a/FirebaseAuthTestingSupport.podspec +++ b/FirebaseAuthTestingSupport.podspec @@ -17,9 +17,9 @@ Pod::Spec.new do |s| :tag => 'CocoaPods-' + s.version.to_s } - ios_deployment_target = '13.0' + ios_deployment_target = '15.0' osx_deployment_target = '10.15' - tvos_deployment_target = '13.0' + tvos_deployment_target = '15.0' watchos_deployment_target = '7.0' s.swift_version = '5.9' diff --git a/FirebaseCombineSwift.podspec b/FirebaseCombineSwift.podspec index 9d9ccf0c52c..c3ce4d0d5b3 100644 --- a/FirebaseCombineSwift.podspec +++ b/FirebaseCombineSwift.podspec @@ -21,9 +21,9 @@ for internal testing only. It should not be published. s.swift_version = '5.9' - ios_deployment_target = '13.0' + ios_deployment_target = '15.0' osx_deployment_target = '10.15' - tvos_deployment_target = '13.0' + tvos_deployment_target = '15.0' watchos_deployment_target = '7.0' s.ios.deployment_target = ios_deployment_target diff --git a/FirebaseCore.podspec b/FirebaseCore.podspec index 49606f63792..7ad1c4509cf 100644 --- a/FirebaseCore.podspec +++ b/FirebaseCore.podspec @@ -18,9 +18,9 @@ Firebase Core includes FIRApp and FIROptions which provide central configuration s.social_media_url = 'https://twitter.com/Firebase' - ios_deployment_target = '12.0' + ios_deployment_target = '15.0' osx_deployment_target = '10.15' - tvos_deployment_target = '13.0' + tvos_deployment_target = '15.0' watchos_deployment_target = '7.0' s.ios.deployment_target = ios_deployment_target diff --git a/FirebaseCore/CHANGELOG.md b/FirebaseCore/CHANGELOG.md index f6e677e74b3..b2e7592f7f1 100644 --- a/FirebaseCore/CHANGELOG.md +++ b/FirebaseCore/CHANGELOG.md @@ -1,4 +1,12 @@ # Unreleased +- [changed] **Breaking change**: Firebase's minimum supported versions have + updated for the following platforms: + - | Platform | Firebase 12 | + | ------------- | ------------- | + | iOS | **15.0** | + | tvOS | **15.0** | + | macOS | 10.15 | + | watchOS | 7.0 | - [removed] **Breaking change**: FirebaseDynamicLinks has been removed. See https://firebase.google.com/support/dynamic-links-faq for more info. - [removed] **Breaking change**: Removed the `Options.deepLinkURLScheme` diff --git a/FirebaseCoreExtension.podspec b/FirebaseCoreExtension.podspec index cd3aab0e1b0..8171d0c5e31 100644 --- a/FirebaseCoreExtension.podspec +++ b/FirebaseCoreExtension.podspec @@ -22,9 +22,9 @@ Pod::Spec.new do |s| s.swift_version = '5.9' - s.ios.deployment_target = '12.0' + s.ios.deployment_target = '15.0' s.osx.deployment_target = '10.15' - s.tvos.deployment_target = '13.0' + s.tvos.deployment_target = '15.0' s.watchos.deployment_target = '7.0' s.source_files = 'FirebaseCore/Extension/*.[hm]' diff --git a/FirebaseCoreInternal.podspec b/FirebaseCoreInternal.podspec index b15c77ff498..8def2d194ed 100644 --- a/FirebaseCoreInternal.podspec +++ b/FirebaseCoreInternal.podspec @@ -18,9 +18,9 @@ Pod::Spec.new do |s| } s.social_media_url = 'https://twitter.com/Firebase' - ios_deployment_target = '12.0' + ios_deployment_target = '15.0' osx_deployment_target = '10.15' - tvos_deployment_target = '13.0' + tvos_deployment_target = '15.0' watchos_deployment_target = '7.0' s.ios.deployment_target = ios_deployment_target @@ -43,9 +43,9 @@ Pod::Spec.new do |s| s.test_spec 'Unit' do |unit_tests| unit_tests.scheme = { :code_coverage => true } unit_tests.platforms = { - :ios => '13.0', - :osx => '10.15', - :tvos => '13.0' + :ios => ios_deployment_target, + :osx => osx_deployment_target, + :tvos => tvos_deployment_target } unit_tests.source_files = [ 'FirebaseCore/Internal/Tests/Unit/**/*.swift', diff --git a/FirebaseCrashlytics.podspec b/FirebaseCrashlytics.podspec index 461cd2e379f..90230be52c4 100644 --- a/FirebaseCrashlytics.podspec +++ b/FirebaseCrashlytics.podspec @@ -11,9 +11,9 @@ Pod::Spec.new do |s| :tag => 'CocoaPods-' + s.version.to_s } - ios_deployment_target = '12.0' + ios_deployment_target = '15.0' osx_deployment_target = '10.15' - tvos_deployment_target = '13.0' + tvos_deployment_target = '15.0' watchos_deployment_target = '7.0' s.swift_version = '5.9' diff --git a/FirebaseDatabase.podspec b/FirebaseDatabase.podspec index 892a9c766e9..09fcacdd28e 100644 --- a/FirebaseDatabase.podspec +++ b/FirebaseDatabase.podspec @@ -17,9 +17,9 @@ Simplify your iOS development, grow your user base, and monetize more effectivel } s.social_media_url = 'https://twitter.com/Firebase' - ios_deployment_target = '13.0' + ios_deployment_target = '15.0' osx_deployment_target = '10.15' - tvos_deployment_target = '13.0' + tvos_deployment_target = '15.0' watchos_deployment_target = '7.0' s.swift_version = '5.9' diff --git a/FirebaseDatabase/Sources/third_party/SocketRocket/FSRWebSocket.m b/FirebaseDatabase/Sources/third_party/SocketRocket/FSRWebSocket.m index 6e0e2c1b3aa..3f1dde86f9a 100644 --- a/FirebaseDatabase/Sources/third_party/SocketRocket/FSRWebSocket.m +++ b/FirebaseDatabase/Sources/third_party/SocketRocket/FSRWebSocket.m @@ -1480,7 +1480,10 @@ - (void)stream:(NSStream *)aStream handleEvent:(NSStreamEvent)eventCode; if (secTrust) { NSInteger numCerts = SecTrustGetCertificateCount(secTrust); for (NSInteger i = 0; i < numCerts && !_pinnedCertFound; i++) { +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" SecCertificateRef cert = SecTrustGetCertificateAtIndex(secTrust, i); +#pragma clang diagnostic pop NSData *certData = CFBridgingRelease(SecCertificateCopyData(cert)); for (id ref in sslCerts) { diff --git a/FirebaseFirestore.podspec b/FirebaseFirestore.podspec index 1dc29d19fd8..9f7601cb469 100644 --- a/FirebaseFirestore.podspec +++ b/FirebaseFirestore.podspec @@ -13,9 +13,9 @@ Google Cloud Firestore is a NoSQL document database built for automatic scaling, :tag => 'CocoaPods-' + s.version.to_s } - s.ios.deployment_target = '13.0' + s.ios.deployment_target = '15.0' s.osx.deployment_target = '10.15' - s.tvos.deployment_target = '13.0' + s.tvos.deployment_target = '15.0' s.swift_version = '5.9' diff --git a/FirebaseFirestoreInternal.podspec b/FirebaseFirestoreInternal.podspec index 11df66fdaea..3bf98b2af95 100644 --- a/FirebaseFirestoreInternal.podspec +++ b/FirebaseFirestoreInternal.podspec @@ -16,9 +16,9 @@ Google Cloud Firestore is a NoSQL document database built for automatic scaling, :tag => 'CocoaPods-' + s.version.to_s } - s.ios.deployment_target = '13.0' + s.ios.deployment_target = '15.0' s.osx.deployment_target = '10.15' - s.tvos.deployment_target = '13.0' + s.tvos.deployment_target = '15.0' s.swift_version = '5.9' diff --git a/FirebaseFirestoreTestingSupport.podspec b/FirebaseFirestoreTestingSupport.podspec index 11509cde08a..446e5f8a728 100644 --- a/FirebaseFirestoreTestingSupport.podspec +++ b/FirebaseFirestoreTestingSupport.podspec @@ -17,9 +17,9 @@ Pod::Spec.new do |s| :tag => 'CocoaPods-' + s.version.to_s } - ios_deployment_target = '13.0' + ios_deployment_target = '15.0' osx_deployment_target = '10.15' - tvos_deployment_target = '13.0' + tvos_deployment_target = '15.0' watchos_deployment_target = '7.0' s.swift_version = '5.9' diff --git a/FirebaseFunctions.podspec b/FirebaseFunctions.podspec index 55f2bac00f5..03d1354bee7 100644 --- a/FirebaseFunctions.podspec +++ b/FirebaseFunctions.podspec @@ -18,9 +18,9 @@ Cloud Functions for Firebase. s.swift_version = '5.9' - ios_deployment_target = '13.0' + ios_deployment_target = '15.0' osx_deployment_target = '10.15' - tvos_deployment_target = '13.0' + tvos_deployment_target = '15.0' watchos_deployment_target = '7.0' s.ios.deployment_target = ios_deployment_target diff --git a/FirebaseInAppMessaging.podspec b/FirebaseInAppMessaging.podspec index 318a70686bf..5316462be25 100644 --- a/FirebaseInAppMessaging.podspec +++ b/FirebaseInAppMessaging.podspec @@ -17,8 +17,8 @@ See more product details at https://firebase.google.com/products/in-app-messagin :tag => 'CocoaPods-' + s.version.to_s } s.social_media_url = 'https://twitter.com/Firebase' - s.ios.deployment_target = '13.0' - s.tvos.deployment_target = '13.0' + s.ios.deployment_target = '15.0' + s.tvos.deployment_target = '15.0' s.swift_version = '5.9' diff --git a/FirebaseInAppMessaging/Swift/Tests/Integration/FIAMSwiftUI/FIAMSwiftUI.xcodeproj/project.pbxproj b/FirebaseInAppMessaging/Swift/Tests/Integration/FIAMSwiftUI/FIAMSwiftUI.xcodeproj/project.pbxproj index 949872fec79..9544efdb7ff 100644 --- a/FirebaseInAppMessaging/Swift/Tests/Integration/FIAMSwiftUI/FIAMSwiftUI.xcodeproj/project.pbxproj +++ b/FirebaseInAppMessaging/Swift/Tests/Integration/FIAMSwiftUI/FIAMSwiftUI.xcodeproj/project.pbxproj @@ -411,7 +411,7 @@ DEVELOPMENT_TEAM = 4A6TPS9RJ5; ENABLE_PREVIEWS = YES; INFOPLIST_FILE = iOS/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 14.0; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -434,7 +434,7 @@ DEVELOPMENT_TEAM = 4A6TPS9RJ5; ENABLE_PREVIEWS = YES; INFOPLIST_FILE = iOS/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 14.0; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", diff --git a/FirebaseInAppMessaging/Swift/Tests/Integration/FIAMSwiftUI/Podfile b/FirebaseInAppMessaging/Swift/Tests/Integration/FIAMSwiftUI/Podfile index 885de064756..407ad491b15 100644 --- a/FirebaseInAppMessaging/Swift/Tests/Integration/FIAMSwiftUI/Podfile +++ b/FirebaseInAppMessaging/Swift/Tests/Integration/FIAMSwiftUI/Podfile @@ -10,5 +10,5 @@ pod 'FirebaseABTesting', :path => '../../../../..' pod 'FirebaseInAppMessaging', :path => '../../../../..' target 'FIAMSwiftUI (iOS)' do - platform :ios, '13.0' + platform :ios, '15.0' end diff --git a/FirebaseInAppMessaging/Tests/Integration/DefaultUITestApp/InAppMessagingDisplay-Sample.xcodeproj/project.pbxproj b/FirebaseInAppMessaging/Tests/Integration/DefaultUITestApp/InAppMessagingDisplay-Sample.xcodeproj/project.pbxproj index f17172ef2ed..10bcfd942bb 100644 --- a/FirebaseInAppMessaging/Tests/Integration/DefaultUITestApp/InAppMessagingDisplay-Sample.xcodeproj/project.pbxproj +++ b/FirebaseInAppMessaging/Tests/Integration/DefaultUITestApp/InAppMessagingDisplay-Sample.xcodeproj/project.pbxproj @@ -424,7 +424,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 13.0; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; @@ -477,7 +477,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 13.0; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; VALIDATE_PRODUCT = YES; diff --git a/FirebaseInAppMessaging/Tests/Integration/DefaultUITestApp/Podfile b/FirebaseInAppMessaging/Tests/Integration/DefaultUITestApp/Podfile index d7eac8d3b1e..30c2c14cf68 100644 --- a/FirebaseInAppMessaging/Tests/Integration/DefaultUITestApp/Podfile +++ b/FirebaseInAppMessaging/Tests/Integration/DefaultUITestApp/Podfile @@ -10,7 +10,7 @@ pod 'FirebaseInstallations', :path => '../../../..' pod 'FirebaseABTesting', :path => '../../../..' target 'FiamDisplaySwiftExample' do - platform :ios, '13.0' + platform :ios, '15.0' pod 'FirebaseInAppMessaging', :path => '../../../..' end diff --git a/FirebaseInAppMessaging/Tests/Integration/FunctionalTestApp/InAppMessaging-Example-iOS.xcodeproj/project.pbxproj b/FirebaseInAppMessaging/Tests/Integration/FunctionalTestApp/InAppMessaging-Example-iOS.xcodeproj/project.pbxproj index d12ce4c31ab..fb6b1838559 100644 --- a/FirebaseInAppMessaging/Tests/Integration/FunctionalTestApp/InAppMessaging-Example-iOS.xcodeproj/project.pbxproj +++ b/FirebaseInAppMessaging/Tests/Integration/FunctionalTestApp/InAppMessaging-Example-iOS.xcodeproj/project.pbxproj @@ -589,7 +589,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 11.0; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; @@ -642,7 +642,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 11.0; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; @@ -670,7 +670,7 @@ "\"${PODS_ROOT}/../../../Firebase/InAppMessaging/\"/**", ); INFOPLIST_FILE = "$(SRCROOT)/App/InAppMessaging-Example-iOS/Info.plist"; - IPHONEOS_DEPLOYMENT_TARGET = 11.0; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = com.google.experimental1.dev; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -700,7 +700,7 @@ "\"${PODS_ROOT}/../../../Firebase/InAppMessaging/\"/**", ); INFOPLIST_FILE = "$(SRCROOT)/App/InAppMessaging-Example-iOS/Info.plist"; - IPHONEOS_DEPLOYMENT_TARGET = 11.0; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = com.google.experimental1.dev; PRODUCT_NAME = "$(TARGET_NAME)"; diff --git a/FirebaseInAppMessaging/Tests/Integration/FunctionalTestApp/Podfile b/FirebaseInAppMessaging/Tests/Integration/FunctionalTestApp/Podfile index 8d78252504b..f7868c2ad3e 100644 --- a/FirebaseInAppMessaging/Tests/Integration/FunctionalTestApp/Podfile +++ b/FirebaseInAppMessaging/Tests/Integration/FunctionalTestApp/Podfile @@ -10,7 +10,7 @@ pod 'FirebaseInstallations', :path => '../../../..' pod 'FirebaseABTesting', :path => '../../../..' target 'InAppMessaging_Example_iOS' do - platform :ios, '13.0' + platform :ios, '15.0' pod 'FirebaseInAppMessaging', :path => '../../../..' diff --git a/FirebaseInstallations.podspec b/FirebaseInstallations.podspec index 579cf3711a7..6973f91be45 100644 --- a/FirebaseInstallations.podspec +++ b/FirebaseInstallations.podspec @@ -17,9 +17,9 @@ Pod::Spec.new do |s| } s.social_media_url = 'https://twitter.com/Firebase' - ios_deployment_target = '12.0' + ios_deployment_target = '15.0' osx_deployment_target = '10.15' - tvos_deployment_target = '13.0' + tvos_deployment_target = '15.0' watchos_deployment_target = '7.0' s.swift_version = '5.9' diff --git a/FirebaseMLModelDownloader.podspec b/FirebaseMLModelDownloader.podspec index a825ba390b1..c7695fe8003 100644 --- a/FirebaseMLModelDownloader.podspec +++ b/FirebaseMLModelDownloader.podspec @@ -18,9 +18,9 @@ Pod::Spec.new do |s| s.social_media_url = 'https://twitter.com/Firebase' s.swift_version = '5.9' - ios_deployment_target = '13.0' + ios_deployment_target = '15.0' osx_deployment_target = '10.15' - tvos_deployment_target = '13.0' + tvos_deployment_target = '15.0' watchos_deployment_target = '7.0' s.ios.deployment_target = ios_deployment_target diff --git a/FirebaseMLModelDownloader/Apps/Sample/MLDownloaderTestApp.xcodeproj/project.pbxproj b/FirebaseMLModelDownloader/Apps/Sample/MLDownloaderTestApp.xcodeproj/project.pbxproj index c596dcd464a..da77f4f1847 100644 --- a/FirebaseMLModelDownloader/Apps/Sample/MLDownloaderTestApp.xcodeproj/project.pbxproj +++ b/FirebaseMLModelDownloader/Apps/Sample/MLDownloaderTestApp.xcodeproj/project.pbxproj @@ -562,7 +562,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 14.0; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; ONLY_ACTIVE_ARCH = YES; @@ -617,7 +617,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 14.0; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; MTL_ENABLE_DEBUG_INFO = NO; MTL_FAST_MATH = YES; SDKROOT = iphoneos; @@ -683,7 +683,7 @@ BUNDLE_LOADER = "$(TEST_HOST)"; CODE_SIGN_STYLE = Automatic; INFOPLIST_FILE = MLDownloaderTestAppTests/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 14.0; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -705,7 +705,7 @@ BUNDLE_LOADER = "$(TEST_HOST)"; CODE_SIGN_STYLE = Automatic; INFOPLIST_FILE = MLDownloaderTestAppTests/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 14.0; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", diff --git a/FirebaseMLModelDownloader/Apps/Sample/Podfile b/FirebaseMLModelDownloader/Apps/Sample/Podfile index ed79be9f17e..58922757f53 100644 --- a/FirebaseMLModelDownloader/Apps/Sample/Podfile +++ b/FirebaseMLModelDownloader/Apps/Sample/Podfile @@ -1,4 +1,4 @@ -platform :ios, '13.0' +platform :ios, '15.0' use_frameworks! source 'https://github.com/firebase/SpecsDev.git' diff --git a/FirebaseMessaging.podspec b/FirebaseMessaging.podspec index 58c29368a43..cf9f4b59742 100644 --- a/FirebaseMessaging.podspec +++ b/FirebaseMessaging.podspec @@ -20,9 +20,9 @@ device, and it is completely free. } s.social_media_url = 'https://twitter.com/Firebase' - ios_deployment_target = '13.0' + ios_deployment_target = '15.0' osx_deployment_target = '10.15' - tvos_deployment_target = '13.0' + tvos_deployment_target = '15.0' watchos_deployment_target = '7.0' s.swift_version = '5.9' diff --git a/FirebaseMessaging/Apps/AdvancedSample/AdvancedSample.xcodeproj/project.pbxproj b/FirebaseMessaging/Apps/AdvancedSample/AdvancedSample.xcodeproj/project.pbxproj index 3487b7fbbd5..ee05ca90174 100644 --- a/FirebaseMessaging/Apps/AdvancedSample/AdvancedSample.xcodeproj/project.pbxproj +++ b/FirebaseMessaging/Apps/AdvancedSample/AdvancedSample.xcodeproj/project.pbxproj @@ -1055,7 +1055,7 @@ CODE_SIGN_STYLE = Manual; DEVELOPMENT_TEAM = EQHXZ8M8AV; INFOPLIST_FILE = NotificationServiceExtension/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 14.3; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -1078,7 +1078,7 @@ CODE_SIGN_STYLE = Manual; DEVELOPMENT_TEAM = EQHXZ8M8AV; INFOPLIST_FILE = NotificationServiceExtension/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 14.3; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", diff --git a/FirebaseMessaging/Apps/AdvancedSample/Podfile b/FirebaseMessaging/Apps/AdvancedSample/Podfile index e58554029ee..e5be0872827 100644 --- a/FirebaseMessaging/Apps/AdvancedSample/Podfile +++ b/FirebaseMessaging/Apps/AdvancedSample/Podfile @@ -12,18 +12,18 @@ def shared_pods end target 'AdvancedSample' do - platform :ios, '13.0' + platform :ios, '15.0' pod 'FirebaseAnalytics' shared_pods end target 'NotificationServiceExtension' do - platform :ios, '13.0' + platform :ios, '15.0' shared_pods end target 'AppClips' do - platform :ios, '13.0' + platform :ios, '15.0' pod 'FirebaseAnalytics' shared_pods end diff --git a/FirebaseMessaging/Apps/Sample/Podfile b/FirebaseMessaging/Apps/Sample/Podfile index bd9effe8e56..1881aad4c9f 100644 --- a/FirebaseMessaging/Apps/Sample/Podfile +++ b/FirebaseMessaging/Apps/Sample/Podfile @@ -5,7 +5,7 @@ source 'https://github.com/firebase/SpecsStaging.git' source 'https://cdn.cocoapods.org/' target 'Sample' do - platform :ios, '13.0' + platform :ios, '15.0' pod 'FirebaseCore', :path => '../../../' pod 'FirebaseCoreInternal', :path => '../../../' diff --git a/FirebaseMessaging/Apps/Sample/Sample.xcodeproj/project.pbxproj b/FirebaseMessaging/Apps/Sample/Sample.xcodeproj/project.pbxproj index 6552aaf0670..de1eb37c2b2 100644 --- a/FirebaseMessaging/Apps/Sample/Sample.xcodeproj/project.pbxproj +++ b/FirebaseMessaging/Apps/Sample/Sample.xcodeproj/project.pbxproj @@ -251,7 +251,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 13.2; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; ONLY_ACTIVE_ARCH = YES; @@ -305,7 +305,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 13.2; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; MTL_ENABLE_DEBUG_INFO = NO; MTL_FAST_MATH = YES; SDKROOT = iphoneos; diff --git a/FirebaseMessaging/Apps/SwiftUISample/SwiftUISample.xcodeproj/project.pbxproj b/FirebaseMessaging/Apps/SwiftUISample/SwiftUISample.xcodeproj/project.pbxproj index 4224b6e136b..dd369b873a9 100644 --- a/FirebaseMessaging/Apps/SwiftUISample/SwiftUISample.xcodeproj/project.pbxproj +++ b/FirebaseMessaging/Apps/SwiftUISample/SwiftUISample.xcodeproj/project.pbxproj @@ -369,7 +369,7 @@ INFOPLIST_KEY_UILaunchScreen_Generation = YES; INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; - IPHONEOS_DEPLOYMENT_TARGET = 14.0; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -404,7 +404,7 @@ INFOPLIST_KEY_UILaunchScreen_Generation = YES; INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; - IPHONEOS_DEPLOYMENT_TARGET = 14.0; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", diff --git a/FirebaseMessagingInterop.podspec b/FirebaseMessagingInterop.podspec index 11b34ae4326..495cc9207b1 100644 --- a/FirebaseMessagingInterop.podspec +++ b/FirebaseMessagingInterop.podspec @@ -20,9 +20,9 @@ Pod::Spec.new do |s| :tag => 'CocoaPods-' + s.version.to_s } s.social_media_url = 'https://twitter.com/Firebase' - s.ios.deployment_target = '13.0' + s.ios.deployment_target = '15.0' s.osx.deployment_target = '10.15' - s.tvos.deployment_target = '13.0' + s.tvos.deployment_target = '15.0' s.watchos.deployment_target = '7.0' s.source_files = 'FirebaseMessaging/Interop/*.[hm]' diff --git a/FirebasePerformance.podspec b/FirebasePerformance.podspec index 4ea778a1992..7cd2f600351 100644 --- a/FirebasePerformance.podspec +++ b/FirebasePerformance.podspec @@ -17,8 +17,8 @@ Firebase Performance library to measure performance of Mobile and Web Apps. } s.social_media_url = 'https://twitter.com/Firebase' - ios_deployment_target = '13.0' - tvos_deployment_target = '13.0' + ios_deployment_target = '15.0' + tvos_deployment_target = '15.0' s.swift_version = '5.9' diff --git a/FirebasePerformance/Tests/FIRPerfE2E/FIRPerfE2E.xcodeproj/project.pbxproj b/FirebasePerformance/Tests/FIRPerfE2E/FIRPerfE2E.xcodeproj/project.pbxproj index 6b76197fb05..c72479c2428 100644 --- a/FirebasePerformance/Tests/FIRPerfE2E/FIRPerfE2E.xcodeproj/project.pbxproj +++ b/FirebasePerformance/Tests/FIRPerfE2E/FIRPerfE2E.xcodeproj/project.pbxproj @@ -716,7 +716,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 13.0; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; ONLY_ACTIVE_ARCH = YES; @@ -768,7 +768,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 13.0; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; MTL_ENABLE_DEBUG_INFO = NO; MTL_FAST_MATH = YES; SDKROOT = iphoneos; @@ -783,7 +783,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_STYLE = Automatic; INFOPLIST_FILE = FIRPerfE2EProd/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 11.0; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -801,7 +801,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_STYLE = Automatic; INFOPLIST_FILE = FIRPerfE2EProd/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 11.0; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -830,7 +830,7 @@ "FPR_AUTOPUSH_ENDPOINT=1", ); INFOPLIST_FILE = FIRPerfE2EAutopush/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 11.0; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -859,7 +859,7 @@ "FPR_AUTOPUSH_ENDPOINT=1", ); INFOPLIST_FILE = FIRPerfE2EAutopush/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 11.0; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -924,7 +924,7 @@ buildSettings = { CODE_SIGN_STYLE = Automatic; INFOPLIST_FILE = FIRPerfE2EUITests/Autopush/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 13.2; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -943,7 +943,7 @@ buildSettings = { CODE_SIGN_STYLE = Automatic; INFOPLIST_FILE = FIRPerfE2EUITests/Autopush/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 13.2; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", diff --git a/FirebasePerformance/Tests/FIRPerfE2E/Podfile b/FirebasePerformance/Tests/FIRPerfE2E/Podfile index 264eab7d644..30c0787a478 100644 --- a/FirebasePerformance/Tests/FIRPerfE2E/Podfile +++ b/FirebasePerformance/Tests/FIRPerfE2E/Podfile @@ -3,7 +3,7 @@ source 'https://github.com/firebase/SpecsStaging.git' source 'https://cdn.cocoapods.org/' # Uncomment the next line to define a global platform for your project -platform :ios, '13.0' +platform :ios, '15.0' target 'FIRPerfE2EAutopush' do # Comment the next line if you don't want to use dynamic frameworks diff --git a/FirebasePerformance/Tests/TestApp/PerfTestRigApp.xcodeproj/project.pbxproj b/FirebasePerformance/Tests/TestApp/PerfTestRigApp.xcodeproj/project.pbxproj index 1cce34f02ab..902f5248bf6 100644 --- a/FirebasePerformance/Tests/TestApp/PerfTestRigApp.xcodeproj/project.pbxproj +++ b/FirebasePerformance/Tests/TestApp/PerfTestRigApp.xcodeproj/project.pbxproj @@ -655,7 +655,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 11.0; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; @@ -697,7 +697,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 11.0; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; TARGETED_DEVICE_FAMILY = "1,2"; diff --git a/FirebasePerformance/Tests/TestApp/Podfile b/FirebasePerformance/Tests/TestApp/Podfile index 6b570bf0908..80a8db0c9b9 100644 --- a/FirebasePerformance/Tests/TestApp/Podfile +++ b/FirebasePerformance/Tests/TestApp/Podfile @@ -1,4 +1,4 @@ -platform :ios, '13.0' +platform :ios, '15.0' #uncomment when need to run pod install locally #source 'sso://cpdc-internal/firebase' diff --git a/FirebaseRemoteConfig.podspec b/FirebaseRemoteConfig.podspec index d2a6118c78a..566e0158927 100644 --- a/FirebaseRemoteConfig.podspec +++ b/FirebaseRemoteConfig.podspec @@ -18,9 +18,9 @@ app update. :tag => 'CocoaPods-' + s.version.to_s } s.social_media_url = 'https://twitter.com/Firebase' - ios_deployment_target = '13.0' + ios_deployment_target = '15.0' osx_deployment_target = '10.15' - tvos_deployment_target = '13.0' + tvos_deployment_target = '15.0' watchos_deployment_target = '7.0' s.swift_version = '5.9' diff --git a/FirebaseRemoteConfig/Tests/FeatureRolloutsTestApp/Podfile b/FirebaseRemoteConfig/Tests/FeatureRolloutsTestApp/Podfile index eaacc5b39c5..a7416b1fd64 100644 --- a/FirebaseRemoteConfig/Tests/FeatureRolloutsTestApp/Podfile +++ b/FirebaseRemoteConfig/Tests/FeatureRolloutsTestApp/Podfile @@ -1,5 +1,5 @@ # Uncomment the next line to define a global platform for your project -# platform :ios, '9.0' +# platform :ios, '15.0' def shared_pods pod 'FirebaseCore', :path => '../../../' @@ -11,7 +11,7 @@ def shared_pods end target 'FeatureRolloutsTestApp_iOS' do - platform :ios, '13.0' + platform :ios, '15.0' # Comment the next line if you don't want to use dynamic frameworks use_frameworks! @@ -20,7 +20,7 @@ target 'FeatureRolloutsTestApp_iOS' do end target 'FeatureRolloutsTestApp_Crashlytics_iOS' do - platform :ios, '13.0' + platform :ios, '15.0' # Comment the next line if you don't want to use dynamic frameworks use_frameworks! @@ -30,7 +30,7 @@ target 'FeatureRolloutsTestApp_Crashlytics_iOS' do end target 'FeatureRolloutsTestApp_RemoteConfig_iOS' do - platform :ios, '13.0' + platform :ios, '15.0' # Comment the next line if you don't want to use dynamic frameworks use_frameworks! @@ -40,7 +40,7 @@ target 'FeatureRolloutsTestApp_RemoteConfig_iOS' do end target 'FeatureRolloutsTestApp_CrashlyticsRemoteConfig_iOS' do - platform :ios, '13.0' + platform :ios, '15.0' # Comment the next line if you don't want to use dynamic frameworks use_frameworks! diff --git a/FirebaseRemoteConfig/Tests/Sample/Podfile b/FirebaseRemoteConfig/Tests/Sample/Podfile index bdce061ec49..cf18482d0c5 100644 --- a/FirebaseRemoteConfig/Tests/Sample/Podfile +++ b/FirebaseRemoteConfig/Tests/Sample/Podfile @@ -1,4 +1,4 @@ -platform :ios, '13.0' +platform :ios, '15.0' source 'https://github.com/firebase/SpecsDev.git' source 'https://github.com/firebase/SpecsStaging.git' diff --git a/FirebaseRemoteConfig/Tests/Sample/RemoteConfigSampleApp.xcodeproj/project.pbxproj b/FirebaseRemoteConfig/Tests/Sample/RemoteConfigSampleApp.xcodeproj/project.pbxproj index 7a0067afc18..933868aca71 100644 --- a/FirebaseRemoteConfig/Tests/Sample/RemoteConfigSampleApp.xcodeproj/project.pbxproj +++ b/FirebaseRemoteConfig/Tests/Sample/RemoteConfigSampleApp.xcodeproj/project.pbxproj @@ -411,7 +411,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 12.4; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; ONLY_ACTIVE_ARCH = YES; @@ -464,7 +464,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 12.4; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; MTL_ENABLE_DEBUG_INFO = NO; MTL_FAST_MATH = YES; SDKROOT = iphoneos; diff --git a/FirebaseRemoteConfigInterop.podspec b/FirebaseRemoteConfigInterop.podspec index 21a39effd3d..ffa06365043 100644 --- a/FirebaseRemoteConfigInterop.podspec +++ b/FirebaseRemoteConfigInterop.podspec @@ -27,9 +27,9 @@ Pod::Spec.new do |s| s.social_media_url = 'https://twitter.com/Firebase' # The ios deployment target must support Crashlytics. - s.ios.deployment_target = '12.0' + s.ios.deployment_target = '15.0' s.osx.deployment_target = '10.15' - s.tvos.deployment_target = '13.0' + s.tvos.deployment_target = '15.0' s.watchos.deployment_target = '7.0' s.source_files = 'FirebaseRemoteConfig/Interop/*.swift' diff --git a/FirebaseRemoteConfigSwift/Apps/SwiftUISample/Podfile b/FirebaseRemoteConfigSwift/Apps/SwiftUISample/Podfile index cb24f4d1858..c5834e639ad 100644 --- a/FirebaseRemoteConfigSwift/Apps/SwiftUISample/Podfile +++ b/FirebaseRemoteConfigSwift/Apps/SwiftUISample/Podfile @@ -1,5 +1,5 @@ # Uncomment the next line to define a global platform for your project -# platform :ios, '14.0' +# platform :ios, '15.0' source 'https://github.com/firebase/SpecsDev.git' source 'https://github.com/firebase/SpecsStaging.git' diff --git a/FirebaseSessions.podspec b/FirebaseSessions.podspec index 308da8c87e3..5d87ac1cba5 100644 --- a/FirebaseSessions.podspec +++ b/FirebaseSessions.podspec @@ -18,9 +18,9 @@ Pod::Spec.new do |s| } s.social_media_url = 'https://twitter.com/Firebase' - ios_deployment_target = '12.0' + ios_deployment_target = '15.0' osx_deployment_target = '10.15' - tvos_deployment_target = '13.0' + tvos_deployment_target = '15.0' watchos_deployment_target = '7.0' s.swift_version = '5.9' diff --git a/FirebaseSessions/Tests/TestApp/Podfile b/FirebaseSessions/Tests/TestApp/Podfile index 3d6630fa178..ffbbaa23c24 100644 --- a/FirebaseSessions/Tests/TestApp/Podfile +++ b/FirebaseSessions/Tests/TestApp/Podfile @@ -1,5 +1,5 @@ # Uncomment the next line to define a global platform for your project -# platform :ios, '9.0' +# platform :ios, '15.0' source 'https://github.com/firebase/SpecsDev.git' source 'https://github.com/firebase/SpecsStaging.git' @@ -16,7 +16,7 @@ def shared_pods end target 'AppQualityDevApp_iOS' do - platform :ios, '13.0' + platform :ios, '15.0' # Comment the next line if you don't want to use dynamic frameworks use_frameworks! @@ -25,7 +25,7 @@ target 'AppQualityDevApp_iOS' do end target 'AppQualityDevApp_Crashlytics_iOS' do - platform :ios, '13.0' + platform :ios, '15.0' # Comment the next line if you don't want to use dynamic frameworks use_frameworks! @@ -35,7 +35,7 @@ target 'AppQualityDevApp_Crashlytics_iOS' do end target 'AppQualityDevApp_Performance_iOS' do - platform :ios, '13.0' + platform :ios, '15.0' # Comment the next line if you don't want to use dynamic frameworks use_frameworks! @@ -45,7 +45,7 @@ target 'AppQualityDevApp_Performance_iOS' do end target 'AppQualityDevApp_CrashlyticsPerformance_iOS' do - platform :ios, '13.0' + platform :ios, '15.0' # Comment the next line if you don't want to use dynamic frameworks use_frameworks! diff --git a/FirebaseSharedSwift.podspec b/FirebaseSharedSwift.podspec index 8f91286b6b6..d91433da223 100644 --- a/FirebaseSharedSwift.podspec +++ b/FirebaseSharedSwift.podspec @@ -20,9 +20,9 @@ Firebase products. FirebaseSharedSwift is not supported for non-Firebase usage. s.swift_version = '5.9' - ios_deployment_target = '13.0' + ios_deployment_target = '15.0' osx_deployment_target = '10.15' - tvos_deployment_target = '13.0' + tvos_deployment_target = '15.0' watchos_deployment_target = '7.0' s.ios.deployment_target = ios_deployment_target diff --git a/FirebaseStorage.podspec b/FirebaseStorage.podspec index c42929db4a7..618ad796b27 100644 --- a/FirebaseStorage.podspec +++ b/FirebaseStorage.podspec @@ -17,9 +17,9 @@ Firebase Storage provides robust, secure file uploads and downloads from Firebas } s.social_media_url = 'https://twitter.com/Firebase' - ios_deployment_target = '13.0' + ios_deployment_target = '15.0' osx_deployment_target = '10.15' - tvos_deployment_target = '13.0' + tvos_deployment_target = '15.0' watchos_deployment_target = '7.0' s.ios.deployment_target = ios_deployment_target diff --git a/FirebaseStorage/Sources/Internal/StorageUtils.swift b/FirebaseStorage/Sources/Internal/StorageUtils.swift index 51f2455b432..6ea83db36ab 100644 --- a/FirebaseStorage/Sources/Internal/StorageUtils.swift +++ b/FirebaseStorage/Sources/Internal/StorageUtils.swift @@ -13,6 +13,8 @@ // limitations under the License. import Foundation +private import UniformTypeIdentifiers + #if os(iOS) || os(tvOS) || os(visionOS) import MobileCoreServices #elseif os(macOS) || os(watchOS) @@ -71,21 +73,28 @@ class StorageUtils { return string.addingPercentEncoding(withAllowedCharacters: allowedSet)! } - class func MIMETypeForExtension(_ fileExtension: String?) -> String { - guard let fileExtension = fileExtension else { + static func MIMETypeForExtension(_ fileExtension: String?) -> String { + guard let fileExtension else { return "application/octet-stream" } - - if let type = UTTypeCreatePreferredIdentifierForTag( - kUTTagClassFilenameExtension, - fileExtension as NSString, - nil - )?.takeRetainedValue() { - if let mimeType = UTTypeCopyPreferredTagWithClass(type, kUTTagClassMIMEType)? - .takeRetainedValue() { - return mimeType as String + // TODO: Remove `else` when min. supported macOS is 11.0+. + if #available(macOS 11.0, iOS 14.0, tvOS 14.0, *) { + guard let mimeType = UTType(filenameExtension: fileExtension)?.preferredMIMEType else { + return "application/octet-stream" } + return mimeType + } else { + if let type = UTTypeCreatePreferredIdentifierForTag( + kUTTagClassFilenameExtension, + fileExtension as NSString, + nil + )?.takeRetainedValue() { + if let mimeType = UTTypeCopyPreferredTagWithClass(type, kUTTagClassMIMEType)? + .takeRetainedValue() { + return mimeType as String + } + } + return "application/octet-stream" } - return "application/octet-stream" } } diff --git a/Firestore/Example/Firestore.xcodeproj/project.pbxproj b/Firestore/Example/Firestore.xcodeproj/project.pbxproj index d106d804805..b312da6945c 100644 --- a/Firestore/Example/Firestore.xcodeproj/project.pbxproj +++ b/Firestore/Example/Firestore.xcodeproj/project.pbxproj @@ -6061,14 +6061,14 @@ GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; HEADER_SEARCH_PATHS = ""; - IPHONEOS_DEPLOYMENT_TARGET = 13.0; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; MACOSX_DEPLOYMENT_TARGET = 10.15; ONLY_ACTIVE_ARCH = YES; OTHER_CFLAGS = ""; SDKROOT = iphoneos; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; - TVOS_DEPLOYMENT_TARGET = 13.0; + TVOS_DEPLOYMENT_TARGET = 15.0; }; name = Debug; }; @@ -6111,14 +6111,14 @@ GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; HEADER_SEARCH_PATHS = ""; - IPHONEOS_DEPLOYMENT_TARGET = 13.0; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; MACOSX_DEPLOYMENT_TARGET = 10.15; OTHER_CFLAGS = ""; SDKROOT = iphoneos; SWIFT_COMPILATION_MODE = wholemodule; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; - TVOS_DEPLOYMENT_TARGET = 13.0; + TVOS_DEPLOYMENT_TARGET = 15.0; VALIDATE_PRODUCT = YES; }; name = Release; diff --git a/Firestore/Example/GoogleBenchmark.podspec b/Firestore/Example/GoogleBenchmark.podspec index c0024acced3..c91365438ca 100644 --- a/Firestore/Example/GoogleBenchmark.podspec +++ b/Firestore/Example/GoogleBenchmark.podspec @@ -33,9 +33,9 @@ Google's C++ benchmark framework. :tag => 'v' + s.version.to_s } - s.ios.deployment_target = '13.0' + s.ios.deployment_target = '15.0' s.osx.deployment_target = '10.15' - s.tvos.deployment_target = '13.0' + s.tvos.deployment_target = '15.0' s.requires_arc = false diff --git a/Firestore/Example/GoogleTest.podspec b/Firestore/Example/GoogleTest.podspec index f7dd32cde06..82cedbe9ef9 100644 --- a/Firestore/Example/GoogleTest.podspec +++ b/Firestore/Example/GoogleTest.podspec @@ -33,9 +33,9 @@ Google's C++ test framework. :commit => 'bf66935e07825318ae519675d73d0f3e313b3ec6' } - s.ios.deployment_target = '13.0' + s.ios.deployment_target = '15.0' s.osx.deployment_target = '10.15' - s.tvos.deployment_target = '13.0' + s.tvos.deployment_target = '15.0' s.requires_arc = false diff --git a/Firestore/Example/LibFuzzer.podspec b/Firestore/Example/LibFuzzer.podspec index c4b7b5f34a8..1014d421714 100644 --- a/Firestore/Example/LibFuzzer.podspec +++ b/Firestore/Example/LibFuzzer.podspec @@ -28,9 +28,9 @@ Pod::Spec.new do |s| s.license = { :type => 'BSD-Like' } s.authors = 'LLVM Team' - s.ios.deployment_target = '13.0' + s.ios.deployment_target = '15.0' s.osx.deployment_target = '10.15' - s.tvos.deployment_target = '13.0' + s.tvos.deployment_target = '15.0' s.source = { :git => 'https://github.com/llvm/llvm-project.git' diff --git a/Firestore/Example/Podfile b/Firestore/Example/Podfile index e16cc345bcb..2563b2e28dd 100644 --- a/Firestore/Example/Podfile +++ b/Firestore/Example/Podfile @@ -95,7 +95,7 @@ end if is_platform(:ios) target 'Firestore_Example_iOS' do - platform :ios, '13.0' + platform :ios, '15.0' configure_local_pods() @@ -129,7 +129,7 @@ if is_platform(:ios) target 'Firestore_FuzzTests_iOS' do inherit! :search_paths - platform :ios, '13.0' + platform :ios, '15.0' pod 'LibFuzzer', :podspec => 'LibFuzzer.podspec', :inhibit_warnings => true end @@ -168,7 +168,7 @@ end if is_platform(:tvos) target 'Firestore_Example_tvOS' do - platform :tvos, '13.0' + platform :tvos, '15.0' configure_local_pods() diff --git a/Firestore/Example/ProtobufCpp.podspec b/Firestore/Example/ProtobufCpp.podspec index fabb0d6dbeb..7ff09957ca4 100644 --- a/Firestore/Example/ProtobufCpp.podspec +++ b/Firestore/Example/ProtobufCpp.podspec @@ -29,9 +29,9 @@ Pod::Spec.new do |s| :tag => "v#{s.version}" } - s.ios.deployment_target = '13.0' + s.ios.deployment_target = '15.0' s.osx.deployment_target = '10.15' - s.tvos.deployment_target = '13.0' + s.tvos.deployment_target = '15.0' s.source_files = 'src/**/*.{h,cc,inc}', # utf8_range is needed too, to avoid build errors. diff --git a/Firestore/Protos/FrameworkMaker.xcodeproj/project.pbxproj b/Firestore/Protos/FrameworkMaker.xcodeproj/project.pbxproj index f9506bfa21a..f7b4761dcfc 100644 --- a/Firestore/Protos/FrameworkMaker.xcodeproj/project.pbxproj +++ b/Firestore/Protos/FrameworkMaker.xcodeproj/project.pbxproj @@ -287,8 +287,8 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 11.0; - MACOSX_DEPLOYMENT_TARGET = 10.13; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; + MACOSX_DEPLOYMENT_TARGET = 10.15; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; @@ -326,8 +326,8 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 11.0; - MACOSX_DEPLOYMENT_TARGET = 10.13; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; + MACOSX_DEPLOYMENT_TARGET = 10.15; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; VALIDATE_PRODUCT = YES; diff --git a/Firestore/Protos/Podfile b/Firestore/Protos/Podfile index 988d7f81e7c..9912e606ae0 100644 --- a/Firestore/Protos/Podfile +++ b/Firestore/Protos/Podfile @@ -4,7 +4,7 @@ project 'FrameworkMaker.xcodeproj' target 'FrameworkMaker_iOS' do - platform :ios, '7.0' + platform :ios, '15.0' # This should be versioned along with 'gRPC-ProtoRPC' in Firestore.podspec pod '!ProtoCompiler-gRPCPlugin' diff --git a/GoogleAppMeasurement.podspec b/GoogleAppMeasurement.podspec index f8586fd5532..0fa73abe680 100644 --- a/GoogleAppMeasurement.podspec +++ b/GoogleAppMeasurement.podspec @@ -21,9 +21,9 @@ Pod::Spec.new do |s| s.cocoapods_version = '>= 1.12.0' - s.ios.deployment_target = '12.0' + s.ios.deployment_target = '15.0' s.osx.deployment_target = '10.15' - s.tvos.deployment_target = '13.0' + s.tvos.deployment_target = '15.0' s.libraries = 'c++', 'sqlite3', 'z' s.frameworks = 'StoreKit' diff --git a/GoogleAppMeasurementOnDeviceConversion.podspec b/GoogleAppMeasurementOnDeviceConversion.podspec index 24b3db89042..2c6c06a93f0 100644 --- a/GoogleAppMeasurementOnDeviceConversion.podspec +++ b/GoogleAppMeasurementOnDeviceConversion.podspec @@ -22,7 +22,7 @@ Pod::Spec.new do |s| s.cocoapods_version = '>= 1.12.0' - s.ios.deployment_target = '12.0' + s.ios.deployment_target = '15.0' s.libraries = 'c++' diff --git a/IntegrationTesting/ClientApp/ClientApp.xcodeproj/project.pbxproj b/IntegrationTesting/ClientApp/ClientApp.xcodeproj/project.pbxproj index 363cc8ff7cb..96db222f56c 100644 --- a/IntegrationTesting/ClientApp/ClientApp.xcodeproj/project.pbxproj +++ b/IntegrationTesting/ClientApp/ClientApp.xcodeproj/project.pbxproj @@ -457,10 +457,10 @@ "INFOPLIST_KEY_UIStatusBarStyle[sdk=iphonesimulator*]" = UIStatusBarStyleDefault; INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; - IPHONEOS_DEPLOYMENT_TARGET = 13.0; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; LD_RUNPATH_SEARCH_PATHS = "@executable_path/Frameworks"; "LD_RUNPATH_SEARCH_PATHS[sdk=macosx*]" = "@executable_path/../Frameworks"; - MACOSX_DEPLOYMENT_TARGET = 10.13; + MACOSX_DEPLOYMENT_TARGET = 10.15; MARKETING_VERSION = 1.0; OTHER_CPLUSPLUSFLAGS = "$(OTHER_CFLAGS)"; PRODUCT_BUNDLE_IDENTIFIER = com.google.firebase.ClientApp; @@ -473,7 +473,7 @@ SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2,3"; - TVOS_DEPLOYMENT_TARGET = 13.0; + TVOS_DEPLOYMENT_TARGET = 15.0; }; name = Debug; }; @@ -500,10 +500,10 @@ "INFOPLIST_KEY_UIStatusBarStyle[sdk=iphonesimulator*]" = UIStatusBarStyleDefault; INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; - IPHONEOS_DEPLOYMENT_TARGET = 13.0; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; LD_RUNPATH_SEARCH_PATHS = "@executable_path/Frameworks"; "LD_RUNPATH_SEARCH_PATHS[sdk=macosx*]" = "@executable_path/../Frameworks"; - MACOSX_DEPLOYMENT_TARGET = 10.13; + MACOSX_DEPLOYMENT_TARGET = 10.15; MARKETING_VERSION = 1.0; OTHER_CPLUSPLUSFLAGS = "$(OTHER_CFLAGS)"; PRODUCT_BUNDLE_IDENTIFIER = com.google.firebase.ClientApp; @@ -515,7 +515,7 @@ SWIFT_EMIT_LOC_STRINGS = YES; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2,3"; - TVOS_DEPLOYMENT_TARGET = 13.0; + TVOS_DEPLOYMENT_TARGET = 15.0; }; name = Release; }; @@ -540,7 +540,7 @@ "INFOPLIST_KEY_UIStatusBarStyle[sdk=iphonesimulator*]" = UIStatusBarStyleDefault; INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; - IPHONEOS_DEPLOYMENT_TARGET = 13.0; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; LD_RUNPATH_SEARCH_PATHS = "@executable_path/Frameworks"; "LD_RUNPATH_SEARCH_PATHS[sdk=macosx*]" = "@executable_path/../Frameworks"; MACOSX_DEPLOYMENT_TARGET = 10.15; @@ -552,7 +552,7 @@ SWIFT_EMIT_LOC_STRINGS = YES; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; - TVOS_DEPLOYMENT_TARGET = 13.0; + TVOS_DEPLOYMENT_TARGET = 15.0; }; name = Debug; }; @@ -577,7 +577,7 @@ "INFOPLIST_KEY_UIStatusBarStyle[sdk=iphonesimulator*]" = UIStatusBarStyleDefault; INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; - IPHONEOS_DEPLOYMENT_TARGET = 13.0; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; LD_RUNPATH_SEARCH_PATHS = "@executable_path/Frameworks"; "LD_RUNPATH_SEARCH_PATHS[sdk=macosx*]" = "@executable_path/../Frameworks"; MACOSX_DEPLOYMENT_TARGET = 10.15; @@ -589,7 +589,7 @@ SWIFT_EMIT_LOC_STRINGS = YES; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; - TVOS_DEPLOYMENT_TARGET = 13.0; + TVOS_DEPLOYMENT_TARGET = 15.0; }; name = Release; }; diff --git a/IntegrationTesting/ClientApp/Podfile b/IntegrationTesting/ClientApp/Podfile index 43ffaf35960..e25a082c513 100644 --- a/IntegrationTesting/ClientApp/Podfile +++ b/IntegrationTesting/ClientApp/Podfile @@ -3,7 +3,7 @@ source 'https://github.com/firebase/SpecsStaging.git' source 'https://cdn.cocoapods.org/' target 'ClientApp-CocoaPods' do - platform :ios, '13.0' + platform :ios, '15.0' use_frameworks! diff --git a/IntegrationTesting/CocoapodsIntegrationTest/CocoapodsIntegrationTest.xcodeproj/project.pbxproj b/IntegrationTesting/CocoapodsIntegrationTest/CocoapodsIntegrationTest.xcodeproj/project.pbxproj index c1224d0f529..325a834adbb 100644 --- a/IntegrationTesting/CocoapodsIntegrationTest/CocoapodsIntegrationTest.xcodeproj/project.pbxproj +++ b/IntegrationTesting/CocoapodsIntegrationTest/CocoapodsIntegrationTest.xcodeproj/project.pbxproj @@ -289,7 +289,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 12.1; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; ONLY_ACTIVE_ARCH = YES; @@ -342,7 +342,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 12.1; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; MTL_ENABLE_DEBUG_INFO = NO; MTL_FAST_MATH = YES; SDKROOT = iphoneos; diff --git a/IntegrationTesting/CocoapodsIntegrationTest/TestEnvironments/Cocoapods_multiprojects_frameworks/Podfile b/IntegrationTesting/CocoapodsIntegrationTest/TestEnvironments/Cocoapods_multiprojects_frameworks/Podfile index e422c6b350c..e582b66c57e 100644 --- a/IntegrationTesting/CocoapodsIntegrationTest/TestEnvironments/Cocoapods_multiprojects_frameworks/Podfile +++ b/IntegrationTesting/CocoapodsIntegrationTest/TestEnvironments/Cocoapods_multiprojects_frameworks/Podfile @@ -3,7 +3,7 @@ source 'https://github.com/firebase/SpecsStaging.git' source 'https://cdn.cocoapods.org/' # Uncomment the next line to define a global platform for your project -platform :ios, '13.0' +platform :ios, '15.0' target 'CocoapodsIntegrationTest' do # Comment the next line if you don't want to use dynamic frameworks @@ -14,6 +14,7 @@ target 'CocoapodsIntegrationTest' do pod 'FirebaseCore', :path => '../../' pod 'FirebaseCoreExtension', :path => '../../' pod 'FirebaseCoreInternal', :path => '../../' + pod 'FirebaseSessions', :path => '../../' pod 'FirebaseCrashlytics', :path => '../../' pod 'FirebaseAuth', :path => '../../' pod 'FirebaseAuthInterop', :path => '../../' diff --git a/ReleaseTooling/Template/FrameworkMaker.xcodeproj/project.pbxproj b/ReleaseTooling/Template/FrameworkMaker.xcodeproj/project.pbxproj index 4018da9ed6d..d32042f4f2d 100644 --- a/ReleaseTooling/Template/FrameworkMaker.xcodeproj/project.pbxproj +++ b/ReleaseTooling/Template/FrameworkMaker.xcodeproj/project.pbxproj @@ -149,7 +149,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 10.0; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; @@ -188,7 +188,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 10.0; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; VALIDATE_PRODUCT = YES; diff --git a/SymbolCollisionTest/Podfile b/SymbolCollisionTest/Podfile index e0047ee2631..658c436c234 100644 --- a/SymbolCollisionTest/Podfile +++ b/SymbolCollisionTest/Podfile @@ -1,4 +1,4 @@ -platform :ios, '14.0' +platform :ios, '15.0' source 'https://github.com/firebase/SpecsDev.git' source 'https://github.com/firebase/SpecsStaging.git' @@ -16,6 +16,7 @@ target 'SymbolCollisionTest' do pod 'FirebaseCore', :path => '../' pod 'FirebaseCoreExtension', :path => '../' pod 'FirebaseCoreInternal', :path => '../' + pod 'FirebaseSessions', :path => '../' pod 'FirebaseCrashlytics', :path => '../' pod 'FirebaseDatabase', :path => '../' pod 'FirebaseFirestore', :path => '../' diff --git a/SymbolCollisionTest/SymbolCollisionTest.xcodeproj/project.pbxproj b/SymbolCollisionTest/SymbolCollisionTest.xcodeproj/project.pbxproj index 7ca6954ac2a..cd35ce40100 100644 --- a/SymbolCollisionTest/SymbolCollisionTest.xcodeproj/project.pbxproj +++ b/SymbolCollisionTest/SymbolCollisionTest.xcodeproj/project.pbxproj @@ -220,7 +220,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 12.1; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; ONLY_ACTIVE_ARCH = YES; @@ -273,7 +273,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 12.1; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; MTL_ENABLE_DEBUG_INFO = NO; MTL_FAST_MATH = YES; SDKROOT = iphoneos; From 17f6f8159ce8de00cda6cddc06b09fe464909f89 Mon Sep 17 00:00:00 2001 From: Nick Cooke <36927374+ncooke3@users.noreply.github.com> Date: Tue, 24 Jun 2025 15:17:58 -0400 Subject: [PATCH 104/113] [Auth] Remove 'ActionCodeSettings.dynamicLinkDomain' (#15036) --- FirebaseAuth/CHANGELOG.md | 4 ++++ .../Swift/ActionCode/ActionCodeSettings.swift | 22 ------------------- .../RPC/GetOOBConfirmationCodeRequest.swift | 21 ------------------ .../Unit/GetOOBConfirmationCodeTests.swift | 3 --- FirebaseAuth/Tests/Unit/ObjCAPITests.m | 1 - FirebaseAuth/Tests/Unit/RPCBaseTests.swift | 2 -- FirebaseAuth/Tests/Unit/SwiftAPI.swift | 1 - 7 files changed, 4 insertions(+), 50 deletions(-) diff --git a/FirebaseAuth/CHANGELOG.md b/FirebaseAuth/CHANGELOG.md index b9278b58399..9c6bc4e9c9c 100644 --- a/FirebaseAuth/CHANGELOG.md +++ b/FirebaseAuth/CHANGELOG.md @@ -1,3 +1,7 @@ +# Unreleased +- [removed] **Breaking Change**: Removed + `ActionCodeSettings.dynamicLinkDomain`. + # 11.15.0 - [fixed] Fixed `Sendable` warnings introduced in the Xcode 26 beta. (#14996) diff --git a/FirebaseAuth/Sources/Swift/ActionCode/ActionCodeSettings.swift b/FirebaseAuth/Sources/Swift/ActionCode/ActionCodeSettings.swift index 2f98f08b332..17bd7a30433 100644 --- a/FirebaseAuth/Sources/Swift/ActionCode/ActionCodeSettings.swift +++ b/FirebaseAuth/Sources/Swift/ActionCode/ActionCodeSettings.swift @@ -62,19 +62,6 @@ import Foundation set { impl.androidInstallIfNotAvailable.withLock { $0 = newValue } } } - /// The Firebase Dynamic Link domain used for out of band code flow. - #if !FIREBASE_CI - @available( - *, - deprecated, - message: "Firebase Dynamic Links is deprecated. Migrate to use Firebase Hosting link and use `linkDomain` to set a custom domain instead." - ) - #endif // !FIREBASE_CI - @objc open var dynamicLinkDomain: String? { - get { impl.dynamicLinkDomain.value() } - set { impl.dynamicLinkDomain.withLock { $0 = newValue } } - } - /// The out of band custom domain for handling code in app. @objc public var linkDomain: String? { get { impl.linkDomain.value() } @@ -130,15 +117,6 @@ private extension ActionCodeSettings { let androidInstallIfNotAvailable = FIRAllocatedUnfairLock(initialState: false) - #if !FIREBASE_CI - @available( - *, - deprecated, - message: "Firebase Dynamic Links is deprecated. Migrate to use Firebase Hosting link and use `linkDomain` to set a custom domain instead." - ) - #endif // !FIREBASE_CI - let dynamicLinkDomain = FIRAllocatedUnfairLock(initialState: nil) - let linkDomain = FIRAllocatedUnfairLock(initialState: nil) init() { diff --git a/FirebaseAuth/Sources/Swift/Backend/RPC/GetOOBConfirmationCodeRequest.swift b/FirebaseAuth/Sources/Swift/Backend/RPC/GetOOBConfirmationCodeRequest.swift index 3dd4a07b59b..dd3ac4fc465 100644 --- a/FirebaseAuth/Sources/Swift/Backend/RPC/GetOOBConfirmationCodeRequest.swift +++ b/FirebaseAuth/Sources/Swift/Backend/RPC/GetOOBConfirmationCodeRequest.swift @@ -75,9 +75,6 @@ private let kAndroidMinimumVersionKey = "androidMinimumVersion" /// or not. private let kCanHandleCodeInAppKey = "canHandleCodeInApp" -/// The key for the "dynamic link domain" value in the request. -private let kDynamicLinkDomainKey = "dynamicLinkDomain" - /// The key for the "link domain" value in the request. private let kLinkDomainKey = "linkDomain" @@ -105,12 +102,6 @@ private let kClientType = "clientType" /// The key for the "recaptchaVersion" value in the request. private let kRecaptchaVersion = "recaptchaVersion" -protocol SuppressWarning { - var dynamicLinkDomain: String? { get set } -} - -extension ActionCodeSettings: SuppressWarning {} - @available(iOS 13, tvOS 13, macOS 10.15, macCatalyst 13, watchOS 7, *) class GetOOBConfirmationCodeRequest: IdentityToolkitRequest, AuthRPCRequest { typealias Response = GetOOBConfirmationCodeResponse @@ -146,9 +137,6 @@ class GetOOBConfirmationCodeRequest: IdentityToolkitRequest, AuthRPCRequest { /// redirected from a Firebase owned web widget. let handleCodeInApp: Bool - /// The Firebase Dynamic Link domain used for out of band code flow. - private let dynamicLinkDomain: String? - /// The Firebase Hosting domain used for out of band code flow. private(set) var linkDomain: String? @@ -183,12 +171,6 @@ class GetOOBConfirmationCodeRequest: IdentityToolkitRequest, AuthRPCRequest { androidMinimumVersion = actionCodeSettings?.androidMinimumVersion androidInstallApp = actionCodeSettings?.androidInstallIfNotAvailable ?? false handleCodeInApp = actionCodeSettings?.handleCodeInApp ?? false - dynamicLinkDomain = - if let actionCodeSettings { - (actionCodeSettings as SuppressWarning).dynamicLinkDomain - } else { - nil - } linkDomain = actionCodeSettings?.linkDomain super.init( @@ -289,9 +271,6 @@ class GetOOBConfirmationCodeRequest: IdentityToolkitRequest, AuthRPCRequest { if handleCodeInApp { body[kCanHandleCodeInAppKey] = true } - if let dynamicLinkDomain { - body[kDynamicLinkDomainKey] = dynamicLinkDomain - } if let linkDomain { body[kLinkDomainKey] = linkDomain } diff --git a/FirebaseAuth/Tests/Unit/GetOOBConfirmationCodeTests.swift b/FirebaseAuth/Tests/Unit/GetOOBConfirmationCodeTests.swift index 5750ea52f32..362d3fef951 100644 --- a/FirebaseAuth/Tests/Unit/GetOOBConfirmationCodeTests.swift +++ b/FirebaseAuth/Tests/Unit/GetOOBConfirmationCodeTests.swift @@ -33,7 +33,6 @@ class GetOOBConfirmationCodeTests: RPCBaseTests { private let kAndroidInstallAppKey = "androidInstallApp" private let kAndroidMinimumVersionKey = "androidMinimumVersion" private let kCanHandleCodeInAppKey = "canHandleCodeInApp" - private let kDynamicLinkDomainKey = "dynamicLinkDomain" private let kLinkDomainKey = "linkDomain" private let kExpectedAPIURL = "https://www.googleapis.com/identitytoolkit/v3/relyingparty/getOobConfirmationCode?key=APIKey" @@ -66,7 +65,6 @@ class GetOOBConfirmationCodeTests: RPCBaseTests { XCTAssertEqual(decodedRequest[kAndroidMinimumVersionKey] as? String, kAndroidMinimumVersion) XCTAssertEqual(decodedRequest[kAndroidInstallAppKey] as? Bool, true) XCTAssertEqual(decodedRequest[kCanHandleCodeInAppKey] as? Bool, true) - XCTAssertEqual(decodedRequest[kDynamicLinkDomainKey] as? String, kDynamicLinkDomain) XCTAssertEqual(decodedRequest[kLinkDomainKey] as? String, kLinkDomain) } } @@ -111,7 +109,6 @@ class GetOOBConfirmationCodeTests: RPCBaseTests { XCTAssertEqual(decodedRequest[kAndroidMinimumVersionKey] as? String, kAndroidMinimumVersion) XCTAssertEqual(decodedRequest[kAndroidInstallAppKey] as? Bool, true) XCTAssertEqual(decodedRequest[kCanHandleCodeInAppKey] as? Bool, true) - XCTAssertEqual(decodedRequest[kDynamicLinkDomainKey] as? String, kDynamicLinkDomain) XCTAssertEqual(decodedRequest[kLinkDomainKey] as? String, kLinkDomain) XCTAssertEqual(decodedRequest[kCaptchaResponseKey] as? String, kTestCaptchaResponse) XCTAssertEqual(decodedRequest[kClientTypeKey] as? String, kTestClientType) diff --git a/FirebaseAuth/Tests/Unit/ObjCAPITests.m b/FirebaseAuth/Tests/Unit/ObjCAPITests.m index 2cb50ab2766..ed664c45e09 100644 --- a/FirebaseAuth/Tests/Unit/ObjCAPITests.m +++ b/FirebaseAuth/Tests/Unit/ObjCAPITests.m @@ -64,7 +64,6 @@ - (void)FIRActionCodeSettings_h { NSString *s = [codeSettings iOSBundleID]; s = [codeSettings androidPackageName]; s = [codeSettings androidMinimumVersion]; - s = [codeSettings dynamicLinkDomain]; s = [codeSettings linkDomain]; } diff --git a/FirebaseAuth/Tests/Unit/RPCBaseTests.swift b/FirebaseAuth/Tests/Unit/RPCBaseTests.swift index 2e619030e49..2d70b0276ef 100644 --- a/FirebaseAuth/Tests/Unit/RPCBaseTests.swift +++ b/FirebaseAuth/Tests/Unit/RPCBaseTests.swift @@ -37,7 +37,6 @@ class RPCBaseTests: XCTestCase { let kIosBundleID = "testBundleID" let kAndroidPackageName = "androidpackagename" let kAndroidMinimumVersion = "3.0" - let kDynamicLinkDomain = "test.page.link" let kLinkDomain = "link.firebaseapp.com" let kTestPhotoURL = "https://host.domain/image" let kCreationDateTimeIntervalInSeconds = 1_505_858_500.0 @@ -304,7 +303,6 @@ class RPCBaseTests: XCTestCase { minimumVersion: kAndroidMinimumVersion) settings.handleCodeInApp = true settings.url = URL(string: kContinueURL) - settings.dynamicLinkDomain = kDynamicLinkDomain settings.linkDomain = kLinkDomain return settings } diff --git a/FirebaseAuth/Tests/Unit/SwiftAPI.swift b/FirebaseAuth/Tests/Unit/SwiftAPI.swift index f61db229730..d24b8db59ad 100644 --- a/FirebaseAuth/Tests/Unit/SwiftAPI.swift +++ b/FirebaseAuth/Tests/Unit/SwiftAPI.swift @@ -41,7 +41,6 @@ class AuthAPI_hOnlyTests: XCTestCase { let _: String = codeSettings.iOSBundleID, let _: String = codeSettings.androidPackageName, let _: String = codeSettings.androidMinimumVersion, - let _: String = codeSettings.dynamicLinkDomain, let _: String = codeSettings.linkDomain {} codeSettings.linkDomain = nil codeSettings.linkDomain = "" From 64820136f930878a87afda1fe0cd1efc8d39a0e4 Mon Sep 17 00:00:00 2001 From: Nick Cooke <36927374+ncooke3@users.noreply.github.com> Date: Tue, 24 Jun 2025 17:25:41 -0400 Subject: [PATCH 105/113] [Infra] Bump to Xcode 16.4 on CI runners (#15034) --- .github/workflows/analytics.yml | 2 +- .github/workflows/auth.yml | 2 +- .github/workflows/common.yml | 2 +- .github/workflows/common_cocoapods.yml | 2 +- .github/workflows/database.yml | 2 +- .github/workflows/firebaseai.yml | 2 +- .github/workflows/firestore.yml | 10 +++++----- .github/workflows/messaging.yml | 2 +- .github/workflows/remoteconfig.yml | 8 ++++---- .github/workflows/spm.yml | 2 +- .github/workflows/storage.yml | 2 +- .github/workflows/symbolcollision.yml | 2 +- .github/workflows/zip.yml | 14 +++++++------- 13 files changed, 26 insertions(+), 26 deletions(-) diff --git a/.github/workflows/analytics.yml b/.github/workflows/analytics.yml index 70f51071a03..59d7ddef646 100644 --- a/.github/workflows/analytics.yml +++ b/.github/workflows/analytics.yml @@ -29,7 +29,7 @@ jobs: - os: macos-14 xcode: Xcode_16.2 - os: macos-15 - xcode: Xcode_16.3 + xcode: Xcode_16.4 runs-on: ${{ matrix.os }} steps: diff --git a/.github/workflows/auth.yml b/.github/workflows/auth.yml index 9f207d650f5..03e8b2526f2 100644 --- a/.github/workflows/auth.yml +++ b/.github/workflows/auth.yml @@ -83,7 +83,7 @@ jobs: scripts/decrypt_gha_secret.sh scripts/gha-encrypted/AuthSample/Credentials.swift.gpg \ FirebaseAuth/Tests/SampleSwift/SwiftApiTests/Credentials.swift "$plist_secret" - name: Xcode - run: sudo xcode-select -s /Applications/Xcode_16.3.app/Contents/Developer + run: sudo xcode-select -s /Applications/Xcode_16.4.app/Contents/Developer - uses: nick-fields/retry@ce71cc2ab81d554ebbe88c79ab5975992d79ba08 # v3 with: timeout_minutes: 120 diff --git a/.github/workflows/common.yml b/.github/workflows/common.yml index 40ba550d095..cd359b0fe4f 100644 --- a/.github/workflows/common.yml +++ b/.github/workflows/common.yml @@ -89,7 +89,7 @@ jobs: strategy: matrix: os: [macos-15] - xcode: [Xcode_16.3] + xcode: [Xcode_16.4] platform: [iOS, tvOS, macOS, watchOS, catalyst, visionOS] include: - os: macos-14 diff --git a/.github/workflows/common_cocoapods.yml b/.github/workflows/common_cocoapods.yml index 6536c5a3f47..cf054ef7743 100644 --- a/.github/workflows/common_cocoapods.yml +++ b/.github/workflows/common_cocoapods.yml @@ -111,7 +111,7 @@ jobs: strategy: matrix: os: [macos-15] - xcode: [Xcode_16.3] + xcode: [Xcode_16.4] platform: [iOS, tvOS, macOS, watchOS] include: - os: macos-14 diff --git a/.github/workflows/database.yml b/.github/workflows/database.yml index 6177b637cae..928c3bf28ad 100644 --- a/.github/workflows/database.yml +++ b/.github/workflows/database.yml @@ -63,7 +63,7 @@ jobs: - name: Install xcpretty run: gem install xcpretty - name: Xcode - run: sudo xcode-select -s /Applications/Xcode_16.3.app/Contents/Developer + run: sudo xcode-select -s /Applications/Xcode_16.4.app/Contents/Developer - name: IntegrationTest # Only iOS to mitigate flakes. run: scripts/third_party/travis/retry.sh scripts/build.sh Database iOS integration diff --git a/.github/workflows/firebaseai.yml b/.github/workflows/firebaseai.yml index 1184ce74897..7ad2a9dff29 100644 --- a/.github/workflows/firebaseai.yml +++ b/.github/workflows/firebaseai.yml @@ -39,7 +39,7 @@ jobs: os: [macos-15] include: - os: macos-15 - xcode: Xcode_16.3 + xcode: Xcode_16.4 runs-on: ${{ matrix.os }} needs: spm env: diff --git a/.github/workflows/firestore.yml b/.github/workflows/firestore.yml index 8f4ac2b1264..3e927287a2e 100644 --- a/.github/workflows/firestore.yml +++ b/.github/workflows/firestore.yml @@ -478,19 +478,19 @@ jobs: xcode: Xcode_16.2 target: iOS - os: macos-15 - xcode: Xcode_16.3 + xcode: Xcode_16.4 target: iOS - os: macos-15 - xcode: Xcode_16.3 + xcode: Xcode_16.4 target: tvOS - os: macos-15 - xcode: Xcode_16.3 + xcode: Xcode_16.4 target: macOS - os: macos-15 - xcode: Xcode_16.3 + xcode: Xcode_16.4 target: catalyst - os: macos-15 - xcode: Xcode_16.3 + xcode: Xcode_16.4 target: visionOS runs-on: ${{ matrix.os }} env: diff --git a/.github/workflows/messaging.yml b/.github/workflows/messaging.yml index cd89ca840fc..838ce5fe4d9 100644 --- a/.github/workflows/messaging.yml +++ b/.github/workflows/messaging.yml @@ -66,7 +66,7 @@ jobs: run: scripts/configure_test_keychain.sh - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1 - name: Xcode - run: sudo xcode-select -s /Applications/Xcode_16.3.app/Contents/Developer + run: sudo xcode-select -s /Applications/Xcode_16.4.app/Contents/Developer - name: Setup Bundler run: scripts/setup_bundler.sh - name: Install xcpretty diff --git a/.github/workflows/remoteconfig.yml b/.github/workflows/remoteconfig.yml index dc764c6a88d..199fd669f41 100644 --- a/.github/workflows/remoteconfig.yml +++ b/.github/workflows/remoteconfig.yml @@ -70,7 +70,7 @@ jobs: run: ([ -z $plist_secret ] || scripts/generate_access_token.sh "$plist_secret" scripts/gha-encrypted/RemoteConfigSwiftAPI/ServiceAccount.json.gpg FirebaseRemoteConfig/Tests/Swift/AccessToken.json) - name: Xcode - run: sudo xcode-select -s /Applications/Xcode_16.3.app/Contents/Developer + run: sudo xcode-select -s /Applications/Xcode_16.4.app/Contents/Developer - name: Fake Console API Tests run: scripts/third_party/travis/retry.sh scripts/build.sh RemoteConfig ${{ matrix.target }} fakeconsole - name: IntegrationTest @@ -94,7 +94,7 @@ jobs: - uses: actions/checkout@v4 - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1 - name: Xcode - run: sudo xcode-select -s /Applications/Xcode_16.3.app/Contents/Developer + run: sudo xcode-select -s /Applications/Xcode_16.4.app/Contents/Developer - name: Setup quickstart run: scripts/setup_quickstart.sh config - name: Install Secret GoogleService-Info.plist @@ -144,7 +144,7 @@ jobs: - name: Setup Bundler run: scripts/setup_bundler.sh - name: Xcode - run: sudo xcode-select -s /Applications/Xcode_16.3.app/Contents/Developer + run: sudo xcode-select -s /Applications/Xcode_16.4.app/Contents/Developer - name: Prereqs run: scripts/install_prereqs.sh RemoteConfigSample iOS - name: Build @@ -165,7 +165,7 @@ jobs: - uses: actions/checkout@v4 - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1 - name: Xcode - run: sudo xcode-select -s /Applications/Xcode_16.3.app/Contents/Developer + run: sudo xcode-select -s /Applications/Xcode_16.4.app/Contents/Developer - name: Setup Bundler run: scripts/setup_bundler.sh - name: PodLibLint RemoteConfig Cron diff --git a/.github/workflows/spm.yml b/.github/workflows/spm.yml index 97a897e2695..5b807927410 100644 --- a/.github/workflows/spm.yml +++ b/.github/workflows/spm.yml @@ -59,7 +59,7 @@ jobs: matrix: include: - os: macos-15 - xcode: Xcode_16.3 + xcode: Xcode_16.4 test: spm - os: macos-14 xcode: Xcode_16.2 diff --git a/.github/workflows/storage.yml b/.github/workflows/storage.yml index f9ffcc0aa73..036037b5ca7 100644 --- a/.github/workflows/storage.yml +++ b/.github/workflows/storage.yml @@ -43,7 +43,7 @@ jobs: language: [Swift, ObjC] include: - os: macos-15 - xcode: Xcode_16.3 + xcode: Xcode_16.4 env: plist_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} runs-on: ${{ matrix.os }} diff --git a/.github/workflows/symbolcollision.yml b/.github/workflows/symbolcollision.yml index 51fc88e262c..00fcde3c3e9 100644 --- a/.github/workflows/symbolcollision.yml +++ b/.github/workflows/symbolcollision.yml @@ -32,7 +32,7 @@ jobs: - name: Setup Bundler run: scripts/setup_bundler.sh - name: Xcode - run: sudo xcode-select -s /Applications/Xcode_16.3.app/Contents/Developer + run: sudo xcode-select -s /Applications/Xcode_16.4.app/Contents/Developer - name: Prereqs run: scripts/install_prereqs.sh SymbolCollision iOS - name: Build diff --git a/.github/workflows/zip.yml b/.github/workflows/zip.yml index 074fc1a26ad..9879e942885 100644 --- a/.github/workflows/zip.yml +++ b/.github/workflows/zip.yml @@ -116,7 +116,7 @@ jobs: - os: macos-15 xcode: Xcode_16.2 # - os: macos-15 - # xcode: Xcode_16.3 + # xcode: Xcode_16.4 runs-on: ${{ matrix.build-env.os }} steps: - uses: actions/checkout@v4 @@ -228,7 +228,7 @@ jobs: - os: macos-15 xcode: Xcode_16.2 # - os: macos-15 - # xcode: Xcode_16.3 + # xcode: Xcode_16.4 runs-on: ${{ matrix.build-env.os }} steps: - uses: actions/checkout@v4 @@ -279,7 +279,7 @@ jobs: - os: macos-15 xcode: Xcode_16.2 # - os: macos-15 - # xcode: Xcode_16.3 + # xcode: Xcode_16.4 runs-on: ${{ matrix.build-env.os }} steps: - uses: actions/checkout@v4 @@ -405,7 +405,7 @@ jobs: - os: macos-15 xcode: Xcode_16.2 # - os: macos-15 - # xcode: Xcode_16.3 + # xcode: Xcode_16.4 runs-on: ${{ matrix.build-env.os }} steps: - uses: actions/checkout@v4 @@ -489,7 +489,7 @@ jobs: - os: macos-15 xcode: Xcode_16.2 # - os: macos-15 - # xcode: Xcode_16.3 + # xcode: Xcode_16.4 runs-on: ${{ matrix.build-env.os }} steps: - uses: actions/checkout@v4 @@ -544,7 +544,7 @@ jobs: - os: macos-15 xcode: Xcode_16.2 # - os: macos-15 - # xcode: Xcode_16.3 + # xcode: Xcode_16.4 runs-on: ${{ matrix.build-env.os }} steps: - uses: actions/checkout@v4 @@ -599,7 +599,7 @@ jobs: - os: macos-15 xcode: Xcode_16.2 # - os: macos-15 - # xcode: Xcode_16.3 + # xcode: Xcode_16.4 runs-on: ${{ matrix.build-env.os }} steps: - uses: actions/checkout@v4 From 3a552e9c22322607d34ae2688b8a228633e5a175 Mon Sep 17 00:00:00 2001 From: Nick Cooke <36927374+ncooke3@users.noreply.github.com> Date: Tue, 24 Jun 2025 17:45:43 -0400 Subject: [PATCH 106/113] [Auth] Remove deprecated string-based provider ID APIs (#15037) --- FirebaseAuth/CHANGELOG.md | 3 ++ .../Swift/AuthProvider/OAuthProvider.swift | 48 +++---------------- FirebaseAuth/Tests/Unit/SwiftAPI.swift | 10 ---- 3 files changed, 9 insertions(+), 52 deletions(-) diff --git a/FirebaseAuth/CHANGELOG.md b/FirebaseAuth/CHANGELOG.md index 9c6bc4e9c9c..4263cf06d7e 100644 --- a/FirebaseAuth/CHANGELOG.md +++ b/FirebaseAuth/CHANGELOG.md @@ -1,6 +1,9 @@ # Unreleased - [removed] **Breaking Change**: Removed `ActionCodeSettings.dynamicLinkDomain`. +- [removed] **Breaking Change**: Remove deprecated Swift APIs using + `String`-typed `productID`s that were in favor of API that leverages the + `AuthProviderID` enum. Note, this only affects Swift clients. # 11.15.0 - [fixed] Fixed `Sendable` warnings introduced in the Xcode 26 beta. (#14996) diff --git a/FirebaseAuth/Sources/Swift/AuthProvider/OAuthProvider.swift b/FirebaseAuth/Sources/Swift/AuthProvider/OAuthProvider.swift index b8cca1f5fca..761f57cf5d1 100644 --- a/FirebaseAuth/Sources/Swift/AuthProvider/OAuthProvider.swift +++ b/FirebaseAuth/Sources/Swift/AuthProvider/OAuthProvider.swift @@ -34,13 +34,7 @@ import Foundation /// - providerID: The provider ID of the IDP for which this auth provider instance will be /// configured. /// - Returns: An instance of OAuthProvider corresponding to the specified provider ID. - #if !FIREBASE_CI - @available( - swift, - deprecated: 0.01, - message: "Use `provider(providerID: AuthProviderID) -> OAuthProvider` instead." - ) - #endif // !FIREBASE_CI + @available(swift 1000.0) // Objective-C only API @objc(providerWithProviderID:) open class func provider(providerID: String) -> OAuthProvider { return OAuthProvider(providerID: providerID, auth: Auth.auth()) } @@ -60,13 +54,7 @@ import Foundation /// configured. /// - auth: The auth instance to be associated with the OAuthProvider instance. /// - Returns: An instance of OAuthProvider corresponding to the specified provider ID. - #if !FIREBASE_CI - @available( - swift, - deprecated: 0.01, - message: "Use `provider(providerID: AuthProviderID, auth: Auth) -> OAuthProvider` instead." - ) - #endif // !FIREBASE_CI + @available(swift 1000.0) // Objective-C only API @objc(providerWithProviderID:auth:) open class func provider(providerID: String, auth: Auth) -> OAuthProvider { return OAuthProvider(providerID: providerID, auth: auth) @@ -136,13 +124,7 @@ import Foundation /// - Parameter accessToken: The access token associated with the Auth credential be created, if /// available. /// - Returns: An AuthCredential for the specified provider ID, ID token and access token. - #if !FIREBASE_CI - @available( - swift, - deprecated: 0.01, - message: "Use `credential(providerID: AuthProviderID, idToken: String, accessToken: String? = nil) -> OAuthCredential` instead." - ) - #endif // !FIREBASE_CI + @available(swift 1000.0) // Objective-C only API @objc(credentialWithProviderID:IDToken:accessToken:) public static func credential(withProviderID providerID: String, idToken: String, @@ -173,13 +155,7 @@ import Foundation /// - Parameter accessToken: The access token associated with the Auth credential be created, if /// available. /// - Returns: An AuthCredential for the specified provider ID, ID token and access token. - #if !FIREBASE_CI - @available( - swift, - deprecated: 0.01, - message: "Use `credential(providerID: AuthProviderID, accessToken: String) -> OAuthCredential` instead." - ) - #endif // !FIREBASE_CI + @available(swift 1000.0) // Objective-C only API @objc(credentialWithProviderID:accessToken:) public static func credential(withProviderID providerID: String, accessToken: String) -> OAuthCredential { @@ -203,13 +179,7 @@ import Foundation /// - Parameter rawNonce: The raw nonce associated with the Auth credential being created. /// - Parameter accessToken: The access token associated with the Auth credential be created. /// - Returns: An AuthCredential for the specified provider ID, ID token and access token. - #if !FIREBASE_CI - @available( - swift, - deprecated: 0.01, - message: "Use `credential(providerID: AuthProviderID, idToken: String, rawNonce: String, accessToken: String? = nil) -> OAuthCredential` instead." - ) - #endif // !FIREBASE_CI + @available(swift 1000.0) // Objective-C only API @objc(credentialWithProviderID:IDToken:rawNonce:accessToken:) public static func credential(withProviderID providerID: String, idToken: String, rawNonce: String, @@ -228,13 +198,7 @@ import Foundation /// - Parameter idToken: The IDToken associated with the Auth credential being created. /// - Parameter rawNonce: The raw nonce associated with the Auth credential being created. /// - Returns: An AuthCredential. - #if !FIREBASE_CI - @available( - swift, - deprecated: 0.01, - message: "Use `credential(providerID: AuthProviderID, idToken: String, rawNonce: String, accessToken: String? = nil) -> OAuthCredential` instead." - ) - #endif // !FIREBASE_CI + @available(swift 1000.0) // Objective-C only API @objc(credentialWithProviderID:IDToken:rawNonce:) public static func credential(withProviderID providerID: String, idToken: String, rawNonce: String) -> OAuthCredential { diff --git a/FirebaseAuth/Tests/Unit/SwiftAPI.swift b/FirebaseAuth/Tests/Unit/SwiftAPI.swift index d24b8db59ad..dec351aff3e 100644 --- a/FirebaseAuth/Tests/Unit/SwiftAPI.swift +++ b/FirebaseAuth/Tests/Unit/SwiftAPI.swift @@ -474,34 +474,24 @@ class AuthAPI_hOnlyTests: XCTestCase { func FIROAuthProvider_h() { let _: (String, Auth) -> OAuthProvider = OAuthProvider.init(providerID:auth:) let _: (AuthProviderID, Auth) -> OAuthProvider = OAuthProvider.init(providerID:auth:) - let _: (String) -> OAuthProvider = OAuthProvider.provider(providerID:) - let _: (String, Auth) -> OAuthProvider = OAuthProvider.provider(providerID:auth:) let _: (AuthProviderID) -> OAuthProvider = OAuthProvider.provider(providerID:) let _: (AuthProviderID, Auth) -> OAuthProvider = OAuthProvider.provider(providerID:auth:) // `auth` defaults to `nil` let provider = OAuthProvider(providerID: "id") let _: String = provider.providerID #if os(iOS) - let _: (String, String, String?) -> OAuthCredential = - OAuthProvider.credential(withProviderID:idToken:accessToken:) let _: (AuthProviderID, String, String?) -> OAuthCredential = OAuthProvider.credential(providerID:idToken:accessToken:) // `accessToken` defaults to `nil` let _: OAuthCredential = OAuthProvider.credential(providerID: .apple, idToken: "") - let _: (String, String) -> OAuthCredential = - OAuthProvider.credential(withProviderID:accessToken:) let _: (AuthProviderID, String) -> OAuthCredential = OAuthProvider .credential(providerID:accessToken:) - let _: (String, String, String, String) -> OAuthCredential = - OAuthProvider.credential(withProviderID:idToken:rawNonce:accessToken:) let _: (AuthProviderID, String, String, String?) -> OAuthCredential = OAuthProvider.credential(providerID:idToken:rawNonce:accessToken:) // `accessToken` defaults to `nil` let _: OAuthCredential = OAuthProvider.credential(providerID: .apple, idToken: "", rawNonce: "") - let _: (String, String, String) -> OAuthCredential = - OAuthProvider.credential(withProviderID:idToken:rawNonce:) provider.getCredentialWith(provider as? AuthUIDelegate) { credential, error in } From f4024f0393f3ae3f0d3f8a76bdd5ad098455db52 Mon Sep 17 00:00:00 2001 From: Nick Cooke <36927374+ncooke3@users.noreply.github.com> Date: Wed, 25 Jun 2025 10:47:45 -0400 Subject: [PATCH 107/113] [Auth] Remove `AuthErrorCode`s '.dynamicLinkNotActivated' & '.invalidDynamicLinkDomain' (#15042) --- FirebaseAuth/CHANGELOG.md | 7 +++++-- .../Sources/Swift/Utilities/AuthErrorUtils.swift | 4 ---- .../Sources/Swift/Utilities/AuthErrors.swift | 15 --------------- FirebaseAuth/Tests/Unit/ObjCAPITests.m | 2 -- FirebaseAuth/Tests/Unit/SwiftAPI.swift | 2 -- 5 files changed, 5 insertions(+), 25 deletions(-) diff --git a/FirebaseAuth/CHANGELOG.md b/FirebaseAuth/CHANGELOG.md index 4263cf06d7e..ff5e4e717f7 100644 --- a/FirebaseAuth/CHANGELOG.md +++ b/FirebaseAuth/CHANGELOG.md @@ -1,6 +1,9 @@ # Unreleased -- [removed] **Breaking Change**: Removed - `ActionCodeSettings.dynamicLinkDomain`. +- [removed] **Breaking Change**: Removed the following Dynamic Links related + APIs: + - `ActionCodeSettings.dynamicLinkDomain` + - `AuthErrorCode.dynamicLinkNotActivated` + - `AuthErrorCode.invalidDynamicLinkDomain` - [removed] **Breaking Change**: Remove deprecated Swift APIs using `String`-typed `productID`s that were in favor of API that leverages the `AuthProviderID` enum. Note, this only affects Swift clients. diff --git a/FirebaseAuth/Sources/Swift/Utilities/AuthErrorUtils.swift b/FirebaseAuth/Sources/Swift/Utilities/AuthErrorUtils.swift index 01ff6449b7f..5c78b223ab4 100644 --- a/FirebaseAuth/Sources/Swift/Utilities/AuthErrorUtils.swift +++ b/FirebaseAuth/Sources/Swift/Utilities/AuthErrorUtils.swift @@ -366,10 +366,6 @@ class AuthErrorUtils { error(code: .invalidProviderID, message: message) } - static func invalidDynamicLinkDomainError(message: String?) -> Error { - error(code: .invalidDynamicLinkDomain, message: message) - } - static func invalidHostingLinkDomainError(message: String?) -> Error { error(code: .invalidHostingLinkDomain, message: message) } diff --git a/FirebaseAuth/Sources/Swift/Utilities/AuthErrors.swift b/FirebaseAuth/Sources/Swift/Utilities/AuthErrors.swift index 4e97f492866..dde29c11ab3 100644 --- a/FirebaseAuth/Sources/Swift/Utilities/AuthErrors.swift +++ b/FirebaseAuth/Sources/Swift/Utilities/AuthErrors.swift @@ -240,9 +240,6 @@ import Foundation /// user was provided. case nullUser = 17067 - /// Indicates that a Firebase Dynamic Link is not activated. - case dynamicLinkNotActivated = 17068 - /// Represents the error code for when the given provider id for a web operation is invalid. case invalidProviderID = 17071 @@ -254,10 +251,6 @@ import Foundation /// ID for an operation that does not support multi-tenancy. case unsupportedTenantOperation = 17073 - /// Indicates that the Firebase Dynamic Link domain used is either not configured or is - /// unauthorized for the current project. - case invalidDynamicLinkDomain = 17074 - /// Indicates that the provided Firebase Hosting Link domain is not owned by the current project. case invalidHostingLinkDomain = 17214 @@ -469,8 +462,6 @@ import Foundation return kErrorNullUser case .invalidProviderID: return kErrorInvalidProviderID - case .invalidDynamicLinkDomain: - return kErrorInvalidDynamicLinkDomain case .invalidHostingLinkDomain: return kErrorInvalidHostingLinkDomain case .webInternalError: @@ -505,8 +496,6 @@ import Foundation return FIRAuthErrorMessageUnsupportedFirstFactor case .emailChangeNeedsVerification: return FIRAuthErrorMessageEmailChangeNeedsVerification - case .dynamicLinkNotActivated: - return kErrorDynamicLinkNotActivated case .rejectedCredential: return kErrorRejectedCredential case .missingOrInvalidNonce: @@ -664,8 +653,6 @@ import Foundation return "ERROR_NULL_USER" case .invalidProviderID: return "ERROR_INVALID_PROVIDER_ID" - case .invalidDynamicLinkDomain: - return "ERROR_INVALID_DYNAMIC_LINK_DOMAIN" case .invalidHostingLinkDomain: return "ERROR_INVALID_HOSTING_LINK_DOMAIN" case .webInternalError: @@ -700,8 +687,6 @@ import Foundation return "ERROR_UNSUPPORTED_FIRST_FACTOR" case .emailChangeNeedsVerification: return "ERROR_EMAIL_CHANGE_NEEDS_VERIFICATION" - case .dynamicLinkNotActivated: - return "ERROR_DYNAMIC_LINK_NOT_ACTIVATED" case .rejectedCredential: return "ERROR_REJECTED_CREDENTIAL" case .missingOrInvalidNonce: diff --git a/FirebaseAuth/Tests/Unit/ObjCAPITests.m b/FirebaseAuth/Tests/Unit/ObjCAPITests.m index ed664c45e09..6784beb8548 100644 --- a/FirebaseAuth/Tests/Unit/ObjCAPITests.m +++ b/FirebaseAuth/Tests/Unit/ObjCAPITests.m @@ -275,11 +275,9 @@ - (void)FIRAuthErrors_h { c = FIRAuthErrorCodeWebSignInUserInteractionFailure; c = FIRAuthErrorCodeLocalPlayerNotAuthenticated; c = FIRAuthErrorCodeNullUser; - c = FIRAuthErrorCodeDynamicLinkNotActivated; c = FIRAuthErrorCodeInvalidProviderID; c = FIRAuthErrorCodeTenantIDMismatch; c = FIRAuthErrorCodeUnsupportedTenantOperation; - c = FIRAuthErrorCodeInvalidDynamicLinkDomain; c = FIRAuthErrorCodeInvalidHostingLinkDomain; c = FIRAuthErrorCodeRejectedCredential; c = FIRAuthErrorCodeGameKitNotLinked; diff --git a/FirebaseAuth/Tests/Unit/SwiftAPI.swift b/FirebaseAuth/Tests/Unit/SwiftAPI.swift index dec351aff3e..f39f188f9f1 100644 --- a/FirebaseAuth/Tests/Unit/SwiftAPI.swift +++ b/FirebaseAuth/Tests/Unit/SwiftAPI.swift @@ -273,11 +273,9 @@ class AuthAPI_hOnlyTests: XCTestCase { _ = AuthErrorCode.webSignInUserInteractionFailure _ = AuthErrorCode.localPlayerNotAuthenticated _ = AuthErrorCode.nullUser - _ = AuthErrorCode.dynamicLinkNotActivated _ = AuthErrorCode.invalidProviderID _ = AuthErrorCode.tenantIDMismatch _ = AuthErrorCode.unsupportedTenantOperation - _ = AuthErrorCode.invalidDynamicLinkDomain _ = AuthErrorCode.invalidHostingLinkDomain _ = AuthErrorCode.rejectedCredential _ = AuthErrorCode.gameKitNotLinked From 1450754c11f316b503a438fe8dc6f2361fa83701 Mon Sep 17 00:00:00 2001 From: Tushar Khandelwal <64364243+tusharkhandelwal8@users.noreply.github.com> Date: Fri, 27 Jun 2025 19:46:10 +0530 Subject: [PATCH 108/113] Improve Real-time response Handling for Remote Config (#15031) Co-authored-by: Nick Cooke <36927374+ncooke3@users.noreply.github.com> --- FirebaseRemoteConfig/CHANGELOG.md | 6 ++++ .../Sources/Private/RCNConfigSettings.h | 4 +++ .../Sources/RCNConfigRealtime.m | 13 ++++++++ .../Sources/RCNConfigSettings.m | 10 ++++++ .../Tests/Unit/RCNRemoteConfigTest.m | 31 +++++++++++++++++++ 5 files changed, 64 insertions(+) diff --git a/FirebaseRemoteConfig/CHANGELOG.md b/FirebaseRemoteConfig/CHANGELOG.md index b1ca12b48c3..dfabf29af0f 100644 --- a/FirebaseRemoteConfig/CHANGELOG.md +++ b/FirebaseRemoteConfig/CHANGELOG.md @@ -1,3 +1,9 @@ +# Unreleased +- [added] Improved how the SDK handles real-time requests when a Firebase + project has exceeded its available quota for real-time services. + Released in anticipation of future quota enforcement, this change is + designed to fetch the latest template even when the quota is exhausted. + # 11.14.0 - [fixed] Fix build warning from comparison of different enumeration types. diff --git a/FirebaseRemoteConfig/Sources/Private/RCNConfigSettings.h b/FirebaseRemoteConfig/Sources/Private/RCNConfigSettings.h index eb2a4ff27f0..d8adb236323 100644 --- a/FirebaseRemoteConfig/Sources/Private/RCNConfigSettings.h +++ b/FirebaseRemoteConfig/Sources/Private/RCNConfigSettings.h @@ -135,6 +135,10 @@ /// indicates a server issue. - (void)updateRealtimeExponentialBackoffTime; +/// Increases the throttling time for Realtime. Should only be called if we receive a Realtime +/// retry interval in the response. +- (void)updateRealtimeBackoffTimeWithInterval:(NSTimeInterval)realtimeRetryInterval; + /// Update last active template version from last fetched template version. - (void)updateLastActiveTemplateVersion; diff --git a/FirebaseRemoteConfig/Sources/RCNConfigRealtime.m b/FirebaseRemoteConfig/Sources/RCNConfigRealtime.m index ddc6f21ccec..2c998eae18a 100644 --- a/FirebaseRemoteConfig/Sources/RCNConfigRealtime.m +++ b/FirebaseRemoteConfig/Sources/RCNConfigRealtime.m @@ -59,6 +59,7 @@ /// Invalidation message field names. static NSString *const kTemplateVersionNumberKey = @"latestTemplateVersionNumber"; static NSString *const kIsFeatureDisabled = @"featureDisabled"; +static NSString *const kRealtime_Retry_Interval = @"retryIntervalSeconds"; static NSTimeInterval gTimeoutSeconds = 330; static NSInteger const gFetchAttempts = 3; @@ -521,6 +522,7 @@ - (void)autoFetch:(NSInteger)remainingAttempts targetVersion:(NSInteger)targetVe - (void)evaluateStreamResponse:(NSDictionary *)response error:(NSError *)dataError { NSInteger updateTemplateVersion = 1; + NSTimeInterval realtimeRetryInterval = 0; if (dataError == nil) { if ([response objectForKey:kTemplateVersionNumberKey]) { updateTemplateVersion = [[response objectForKey:kTemplateVersionNumberKey] integerValue]; @@ -528,6 +530,9 @@ - (void)evaluateStreamResponse:(NSDictionary *)response error:(NSError *)dataErr if ([response objectForKey:kIsFeatureDisabled]) { self->_isRealtimeDisabled = [response objectForKey:kIsFeatureDisabled]; } + if ([response objectForKey:kRealtime_Retry_Interval]) { + realtimeRetryInterval = [[response objectForKey:kRealtime_Retry_Interval] integerValue]; + } if (self->_isRealtimeDisabled) { [self pauseRealtimeStream]; @@ -544,6 +549,14 @@ - (void)evaluateStreamResponse:(NSDictionary *)response error:(NSError *)dataErr if (updateTemplateVersion > clientTemplateVersion) { [self autoFetch:gFetchAttempts targetVersion:updateTemplateVersion]; } + + /// This field in the response indicates that the realtime request should retry after the + /// specified interval to establish a long-lived connection. This interval extends the backoff + /// duration without affecting the number of retries, so it will not enter an exponential + /// backoff state. + if (realtimeRetryInterval > 0) { + [self->_settings updateRealtimeBackoffTimeWithInterval:realtimeRetryInterval]; + } } } else { NSError *error = diff --git a/FirebaseRemoteConfig/Sources/RCNConfigSettings.m b/FirebaseRemoteConfig/Sources/RCNConfigSettings.m index 5fe34c724fd..115a615b845 100644 --- a/FirebaseRemoteConfig/Sources/RCNConfigSettings.m +++ b/FirebaseRemoteConfig/Sources/RCNConfigSettings.m @@ -234,6 +234,16 @@ - (void)updateRealtimeExponentialBackoffTime { setCurrentRealtimeThrottlingRetryIntervalSeconds:_realtimeExponentialBackoffRetryInterval]; } +/// Increase the real-time stream's backoff period from the current time plus the retry interval. +/// Any subsequent Realtime requests will be checked and allowed only if past this throttle end +/// time. +- (void)updateRealtimeBackoffTimeWithInterval:(NSTimeInterval)realtimeRetryInterval { + _realtimeExponentialBackoffThrottleEndTime = + [[NSDate date] timeIntervalSince1970] + realtimeRetryInterval; + + [_userDefaultsManager setRealtimeThrottleEndTime:_realtimeExponentialBackoffThrottleEndTime]; +} + - (void)setRealtimeRetryCount:(int)realtimeRetryCount { _realtimeRetryCount = realtimeRetryCount; [_userDefaultsManager setRealtimeRetryCount:_realtimeRetryCount]; diff --git a/FirebaseRemoteConfig/Tests/Unit/RCNRemoteConfigTest.m b/FirebaseRemoteConfig/Tests/Unit/RCNRemoteConfigTest.m index 9786af20cbf..7e5ad497b12 100644 --- a/FirebaseRemoteConfig/Tests/Unit/RCNRemoteConfigTest.m +++ b/FirebaseRemoteConfig/Tests/Unit/RCNRemoteConfigTest.m @@ -1785,6 +1785,37 @@ - (void)testRealtimeDisabled { } } +- (void)testRealtimeUpdatesBackoffMetadataWhenRetryIntervalIsProvided { + NSMutableArray *expectations = + [[NSMutableArray alloc] initWithCapacity:RCNTestRCNumTotalInstances]; + for (int i = 0; i < RCNTestRCNumTotalInstances; i++) { + expectations[i] = + [self expectationWithDescription: + [NSString stringWithFormat:@"Test backoff metadata updates with a provided retry " + @"interval in the stream response - instance %d", + i]]; + NSTimeInterval realtimeRetryInterval = 240; + NSMutableDictionary *dictionary = [[NSMutableDictionary alloc] init]; + [dictionary setValue:@"1" forKey:@"latestTemplateVersionNumber"]; + [dictionary setValue:@(realtimeRetryInterval) forKey:@"retryIntervalSeconds"]; + + NSTimeInterval expectedThrottleEndTime = + [[NSDate date] timeIntervalSince1970] + realtimeRetryInterval; + + [_configRealtime[i] evaluateStreamResponse:dictionary error:nil]; + dispatch_after( + dispatch_time(DISPATCH_TIME_NOW, (int64_t)(_checkCompletionTimeout * NSEC_PER_SEC)), + dispatch_get_main_queue(), ^{ + NSTimeInterval retrievedThrottleEndTime = + self->_configInstances[i].settings.realtimeExponentialBackoffThrottleEndTime; + XCTAssertEqualWithAccuracy(retrievedThrottleEndTime, expectedThrottleEndTime, 1.0); + [expectations[i] fulfill]; + }); + + [self waitForExpectationsWithTimeout:_expectationTimeout handler:nil]; + } +} + - (void)testRealtimeStreamRequestBody { XCTestExpectation *requestBodyExpectation = [self expectationWithDescription:@"requestBody"]; __block NSData *requestBody; From ddcd6e99f15c05b31f3ac8fa6f240406b2eaf576 Mon Sep 17 00:00:00 2001 From: themiswang Date: Fri, 27 Jun 2025 18:56:10 +0000 Subject: [PATCH 109/113] Change iPadOS26 session background listener for session background (#15047) --- .../Sources/SessionInitiator.swift | 28 +++++++++++++++---- 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/FirebaseSessions/Sources/SessionInitiator.swift b/FirebaseSessions/Sources/SessionInitiator.swift index 745f8e969c5..9524fdbae73 100644 --- a/FirebaseSessions/Sources/SessionInitiator.swift +++ b/FirebaseSessions/Sources/SessionInitiator.swift @@ -22,6 +22,12 @@ import Foundation import WatchKit #endif // os(iOS) || os(tvOS) +#if SWIFT_PACKAGE + internal import GoogleUtilities_Environment +#else + internal import GoogleUtilities +#endif // SWIFT_PACKAGE + /// The SessionInitiator is responsible for: /// 1) Running the initiate callback whenever a Session Start Event should /// begin sending. This can happen at a cold start of the app, and when it @@ -45,12 +51,22 @@ class SessionInitiator { let notificationCenter = NotificationCenter.default #if os(iOS) || os(tvOS) || os(visionOS) - notificationCenter.addObserver( - self, - selector: #selector(appBackgrounded), - name: UIApplication.didEnterBackgroundNotification, - object: nil - ) + // Change background update event listerner for iPadOS 26 multi-windowing supoort + if #available(iOS 26, *), GULAppEnvironmentUtil.appleDevicePlatform().contains("ipados") { + notificationCenter.addObserver( + self, + selector: #selector(appBackgrounded), + name: UIApplication.willResignActiveNotification, + object: nil + ) + } else { + notificationCenter.addObserver( + self, + selector: #selector(appBackgrounded), + name: UIApplication.didEnterBackgroundNotification, + object: nil + ) + } notificationCenter.addObserver( self, selector: #selector(appForegrounded), From 25f2f46adcd6384716d2c34d1b19337263409608 Mon Sep 17 00:00:00 2001 From: Nick Cooke <36927374+ncooke3@users.noreply.github.com> Date: Fri, 27 Jun 2025 18:04:16 -0400 Subject: [PATCH 110/113] [Infra] For SPM, defer to Xcode for supported platform versions (#15039) --- Package.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Package.swift b/Package.swift index ca900df3f4b..9e7a4a0b4fc 100644 --- a/Package.swift +++ b/Package.swift @@ -23,7 +23,7 @@ let firebaseVersion = "12.0.0" let package = Package( name: "Firebase", - platforms: [.iOS(.v12), .macCatalyst(.v13), .macOS(.v10_15), .tvOS(.v13), .watchOS(.v7)], + platforms: [.iOS(.v15), .macCatalyst(.v15), .macOS(.v10_15), .tvOS(.v15), .watchOS(.v7)], products: [ .library( name: "FirebaseAI", From 5af1fdbf805054900400aeab17c310c76b4bd0c4 Mon Sep 17 00:00:00 2001 From: Nick Cooke <36927374+ncooke3@users.noreply.github.com> Date: Mon, 30 Jun 2025 09:49:50 -0400 Subject: [PATCH 111/113] [FIAM] Remove dep. warning (#15051) --- .../Public/FirebaseInAppMessaging/FirebaseInAppMessaging.h | 4 ---- 1 file changed, 4 deletions(-) diff --git a/FirebaseInAppMessaging/Sources/Public/FirebaseInAppMessaging/FirebaseInAppMessaging.h b/FirebaseInAppMessaging/Sources/Public/FirebaseInAppMessaging/FirebaseInAppMessaging.h index b2ebc7dae8f..cbfc7bed0f6 100644 --- a/FirebaseInAppMessaging/Sources/Public/FirebaseInAppMessaging/FirebaseInAppMessaging.h +++ b/FirebaseInAppMessaging/Sources/Public/FirebaseInAppMessaging/FirebaseInAppMessaging.h @@ -17,7 +17,3 @@ #import "FIRInAppMessaging.h" #import "FIRInAppMessagingErrors.h" #import "FIRInAppMessagingRendering.h" - -#if __has_include() -#warning The FirebaseInAppMessagingDisplay subspec is deprecated. Please remove FirebaseInAppMessagingDisplay from your Podfile (or delete the framework). -#endif From c3cc79ace252e26d2b61c471d75f51d7a28266c1 Mon Sep 17 00:00:00 2001 From: cherylEnkidu Date: Mon, 30 Jun 2025 15:09:50 -0400 Subject: [PATCH 112/113] fix merge --- FirebaseAnalyticsCoreWrapper/include/dummy.h | 8 ------ .../FirebaseFirestore/FIRPipelineBridge.h | 26 ------------------- 2 files changed, 34 deletions(-) delete mode 100644 FirebaseFirestoreInternal/FirebaseFirestore/FIRPipelineBridge.h diff --git a/FirebaseAnalyticsCoreWrapper/include/dummy.h b/FirebaseAnalyticsCoreWrapper/include/dummy.h index 875962d7967..4fe40eb40cd 100644 --- a/FirebaseAnalyticsCoreWrapper/include/dummy.h +++ b/FirebaseAnalyticsCoreWrapper/include/dummy.h @@ -1,9 +1,5 @@ /* -<<<<<<<< HEAD:FirebaseFirestoreInternal/FirebaseFirestore/FIRPipelineBridge.h - * Copyright 2025 Google LLC -======== * Copyright 2021 Google LLC ->>>>>>>> main:FirebaseAnalyticsCoreWrapper/include/dummy.h * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,9 +14,5 @@ * limitations under the License. */ -<<<<<<<< HEAD:FirebaseFirestoreInternal/FirebaseFirestore/FIRPipelineBridge.h -#import -======== // Swift Package Manager needs at least one header to prevent a warning. See // https://github.com/firebase/firebase-ios-sdk/pull/6504. ->>>>>>>> main:FirebaseAnalyticsCoreWrapper/include/dummy.h diff --git a/FirebaseFirestoreInternal/FirebaseFirestore/FIRPipelineBridge.h b/FirebaseFirestoreInternal/FirebaseFirestore/FIRPipelineBridge.h deleted file mode 100644 index 875962d7967..00000000000 --- a/FirebaseFirestoreInternal/FirebaseFirestore/FIRPipelineBridge.h +++ /dev/null @@ -1,26 +0,0 @@ -/* -<<<<<<<< HEAD:FirebaseFirestoreInternal/FirebaseFirestore/FIRPipelineBridge.h - * Copyright 2025 Google LLC -======== - * Copyright 2021 Google LLC ->>>>>>>> main:FirebaseAnalyticsCoreWrapper/include/dummy.h - * - * 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. - */ - -<<<<<<<< HEAD:FirebaseFirestoreInternal/FirebaseFirestore/FIRPipelineBridge.h -#import -======== -// Swift Package Manager needs at least one header to prevent a warning. See -// https://github.com/firebase/firebase-ios-sdk/pull/6504. ->>>>>>>> main:FirebaseAnalyticsCoreWrapper/include/dummy.h From 33bc8892ea53eaffb699341e38ff2262b98dcc39 Mon Sep 17 00:00:00 2001 From: cherylEnkidu <96084918+cherylEnkidu@users.noreply.github.com> Date: Mon, 30 Jun 2025 15:59:16 -0400 Subject: [PATCH 113/113] Pipeline tests part 3 (#15005) Co-authored-by: wu-hui Co-authored-by: Nick Cooke <36927374+ncooke3@users.noreply.github.com> --- Firestore/Source/API/FIRPipelineBridge.mm | 40 +- .../FirebaseFirestore/FIRPipelineBridge.h | 7 +- Firestore/Swift/Source/ExprImpl.swift | 85 +- .../Swift/Source/Helper/PipelineHelper.swift | 50 +- .../Swift/Source/SwiftAPI/Pipeline/Expr.swift | 90 +- .../SwiftAPI/Pipeline/Expr/Constant.swift | 9 +- .../Source/SwiftAPI/Pipeline/Expr/Field.swift | 14 +- .../Expr/FunctionExpr/BooleanExpr.swift | 4 + .../Expr/FunctionExpr/RandomExpr.swift | 19 + .../SwiftAPI/Pipeline/PipelineResult.swift | 8 +- Firestore/Swift/Source/SwiftAPI/Stages.swift | 2 +- .../Tests/Integration/PipelineTests.swift | 1682 ++++++++++++++++- .../Swift/Tests/TestHelper/TestHelper.swift | 12 +- Firestore/core/src/api/stages.cc | 10 +- Firestore/core/src/api/stages.h | 10 +- 15 files changed, 1870 insertions(+), 172 deletions(-) create mode 100644 Firestore/Swift/Source/SwiftAPI/Pipeline/Expr/FunctionExpr/RandomExpr.swift diff --git a/Firestore/Source/API/FIRPipelineBridge.mm b/Firestore/Source/API/FIRPipelineBridge.mm index 11f3f4c56d5..4a87351c4c5 100644 --- a/Firestore/Source/API/FIRPipelineBridge.mm +++ b/Firestore/Source/API/FIRPipelineBridge.mm @@ -73,7 +73,9 @@ using firebase::firestore::api::Union; using firebase::firestore::api::Unnest; using firebase::firestore::api::Where; +using firebase::firestore::model::DeepClone; using firebase::firestore::model::FieldPath; +using firebase::firestore::nanopb::MakeSharedMessage; using firebase::firestore::nanopb::SharedMessage; using firebase::firestore::util::ComparisonResult; using firebase::firestore::util::MakeCallback; @@ -94,13 +96,24 @@ @implementation FIRExprBridge @end @implementation FIRFieldBridge { + FIRFieldPath *field_path; std::shared_ptr field; } -- (id)init:(NSString *)name { +- (id)initWithName:(NSString *)name { self = [super init]; if (self) { - field = std::make_shared(MakeString(name)); + field_path = [FIRFieldPath pathWithDotSeparatedString:name]; + field = std::make_shared([field_path internalValue].CanonicalString()); + } + return self; +} + +- (id)initWithPath:(FIRFieldPath *)path { + self = [super init]; + if (self) { + field_path = path; + field = std::make_shared([field_path internalValue].CanonicalString()); } return self; } @@ -109,6 +122,10 @@ - (id)init:(NSString *)name { return field; } +- (NSString *)field_name { + return MakeNSString([field_path internalValue].CanonicalString()); +} + @end @implementation FIRConstantBridge { @@ -560,7 +577,7 @@ @implementation FIRFindNearestStageBridge { FIRVectorValue *_vectorValue; NSString *_distanceMeasure; NSNumber *_limit; - NSString *_Nullable _distanceField; + FIRExprBridge *_Nullable _distanceField; Boolean isUserDataRead; std::shared_ptr cpp_find_nearest; } @@ -569,7 +586,7 @@ - (id)initWithField:(FIRFieldBridge *)field vectorValue:(FIRVectorValue *)vectorValue distanceMeasure:(NSString *)distanceMeasure limit:(NSNumber *_Nullable)limit - distanceField:(NSString *_Nullable)distanceField { + distanceField:(FIRExprBridge *_Nullable)distanceField { self = [super init]; if (self) { _field = field; @@ -584,21 +601,16 @@ - (id)initWithField:(FIRFieldBridge *)field - (std::shared_ptr)cppStageWithReader:(FSTUserDataReader *)reader { if (!isUserDataRead) { - std::unordered_map> - optional_value; + std::unordered_map optional_value; if (_limit) { - optional_value.emplace( - std::make_pair(std::string("limit"), - nanopb::SharedMessage( - [reader parsedQueryValue:_limit]))); + optional_value.emplace(std::make_pair( + std::string("limit"), *DeepClone(*[reader parsedQueryValue:_limit]).release())); } if (_distanceField) { + std::shared_ptr cpp_distance_field = [_distanceField cppExprWithReader:reader]; optional_value.emplace( - std::make_pair(std::string("distance_field"), - nanopb::SharedMessage( - [reader parsedQueryValue:_distanceField]))); + std::make_pair(std::string("distance_field"), cpp_distance_field->to_proto())); } FindNearestStage::DistanceMeasure::Measure measure_enum; diff --git a/Firestore/Source/Public/FirebaseFirestore/FIRPipelineBridge.h b/Firestore/Source/Public/FirebaseFirestore/FIRPipelineBridge.h index cf72c897f3b..e148637d48a 100644 --- a/Firestore/Source/Public/FirebaseFirestore/FIRPipelineBridge.h +++ b/Firestore/Source/Public/FirebaseFirestore/FIRPipelineBridge.h @@ -23,6 +23,7 @@ @class FIRTimestamp; @class FIRVectorValue; @class FIRPipelineBridge; +@class FIRFieldPath; NS_ASSUME_NONNULL_BEGIN @@ -34,7 +35,9 @@ NS_SWIFT_NAME(ExprBridge) NS_SWIFT_SENDABLE NS_SWIFT_NAME(FieldBridge) @interface FIRFieldBridge : FIRExprBridge -- (id)init:(NSString *)name; +- (id)initWithName:(NSString *)name; +- (id)initWithPath:(FIRFieldPath *)path; +- (NSString *)field_name; @end NS_SWIFT_SENDABLE @@ -160,7 +163,7 @@ NS_SWIFT_NAME(FindNearestStageBridge) vectorValue:(FIRVectorValue *)vectorValue distanceMeasure:(NSString *)distanceMeasure limit:(NSNumber *_Nullable)limit - distanceField:(NSString *_Nullable)distanceField; + distanceField:(FIRExprBridge *_Nullable)distanceField; @end NS_SWIFT_SENDABLE diff --git a/Firestore/Swift/Source/ExprImpl.swift b/Firestore/Swift/Source/ExprImpl.swift index 6d55a7b479b..51a82966b86 100644 --- a/Firestore/Swift/Source/ExprImpl.swift +++ b/Firestore/Swift/Source/ExprImpl.swift @@ -25,14 +25,12 @@ public extension Expr { // MARK: Arithmetic Operators - func add(_ second: Expr, _ others: Expr...) -> FunctionExpr { - return FunctionExpr("add", [self, second] + others) + func add(_ value: Expr) -> FunctionExpr { + return FunctionExpr("add", [self, value]) } - func add(_ second: Sendable, _ others: Sendable...) -> FunctionExpr { - let exprs = [self] + [Helper.sendableToExpr(second)] + others - .map { Helper.sendableToExpr($0) } - return FunctionExpr("add", exprs) + func add(_ value: Sendable) -> FunctionExpr { + return FunctionExpr("add", [self, Helper.sendableToExpr(value)]) } func subtract(_ other: Expr) -> FunctionExpr { @@ -43,14 +41,12 @@ public extension Expr { return FunctionExpr("subtract", [self, Helper.sendableToExpr(other)]) } - func multiply(_ second: Expr, _ others: Expr...) -> FunctionExpr { - return FunctionExpr("multiply", [self, second] + others) + func multiply(_ value: Expr) -> FunctionExpr { + return FunctionExpr("multiply", [self, value]) } - func multiply(_ second: Sendable, _ others: Sendable...) -> FunctionExpr { - let exprs = [self] + [Helper.sendableToExpr(second)] + others - .map { Helper.sendableToExpr($0) } - return FunctionExpr("multiply", exprs) + func multiply(_ value: Sendable) -> FunctionExpr { + return FunctionExpr("multiply", [self, Helper.sendableToExpr(value)]) } func divide(_ other: Expr) -> FunctionExpr { @@ -89,34 +85,32 @@ public extension Expr { return BooleanExpr("array_contains", [self, Helper.sendableToExpr(element)]) } - func arrayContainsAll(_ values: Expr...) -> BooleanExpr { - return BooleanExpr("array_contains_all", [self] + values) + func arrayContainsAll(_ values: [Expr]) -> BooleanExpr { + return BooleanExpr("array_contains_all", [self, Helper.array(values)]) } - func arrayContainsAll(_ values: Sendable...) -> BooleanExpr { - let exprValues = values.map { Helper.sendableToExpr($0) } - return BooleanExpr("array_contains_all", [self] + exprValues) + func arrayContainsAll(_ values: [Sendable]) -> BooleanExpr { + return BooleanExpr("array_contains_all", [self, Helper.array(values)]) } - func arrayContainsAny(_ values: Expr...) -> BooleanExpr { - return BooleanExpr("array_contains_any", [self] + values) + func arrayContainsAny(_ values: [Expr]) -> BooleanExpr { + return BooleanExpr("array_contains_any", [self, Helper.array(values)]) } - func arrayContainsAny(_ values: Sendable...) -> BooleanExpr { - let exprValues = values.map { Helper.sendableToExpr($0) } - return BooleanExpr("array_contains_any", [self] + exprValues) + func arrayContainsAny(_ values: [Sendable]) -> BooleanExpr { + return BooleanExpr("array_contains_any", [self, Helper.array(values)]) } func arrayLength() -> FunctionExpr { return FunctionExpr("array_length", [self]) } - func arrayOffset(_ offset: Int) -> FunctionExpr { - return FunctionExpr("array_offset", [self, Helper.sendableToExpr(offset)]) + func arrayGet(_ offset: Int) -> FunctionExpr { + return FunctionExpr("array_get", [self, Helper.sendableToExpr(offset)]) } - func arrayOffset(_ offsetExpr: Expr) -> FunctionExpr { - return FunctionExpr("array_offset", [self, offsetExpr]) + func arrayGet(_ offsetExpr: Expr) -> FunctionExpr { + return FunctionExpr("array_get", [self, offsetExpr]) } func gt(_ other: Expr) -> BooleanExpr { @@ -172,31 +166,28 @@ public extension Expr { return BooleanExpr("eq", [self, exprOther]) } - func neq(_ others: Expr...) -> BooleanExpr { - return BooleanExpr("neq", [self] + others) + func neq(_ other: Expr) -> BooleanExpr { + return BooleanExpr("neq", [self, other]) } - func neq(_ others: Sendable...) -> BooleanExpr { - let exprOthers = others.map { Helper.sendableToExpr($0) } - return BooleanExpr("neq", [self] + exprOthers) + func neq(_ other: Sendable) -> BooleanExpr { + return BooleanExpr("neq", [self, Helper.sendableToExpr(other)]) } - func eqAny(_ others: Expr...) -> BooleanExpr { - return BooleanExpr("eq_any", [self] + others) + func eqAny(_ others: [Expr]) -> BooleanExpr { + return BooleanExpr("eq_any", [self, Helper.array(others)]) } - func eqAny(_ others: Sendable...) -> BooleanExpr { - let exprOthers = others.map { Helper.sendableToExpr($0) } - return BooleanExpr("eq_any", [self] + exprOthers) + func eqAny(_ others: [Sendable]) -> BooleanExpr { + return BooleanExpr("eq_any", [self, Helper.array(others)]) } - func notEqAny(_ others: Expr...) -> BooleanExpr { - return BooleanExpr("not_eq_any", [self] + others) + func notEqAny(_ others: [Expr]) -> BooleanExpr { + return BooleanExpr("not_eq_any", [self, Helper.array(others)]) } - func notEqAny(_ others: Sendable...) -> BooleanExpr { - let exprOthers = others.map { Helper.sendableToExpr($0) } - return BooleanExpr("not_eq_any", [self] + exprOthers) + func notEqAny(_ others: [Sendable]) -> BooleanExpr { + return BooleanExpr("not_eq_any", [self, Helper.array(others)]) } // MARK: Checks @@ -237,12 +228,12 @@ public extension Expr { return FunctionExpr("char_length", [self]) } - func like(_ pattern: String) -> FunctionExpr { - return FunctionExpr("like", [self, Helper.sendableToExpr(pattern)]) + func like(_ pattern: String) -> BooleanExpr { + return BooleanExpr("like", [self, Helper.sendableToExpr(pattern)]) } - func like(_ pattern: Expr) -> FunctionExpr { - return FunctionExpr("like", [self, pattern]) + func like(_ pattern: Expr) -> BooleanExpr { + return BooleanExpr("like", [self, pattern]) } func regexContains(_ pattern: String) -> BooleanExpr { @@ -414,13 +405,13 @@ public extension Expr { } func logicalMinimum(_ second: Expr, _ others: Expr...) -> FunctionExpr { - return FunctionExpr("logical_min", [self, second] + others) + return FunctionExpr("logical_minimum", [self, second] + others) } func logicalMinimum(_ second: Sendable, _ others: Sendable...) -> FunctionExpr { let exprs = [self] + [Helper.sendableToExpr(second)] + others .map { Helper.sendableToExpr($0) } - return FunctionExpr("logical_min", exprs) + return FunctionExpr("logical_minimum", exprs) } // MARK: Vector Operations diff --git a/Firestore/Swift/Source/Helper/PipelineHelper.swift b/Firestore/Swift/Source/Helper/PipelineHelper.swift index cde334b7ae8..0d0e6b55d59 100644 --- a/Firestore/Swift/Source/Helper/PipelineHelper.swift +++ b/Firestore/Swift/Source/Helper/PipelineHelper.swift @@ -18,12 +18,14 @@ enum Helper { return Constant.nil } - if value is Expr { - return value as! Expr - } else if value is [String: Sendable?] { - return map(value as! [String: Sendable?]) - } else if value is [Sendable?] { - return array(value as! [Sendable?]) + if let exprValue = value as? Expr { + return exprValue + } else if let dictionaryValue = value as? [String: Sendable?] { + return map(dictionaryValue) + } else if let arrayValue = value as? [Sendable?] { + return array(arrayValue) + } else if let timeUnitValue = value as? TimeUnit { + return Constant(timeUnitValue.rawValue) } else { return Constant(value) } @@ -31,7 +33,9 @@ enum Helper { static func selectablesToMap(selectables: [Selectable]) -> [String: Expr] { let exprMap = selectables.reduce(into: [String: Expr]()) { result, selectable in - let value = selectable as! SelectableWrapper + guard let value = selectable as? SelectableWrapper else { + fatalError("Selectable class must conform to SelectableWrapper.") + } result[value.alias] = value.expr } return exprMap @@ -55,22 +59,18 @@ enum Helper { // This function is used to convert Swift type into Objective-C type. static func sendableToAnyObjectForRawStage(_ value: Sendable?) -> AnyObject { - guard let value = value else { - return Constant.nil.bridge - } - - guard !(value is NSNull) else { + guard let value = value, !(value is NSNull) else { return Constant.nil.bridge } - if value is Expr { - return (value as! Expr).toBridge() - } else if value is AggregateFunction { - return (value as! AggregateFunction).toBridge() - } else if value is [String: Sendable?] { - let mappedValue: [String: Sendable?] = (value as! [String: Sendable?]).mapValues { - if $0 is AggregateFunction { - return ($0 as! AggregateFunction).toBridge() + if let exprValue = value as? Expr { + return exprValue.toBridge() + } else if let aggregateFunctionValue = value as? AggregateFunction { + return aggregateFunctionValue.toBridge() + } else if let dictionaryValue = value as? [String: Sendable?] { + let mappedValue: [String: Sendable] = dictionaryValue.mapValues { + if let aggFunc = $0 as? AggregateFunction { + return aggFunc.toBridge() } return sendableToExpr($0).toBridge() } @@ -79,4 +79,14 @@ enum Helper { return Constant(value).bridge } } + + static func convertObjCToSwift(_ objValue: Sendable) -> Sendable? { + switch objValue { + case is NSNull: + return nil + + default: + return objValue + } + } } diff --git a/Firestore/Swift/Source/SwiftAPI/Pipeline/Expr.swift b/Firestore/Swift/Source/SwiftAPI/Pipeline/Expr.swift index 7cd9b0d5adf..d05c6a4c251 100644 --- a/Firestore/Swift/Source/SwiftAPI/Pipeline/Expr.swift +++ b/Firestore/Swift/Source/SwiftAPI/Pipeline/Expr.swift @@ -49,10 +49,9 @@ public protocol Expr: Sendable { /// Field("subtotal").add(Field("tax"), Field("shipping")) /// ``` /// - /// - Parameter second: An `Expr` to add to this expression. - /// - Parameter others: Optional additional `Expr` values to add. + /// - Parameter value: Expr` values to add. /// - Returns: A new `FunctionExpr` representing the addition operation. - func add(_ second: Expr, _ others: Expr...) -> FunctionExpr + func add(_ value: Expr) -> FunctionExpr /// Creates an expression that adds this expression to one or more literal values. /// Assumes `self` and all parameters evaluate to compatible types for addition. @@ -65,10 +64,9 @@ public protocol Expr: Sendable { /// Field("score").add(10, 20, -5) /// ``` /// - /// - Parameter second: A `Sendable` literal value to add to this expression. - /// - Parameter others: Optional additional `Sendable` literal values to add. + /// - Parameter value: Expr` value to add. /// - Returns: A new `FunctionExpr` representing the addition operation. - func add(_ second: Sendable, _ others: Sendable...) -> FunctionExpr + func add(_ value: Sendable) -> FunctionExpr /// Creates an expression that subtracts another expression from this expression. /// Assumes `self` and `other` evaluate to numeric types. @@ -105,10 +103,9 @@ public protocol Expr: Sendable { /// Field("rate").multiply(Field("time"), Field("conversionFactor")) /// ``` /// - /// - Parameter second: An `Expr` to multiply by. - /// - Parameter others: Optional additional `Expr` values to multiply by. + /// - Parameter value: `Expr` value to multiply by. /// - Returns: A new `FunctionExpr` representing the multiplication operation. - func multiply(_ second: Expr, _ others: Expr...) -> FunctionExpr + func multiply(_ value: Expr) -> FunctionExpr /// Creates an expression that multiplies this expression by one or more literal values. /// Assumes `self` evaluates to a numeric type. @@ -121,10 +118,9 @@ public protocol Expr: Sendable { /// Field("base").multiply(2, 3.0) /// ``` /// - /// - Parameter second: A `Sendable` literal value to multiply by. - /// - Parameter others: Optional additional `Sendable` literal values to multiply by. + /// - Parameter value: `Sendable` literal value to multiply by. /// - Returns: A new `FunctionExpr` representing the multiplication operation. - func multiply(_ second: Sendable, _ others: Sendable...) -> FunctionExpr + func multiply(_ value: Sendable) -> FunctionExpr /// Creates an expression that divides this expression by another expression. /// Assumes `self` and `other` evaluate to numeric types. @@ -239,13 +235,13 @@ public protocol Expr: Sendable { /// ```swift /// // Check if 'candidateSkills' contains all skills from 'requiredSkill1' and 'requiredSkill2' /// fields - /// Field("candidateSkills").arrayContainsAll(Field("requiredSkill1"), Field("requiredSkill2")) + /// Field("candidateSkills").arrayContainsAll([Field("requiredSkill1"), Field("requiredSkill2")]) /// ``` /// - /// - Parameter values: A variadic list of `Expr` elements to check for in the array represented + /// - Parameter values: A list of `Expr` elements to check for in the array represented /// by `self`. /// - Returns: A new `BooleanExpr` representing the 'array_contains_all' comparison. - func arrayContainsAll(_ values: Expr...) -> BooleanExpr + func arrayContainsAll(_ values: [Expr]) -> BooleanExpr /// Creates an expression that checks if an array (from `self`) contains all the specified literal /// elements. @@ -253,13 +249,13 @@ public protocol Expr: Sendable { /// /// ```swift /// // Check if 'tags' contains both "urgent" and "review" - /// Field("tags").arrayContainsAll("urgent", "review") + /// Field("tags").arrayContainsAll(["urgent", "review"]) /// ``` /// - /// - Parameter values: A variadic list of `Sendable` literal elements to check for in the array + /// - Parameter values: A list of `Sendable` literal elements to check for in the array /// represented by `self`. /// - Returns: A new `BooleanExpr` representing the 'array_contains_all' comparison. - func arrayContainsAll(_ values: Sendable...) -> BooleanExpr + func arrayContainsAll(_ values: [Sendable]) -> BooleanExpr /// Creates an expression that checks if an array (from `self`) contains any of the specified /// element expressions. @@ -267,13 +263,13 @@ public protocol Expr: Sendable { /// /// ```swift /// // Check if 'userGroups' contains any group from 'allowedGroup1' or 'allowedGroup2' fields - /// Field("userGroups").arrayContainsAny(Field("allowedGroup1"), Field("allowedGroup2")) + /// Field("userGroups").arrayContainsAny([Field("allowedGroup1"), Field("allowedGroup2")]) /// ``` /// - /// - Parameter values: A variadic list of `Expr` elements to check for in the array represented + /// - Parameter values: A list of `Expr` elements to check for in the array represented /// by `self`. /// - Returns: A new `BooleanExpr` representing the 'array_contains_any' comparison. - func arrayContainsAny(_ values: Expr...) -> BooleanExpr + func arrayContainsAny(_ values: [Expr]) -> BooleanExpr /// Creates an expression that checks if an array (from `self`) contains any of the specified /// literal elements. @@ -281,13 +277,13 @@ public protocol Expr: Sendable { /// /// ```swift /// // Check if 'categories' contains either "electronics" or "books" - /// Field("categories").arrayContainsAny("electronics", "books") + /// Field("categories").arrayContainsAny(["electronics", "books"]) /// ``` /// - /// - Parameter values: A variadic list of `Sendable` literal elements to check for in the array + /// - Parameter values: A list of `Sendable` literal elements to check for in the array /// represented by `self`. /// - Returns: A new `BooleanExpr` representing the 'array_contains_any' comparison. - func arrayContainsAny(_ values: Sendable...) -> BooleanExpr + func arrayContainsAny(_ values: [Sendable]) -> BooleanExpr /// Creates an expression that calculates the length of an array. /// Assumes `self` evaluates to an array. @@ -308,14 +304,14 @@ public protocol Expr: Sendable { /// /// ```swift /// // Return the value in the 'tags' field array at index 1. - /// Field("tags").arrayOffset(1) + /// Field("tags").arrayGet(1) /// // Return the last element in the 'tags' field array. - /// Field("tags").arrayOffset(-1) + /// Field("tags").arrayGet(-1) /// ``` /// /// - Parameter offset: The literal `Int` offset of the element to return. - /// - Returns: A new `FunctionExpr` representing the 'arrayOffset' operation. - func arrayOffset(_ offset: Int) -> FunctionExpr + /// - Returns: A new `FunctionExpr` representing the 'arrayGet' operation. + func arrayGet(_ offset: Int) -> FunctionExpr /// Creates an expression that accesses an element in an array (from `self`) at the offset /// specified by an expression. @@ -325,13 +321,13 @@ public protocol Expr: Sendable { /// /// ```swift /// // Return the value in the tags field array at index specified by field 'favoriteTagIndex'. - /// Field("tags").arrayOffset(Field("favoriteTagIndex")) + /// Field("tags").arrayGet(Field("favoriteTagIndex")) /// ``` /// /// - Parameter offsetExpr: An `Expr` (evaluating to an Int) representing the offset of the /// element to return. - /// - Returns: A new `FunctionExpr` representing the 'arrayOffset' operation. - func arrayOffset(_ offsetExpr: Expr) -> FunctionExpr + /// - Returns: A new `FunctionExpr` representing the 'arrayGet' operation. + func arrayGet(_ offsetExpr: Expr) -> FunctionExpr // MARK: Equality with Sendable @@ -341,12 +337,12 @@ public protocol Expr: Sendable { /// /// ```swift /// // Check if 'categoryID' field is equal to 'featuredCategory' or 'popularCategory' fields - /// Field("categoryID").eqAny(Field("featuredCategory"), Field("popularCategory")) + /// Field("categoryID").eqAny([Field("featuredCategory"), Field("popularCategory")]) /// ``` /// - /// - Parameter others: A variadic list of `Expr` values to check against. + /// - Parameter others: A list of `Expr` values to check against. /// - Returns: A new `BooleanExpr` representing the 'IN' comparison (eq_any). - func eqAny(_ others: Expr...) -> BooleanExpr + func eqAny(_ others: [Expr]) -> BooleanExpr /// Creates an expression that checks if this expression is equal to any of the provided literal /// values. @@ -354,12 +350,12 @@ public protocol Expr: Sendable { /// /// ```swift /// // Check if 'category' is "Electronics", "Books", or "Home Goods" - /// Field("category").eqAny("Electronics", "Books", "Home Goods") + /// Field("category").eqAny(["Electronics", "Books", "Home Goods"]) /// ``` /// - /// - Parameter others: A variadic list of `Sendable` literal values to check against. + /// - Parameter others: A list of `Sendable` literal values to check against. /// - Returns: A new `BooleanExpr` representing the 'IN' comparison (eq_any). - func eqAny(_ others: Sendable...) -> BooleanExpr + func eqAny(_ others: [Sendable]) -> BooleanExpr /// Creates an expression that checks if this expression is not equal to any of the provided /// expression values. @@ -367,12 +363,12 @@ public protocol Expr: Sendable { /// /// ```swift /// // Check if 'statusValue' is not equal to 'archivedStatus' or 'deletedStatus' fields - /// Field("statusValue").notEqAny(Field("archivedStatus"), Field("deletedStatus")) + /// Field("statusValue").notEqAny([Field("archivedStatus"), Field("deletedStatus")]) /// ``` /// - /// - Parameter others: A variadic list of `Expr` values to check against. + /// - Parameter others: A list of `Expr` values to check against. /// - Returns: A new `BooleanExpr` representing the 'NOT IN' comparison (not_eq_any). - func notEqAny(_ others: Expr...) -> BooleanExpr + func notEqAny(_ others: [Expr]) -> BooleanExpr /// Creates an expression that checks if this expression is not equal to any of the provided /// literal values. @@ -380,12 +376,12 @@ public protocol Expr: Sendable { /// /// ```swift /// // Check if 'status' is neither "pending" nor "archived" - /// Field("status").notEqAny("pending", "archived") + /// Field("status").notEqAny(["pending", "archived"]) /// ``` /// - /// - Parameter others: A variadic list of `Sendable` literal values to check against. + /// - Parameter others: A list of `Sendable` literal values to check against. /// - Returns: A new `BooleanExpr` representing the 'NOT IN' comparison (not_eq_any). - func notEqAny(_ others: Sendable...) -> BooleanExpr + func notEqAny(_ others: [Sendable]) -> BooleanExpr // MARK: Checks @@ -428,7 +424,7 @@ public protocol Expr: Sendable { /// /// ```swift /// // Check if accessing a non-existent array index causes an error - /// Field("myArray").arrayOffset(100).isError() + /// Field("myArray").arrayGet(100).isError() /// ``` /// /// - Returns: A new `BooleanExpr` representing the 'isError' check. @@ -495,7 +491,7 @@ public protocol Expr: Sendable { /// /// - Parameter pattern: The literal string pattern to search for. Use "%" as a wildcard. /// - Returns: A new `FunctionExpr` representing the 'like' comparison. - func like(_ pattern: String) -> FunctionExpr + func like(_ pattern: String) -> BooleanExpr /// Creates an expression that performs a case-sensitive string comparison using wildcards against /// an expression pattern. @@ -509,7 +505,7 @@ public protocol Expr: Sendable { /// - Parameter pattern: An `Expr` (evaluating to a string) representing the pattern to search /// for. /// - Returns: A new `FunctionExpr` representing the 'like' comparison. - func like(_ pattern: Expr) -> FunctionExpr + func like(_ pattern: Expr) -> BooleanExpr /// Creates an expression that checks if a string (from `self`) contains a specified regular /// expression literal as a substring. @@ -1524,7 +1520,7 @@ public protocol Expr: Sendable { /// /// ```swift /// // Get first item in 'title' array, or return "Default Title" if error (e.g., empty array) - /// Field("title").arrayOffset(0).ifError("Default Title") + /// Field("title").arrayGet(0).ifError("Default Title") /// ``` /// /// - Parameter catchValue: The literal `Sendable` value to return if this expression errors. diff --git a/Firestore/Swift/Source/SwiftAPI/Pipeline/Expr/Constant.swift b/Firestore/Swift/Source/SwiftAPI/Pipeline/Expr/Constant.swift index bfb958b468c..8f6b3709892 100644 --- a/Firestore/Swift/Source/SwiftAPI/Pipeline/Expr/Constant.swift +++ b/Firestore/Swift/Source/SwiftAPI/Pipeline/Expr/Constant.swift @@ -33,7 +33,12 @@ public struct Constant: Expr, BridgeWrapper, @unchecked Sendable { } } - // Initializer for numbers + // Initializer for integer + public init(_ value: Int) { + self.init(value as Any) + } + + // Initializer for double public init(_ value: Double) { self.init(value as Any) } @@ -49,7 +54,7 @@ public struct Constant: Expr, BridgeWrapper, @unchecked Sendable { } // Initializer for Bytes - public init(_ value: [UInt8]) { + public init(_ value: Data) { self.init(value as Any) } diff --git a/Firestore/Swift/Source/SwiftAPI/Pipeline/Expr/Field.swift b/Firestore/Swift/Source/SwiftAPI/Pipeline/Expr/Field.swift index fa1dc7d7510..99dc7e1b21d 100644 --- a/Firestore/Swift/Source/SwiftAPI/Pipeline/Expr/Field.swift +++ b/Firestore/Swift/Source/SwiftAPI/Pipeline/Expr/Field.swift @@ -24,9 +24,17 @@ public class Field: ExprBridge, Expr, Selectable, BridgeWrapper, SelectableWrapp public let fieldName: String - public init(_ fieldName: String) { - self.fieldName = fieldName + public init(_ name: String) { + let fieldBridge = FieldBridge(name: name) + bridge = fieldBridge + fieldName = fieldBridge.field_name() + alias = fieldName + } + + public init(_ path: FieldPath) { + let fieldBridge = FieldBridge(path: path) + bridge = fieldBridge + fieldName = fieldBridge.field_name() alias = fieldName - bridge = FieldBridge(alias) } } diff --git a/Firestore/Swift/Source/SwiftAPI/Pipeline/Expr/FunctionExpr/BooleanExpr.swift b/Firestore/Swift/Source/SwiftAPI/Pipeline/Expr/FunctionExpr/BooleanExpr.swift index 8b4bfe23b80..701276d51f7 100644 --- a/Firestore/Swift/Source/SwiftAPI/Pipeline/Expr/FunctionExpr/BooleanExpr.swift +++ b/Firestore/Swift/Source/SwiftAPI/Pipeline/Expr/FunctionExpr/BooleanExpr.swift @@ -21,6 +21,10 @@ public class BooleanExpr: FunctionExpr, @unchecked Sendable { return AggregateFunction("count_if", [self]) } + public func then(_ thenExpr: Expr, else elseExpr: Expr) -> FunctionExpr { + return FunctionExpr("cond", [self, thenExpr, elseExpr]) + } + public static func && (lhs: BooleanExpr, rhs: @autoclosure () throws -> BooleanExpr) rethrows -> BooleanExpr { try BooleanExpr("and", [lhs, rhs()]) diff --git a/Firestore/Swift/Source/SwiftAPI/Pipeline/Expr/FunctionExpr/RandomExpr.swift b/Firestore/Swift/Source/SwiftAPI/Pipeline/Expr/FunctionExpr/RandomExpr.swift new file mode 100644 index 00000000000..5ea39db81fc --- /dev/null +++ b/Firestore/Swift/Source/SwiftAPI/Pipeline/Expr/FunctionExpr/RandomExpr.swift @@ -0,0 +1,19 @@ +// Copyright 2025 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. + +public class RandomExpr: FunctionExpr, @unchecked Sendable { + public init() { + super.init("rand", []) + } +} diff --git a/Firestore/Swift/Source/SwiftAPI/Pipeline/PipelineResult.swift b/Firestore/Swift/Source/SwiftAPI/Pipeline/PipelineResult.swift index e5728d44409..67e55663268 100644 --- a/Firestore/Swift/Source/SwiftAPI/Pipeline/PipelineResult.swift +++ b/Firestore/Swift/Source/SwiftAPI/Pipeline/PipelineResult.swift @@ -27,7 +27,7 @@ public struct PipelineResult: @unchecked Sendable { self.bridge = bridge ref = self.bridge.reference id = self.bridge.documentID - data = self.bridge.data() + data = self.bridge.data().mapValues { Helper.convertObjCToSwift($0) } createTime = self.bridge.create_time updateTime = self.bridge.update_time } @@ -51,20 +51,20 @@ public struct PipelineResult: @unchecked Sendable { /// - Parameter fieldPath: The field path (e.g., "foo" or "foo.bar"). /// - Returns: The data at the specified field location or `nil` if no such field exists. public func get(_ fieldName: String) -> Sendable? { - return bridge.get(fieldName) + return Helper.convertObjCToSwift(bridge.get(fieldName)) } /// Retrieves the field specified by `fieldPath`. /// - Parameter fieldPath: The field path (e.g., "foo" or "foo.bar"). /// - Returns: The data at the specified field location or `nil` if no such field exists. public func get(_ fieldPath: FieldPath) -> Sendable? { - return bridge.get(fieldPath) + return Helper.convertObjCToSwift(bridge.get(fieldPath)) } /// Retrieves the field specified by `fieldPath`. /// - Parameter fieldPath: The field path (e.g., "foo" or "foo.bar"). /// - Returns: The data at the specified field location or `nil` if no such field exists. public func get(_ field: Field) -> Sendable? { - return bridge.get(field.fieldName) + return Helper.convertObjCToSwift(bridge.get(field.fieldName)) } } diff --git a/Firestore/Swift/Source/SwiftAPI/Stages.swift b/Firestore/Swift/Source/SwiftAPI/Stages.swift index 9ecab6945f4..9f6d071d9ff 100644 --- a/Firestore/Swift/Source/SwiftAPI/Stages.swift +++ b/Firestore/Swift/Source/SwiftAPI/Stages.swift @@ -262,7 +262,7 @@ class FindNearest: Stage { vectorValue: VectorValue(vectorValue), distanceMeasure: distanceMeasure.kind.rawValue, limit: limit as NSNumber?, - distanceField: distanceField + distanceField: distanceField.map { Field($0).toBridge() } ?? nil ) } } diff --git a/Firestore/Swift/Tests/Integration/PipelineTests.swift b/Firestore/Swift/Tests/Integration/PipelineTests.swift index cf522b9e1f1..f05a7dcc9eb 100644 --- a/Firestore/Swift/Tests/Integration/PipelineTests.swift +++ b/Firestore/Swift/Tests/Integration/PipelineTests.swift @@ -485,10 +485,9 @@ class PipelineIntegrationTests: FSTIntegrationTestCase { Constant(GeoPoint(latitude: 0.1, longitude: 0.2)).as("geoPoint"), Constant(refTimestamp).as("timestamp"), Constant(refDate).as("date"), // Firestore will convert this to a Timestamp - Constant([1, 2, 3, 4, 5, 6, 7, 0] as [UInt8]).as("bytes"), + Constant(Data([1, 2, 3, 4, 5, 6, 7, 0])).as("bytes"), Constant(db.document("foo/bar")).as("documentReference"), Constant(VectorValue([1, 2, 3])).as("vectorValue"), - Constant([1, 2, 3]).as("arrayValue"), // Treated as an array of numbers ] let constantsSecond: [Selectable] = [ @@ -500,7 +499,7 @@ class PipelineIntegrationTests: FSTIntegrationTestCase { "geoPoint": GeoPoint(latitude: 0.1, longitude: 0.2), "timestamp": refTimestamp, "date": refDate, - "uint8Array": Data([1, 2, 3, 4, 5, 6, 7, 0]), + "bytesArray": Data([1, 2, 3, 4, 5, 6, 7, 0]), "documentReference": Constant(db.document("foo/bar")), "vectorValue": VectorValue([1, 2, 3]), "map": [ @@ -517,7 +516,7 @@ class PipelineIntegrationTests: FSTIntegrationTestCase { GeoPoint(latitude: 10.1, longitude: 20.2), Timestamp(date: Date(timeIntervalSince1970: 1_700_000_000)), // Different timestamp Date(timeIntervalSince1970: 1_700_000_000), // Different date - [11, 22, 33] as [UInt8], + Data([11, 22, 33]), db.document("another/doc"), VectorValue([7, 8, 9]), [ @@ -536,10 +535,9 @@ class PipelineIntegrationTests: FSTIntegrationTestCase { "geoPoint": GeoPoint(latitude: 0.1, longitude: 0.2), "timestamp": refTimestamp, "date": refTimestamp, // Dates are converted to Timestamps - "bytes": [1, 2, 3, 4, 5, 6, 7, 0] as [UInt8], + "bytes": Data([1, 2, 3, 4, 5, 6, 7, 0]), "documentReference": db.document("foo/bar"), "vectorValue": VectorValue([1, 2, 3]), - "arrayValue": [1, 2, 3], "map": [ "number": 1, "string": "a string", @@ -548,7 +546,7 @@ class PipelineIntegrationTests: FSTIntegrationTestCase { "geoPoint": GeoPoint(latitude: 0.1, longitude: 0.2), "timestamp": refTimestamp, "date": refTimestamp, - "uint8Array": Data([1, 2, 3, 4, 5, 6, 7, 0]), + "bytesArray": Data([1, 2, 3, 4, 5, 6, 7, 0]), "documentReference": db.document("foo/bar"), "vectorValue": VectorValue([1, 2, 3]), "map": [ @@ -565,7 +563,7 @@ class PipelineIntegrationTests: FSTIntegrationTestCase { GeoPoint(latitude: 10.1, longitude: 20.2), Timestamp(date: Date(timeIntervalSince1970: 1_700_000_000)), Timestamp(date: Date(timeIntervalSince1970: 1_700_000_000)), // Dates are converted - [11, 22, 33] as [UInt8], + Data([11, 22, 33]), db.document("another/doc"), VectorValue([7, 8, 9]), [ @@ -595,9 +593,6 @@ class PipelineIntegrationTests: FSTIntegrationTestCase { // A pipeline query with .select against an empty collection might not behave as expected. try await randomCol.document("dummyDoc").setData(["field": "value"]) - let refDate = Date(timeIntervalSince1970: 1_678_886_400) - let refTimestamp = Timestamp(date: refDate) - let constantsFirst: [Selectable] = [ Constant.nil.as("nil"), ] @@ -1379,12 +1374,33 @@ class PipelineIntegrationTests: FSTIntegrationTestCase { .collection(collRef.path) .union(db.pipeline() .collection(collRef.path)) + .sort(Field(FieldPath.documentID()).ascending()) let snapshot = try await pipeline.execute() - let bookSequence = (1 ... 10).map { "book\($0)" } - let repeatedIDs = bookSequence + bookSequence - TestHelper.compare(pipelineSnapshot: snapshot, expectedIDs: repeatedIDs, enforceOrder: false) + let books = [ + "book1", + "book1", + "book10", + "book10", + "book2", + "book2", + "book3", + "book3", + "book4", + "book4", + "book5", + "book5", + "book6", + "book6", + "book7", + "book7", + "book8", + "book8", + "book9", + "book9", + ] + TestHelper.compare(pipelineSnapshot: snapshot, expectedIDs: books, enforceOrder: false) } func testUnnestStage() async throws { @@ -1508,4 +1524,1642 @@ class PipelineIntegrationTests: FSTIntegrationTestCase { TestHelper.compare(pipelineSnapshot: snapshot, expected: expectedResults, enforceOrder: false) } + + func testFindNearest() async throws { + let collRef = collectionRef(withDocuments: bookDocs) + let db = collRef.firestore + + let measures: [DistanceMeasure] = [.euclidean, .dotProduct, .cosine] + let expectedResults: [[String: Sendable]] = [ + ["title": "The Hitchhiker's Guide to the Galaxy"], + ["title": "One Hundred Years of Solitude"], + ["title": "The Handmaid's Tale"], + ] + + for measure in measures { + let pipeline = db.pipeline() + .collection(collRef.path) + .findNearest( + field: Field("embedding"), + vectorValue: [10, 1, 3, 1, 2, 1, 1, 1, 1, 1], + distanceMeasure: measure, limit: 3 + ) + .select("title") + let snapshot = try await pipeline.execute() + TestHelper.compare(pipelineSnapshot: snapshot, expected: expectedResults, enforceOrder: true) + } + } + + func testFindNearestWithDistance() async throws { + let collRef = collectionRef(withDocuments: bookDocs) + let db = collRef.firestore + + let expectedResults: [[String: Sendable]] = [ + [ + "title": "The Hitchhiker's Guide to the Galaxy", + "computedDistance": 1.0, + ], + [ + "title": "One Hundred Years of Solitude", + "computedDistance": 12.041594578792296, + ], + ] + + let pipeline = db.pipeline() + .collection(collRef.path) + .findNearest( + field: Field("embedding"), + vectorValue: [10, 1, 2, 1, 1, 1, 1, 1, 1, 1], + distanceMeasure: .euclidean, limit: 2, + distanceField: "computedDistance" + ) + .select("title", "computedDistance") + let snapshot = try await pipeline.execute() + TestHelper.compare(pipelineSnapshot: snapshot, expected: expectedResults, enforceOrder: false) + } + + func testLogicalMaxWorks() async throws { + let collRef = collectionRef(withDocuments: bookDocs) + let db = collRef.firestore + + let pipeline = db.pipeline() + .collection(collRef.path) + .select( + Field("title"), + Field("published").logicalMaximum(Constant(1960), 1961).as("published-safe") + ) + .sort(Field("title").ascending()) + .limit(3) + + let snapshot = try await pipeline.execute() + + let expectedResults: [[String: Sendable]] = [ + ["title": "1984", "published-safe": 1961], + ["title": "Crime and Punishment", "published-safe": 1961], + ["title": "Dune", "published-safe": 1965], + ] + + TestHelper.compare(pipelineSnapshot: snapshot, expected: expectedResults, enforceOrder: true) + } + + func testLogicalMinWorks() async throws { + let collRef = collectionRef(withDocuments: bookDocs) + let db = collRef.firestore + + let pipeline = db.pipeline() + .collection(collRef.path) + .select( + Field("title"), + Field("published").logicalMinimum(Constant(1960), 1961).as("published-safe") + ) + .sort(Field("title").ascending()) + .limit(3) + + let snapshot = try await pipeline.execute() + + let expectedResults: [[String: Sendable]] = [ + ["title": "1984", "published-safe": 1949], + ["title": "Crime and Punishment", "published-safe": 1866], + ["title": "Dune", "published-safe": 1960], + ] + + TestHelper.compare(pipelineSnapshot: snapshot, expected: expectedResults, enforceOrder: true) + } + + func testCondWorks() async throws { + let collRef = collectionRef(withDocuments: bookDocs) + let db = collRef.firestore + + let pipeline = db.pipeline() + .collection(collRef.path) + .select( + Field("title"), + Field("published").lt(1960).then(Constant(1960), else: Field("published")) + .as("published-safe") + ) + .sort(Field("title").ascending()) + .limit(3) + + let snapshot = try await pipeline.execute() + + let expectedResults: [[String: Sendable]] = [ + ["title": "1984", "published-safe": 1960], + ["title": "Crime and Punishment", "published-safe": 1960], + ["title": "Dune", "published-safe": 1965], + ] + + TestHelper.compare(pipelineSnapshot: snapshot, expected: expectedResults, enforceOrder: true) + } + + func testEqAnyWorks() async throws { + let collRef = collectionRef(withDocuments: bookDocs) + let db = collRef.firestore + + let pipeline = db.pipeline() + .collection(collRef.path) + .where(Field("published").eqAny([1979, 1999, 1967])) + .sort(Field("title").descending()) + .select("title") + + let snapshot = try await pipeline.execute() + + let expectedResults: [[String: Sendable]] = [ + ["title": "The Hitchhiker's Guide to the Galaxy"], + ["title": "One Hundred Years of Solitude"], + ] + + TestHelper.compare(pipelineSnapshot: snapshot, expected: expectedResults, enforceOrder: true) + } + + func testNotEqAnyWorks() async throws { + let collRef = collectionRef(withDocuments: bookDocs) + let db = collRef.firestore + + let pipeline = db.pipeline() + .collection(collRef.path) + .where(Field("published").notEqAny([1965, 1925, 1949, 1960, 1866, 1985, 1954, 1967, 1979])) + .select("title") + + let snapshot = try await pipeline.execute() + + let expectedResults: [[String: Sendable]] = [ + ["title": "Pride and Prejudice"], + ] + + TestHelper.compare(pipelineSnapshot: snapshot, expected: expectedResults, enforceOrder: false) + } + + func testArrayContainsWorks() async throws { + let collRef = collectionRef(withDocuments: bookDocs) + let db = collRef.firestore + + let pipeline = db.pipeline() + .collection(collRef.path) + .where(Field("tags").arrayContains("comedy")) + .select("title") + + let snapshot = try await pipeline.execute() + + let expectedResults: [[String: Sendable]] = [ + ["title": "The Hitchhiker's Guide to the Galaxy"], + ] + + TestHelper.compare(pipelineSnapshot: snapshot, expected: expectedResults, enforceOrder: false) + } + + func testArrayContainsAnyWorks() async throws { + let collRef = collectionRef(withDocuments: bookDocs) + let db = collRef.firestore + + let pipeline = db.pipeline() + .collection(collRef.path) + .where(Field("tags").arrayContainsAny(["comedy", "classic"])) + .sort(Field("title").descending()) + .select("title") + + let snapshot = try await pipeline.execute() + + let expectedResults: [[String: Sendable]] = [ + ["title": "The Hitchhiker's Guide to the Galaxy"], + ["title": "Pride and Prejudice"], + ] + + TestHelper.compare(pipelineSnapshot: snapshot, expected: expectedResults, enforceOrder: true) + } + + func testArrayContainsAllWorks() async throws { + let collRef = collectionRef(withDocuments: bookDocs) + let db = collRef.firestore + + let pipeline = db.pipeline() + .collection(collRef.path) + .where(Field("tags").arrayContainsAll(["adventure", "magic"])) + .select("title") + + let snapshot = try await pipeline.execute() + + let expectedResults: [[String: Sendable]] = [ + ["title": "The Lord of the Rings"], + ] + + TestHelper.compare(pipelineSnapshot: snapshot, expected: expectedResults, enforceOrder: false) + } + + func testArrayLengthWorks() async throws { + let collRef = collectionRef(withDocuments: bookDocs) + let db = collRef.firestore + + let pipeline = db.pipeline() + .collection(collRef.path) + .select(Field("tags").arrayLength().as("tagsCount")) + .where(Field("tagsCount").eq(3)) + + let snapshot = try await pipeline.execute() + + XCTAssertEqual(snapshot.results.count, 10) + } + + func testStrConcat() async throws { + let collRef = collectionRef(withDocuments: bookDocs) + let db = collRef.firestore + + let pipeline = db.pipeline() + .collection(collRef.path) + .sort(Field("author").ascending()) + .select(Field("author").strConcat(Constant(" - "), Field("title")).as("bookInfo")) + .limit(1) + + let snapshot = try await pipeline.execute() + + let expectedResults: [[String: Sendable]] = [ + ["bookInfo": "Douglas Adams - The Hitchhiker's Guide to the Galaxy"], + ] + + TestHelper.compare(pipelineSnapshot: snapshot, expected: expectedResults, enforceOrder: true) + } + + func testStartsWith() async throws { + let collRef = collectionRef(withDocuments: bookDocs) + let db = collRef.firestore + + let pipeline = db.pipeline() + .collection(collRef.path) + .where(Field("title").startsWith("The")) + .select("title") + .sort(Field("title").ascending()) + + let snapshot = try await pipeline.execute() + + let expectedResults: [[String: Sendable]] = [ + ["title": "The Great Gatsby"], + ["title": "The Handmaid's Tale"], + ["title": "The Hitchhiker's Guide to the Galaxy"], + ["title": "The Lord of the Rings"], + ] + + TestHelper.compare(pipelineSnapshot: snapshot, expected: expectedResults, enforceOrder: true) + } + + func testEndsWith() async throws { + let collRef = collectionRef(withDocuments: bookDocs) + let db = collRef.firestore + + let pipeline = db.pipeline() + .collection(collRef.path) + .where(Field("title").endsWith("y")) + .select("title") + .sort(Field("title").descending()) + + let snapshot = try await pipeline.execute() + + let expectedResults: [[String: Sendable]] = [ + ["title": "The Hitchhiker's Guide to the Galaxy"], + ["title": "The Great Gatsby"], + ] + + TestHelper.compare(pipelineSnapshot: snapshot, expected: expectedResults, enforceOrder: true) + } + + func testStrContains() async throws { + let collRef = collectionRef(withDocuments: bookDocs) + let db = collRef.firestore + + let pipeline = db.pipeline() + .collection(collRef.path) + .where(Field("title").strContains("'s")) + .select("title") + .sort(Field("title").ascending()) + + let snapshot = try await pipeline.execute() + + let expectedResults: [[String: Sendable]] = [ + ["title": "The Handmaid's Tale"], + ["title": "The Hitchhiker's Guide to the Galaxy"], + ] + + TestHelper.compare(pipelineSnapshot: snapshot, expected: expectedResults, enforceOrder: true) + } + + func testCharLength() async throws { + let collRef = collectionRef(withDocuments: bookDocs) + let db = collRef.firestore + + let pipeline = db.pipeline() + .collection(collRef.path) + .select( + Field("title").charLength().as("titleLength"), + Field("title") + ) + .where(Field("titleLength").gt(20)) + .sort(Field("title").ascending()) + + let snapshot = try await pipeline.execute() + + let expectedResults: [[String: Sendable]] = [ + ["titleLength": 29, "title": "One Hundred Years of Solitude"], + ["titleLength": 36, "title": "The Hitchhiker's Guide to the Galaxy"], + ["titleLength": 21, "title": "The Lord of the Rings"], + ["titleLength": 21, "title": "To Kill a Mockingbird"], + ] + + TestHelper.compare(pipelineSnapshot: snapshot, expected: expectedResults, enforceOrder: true) + } + + func testLike() async throws { + let collRef = collectionRef(withDocuments: bookDocs) + let db = collRef.firestore + + let pipeline = db.pipeline() + .collection(collRef.path) + .where(Field("title").like("%Guide%")) + .select("title") + + let snapshot = try await pipeline.execute() + + let expectedResults: [[String: Sendable]] = [ + ["title": "The Hitchhiker's Guide to the Galaxy"], + ] + + TestHelper.compare(pipelineSnapshot: snapshot, expected: expectedResults, enforceOrder: false) + } + + func testRegexContains() async throws { + let collRef = collectionRef(withDocuments: bookDocs) + let db = collRef.firestore + + let pipeline = db.pipeline() + .collection(collRef.path) + .where(Field("title").regexContains("(?i)(the|of)")) + + let snapshot = try await pipeline.execute() + + XCTAssertEqual(snapshot.results.count, 5) + } + + func testRegexMatches() async throws { + let collRef = collectionRef(withDocuments: bookDocs) + let db = collRef.firestore + + let pipeline = db.pipeline() + .collection(collRef.path) + .where(Field("title").regexMatch(".*(?i)(the|of).*")) + + let snapshot = try await pipeline.execute() + + XCTAssertEqual(snapshot.results.count, 5) + } + + func testArithmeticOperations() async throws { + let collRef = collectionRef(withDocuments: bookDocs) + let db = collRef.firestore + + let pipeline = db.pipeline() + .collection(collRef.path) + .where(Field("title").eq("To Kill a Mockingbird")) + .select( + Field("rating").add(1).as("ratingPlusOne"), + Field("published").subtract(1900).as("yearsSince1900"), + Field("rating").multiply(10).as("ratingTimesTen"), + Field("rating").divide(2).as("ratingDividedByTwo"), + Field("rating").multiply(20).as("ratingTimes20"), + Field("rating").add(3).as("ratingPlus3"), + Field("rating").mod(2).as("ratingMod2") + ) + .limit(1) + + let snapshot = try await pipeline.execute() + + XCTAssertEqual(snapshot.results.count, 1, "Should retrieve one document") + + if let resultDoc = snapshot.results.first { + let expectedResults: [String: Sendable?] = [ + "ratingPlusOne": 5.2, + "yearsSince1900": 60, + "ratingTimesTen": 42.0, + "ratingDividedByTwo": 2.1, + "ratingTimes20": 84.0, + "ratingPlus3": 7.2, + "ratingMod2": 0.20000000000000018, + ] + TestHelper.compare(pipelineResult: resultDoc, expected: expectedResults) + } else { + XCTFail("No document retrieved for arithmetic operations test") + } + } + + func testComparisonOperators() async throws { + let collRef = collectionRef(withDocuments: bookDocs) + let db = collRef.firestore + + let pipeline = db.pipeline() + .collection(collRef.path) + .where( + Field("rating").gt(4.2) && + Field("rating").lte(4.5) && + Field("genre").neq("Science Fiction") + ) + .select("rating", "title") + .sort(Field("title").ascending()) + + let snapshot = try await pipeline.execute() + + let expectedResults: [[String: Sendable]] = [ + ["rating": 4.3, "title": "Crime and Punishment"], + ["rating": 4.3, "title": "One Hundred Years of Solitude"], + ["rating": 4.5, "title": "Pride and Prejudice"], + ] + + TestHelper.compare(pipelineSnapshot: snapshot, expected: expectedResults, enforceOrder: true) + } + + func testLogicalOperators() async throws { + let collRef = collectionRef(withDocuments: bookDocs) + let db = collRef.firestore + + let pipeline = db.pipeline() + .collection(collRef.path) + .where( + (Field("rating").gt(4.5) && Field("genre").eq("Science Fiction")) || + Field("published").lt(1900) + ) + .select("title") + .sort(Field("title").ascending()) + + let snapshot = try await pipeline.execute() + + let expectedResults: [[String: Sendable]] = [ + ["title": "Crime and Punishment"], + ["title": "Dune"], + ["title": "Pride and Prejudice"], + ] + + TestHelper.compare(pipelineSnapshot: snapshot, expected: expectedResults, enforceOrder: true) + } + + func testChecks() async throws { + let collRef = collectionRef(withDocuments: bookDocs) + let db = collRef.firestore + + // Part 1 + var pipeline = db.pipeline() + .collection(collRef.path) + .sort(Field("rating").descending()) + .limit(1) + .select( + Field("rating").isNull().as("ratingIsNull"), + Field("rating").isNan().as("ratingIsNaN"), + Field("title").arrayGet(0).isError().as("isError"), + Field("title").arrayGet(0).ifError(Constant("was error")).as("ifError"), + Field("foo").isAbsent().as("isAbsent"), + Field("title").isNotNull().as("titleIsNotNull"), + Field("cost").isNotNan().as("costIsNotNan"), + Field("fooBarBaz").exists().as("fooBarBazExists"), + Field("title").exists().as("titleExists") + ) + + var snapshot = try await pipeline.execute() + XCTAssertEqual(snapshot.results.count, 1, "Should retrieve one document for checks part 1") + + if let resultDoc = snapshot.results.first { + let expectedResults: [String: Sendable?] = [ + "ratingIsNull": false, + "ratingIsNaN": false, + "isError": true, + "ifError": "was error", + "isAbsent": true, + "titleIsNotNull": true, + "costIsNotNan": false, + "fooBarBazExists": false, + "titleExists": true, + ] + TestHelper.compare(pipelineResult: resultDoc, expected: expectedResults) + } else { + XCTFail("No document retrieved for checks part 1") + } + + // Part 2 + pipeline = db.pipeline() + .collection(collRef.path) + .sort(Field("rating").descending()) + .limit(1) + .select( + Field("rating").isNull().as("ratingIsNull"), + Field("rating").isNan().as("ratingIsNaN"), + Field("title").arrayGet(0).isError().as("isError"), + Field("title").arrayGet(0).ifError(Constant("was error")).as("ifError"), + Field("foo").isAbsent().as("isAbsent"), + Field("title").isNotNull().as("titleIsNotNull"), + Field("cost").isNotNan().as("costIsNotNan") + ) + + snapshot = try await pipeline.execute() + XCTAssertEqual(snapshot.results.count, 1, "Should retrieve one document for checks part 2") + + if let resultDoc = snapshot.results.first { + let expectedResults: [String: Sendable?] = [ + "ratingIsNull": false, + "ratingIsNaN": false, + "isError": true, + "ifError": "was error", + "isAbsent": true, + "titleIsNotNull": true, + "costIsNotNan": false, + ] + TestHelper.compare(pipelineResult: resultDoc, expected: expectedResults) + } else { + XCTFail("No document retrieved for checks part 2") + } + } + + func testMapGet() async throws { + let collRef = collectionRef(withDocuments: bookDocs) + let db = collRef.firestore + + let pipeline = db.pipeline() + .collection(collRef.path) + .sort(Field("published").descending()) + .select( + Field("awards").mapGet("hugo").as("hugoAward"), + Field("awards").mapGet("others").as("others"), + Field("title") + ) + .where(Field("hugoAward").eq(true)) + + let snapshot = try await pipeline.execute() + + // Expected results are ordered by "published" descending for those with hugoAward == true + // 1. The Hitchhiker's Guide to the Galaxy (1979) + // 2. Dune (1965) + let expectedResults: [[String: Sendable?]] = [ + [ + "hugoAward": true, + "title": "The Hitchhiker's Guide to the Galaxy", + "others": ["unknown": ["year": 1980]], + ], + [ + "hugoAward": true, + "title": "Dune", + "others": nil, + ], + ] + + TestHelper.compare(pipelineSnapshot: snapshot, expected: expectedResults, enforceOrder: true) + } + + func testDistanceFunctions() async throws { + let db = firestore() + let randomCol = collectionRef() // Ensure a unique collection for the test + // Add a dummy document to the collection for the select stage to operate on. + try await randomCol.document("dummyDocForDistanceTest").setData(["field": "value"]) + + let sourceVector: [Double] = [0.1, 0.1] + let targetVector: [Double] = [0.5, 0.8] + let targetVectorValue = VectorValue(targetVector) + + let expectedCosineDistance = 0.02560880430538015 + let expectedDotProductDistance = 0.13 + let expectedEuclideanDistance = 0.806225774829855 + let accuracy = 0.000000000000001 // Define a suitable accuracy for floating-point comparisons + + let pipeline = db.pipeline() + .collection(randomCol.path) + .select( + Constant(VectorValue(sourceVector)).cosineDistance(targetVectorValue).as("cosineDistance"), + Constant(VectorValue(sourceVector)).dotProduct(targetVectorValue).as("dotProductDistance"), + Constant(VectorValue(sourceVector)).euclideanDistance(targetVectorValue) + .as("euclideanDistance") + ) + .limit(1) + + let snapshot = try await pipeline.execute() + XCTAssertEqual( + snapshot.results.count, + 1, + "Should retrieve one document for distance functions part 1" + ) + + if let resultDoc = snapshot.results.first { + XCTAssertEqual( + resultDoc.get("cosineDistance")! as! Double, + expectedCosineDistance, + accuracy: accuracy + ) + XCTAssertEqual( + resultDoc.get("dotProductDistance")! as! Double, + expectedDotProductDistance, + accuracy: accuracy + ) + XCTAssertEqual( + resultDoc.get("euclideanDistance")! as! Double, + expectedEuclideanDistance, + accuracy: accuracy + ) + } else { + XCTFail("No document retrieved for distance functions part 1") + } + } + + func testVectorLength() async throws { + let collRef = collectionRef() // Using a new collection for this test + let db = collRef.firestore + let docRef = collRef.document("vectorDocForLengthTestFinal") + + // Add a document with a known vector field + try await docRef.setData(["embedding": VectorValue([1.0, 2.0, 3.0])]) + + // Construct a pipeline query + let pipeline = db.pipeline() + .collection(collRef.path) + .limit(1) // Limit to the document we just added + .select(Field("embedding").vectorLength().as("vectorLength")) + + // Execute the pipeline + let snapshot = try await pipeline.execute() + + // Assert that the vectorLength in the result is 3 + XCTAssertEqual(snapshot.results.count, 1, "Should retrieve one document") + if let resultDoc = snapshot.results.first { + let expectedResult: [String: Sendable?] = ["vectorLength": 3] + TestHelper.compare(pipelineResult: resultDoc, expected: expectedResult) + } else { + XCTFail("No document retrieved for vectorLength test") + } + } + + func testNestedFields() async throws { + let collRef = collectionRef(withDocuments: bookDocs) + let db = collRef.firestore + + let pipeline = db.pipeline() + .collection(collRef.path) + .where(Field("awards.hugo").eq(true)) + .sort(Field("title").descending()) + .select(Field("title"), Field("awards.hugo")) + + let snapshot = try await pipeline.execute() + + let expectedResults: [[String: Sendable?]] = [ + ["title": "The Hitchhiker's Guide to the Galaxy", "awards.hugo": true], + ["title": "Dune", "awards.hugo": true], + ] + + TestHelper.compare(pipelineSnapshot: snapshot, expected: expectedResults, enforceOrder: true) + } + + func testMapGetWithFieldNameIncludingDotNotation() async throws { + let collRef = collectionRef(withDocuments: bookDocs) + let db = collRef.firestore + + let pipeline = db.pipeline() + .collection(collRef.path) + .where(Field("awards.hugo").eq(true)) // Filters to book1 and book10 + .select( + Field("title"), + Field("nestedField.level.1"), + Field("nestedField").mapGet("level.1").mapGet("level.2").as("nested") + ) + .sort(Field("title").descending()) + + let snapshot = try await pipeline.execute() + + XCTAssertEqual(snapshot.results.count, 2, "Should retrieve two documents") + + let expectedResultsArray: [[String: Sendable?]] = [ + [ + "title": "The Hitchhiker's Guide to the Galaxy", + "nestedField.level.`1`": nil, + "nested": true, + ], + [ + "title": "Dune", + "nestedField.level.`1`": nil, + "nested": nil, + ], + ] + TestHelper.compare( + pipelineSnapshot: snapshot, + expected: expectedResultsArray, + enforceOrder: true + ) + } + + func testGenericFunctionAddSelectable() async throws { + let collRef = collectionRef(withDocuments: bookDocs) + let db = collRef.firestore + + let pipeline = db.pipeline() + .collection(collRef.path) + .sort(Field("rating").descending()) + .limit(1) + .select( + FunctionExpr("add", [Field("rating"), Constant(1)]).as( + "rating" + ) + ) + + let snapshot = try await pipeline.execute() + + XCTAssertEqual(snapshot.results.count, 1, "Should retrieve one document") + + let expectedResult: [String: Sendable?] = [ + "rating": 5.7, + ] + + if let resultDoc = snapshot.results.first { + TestHelper.compare(pipelineResult: resultDoc, expected: expectedResult) + } else { + XCTFail("No document retrieved for testGenericFunctionAddSelectable") + } + } + + func testGenericFunctionAndVariadicSelectable() async throws { + let collRef = collectionRef(withDocuments: bookDocs) + let db = collRef.firestore + + let pipeline = db.pipeline() + .collection(collRef.path) + .where( + BooleanExpr("and", [Field("rating").gt(0), + Field("title").charLength().lt(5), + Field("tags").arrayContains("propaganda")]) + ) + .select("title") + + let snapshot = try await pipeline.execute() + + XCTAssertEqual(snapshot.results.count, 1, "Should retrieve one document") + + let expectedResult: [[String: Sendable?]] = [ + ["title": "1984"], + ] + + TestHelper.compare(pipelineSnapshot: snapshot, expected: expectedResult, enforceOrder: false) + } + + func testGenericFunctionArrayContainsAny() async throws { + let collRef = collectionRef(withDocuments: bookDocs) + let db = collRef.firestore + + let pipeline = db.pipeline() + .collection(collRef.path) + .where(BooleanExpr("array_contains_any", [Field("tags"), ArrayExpression(["politics"])])) + .select(Field("title")) + + let snapshot = try await pipeline.execute() + + XCTAssertEqual(snapshot.results.count, 1, "Should retrieve one document") + + let expectedResult: [[String: Sendable?]] = [ + ["title": "Dune"], + ] + + TestHelper.compare(pipelineSnapshot: snapshot, expected: expectedResult, enforceOrder: false) + } + + func testGenericFunctionCountIfAggregate() async throws { + let collRef = collectionRef(withDocuments: bookDocs) + let db = collRef.firestore + + let pipeline = db.pipeline() + .collection(collRef.path) + .aggregate(AggregateFunction("count_if", [Field("rating").gte(4.5)]).as("countOfBest")) + + let snapshot = try await pipeline.execute() + + XCTAssertEqual(snapshot.results.count, 1, "Aggregate should return a single document") + + let expectedResult: [String: Sendable?] = [ + "countOfBest": 3, + ] + + if let resultDoc = snapshot.results.first { + TestHelper.compare(pipelineResult: resultDoc, expected: expectedResult) + } else { + XCTFail("No document retrieved for testGenericFunctionCountIfAggregate") + } + } + + func testGenericFunctionSortByCharLen() async throws { + let collRef = collectionRef(withDocuments: bookDocs) + let db = collRef.firestore + + let pipeline = db.pipeline() + .collection(collRef.path) + .sort( + FunctionExpr("char_length", [Field("title")]).ascending(), + Field("__name__").descending() + ) + .limit(3) + .select(Field("title")) + + let snapshot = try await pipeline.execute() + + XCTAssertEqual(snapshot.results.count, 3, "Should retrieve three documents") + + let expectedResults: [[String: Sendable?]] = [ + ["title": "1984"], + ["title": "Dune"], + ["title": "The Great Gatsby"], + ] + + TestHelper.compare(pipelineSnapshot: snapshot, expected: expectedResults, enforceOrder: true) + } + + func testSupportsRand() async throws { + let collRef = collectionRef(withDocuments: bookDocs) + let db = collRef.firestore + + let pipeline = db.pipeline() + .collection(collRef.path) + .limit(10) + .select(RandomExpr().as("result")) + + let snapshot = try await pipeline.execute() + + XCTAssertEqual(snapshot.results.count, 10, "Should fetch 10 documents") + + for doc in snapshot.results { + guard let resultValue = doc.get("result") else { + XCTFail("Document \(doc.id ?? "unknown") should have a 'result' field") + continue + } + guard let doubleValue = resultValue as? Double else { + XCTFail("Result value for document \(doc.id ?? "unknown") is not a Double: \(resultValue)") + continue + } + XCTAssertGreaterThanOrEqual( + doubleValue, + 0.0, + "Result for \(doc.id ?? "unknown") should be >= 0.0" + ) + XCTAssertLessThan(doubleValue, 1.0, "Result for \(doc.id ?? "unknown") should be < 1.0") + } + } + + func testSupportsArray() async throws { + let db = firestore() + let collRef = collectionRef(withDocuments: bookDocs) + + let pipeline = db.pipeline() + .collection(collRef.path) + .sort(Field("rating").descending()) + .limit(1) + .select(ArrayExpression([1, 2, 3, 4]).as("metadata")) + + let snapshot = try await pipeline.execute() + + XCTAssertEqual(snapshot.results.count, 1, "Should retrieve one document") + + let expectedResults: [String: Sendable?] = ["metadata": [1, 2, 3, 4]] + + if let resultDoc = snapshot.results.first { + TestHelper.compare(pipelineResult: resultDoc, expected: expectedResults) + } else { + XCTFail("No document retrieved for testSupportsArray") + } + } + + func testEvaluatesExpressionInArray() async throws { + let db = firestore() + let collRef = collectionRef(withDocuments: bookDocs) + + let pipeline = db.pipeline() + .collection(collRef.path) + .sort(Field("rating").descending()) + .limit(1) + .select(ArrayExpression([ + 1, + 2, + Field("genre"), + Field("rating").multiply(10), + ]).as("metadata")) + + let snapshot = try await pipeline.execute() + + XCTAssertEqual(snapshot.results.count, 1, "Should retrieve one document") + + let expectedResults: [String: Sendable?] = ["metadata": [1, 2, "Fantasy", 47.0]] + + if let resultDoc = snapshot.results.first { + TestHelper.compare(pipelineResult: resultDoc, expected: expectedResults) + } else { + XCTFail("No document retrieved for testEvaluatesExpressionInArray") + } + } + + func testSupportsArrayOffset() async throws { + let db = firestore() + let collRef = collectionRef(withDocuments: bookDocs) + + let expectedResultsPart1: [[String: Sendable?]] = [ + ["firstTag": "adventure"], + ["firstTag": "politics"], + ["firstTag": "classic"], + ] + + let pipeline1 = db.pipeline() + .collection(collRef.path) + .sort(Field("rating").descending()) + .limit(3) + .select(Field("tags").arrayGet(0).as("firstTag")) + + let snapshot1 = try await pipeline1.execute() + XCTAssertEqual(snapshot1.results.count, 3, "Part 1: Should retrieve three documents") + TestHelper.compare( + pipelineSnapshot: snapshot1, + expected: expectedResultsPart1, + enforceOrder: true + ) + } + + func testSupportsMap() async throws { + let db = firestore() + let collRef = collectionRef(withDocuments: bookDocs) + + let pipeline = db.pipeline() + .collection(collRef.path) + .sort(Field("rating").descending()) + .limit(1) + .select(MapExpression(["foo": "bar"]).as("metadata")) + + let snapshot = try await pipeline.execute() + + XCTAssertEqual(snapshot.results.count, 1, "Should retrieve one document") + + let expectedResult: [String: Sendable?] = ["metadata": ["foo": "bar"]] + + if let resultDoc = snapshot.results.first { + TestHelper.compare(pipelineResult: resultDoc, expected: expectedResult) + } else { + XCTFail("No document retrieved for testSupportsMap") + } + } + + func testEvaluatesExpressionInMap() async throws { + let db = firestore() + let collRef = collectionRef(withDocuments: bookDocs) + + let pipeline = db.pipeline() + .collection(collRef.path) + .sort(Field("rating").descending()) + .limit(1) + .select(MapExpression([ + "genre": Field("genre"), // "Fantasy" + "rating": Field("rating").multiply(10), // 4.7 * 10 = 47.0 + ]).as("metadata")) + + let snapshot = try await pipeline.execute() + + XCTAssertEqual(snapshot.results.count, 1, "Should retrieve one document") + + // Expected: genre is "Fantasy", rating is 4.7 for book4 + let expectedResult: [String: Sendable?] = ["metadata": ["genre": "Fantasy", "rating": 47.0]] + + if let resultDoc = snapshot.results.first { + TestHelper.compare(pipelineResult: resultDoc, expected: expectedResult) + } else { + XCTFail("No document retrieved for testEvaluatesExpressionInMap") + } + } + + func testSupportsMapRemove() async throws { + let db = firestore() + let collRef = collectionRef(withDocuments: bookDocs) + + let expectedResult: [String: Sendable?] = ["awards": ["nebula": false]] + + let pipeline2 = db.pipeline() + .collection(collRef.path) + .sort(Field("rating").descending()) + .limit(1) + .select(Field("awards").mapRemove("hugo").as("awards")) + + let snapshot2 = try await pipeline2.execute() + XCTAssertEqual(snapshot2.results.count, 1, "Should retrieve one document") + if let resultDoc2 = snapshot2.results.first { + TestHelper.compare(pipelineResult: resultDoc2, expected: expectedResult) + } else { + XCTFail("No document retrieved for testSupportsMapRemove") + } + } + + func testSupportsMapMerge() async throws { + let db = firestore() + let collRef = collectionRef(withDocuments: bookDocs) + + let expectedResult: [String: Sendable?] = + ["awards": ["hugo": false, "nebula": false, "fakeAward": true]] + let mergeMap: [String: Sendable] = ["fakeAward": true] + + let pipeline = db.pipeline() + .collection(collRef.path) + .sort(Field("rating").descending()) + .limit(1) + .select(Field("awards").mapMerge(mergeMap).as("awards")) + + let snapshot = try await pipeline.execute() + XCTAssertEqual(snapshot.results.count, 1, "Should retrieve one document") + if let resultDoc = snapshot.results.first { + TestHelper.compare(pipelineResult: resultDoc, expected: expectedResult) + } else { + XCTFail("No document retrieved for testSupportsMapMerge") + } + } + + func testSupportsTimestampConversions() async throws { + let db = firestore() + let randomCol = collectionRef() // Unique collection for this test + + // Add a dummy document to ensure the select stage has an input + try await randomCol.document("dummyTimeDoc").setData(["field": "value"]) + + let pipeline = db.pipeline() + .collection(randomCol.path) + .limit(1) + .select( + Constant(1_741_380_235).unixSecondsToTimestamp().as("unixSecondsToTimestamp"), + Constant(1_741_380_235_123).unixMillisToTimestamp().as("unixMillisToTimestamp"), + Constant(1_741_380_235_123_456).unixMicrosToTimestamp().as("unixMicrosToTimestamp"), + Constant(Timestamp(seconds: 1_741_380_235, nanoseconds: 123_456_789)) + .timestampToUnixSeconds().as("timestampToUnixSeconds"), + Constant(Timestamp(seconds: 1_741_380_235, nanoseconds: 123_456_789)) + .timestampToUnixMillis().as("timestampToUnixMillis"), + Constant(Timestamp(seconds: 1_741_380_235, nanoseconds: 123_456_789)) + .timestampToUnixMicros().as("timestampToUnixMicros") + ) + + let snapshot = try await pipeline.execute() + XCTAssertEqual( + snapshot.results.count, + 1, + "Should retrieve one document for timestamp conversions" + ) + + let expectedResults: [String: Sendable?] = [ + "unixSecondsToTimestamp": Timestamp(seconds: 1_741_380_235, nanoseconds: 0), + "unixMillisToTimestamp": Timestamp(seconds: 1_741_380_235, nanoseconds: 123_000_000), + "unixMicrosToTimestamp": Timestamp(seconds: 1_741_380_235, nanoseconds: 123_456_000), + "timestampToUnixSeconds": 1_741_380_235, + "timestampToUnixMillis": 1_741_380_235_123, + "timestampToUnixMicros": 1_741_380_235_123_456, + ] + + if let resultDoc = snapshot.results.first { + TestHelper.compare(pipelineResult: resultDoc, expected: expectedResults) + } else { + XCTFail("No document retrieved for testSupportsTimestampConversions") + } + } + + func testSupportsTimestampMath() async throws { + let db = firestore() + let randomCol = collectionRef() + try await randomCol.document("dummyDoc").setData(["field": "value"]) + + let initialTimestamp = Timestamp(seconds: 1_741_380_235, nanoseconds: 0) + + let pipeline = db.pipeline() + .collection(randomCol.path) + .limit(1) + .select( + Constant(initialTimestamp).as("timestamp") + ) + .select( + Field("timestamp").timestampAdd(.day, 10).as("plus10days"), + Field("timestamp").timestampAdd(.hour, 10).as("plus10hours"), + Field("timestamp").timestampAdd(.minute, 10).as("plus10minutes"), + Field("timestamp").timestampAdd(.second, 10).as("plus10seconds"), + Field("timestamp").timestampAdd(.microsecond, 10).as("plus10micros"), + Field("timestamp").timestampAdd(.millisecond, 10).as("plus10millis"), + Field("timestamp").timestampSub(.day, 10).as("minus10days"), + Field("timestamp").timestampSub(.hour, 10).as("minus10hours"), + Field("timestamp").timestampSub(.minute, 10).as("minus10minutes"), + Field("timestamp").timestampSub(.second, 10).as("minus10seconds"), + Field("timestamp").timestampSub(.microsecond, 10).as("minus10micros"), + Field("timestamp").timestampSub(.millisecond, 10).as("minus10millis") + ) + + let snapshot = try await pipeline.execute() + + let expectedResults: [String: Timestamp] = [ + "plus10days": Timestamp(seconds: 1_742_244_235, nanoseconds: 0), + "plus10hours": Timestamp(seconds: 1_741_416_235, nanoseconds: 0), + "plus10minutes": Timestamp(seconds: 1_741_380_835, nanoseconds: 0), + "plus10seconds": Timestamp(seconds: 1_741_380_245, nanoseconds: 0), + "plus10micros": Timestamp(seconds: 1_741_380_235, nanoseconds: 10000), + "plus10millis": Timestamp(seconds: 1_741_380_235, nanoseconds: 10_000_000), + "minus10days": Timestamp(seconds: 1_740_516_235, nanoseconds: 0), + "minus10hours": Timestamp(seconds: 1_741_344_235, nanoseconds: 0), + "minus10minutes": Timestamp(seconds: 1_741_379_635, nanoseconds: 0), + "minus10seconds": Timestamp(seconds: 1_741_380_225, nanoseconds: 0), + "minus10micros": Timestamp(seconds: 1_741_380_234, nanoseconds: 999_990_000), + "minus10millis": Timestamp(seconds: 1_741_380_234, nanoseconds: 990_000_000), + ] + + XCTAssertEqual(snapshot.results.count, 1, "Should retrieve one document") + if let resultDoc = snapshot.results.first { + TestHelper.compare(pipelineResult: resultDoc, expected: expectedResults) + } else { + XCTFail("No document retrieved for timestamp math test") + } + } + + func testSupportsByteLength() async throws { + let db = firestore() + let randomCol = collectionRef() + try await randomCol.document("dummyDoc").setData(["field": "value"]) + + let bytes = Data([1, 2, 3, 4, 5, 6, 7, 0]) + + let pipeline = db.pipeline() + .collection(randomCol.path) + .limit(1) + .select( + Constant(bytes).as("bytes") + ) + .select( + Field("bytes").byteLength().as("byteLength") + ) + + let snapshot = try await pipeline.execute() + + let expectedResults: [String: Sendable] = [ + "byteLength": 8, + ] + + XCTAssertEqual(snapshot.results.count, 1, "Should retrieve one document") + if let resultDoc = snapshot.results.first { + TestHelper.compare( + pipelineResult: resultDoc, + expected: expectedResults.mapValues { $0 as Sendable } + ) + } else { + XCTFail("No document retrieved for byte length test") + } + } + + func testSupportsNot() async throws { + let db = firestore() + let randomCol = collectionRef() + try await randomCol.document("dummyDoc").setData(["field": "value"]) + + let pipeline = db.pipeline() + .collection(randomCol.path) + .limit(1) + .select(Constant(true).as("trueField")) + .select( + Field("trueField"), + (!(Field("trueField").eq(true))).as("falseField") + ) + + let snapshot = try await pipeline.execute() + + let expectedResults: [String: Bool] = [ + "trueField": true, + "falseField": false, + ] + + XCTAssertEqual(snapshot.results.count, 1, "Should retrieve one document") + if let resultDoc = snapshot.results.first { + TestHelper.compare(pipelineResult: resultDoc, expected: expectedResults) + } else { + XCTFail("No document retrieved for not operator test") + } + } + + func testReplaceFirst() async throws { + try XCTSkipIf(true, "Skip this test since backend has not yet supported.") + let collRef = collectionRef(withDocuments: bookDocs) + let db = collRef.firestore + + let pipeline = db.pipeline() + .collection(collRef.path) + .where(Field("title").eq("The Lord of the Rings")) + .limit(1) + .select(Field("title").replaceFirst("o", "0").as("newName")) + let snapshot = try await pipeline.execute() + TestHelper.compare( + pipelineSnapshot: snapshot, + expected: [["newName": "The L0rd of the Rings"]], + enforceOrder: false + ) + } + + func testReplaceAll() async throws { + try XCTSkipIf(true, "Skip this test since backend has not yet supported.") + let collRef = collectionRef(withDocuments: bookDocs) + let db = collRef.firestore + + let pipeline = db.pipeline() + .collection(collRef.path) + .where(Field("title").eq("The Lord of the Rings")) + .limit(1) + .select(Field("title").replaceAll("o", "0").as("newName")) + let snapshot = try await pipeline.execute() + TestHelper.compare( + pipelineSnapshot: snapshot, + expected: [["newName": "The L0rd 0f the Rings"]], + enforceOrder: false + ) + } + + func testBitAnd() async throws { + try XCTSkipIf(true, "Skip this test since backend has not yet supported.") + let db = firestore() + let randomCol = collectionRef() + try await randomCol.document("dummyDoc").setData(["field": "value"]) + + let pipeline = db.pipeline() + .collection(randomCol.path) + .limit(1) + .select(Constant(5).bitAnd(12).as("result")) + let snapshot = try await pipeline.execute() + TestHelper.compare(pipelineSnapshot: snapshot, expected: [["result": 4]], enforceOrder: false) + } + + func testBitOr() async throws { + try XCTSkipIf(true, "Skip this test since backend has not yet supported.") + let db = firestore() + let randomCol = collectionRef() + try await randomCol.document("dummyDoc").setData(["field": "value"]) + + let pipeline = db.pipeline() + .collection(randomCol.path) + .limit(1) + .select(Constant(5).bitOr(12).as("result")) + let snapshot = try await pipeline.execute() + TestHelper.compare(pipelineSnapshot: snapshot, expected: [["result": 13]], enforceOrder: false) + } + + func testBitXor() async throws { + try XCTSkipIf(true, "Skip this test since backend has not yet supported.") + let db = firestore() + let randomCol = collectionRef() + try await randomCol.document("dummyDoc").setData(["field": "value"]) + + let pipeline = db.pipeline() + .collection(randomCol.path) + .limit(1) + .select(Constant(5).bitXor(12).as("result")) + let snapshot = try await pipeline.execute() + TestHelper.compare(pipelineSnapshot: snapshot, expected: [["result": 9]], enforceOrder: false) + } + + func testBitNot() async throws { + try XCTSkipIf(true, "Skip this test since backend has not yet supported.") + let db = firestore() + let randomCol = collectionRef() + try await randomCol.document("dummyDoc").setData(["field": "value"]) + let bytesInput = Data([0xFD]) + let expectedOutput = Data([0x02]) + + let pipeline = db.pipeline() + .collection(randomCol.path) + .limit(1) + .select(Constant(bytesInput).bitNot().as("result")) + let snapshot = try await pipeline.execute() + TestHelper.compare( + pipelineSnapshot: snapshot, + expected: [["result": expectedOutput]], + enforceOrder: false + ) + } + + func testBitLeftShift() async throws { + try XCTSkipIf(true, "Skip this test since backend has not yet supported.") + let db = firestore() + let randomCol = collectionRef() + try await randomCol.document("dummyDoc").setData(["field": "value"]) + let bytesInput = Data([0x02]) + let expectedOutput = Data([0x08]) + + let pipeline = db.pipeline() + .collection(randomCol.path) + .limit(1) + .select(Constant(bytesInput).bitLeftShift(2).as("result")) + let snapshot = try await pipeline.execute() + TestHelper.compare( + pipelineSnapshot: snapshot, + expected: [["result": expectedOutput]], + enforceOrder: false + ) + } + + func testBitRightShift() async throws { + try XCTSkipIf(true, "Skip this test since backend has not yet supported.") + let db = firestore() + let randomCol = collectionRef() + try await randomCol.document("dummyDoc").setData(["field": "value"]) + let bytesInput = Data([0x02]) + let expectedOutput = Data([0x00]) + + let pipeline = db.pipeline() + .collection(randomCol.path) + .limit(1) + .select(Constant(bytesInput).bitRightShift(2).as("result")) + let snapshot = try await pipeline.execute() + TestHelper.compare( + pipelineSnapshot: snapshot, + expected: [["result": expectedOutput]], + enforceOrder: false + ) + } + + func testDocumentId() async throws { + try XCTSkipIf(true, "Skip this test since backend has not yet supported.") + let collRef = collectionRef(withDocuments: bookDocs) + let db = collRef.firestore + + let pipeline = db.pipeline() + .collection(collRef.path) + .sort(Field("rating").descending()) + .limit(1) + .select(Field("__path__").documentId().as("docId")) + let snapshot = try await pipeline.execute() + TestHelper.compare( + pipelineSnapshot: snapshot, + expected: [["docId": "book4"]], + enforceOrder: false + ) + } + + func testSubstr() async throws { + try XCTSkipIf(true, "Skip this test since backend has not yet supported.") + let collRef = collectionRef(withDocuments: bookDocs) + let db = collRef.firestore + + let pipeline = db.pipeline() + .collection(collRef.path) + .sort(Field("rating").descending()) + .limit(1) + .select(Field("title").substr(9, 2).as("of")) + let snapshot = try await pipeline.execute() + TestHelper.compare(pipelineSnapshot: snapshot, expected: [["of": "of"]], enforceOrder: false) + } + + func testSubstrWithoutLength() async throws { + try XCTSkipIf(true, "Skip this test since backend has not yet supported.") + let collRef = collectionRef(withDocuments: bookDocs) + let db = collRef.firestore + + let pipeline = db.pipeline() + .collection(collRef.path) + .sort(Field("rating").descending()) + .limit(1) + .select(Field("title").substr(9).as("of")) + let snapshot = try await pipeline.execute() + TestHelper.compare( + pipelineSnapshot: snapshot, + expected: [["of": "of the Rings"]], + enforceOrder: false + ) + } + + func testArrayConcat() async throws { + try XCTSkipIf(true, "Skip this test since backend has not yet supported.") + let collRef = collectionRef(withDocuments: bookDocs) + let db = collRef.firestore + + var pipeline = db.pipeline() + .collection(collRef.path) + .limit(1) // Assuming we operate on the first book (book1) + .select( + Field("tags").arrayConcat( + ["newTag1", "newTag2"], + [Field("tags")], + [Constant.nil] + ).as("modifiedTags") + ) + var snapshot = try await pipeline.execute() + + let expectedTags: [Sendable?] = [ + "comedy", "space", "adventure", + "newTag1", "newTag2", + "comedy", "space", "adventure", + nil, + ] + + TestHelper.compare( + pipelineSnapshot: snapshot, + expected: [["modifiedTags": expectedTags]], + enforceOrder: false + ) + + pipeline = db.pipeline() + .collection(collRef.path) + .limit(1) // Assuming we operate on the first book (book1) + .select( + Field("tags").arrayConcat( + Field("newTag1"), Field("newTag2"), + Field("tags"), + Constant.nil + ).as("modifiedTags") + ) + snapshot = try await pipeline.execute() + + TestHelper.compare( + pipelineSnapshot: snapshot, + expected: [["modifiedTags": expectedTags]], + enforceOrder: false + ) + } + + func testToLowercase() async throws { + try XCTSkipIf(true, "Skip this test since backend has not yet supported.") + let collRef = collectionRef(withDocuments: bookDocs) + let db = collRef.firestore + + let pipeline = db.pipeline() + .collection(collRef.path) + .limit(1) + .select(Field("title").lowercased().as("lowercaseTitle")) + let snapshot = try await pipeline.execute() + TestHelper.compare( + pipelineSnapshot: snapshot, + expected: [["lowercaseTitle": "the hitchhiker's guide to the galaxy"]], + enforceOrder: false + ) + } + + func testToUppercase() async throws { + try XCTSkipIf(true, "Skip this test since backend has not yet supported.") + let collRef = collectionRef(withDocuments: bookDocs) + let db = collRef.firestore + + let pipeline = db.pipeline() + .collection(collRef.path) + .limit(1) + .select(Field("author").uppercased().as("uppercaseAuthor")) + let snapshot = try await pipeline.execute() + TestHelper.compare( + pipelineSnapshot: snapshot, + expected: [["uppercaseAuthor": "DOUGLAS ADAMS"]], + enforceOrder: false + ) + } + + func testTrim() async throws { + try XCTSkipIf(true, "Skip this test since backend has not yet supported.") + let collRef = collectionRef(withDocuments: bookDocs) + let db = collRef.firestore + + let pipeline = db.pipeline() + .collection(collRef.path) + .addFields(Constant(" The Hitchhiker's Guide to the Galaxy ").as("spacedTitle")) + .select(Field("spacedTitle").trim().as("trimmedTitle"), Field("spacedTitle")) + .limit(1) + let snapshot = try await pipeline.execute() + TestHelper.compare( + pipelineSnapshot: snapshot, + expected: [[ + "spacedTitle": " The Hitchhiker's Guide to the Galaxy ", + "trimmedTitle": "The Hitchhiker's Guide to the Galaxy", + ]], + enforceOrder: false + ) + } + + func testReverseString() async throws { + // Renamed from testReverse to avoid conflict if a generic reverse exists elsewhere + try XCTSkipIf(true, "Skip this test since backend has not yet supported.") + let collRef = collectionRef(withDocuments: bookDocs) + let db = collRef.firestore + + let pipeline = db.pipeline() + .collection(collRef.path) + .where(Field("title").eq("1984")) + .limit(1) + .select(Field("title").reverse().as("reverseTitle")) + let snapshot = try await pipeline.execute() + TestHelper.compare( + pipelineSnapshot: snapshot, + expected: [["reverseTitle": "4891"]], + enforceOrder: false + ) + } + + private func addBooks(to collectionReference: CollectionReference) async throws { + try await collectionReference.document("book11").setData([ + "title": "Jonathan Strange & Mr Norrell", + "author": "Susanna Clarke", + "genre": "Fantasy", + "published": 2004, + "rating": 4.6, + "tags": ["historical fantasy", "magic", "alternate history", "england"], + "awards": ["hugo": false, "nebula": false], + ]) + try await collectionReference.document("book12").setData([ + "title": "The Master and Margarita", + "author": "Mikhail Bulgakov", + "genre": "Satire", + "published": 1967, + "rating": 4.6, + "tags": ["russian literature", "supernatural", "philosophy", "dark comedy"], + "awards": [:], + ]) + try await collectionReference.document("book13").setData([ + "title": "A Long Way to a Small, Angry Planet", + "author": "Becky Chambers", + "genre": "Science Fiction", + "published": 2014, + "rating": 4.6, + "tags": ["space opera", "found family", "character-driven", "optimistic"], + "awards": ["hugo": false, "nebula": false, "kitschies": true], + ]) + } + + func testSupportsPaginationWithOffsetsUsingName() async throws { + try XCTSkipIf(true, "Skip this test since backend has not yet supported.") + + let collRef = collectionRef(withDocuments: bookDocs) + let db = collRef.firestore + try await addBooks(to: collRef) + + let pageSize = 2 + + let pipeline = db.pipeline() + .collection(collRef.path) + .select("title", "rating", "__name__") + .sort( + Field("rating").descending(), + Field("__name__").ascending() + ) + + var snapshot = try await pipeline.limit(Int32(pageSize)).execute() + + TestHelper.compare( + pipelineSnapshot: snapshot, + expected: [ + ["title": "The Lord of the Rings", "rating": 4.7], + ["title": "Jonathan Strange & Mr Norrell", "rating": 4.6], + ], + enforceOrder: true + ) + + let lastDoc = snapshot.results.last! + + snapshot = try await pipeline.where( + (Field("rating").eq(lastDoc.get("rating")!) + && Field("rating").lt(lastDoc.get("rating")!)) + || Field("rating").lt(lastDoc.get("rating")!) + ).limit(Int32(pageSize)).execute() + + TestHelper.compare( + pipelineSnapshot: snapshot, + expected: [ + ["title": "Pride and Prejudice", "rating": 4.5], + ["title": "Crime and Punishment", "rating": 4.3], + ], + enforceOrder: false + ) + } + + func testSupportsPaginationWithOffsetsUsingPath() async throws { + try XCTSkipIf(true, "Skip this test since backend has not yet supported.") + + let collRef = collectionRef(withDocuments: bookDocs) + let db = collRef.firestore + try await addBooks(to: collRef) + + let pageSize = 2 + var currPage = 0 + + let pipeline = db.pipeline() + .collection(collRef.path) + .select("title", "rating", "__path__") + .sort( + Field("rating").descending(), + Field("__path__").ascending() + ) + + var snapshot = try await pipeline.offset(Int32(currPage) * Int32(pageSize)).limit( + Int32(pageSize) + ).execute() + + currPage += 1 + + TestHelper.compare( + pipelineSnapshot: snapshot, + expected: [ + ["title": "The Lord of the Rings", "rating": 4.7], + ["title": "Dune", "rating": 4.6], + ], + enforceOrder: true + ) + + snapshot = try await pipeline.offset(Int32(currPage) * Int32(pageSize)).limit( + Int32(pageSize) + ).execute() + + currPage += 1 + + TestHelper.compare( + pipelineSnapshot: snapshot, + expected: [ + ["title": "A Long Way to a Small, Angry Planet", "rating": 4.6], + ["title": "Pride and Prejudice", "rating": 4.5], + ], + enforceOrder: true + ) + } } diff --git a/Firestore/Swift/Tests/TestHelper/TestHelper.swift b/Firestore/Swift/Tests/TestHelper/TestHelper.swift index e65d3960176..a98e1bd4fa2 100644 --- a/Firestore/Swift/Tests/TestHelper/TestHelper.swift +++ b/Firestore/Swift/Tests/TestHelper/TestHelper.swift @@ -163,10 +163,10 @@ public enum TestHelper { guard let value2 = dict2[key], areEqual(value1, value2) else { XCTFail(""" Dictionary value mismatch for key: '\(key)' - Expected value: '\(String(describing: value1))' (from dict1) - Actual value: '\(String(describing: dict2[key]))' (from dict2) - Full dict1: \(String(describing: dict1)) - Full dict2: \(String(describing: dict2)) + Actual value: '\(String(describing: value1))' (from dict1) + Expected value: '\(String(describing: dict2[key]))' (from dict2) + Full actual value: \(String(describing: dict1)) + Full expected value: \(String(describing: dict2)) """) return false } @@ -182,8 +182,8 @@ public enum TestHelper { if !areEqual(value1, value2) { XCTFail(""" Array value mismatch. - Expected array value: '\(String(describing: value1))' - Actual array value: '\(String(describing: value2))' + Actual array value: '\(String(describing: value1))' + Expected array value: '\(String(describing: value2))' """) return false } diff --git a/Firestore/core/src/api/stages.cc b/Firestore/core/src/api/stages.cc index 0c514fe0ee6..a32dfe6f40e 100644 --- a/Firestore/core/src/api/stages.cc +++ b/Firestore/core/src/api/stages.cc @@ -28,6 +28,8 @@ namespace firebase { namespace firestore { namespace api { +using model::DeepClone; + google_firestore_v1_Pipeline_Stage CollectionSource::to_proto() const { google_firestore_v1_Pipeline_Stage result; @@ -191,16 +193,14 @@ google_firestore_v1_Pipeline_Stage FindNearestStage::to_proto() const { result.args_count = 3; result.args = nanopb::MakeArray(3); result.args[0] = property_->to_proto(); - result.args[1] = *vector_; + result.args[1] = *DeepClone(*vector_).release(); result.args[2] = distance_measure_.proto(); nanopb::SetRepeatedField( &result.options, &result.options_count, options_, - [](const std::pair>& - entry) { + [](const std::pair& entry) { return _google_firestore_v1_Pipeline_Stage_OptionsEntry{ - nanopb::MakeBytesArray(entry.first), *entry.second}; + nanopb::MakeBytesArray(entry.first), entry.second}; }); return result; diff --git a/Firestore/core/src/api/stages.h b/Firestore/core/src/api/stages.h index e8bf34ac70a..be0cbf3e68b 100644 --- a/Firestore/core/src/api/stages.h +++ b/Firestore/core/src/api/stages.h @@ -150,13 +150,11 @@ class FindNearestStage : public Stage { std::shared_ptr property, nanopb::SharedMessage vector, DistanceMeasure distance_measure, - std::unordered_map> - options) + std::unordered_map options) : property_(std::move(property)), vector_(std::move(vector)), distance_measure_(distance_measure), - options_(options) { + options_(std::move(options)) { } ~FindNearestStage() override = default; @@ -167,9 +165,7 @@ class FindNearestStage : public Stage { std::shared_ptr property_; nanopb::SharedMessage vector_; DistanceMeasure distance_measure_; - std::unordered_map> - options_; + std::unordered_map options_; }; class LimitStage : public Stage {