From cbe193228ce43fcf4f2242b690d7cc4c8968e030 Mon Sep 17 00:00:00 2001 From: Tom Andersen Date: Mon, 29 May 2023 16:37:46 -0400 Subject: [PATCH 01/25] OR Query Implementation --- app/CMakeLists.txt | 1 + firestore/CMakeLists.txt | 7 + .../integration_test_internal/CMakeLists.txt | 2 + .../src/filter_test.cc | 224 ++++++++++++++++++ firestore/src/common/filter.cc | 162 +++++++++++++ firestore/src/common/query.cc | 6 + firestore/src/common/type_mapping.h | 6 + firestore/src/include/firebase/firestore.h | 1 + .../include/firebase/firestore/field_path.h | 1 + .../src/include/firebase/firestore/filter.h | 85 +++++++ .../src/include/firebase/firestore/query.h | 9 + firestore/src/main/composite_filter_main.cc | 52 ++++ firestore/src/main/composite_filter_main.h | 52 ++++ firestore/src/main/converter_main.h | 10 + firestore/src/main/filter_main.cc | 54 +++++ firestore/src/main/filter_main.h | 131 ++++++++++ firestore/src/main/query_main.cc | 11 +- firestore/src/main/query_main.h | 2 + firestore/src/main/unary_filter_main.cc | 53 +++++ firestore/src/main/unary_filter_main.h | 54 +++++ 20 files changed, 921 insertions(+), 2 deletions(-) create mode 100644 firestore/integration_test_internal/src/filter_test.cc create mode 100644 firestore/src/common/filter.cc create mode 100644 firestore/src/include/firebase/firestore/filter.h create mode 100644 firestore/src/main/composite_filter_main.cc create mode 100644 firestore/src/main/composite_filter_main.h create mode 100644 firestore/src/main/filter_main.cc create mode 100644 firestore/src/main/filter_main.h create mode 100644 firestore/src/main/unary_filter_main.cc create mode 100644 firestore/src/main/unary_filter_main.h diff --git a/app/CMakeLists.txt b/app/CMakeLists.txt index cb272aa4e4..53921ea64c 100644 --- a/app/CMakeLists.txt +++ b/app/CMakeLists.txt @@ -522,6 +522,7 @@ if (IOS) ${FIREBASE_SOURCE_DIR}/firestore/src/include/firebase/firestore/document_snapshot.h ${FIREBASE_SOURCE_DIR}/firestore/src/include/firebase/firestore/field_path.h ${FIREBASE_SOURCE_DIR}/firestore/src/include/firebase/firestore/field_value.h + ${FIREBASE_SOURCE_DIR}/firestore/src/include/firebase/firestore/filter.h ${FIREBASE_SOURCE_DIR}/firestore/src/include/firebase/firestore/listener_registration.h ${FIREBASE_SOURCE_DIR}/firestore/src/include/firebase/firestore/load_bundle_task_progress.h ${FIREBASE_SOURCE_DIR}/firestore/src/include/firebase/firestore/map_field_value.h diff --git a/firestore/CMakeLists.txt b/firestore/CMakeLists.txt index 762d217554..bc39b48609 100644 --- a/firestore/CMakeLists.txt +++ b/firestore/CMakeLists.txt @@ -31,6 +31,7 @@ set(common_SRCS src/common/document_snapshot.cc src/common/exception_common.cc src/common/exception_common.h + src/common/filter.cc src/common/field_path.cc src/common/field_value.cc src/common/firestore.cc @@ -199,6 +200,8 @@ set(main_SRCS src/main/aggregate_query_snapshot_main.h src/main/collection_reference_main.cc src/main/collection_reference_main.h + src/main/composite_filter_main.cc + src/main/composite_filter_main.h src/main/converter_main.h src/main/document_change_main.cc src/main/document_change_main.h @@ -206,6 +209,8 @@ set(main_SRCS src/main/document_reference_main.h src/main/document_snapshot_main.cc src/main/document_snapshot_main.h + src/main/filter_main.cc + src/main/filter_main.h src/main/field_value_main.cc src/main/field_value_main.h src/main/firestore_main.cc @@ -225,6 +230,8 @@ set(main_SRCS src/main/transaction_main.h src/main/user_data_converter_main.cc src/main/user_data_converter_main.h + src/main/unary_filter_main.cc + src/main/unary_filter_main.h src/main/util_main.h src/main/write_batch_main.cc src/main/write_batch_main.h) diff --git a/firestore/integration_test_internal/CMakeLists.txt b/firestore/integration_test_internal/CMakeLists.txt index 5aa57311f3..65a5339958 100644 --- a/firestore/integration_test_internal/CMakeLists.txt +++ b/firestore/integration_test_internal/CMakeLists.txt @@ -91,6 +91,7 @@ set(FIREBASE_INTEGRATION_TEST_PORTABLE_TEST_SRCS # public API are performed. src/integration_test.cc # Internal tests below. + src/aggregate_count_test.cc src/aggregate_query_snapshot_test.cc src/aggregate_query_test.cc src/bundle_test.cc @@ -99,6 +100,7 @@ set(FIREBASE_INTEGRATION_TEST_PORTABLE_TEST_SRCS src/document_change_test.cc src/document_reference_test.cc src/document_snapshot_test.cc + src/filter_test.cc src/field_value_test.cc src/fields_test.cc src/firestore_test.cc diff --git a/firestore/integration_test_internal/src/filter_test.cc b/firestore/integration_test_internal/src/filter_test.cc new file mode 100644 index 0000000000..d946d71fa5 --- /dev/null +++ b/firestore/integration_test_internal/src/filter_test.cc @@ -0,0 +1,224 @@ +/* +* 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. +*/ + +#include "firebase/firestore.h" +#include "firestore_integration_test.h" + +namespace firebase { +namespace firestore { +namespace { + +using FilterTest = FirestoreIntegrationTest; + +TEST_F(FilterTest, IdenticalShouldBeEqual) { + FieldPath foo_path{std::vector{"foo"}}; + + Filter filter1a = Filter::ArrayContains("foo", FieldValue::Integer(42)); + Filter filter1b = Filter::ArrayContains(foo_path, FieldValue::Integer(42)); + + Filter filter2a = Filter::ArrayContainsAny("foo", std::vector{FieldValue::Integer(42)}); + Filter filter2b = Filter::ArrayContainsAny(foo_path, std::vector{FieldValue::Integer(42)}); + + Filter filter3a = Filter::EqualTo("foo", FieldValue::Integer(42)); + Filter filter3b = Filter::EqualTo(foo_path, FieldValue::Integer(42)); + + Filter filter4a = Filter::NotEqualTo("foo", FieldValue::Integer(42)); + Filter filter4b = Filter::NotEqualTo(foo_path, FieldValue::Integer(42)); + + Filter filter5a = Filter::GreaterThan("foo", FieldValue::Integer(42)); + Filter filter5b = Filter::GreaterThan(foo_path, FieldValue::Integer(42)); + + Filter filter6a = Filter::GreaterThanOrEqualTo("foo", FieldValue::Integer(42)); + Filter filter6b = Filter::GreaterThanOrEqualTo(foo_path, FieldValue::Integer(42)); + + Filter filter7a = Filter::LessThan("foo", FieldValue::Integer(42)); + Filter filter7b = Filter::LessThan(foo_path, FieldValue::Integer(42)); + + Filter filter8a = Filter::LessThanOrEqualTo("foo", FieldValue::Integer(42)); + Filter filter8b = Filter::LessThanOrEqualTo(foo_path, FieldValue::Integer(42)); + + Filter filter9a = Filter::In("foo", std::vector{FieldValue::Integer(42)}); + Filter filter9b = Filter::In(foo_path, std::vector{FieldValue::Integer(42)}); + + Filter filter10a = Filter::NotIn("foo", std::vector{FieldValue::Integer(42)}); + Filter filter10b = Filter::NotIn(foo_path, std::vector{FieldValue::Integer(42)}); + + EXPECT_TRUE(filter1a == filter1a); + EXPECT_TRUE(filter2a == filter2a); + EXPECT_TRUE(filter3a == filter3a); + EXPECT_TRUE(filter4a == filter4a); + EXPECT_TRUE(filter5a == filter5a); + EXPECT_TRUE(filter6a == filter6a); + EXPECT_TRUE(filter7a == filter7a); + EXPECT_TRUE(filter8a == filter8a); + EXPECT_TRUE(filter9a == filter9a); + EXPECT_TRUE(filter10a == filter10a); + + EXPECT_TRUE(filter1a == filter1b); + EXPECT_TRUE(filter2a == filter2b); + EXPECT_TRUE(filter3a == filter3b); + EXPECT_TRUE(filter4a == filter4b); + EXPECT_TRUE(filter5a == filter5b); + EXPECT_TRUE(filter6a == filter6b); + EXPECT_TRUE(filter7a == filter7b); + EXPECT_TRUE(filter8a == filter8b); + EXPECT_TRUE(filter9a == filter9b); + EXPECT_TRUE(filter10a == filter10b); + + EXPECT_FALSE(filter1a != filter1a); + EXPECT_FALSE(filter2a != filter2a); + EXPECT_FALSE(filter3a != filter3a); + EXPECT_FALSE(filter4a != filter4a); + EXPECT_FALSE(filter5a != filter5a); + EXPECT_FALSE(filter6a != filter6a); + EXPECT_FALSE(filter7a != filter7a); + EXPECT_FALSE(filter8a != filter8a); + EXPECT_FALSE(filter9a != filter9a); + EXPECT_FALSE(filter10a != filter10a); + + EXPECT_FALSE(filter1a != filter1b); + EXPECT_FALSE(filter2a != filter2b); + EXPECT_FALSE(filter3a != filter3b); + EXPECT_FALSE(filter4a != filter4b); + EXPECT_FALSE(filter5a != filter5b); + EXPECT_FALSE(filter6a != filter6b); + EXPECT_FALSE(filter7a != filter7b); + EXPECT_FALSE(filter8a != filter8b); + EXPECT_FALSE(filter9a != filter9b); + EXPECT_FALSE(filter10a != filter10b); + + EXPECT_TRUE(filter1a != filter2a); + EXPECT_TRUE(filter1a != filter3a); + EXPECT_TRUE(filter1a != filter4a); + EXPECT_TRUE(filter1a != filter5a); + EXPECT_TRUE(filter1a != filter6a); + EXPECT_TRUE(filter1a != filter7a); + EXPECT_TRUE(filter1a != filter8a); + EXPECT_TRUE(filter1a != filter9a); + EXPECT_TRUE(filter1a != filter10a); + EXPECT_TRUE(filter2a != filter3a); + EXPECT_TRUE(filter2a != filter4a); + EXPECT_TRUE(filter2a != filter5a); + EXPECT_TRUE(filter2a != filter6a); + EXPECT_TRUE(filter2a != filter7a); + EXPECT_TRUE(filter2a != filter8a); + EXPECT_TRUE(filter2a != filter9a); + EXPECT_TRUE(filter2a != filter10a); + EXPECT_TRUE(filter3a != filter4a); + EXPECT_TRUE(filter3a != filter5a); + EXPECT_TRUE(filter3a != filter6a); + EXPECT_TRUE(filter3a != filter7a); + EXPECT_TRUE(filter3a != filter8a); + EXPECT_TRUE(filter3a != filter9a); + EXPECT_TRUE(filter3a != filter10a); + EXPECT_TRUE(filter4a != filter5a); + EXPECT_TRUE(filter4a != filter6a); + EXPECT_TRUE(filter4a != filter7a); + EXPECT_TRUE(filter4a != filter8a); + EXPECT_TRUE(filter4a != filter9a); + EXPECT_TRUE(filter4a != filter10a); + EXPECT_TRUE(filter5a != filter6a); + EXPECT_TRUE(filter5a != filter7a); + EXPECT_TRUE(filter5a != filter8a); + EXPECT_TRUE(filter5a != filter9a); + EXPECT_TRUE(filter5a != filter10a); + EXPECT_TRUE(filter6a != filter7a); + EXPECT_TRUE(filter6a != filter8a); + EXPECT_TRUE(filter6a != filter9a); + EXPECT_TRUE(filter6a != filter10a); + EXPECT_TRUE(filter7a != filter8a); + EXPECT_TRUE(filter7a != filter9a); + EXPECT_TRUE(filter7a != filter10a); + EXPECT_TRUE(filter8a != filter9a); + EXPECT_TRUE(filter8a != filter10a); + EXPECT_TRUE(filter9a != filter10a); +} + +TEST_F(FilterTest, DifferentValuesAreNotEqual) { + Filter filter1a = Filter::ArrayContains("foo", FieldValue::Integer(24)); + Filter filter1b = Filter::ArrayContains("foo", FieldValue::Integer(42)); + + Filter filter2a = Filter::EqualTo("foo", FieldValue::Integer(24)); + Filter filter2b = Filter::EqualTo("foo", FieldValue::Integer(42)); + + Filter filter3a = Filter::NotEqualTo("foo", FieldValue::Integer(24)); + Filter filter3b = Filter::NotEqualTo("foo", FieldValue::Integer(42)); + + Filter filter4a = Filter::GreaterThan("foo", FieldValue::Integer(24)); + Filter filter4b = Filter::GreaterThan("foo", FieldValue::Integer(42)); + + Filter filter5a = Filter::GreaterThanOrEqualTo("foo", FieldValue::Integer(24)); + Filter filter5b = Filter::GreaterThanOrEqualTo("foo", FieldValue::Integer(42)); + + Filter filter6a = Filter::LessThan("foo", FieldValue::Integer(24)); + Filter filter6b = Filter::LessThan("foo", FieldValue::Integer(42)); + + Filter filter7a = Filter::LessThanOrEqualTo("foo", FieldValue::Integer(24)); + Filter filter7b = Filter::LessThanOrEqualTo("foo", FieldValue::Integer(42)); + + EXPECT_FALSE(filter1a == filter1b); + EXPECT_FALSE(filter2a == filter2b); + EXPECT_FALSE(filter3a == filter3b); + EXPECT_FALSE(filter4a == filter4b); + EXPECT_FALSE(filter5a == filter5b); + EXPECT_FALSE(filter6a == filter6b); + EXPECT_FALSE(filter7a == filter7b); + + EXPECT_TRUE(filter1a != filter1b); + EXPECT_TRUE(filter2a != filter2b); + EXPECT_TRUE(filter3a != filter3b); + EXPECT_TRUE(filter4a != filter4b); + EXPECT_TRUE(filter5a != filter5b); + EXPECT_TRUE(filter6a != filter6b); + EXPECT_TRUE(filter7a != filter7b); +} + +TEST_F(FilterTest, DifferentOrderOfValuesAreNotEqual) { + const std::vector& valueOrderA = std::vector{ + FieldValue::Integer(1), + FieldValue::Integer(2) + }; + const std::vector& valueOrderB = std::vector{ + FieldValue::Integer(2), + FieldValue::Integer(1) + }; + + { + Filter filter1 = Filter::ArrayContainsAny("foo", valueOrderA); + Filter filter2 = Filter::ArrayContainsAny("foo", valueOrderB); + EXPECT_FALSE(filter1 == filter2); + EXPECT_TRUE(filter1 != filter2); + } + + { + Filter filter1 = Filter::In("foo", valueOrderA); + Filter filter2 = Filter::In("foo", valueOrderB); + EXPECT_FALSE(filter1 == filter2); + EXPECT_TRUE(filter1 != filter2); + } + + { + Filter filter1 = Filter::NotIn("foo", valueOrderA); + Filter filter2 = Filter::NotIn("foo", valueOrderB); + EXPECT_FALSE(filter1 == filter2); + EXPECT_TRUE(filter1 != filter2); + } +} + +} + +} // namespace firestore +} // namespace firebase diff --git a/firestore/src/common/filter.cc b/firestore/src/common/filter.cc new file mode 100644 index 0000000000..30f11cbf2e --- /dev/null +++ b/firestore/src/common/filter.cc @@ -0,0 +1,162 @@ +/* +* 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. + */ + +#include "firebase/firestore/filter.h" + +#include "firestore/src/common/cleanup.h" +#include "firestore/src/common/hard_assert_common.h" + +#if defined(__ANDROID__) +#include "firestore/src/android/filter_android.h" +#else +#include "firestore/src/main/filter_main.h" +#endif // defined(__ANDROID__) + +namespace firebase { +namespace firestore { + +Filter::Filter(const Filter& other) { + internal_ = other.internal_->clone(); +} + +Filter::Filter(Filter&& other) noexcept { + std::swap(internal_, other.internal_); +} + +Filter::Filter(FilterInternal* internal) : internal_(internal) { + SIMPLE_HARD_ASSERT(internal != nullptr); +} + +Filter::~Filter() { + delete internal_; + internal_ = nullptr; +} + +Filter& Filter::operator=(const Filter& other) { + if (this == &other) { + return *this; + } + delete internal_; + internal_ = other.internal_->clone(); + return *this; +} + +Filter& Filter::operator=(Filter&& other) noexcept { + if (this == &other) { + return *this; + } + delete internal_; + internal_ = other.internal_; + other.internal_ = nullptr; + return *this; +} + +Filter Filter::ArrayContains(const std::string &field, const FieldValue & value) { + return ArrayContains(FieldPath::FromDotSeparatedString(field), value); +} + +Filter Filter::ArrayContainsAny(const std::string &field, const std::vector &values) { + return ArrayContainsAny(FieldPath::FromDotSeparatedString(field), values); +} + +Filter Filter::EqualTo(const std::string& field, const firebase::firestore::FieldValue& value) { + return EqualTo(FieldPath::FromDotSeparatedString(field), value); +} + +Filter Filter::NotEqualTo(const std::string &field, const FieldValue &value) { + return NotEqualTo(FieldPath::FromDotSeparatedString(field), value); +} + +Filter Filter::GreaterThan(const std::string &field, const FieldValue &value) { + return GreaterThan(FieldPath::FromDotSeparatedString(field), value); +} + +Filter Filter::GreaterThanOrEqualTo(const std::string &field, const FieldValue &value) { + return GreaterThanOrEqualTo(FieldPath::FromDotSeparatedString(field), value); +} + +Filter Filter::LessThan(const std::string &field, const FieldValue &value) { + return LessThan(FieldPath::FromDotSeparatedString(field), value); +} + +Filter Filter::LessThanOrEqualTo(const std::string &field, const FieldValue &value) { + return LessThanOrEqualTo(FieldPath::FromDotSeparatedString(field), value); +} + +Filter Filter::In(const std::string &field, const std::vector &values) { + return In(FieldPath::FromDotSeparatedString(field), values); +} + +Filter Filter::NotIn(const std::string &field, const std::vector &values) { + return NotIn(FieldPath::FromDotSeparatedString(field), values); +} + +Filter Filter::ArrayContains(const FieldPath &field, const FieldValue &value) { + return FilterInternal::ArrayContains(field, value); +} + +Filter Filter::ArrayContainsAny(const FieldPath &field, const std::vector &values) { + return FilterInternal::ArrayContainsAny(field, values); +} + +Filter Filter::EqualTo(const FieldPath &field, const FieldValue &value) { + return FilterInternal::EqualTo(field, value); +} + +Filter Filter::NotEqualTo(const FieldPath &field, const FieldValue &value) { + return FilterInternal::NotEqualTo(field, value); +} + +Filter Filter::GreaterThan(const FieldPath &field, const FieldValue &value) { + return FilterInternal::GreaterThan(field, value); +} + +Filter Filter::GreaterThanOrEqualTo(const FieldPath &field, const FieldValue &value) { + return FilterInternal::GreaterThanOrEqualTo(field, value); +} + +Filter Filter::LessThan(const FieldPath &field, const FieldValue &value) { + return FilterInternal::LessThan(field, value); +} + +Filter Filter::LessThanOrEqualTo(const FieldPath &field, const FieldValue &value) { + return FilterInternal::LessThanOrEqualTo(field, value); +} + +Filter Filter::In(const FieldPath &field, const std::vector &values) { + return FilterInternal::In(field, values); +} + +Filter Filter::NotIn(const FieldPath &field, const std::vector &values) { + return FilterInternal::NotIn(field, values); +} + +template +Filter Filter::Or(const Filter& filter, const Filters& ... filters) { + return FilterInternal::Or(filter, filters...); +} + +template +Filter Filter::And(const Filter& filter, const Filters& ... filters) { + return FilterInternal::And(filter, filters...); +} + +bool operator==(const Filter& lhs, const Filter& rhs) { + return &lhs == &rhs || *lhs.internal_ == *rhs.internal_; +} + +} // namespace firestore +} // namespace firebase diff --git a/firestore/src/common/query.cc b/firestore/src/common/query.cc index 7edbdd7602..08f3381b48 100644 --- a/firestore/src/common/query.cc +++ b/firestore/src/common/query.cc @@ -25,6 +25,7 @@ #include "firestore/src/common/util.h" #include "firestore/src/include/firebase/firestore/aggregate_query.h" #include "firestore/src/include/firebase/firestore/document_snapshot.h" +#include "firestore/src/include/firebase/firestore/filter.h" #include "firestore/src/include/firebase/firestore/field_path.h" #include "firestore/src/include/firebase/firestore/field_value.h" #include "firestore/src/include/firebase/firestore/listener_registration.h" @@ -112,6 +113,11 @@ AggregateQuery Query::Count() const { return internal_->Count(); } +Query Query::Where(const Filter& filter) const { + if (!internal_) return {}; + return internal_->Where(filter); +} + Query Query::WhereEqualTo(const std::string& field, const FieldValue& value) const { return WhereEqualTo(FieldPath::FromDotSeparatedString(field), value); diff --git a/firestore/src/common/type_mapping.h b/firestore/src/common/type_mapping.h index 269b92a410..5501181da3 100644 --- a/firestore/src/common/type_mapping.h +++ b/firestore/src/common/type_mapping.h @@ -34,6 +34,8 @@ class DocumentReference; class DocumentReferenceInternal; class DocumentSnapshot; class DocumentSnapshotInternal; +class Filter; +class FilterInternal; class FieldValue; class FieldValueInternal; class Firestore; @@ -83,6 +85,10 @@ struct InternalTypeMap { using type = DocumentSnapshotInternal; }; template <> +struct InternalTypeMap { + using type = FilterInternal; +}; +template <> struct InternalTypeMap { using type = FieldValueInternal; }; diff --git a/firestore/src/include/firebase/firestore.h b/firestore/src/include/firebase/firestore.h index 7cc0274812..c3cf04e07f 100644 --- a/firestore/src/include/firebase/firestore.h +++ b/firestore/src/include/firebase/firestore.h @@ -36,6 +36,7 @@ #include "firebase/firestore/document_snapshot.h" #include "firebase/firestore/field_path.h" #include "firebase/firestore/field_value.h" +#include "firebase/firestore/filter.h" #include "firebase/firestore/firestore_errors.h" #include "firebase/firestore/geo_point.h" #include "firebase/firestore/listener_registration.h" diff --git a/firestore/src/include/firebase/firestore/field_path.h b/firestore/src/include/firebase/firestore/field_path.h index d09dec6411..81c8cb5739 100644 --- a/firestore/src/include/firebase/firestore/field_path.h +++ b/firestore/src/include/firebase/firestore/field_path.h @@ -164,6 +164,7 @@ class FieldPath final { friend bool operator!=(const FieldPath& lhs, const FieldPath& rhs); friend struct std::hash; + friend class Filter; friend class DocumentSnapshot; // For access to `FromDotSeparatedString` friend class Query; friend class QueryInternal; diff --git a/firestore/src/include/firebase/firestore/filter.h b/firestore/src/include/firebase/firestore/filter.h new file mode 100644 index 0000000000..6a25955c54 --- /dev/null +++ b/firestore/src/include/firebase/firestore/filter.h @@ -0,0 +1,85 @@ +/* + * 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. + */ + +#ifndef FIREBASE_FIRESTORE_SRC_INCLUDE_FIREBASE_FIRESTORE_FILTER_H_ +#define FIREBASE_FIRESTORE_SRC_INCLUDE_FIREBASE_FIRESTORE_FILTER_H_ + +#include + +#include "firebase/firestore/field_value.h" + +namespace firebase { +namespace firestore { + +class FilterInternal; + +class Filter { + public: + static Filter ArrayContains(const std::string &field, const FieldValue & value); + static Filter ArrayContainsAny(const std::string &field, const std::vector &values); + static Filter EqualTo(const std::string &field, const FieldValue &value); + static Filter NotEqualTo(const std::string &field, const FieldValue &value); + static Filter GreaterThan(const std::string &field, const FieldValue &value); + static Filter GreaterThanOrEqualTo(const std::string &field, const FieldValue &value); + static Filter LessThan(const std::string &field, const FieldValue &value); + static Filter LessThanOrEqualTo(const std::string &field, const FieldValue &value); + static Filter In(const std::string &field, const std::vector &values); + static Filter NotIn(const std::string &field, const std::vector &values); + + static Filter ArrayContains(const FieldPath &field, const FieldValue &value); + static Filter ArrayContainsAny(const FieldPath &field, const std::vector &values); + static Filter EqualTo(const FieldPath &field, const FieldValue &value); + static Filter NotEqualTo(const FieldPath &field, const FieldValue &value); + static Filter GreaterThan(const FieldPath &field, const FieldValue &value); + static Filter GreaterThanOrEqualTo(const FieldPath &field, const FieldValue &value); + static Filter LessThan(const FieldPath &field, const FieldValue &value); + static Filter LessThanOrEqualTo(const FieldPath &field, const FieldValue &value); + static Filter In(const FieldPath &field, const std::vector &values); + static Filter NotIn(const FieldPath &field, const std::vector &values); + + template + static Filter Or(const Filter& filter, const Filters & ... filters); + + template + static Filter And(const Filter & filter, const Filters & ... filters); + + Filter(const Filter& other); + Filter(Filter&& other) noexcept; + Filter& operator=(const Filter& other); + Filter& operator=(Filter&& other) noexcept; + + ~Filter(); + + private: + friend bool operator==(const Filter& lhs, const Filter& rhs); + friend struct ConverterImpl; + + explicit Filter(FilterInternal* internal); + FilterInternal* internal_; +}; + +/** Checks `lhs` and `rhs` for equality. */ +bool operator==(const Filter& lhs, const Filter& rhs); + +/** Checks `lhs` and `rhs` for inequality. */ +inline bool operator!=(const Filter& lhs, const Filter& rhs) { + return !(lhs == rhs); +} + +} // namespace firestore +} // namespace firebase + +#endif // FIREBASE_FIRESTORE_SRC_INCLUDE_FIREBASE_FIRESTORE_FILTER_H_ diff --git a/firestore/src/include/firebase/firestore/query.h b/firestore/src/include/firebase/firestore/query.h index 0586756854..6666cf2ee3 100644 --- a/firestore/src/include/firebase/firestore/query.h +++ b/firestore/src/include/firebase/firestore/query.h @@ -41,6 +41,7 @@ class AggregateQuery; class DocumentSnapshot; template class EventListener; +class Filter; class FieldPath; class FieldValue; class ListenerRegistration; @@ -161,6 +162,14 @@ class Query { */ virtual AggregateQuery Count() const; + /** + * @brief Creates and returns a new Query with the additional filter. + * + * @param filter The new filter to apply to the existing query. + * @return The created Query. + */ + virtual Query Where(const Filter& filter) const; + /** * @brief Creates and returns a new Query with the additional filter that * documents must contain the specified field and the value should be equal to diff --git a/firestore/src/main/composite_filter_main.cc b/firestore/src/main/composite_filter_main.cc new file mode 100644 index 0000000000..49a7b9680b --- /dev/null +++ b/firestore/src/main/composite_filter_main.cc @@ -0,0 +1,52 @@ +/* +* Copyright 2023 Google LLC +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. + */ + +#if defined(__ANDROID__) +#error "This header should not be used on Android." +#endif + +#include "firestore/src/main/composite_filter_main.h" +#include "Firestore/core/src/core/composite_filter.h" + +namespace firebase { +namespace firestore { + +template +CompositeFilterInternal::CompositeFilterInternal( + core::CompositeFilter::Operator op, + const Filter& filter, Ts... filters) + : FilterInternal(FilterType::Composite), op_(op), filters_(filter, filters...) {} + +CompositeFilterInternal* CompositeFilterInternal::clone() { + return new CompositeFilterInternal(*this); +} + +core::Filter CompositeFilterInternal::filter_core( + const api::Query& query, + const firebase::firestore::UserDataConverter& user_data_converter) const { + std::vector core_filters; + for (auto& filter : filters_) { + core_filters.push_back(filter->filter_core(query, user_data_converter)); + } + return core::CompositeFilter::Create(std::move(core_filters), op_); +} + +bool operator==(const CompositeFilterInternal& lhs, const CompositeFilterInternal& rhs) { + return lhs.op_ == rhs.op_ && lhs.filters_ == rhs.filters_; +} + +} // namespace firestore +} // namespace firebase diff --git a/firestore/src/main/composite_filter_main.h b/firestore/src/main/composite_filter_main.h new file mode 100644 index 0000000000..43bd945e7d --- /dev/null +++ b/firestore/src/main/composite_filter_main.h @@ -0,0 +1,52 @@ +/* +* 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. + */ + +#ifndef FIREBASE_FIRESTORE_SRC_MAIN_COMPOSITE_FILTER_MAIN_H_ +#define FIREBASE_FIRESTORE_SRC_MAIN_COMPOSITE_FILTER_MAIN_H_ + +#if defined(__ANDROID__) +#error "This header should not be used on Android." +#endif + +#include "Firestore/core/src/api/query_core.h" +#include "firestore/src/main/filter_main.h" + +namespace firebase { +namespace firestore { + +class CompositeFilterInternal : public FilterInternal { + public: + template + CompositeFilterInternal(core::CompositeFilter::Operator op, const Filter& filter, Ts... filters); + + core::Filter filter_core(const api::Query& query, const UserDataConverter& user_data_converter) const override; + + friend bool operator==(const CompositeFilterInternal& lhs, const CompositeFilterInternal& rhs); + private: + CompositeFilterInternal* clone() override; + + const core::CompositeFilter::Operator op_; + const std::vector> filters_; +}; + +inline bool operator!=(const CompositeFilterInternal& lhs, const CompositeFilterInternal& rhs) { + return !(lhs == rhs); +} + +} // namespace firestore +} // namespace firebase + +#endif // FIREBASE_FIRESTORE_SRC_MAIN_COMPOSITE_FILTER_MAIN_H_ diff --git a/firestore/src/main/converter_main.h b/firestore/src/main/converter_main.h index 14dac38a59..a4f1146e3c 100644 --- a/firestore/src/main/converter_main.h +++ b/firestore/src/main/converter_main.h @@ -38,6 +38,7 @@ #include "firestore/src/main/aggregate_query_main.h" #include "firestore/src/main/aggregate_query_snapshot_main.h" #include "firestore/src/main/collection_reference_main.h" +#include "firestore/src/main/composite_filter_main.h" #include "firestore/src/main/document_change_main.h" #include "firestore/src/main/document_reference_main.h" #include "firestore/src/main/document_snapshot_main.h" @@ -46,6 +47,7 @@ #include "firestore/src/main/query_main.h" #include "firestore/src/main/query_snapshot_main.h" #include "firestore/src/main/transaction_main.h" +#include "firestore/src/main/unary_filter_main.h" #include "firestore/src/main/write_batch_main.h" #if defined(__ANDROID__) @@ -108,6 +110,14 @@ inline DocumentSnapshot MakePublic(api::DocumentSnapshot&& from) { return ConverterImpl::MakePublicFromCore(std::move(from)); } +inline Filter MakePublic(UnaryFilterInternal&& from) { + return ConverterImpl::MakePublicFromInternal(std::move(from)); +} + +inline Filter MakePublic(CompositeFilterInternal&& from) { + return ConverterImpl::MakePublicFromInternal(std::move(from)); +} + inline FieldValue MakePublic(FieldValueInternal&& from) { return ConverterImpl::MakePublicFromInternal(std::move(from)); } diff --git a/firestore/src/main/filter_main.cc b/firestore/src/main/filter_main.cc new file mode 100644 index 0000000000..96253a1142 --- /dev/null +++ b/firestore/src/main/filter_main.cc @@ -0,0 +1,54 @@ +/* +* 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. + */ + +#include "firestore/src/main/converter_main.h" +#include "firestore/src/main/filter_main.h" +#include "firestore/src/main/unary_filter_main.h" +#include "firestore/src/main/composite_filter_main.h" + +namespace firebase { +namespace firestore { + +FilterInternal::FilterInternal(FilterInternal::FilterType filter_type) : filter_type_(filter_type) {} + +Filter FilterInternal::UnaryFilter(const FieldPath& field_path, + UnaryOperator op, const FieldValue& value) { + return MakePublic(UnaryFilterInternal(field_path, op, value)); +} + +Filter FilterInternal::UnaryFilter(const FieldPath& field_path, UnaryOperator op, const std::vector& values) { + return MakePublic(UnaryFilterInternal(field_path, op, values)); +} + +template +Filter FilterInternal::CompositeFilter(core::CompositeFilter::Operator op, const Filter& filter, const Filters&... filters) { + return MakePublic(CompositeFilterInternal(op, filter, filters...)); +} + +bool operator==(const FilterInternal& lhs, const FilterInternal& rhs) { + if (lhs.filter_type_ == rhs.filter_type_) { + switch (lhs.filter_type_) { + case FilterInternal::Composite: + return *static_cast(&lhs) == *static_cast(&rhs); + case FilterInternal::Unary: + return *static_cast(&lhs) == *static_cast(&rhs); + } + } + return false; +} + +} // namespace firestore +} // namespace firebase diff --git a/firestore/src/main/filter_main.h b/firestore/src/main/filter_main.h new file mode 100644 index 0000000000..ce75b8b8c1 --- /dev/null +++ b/firestore/src/main/filter_main.h @@ -0,0 +1,131 @@ +/* +* 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. +*/ + +#ifndef FIREBASE_FIRESTORE_SRC_MAIN_FILTER_MAIN_H_ +#define FIREBASE_FIRESTORE_SRC_MAIN_FILTER_MAIN_H_ + +#if defined(__ANDROID__) +#error "This header should not be used on Android." +#endif + +#include "Firestore/core/src/core/composite_filter.h" +#include "Firestore/core/src/core/filter.h" +#include "Firestore/core/src/core/field_filter.h" +#include "firestore/src/include/firebase/firestore/filter.h" +#include "firestore/src/main/user_data_converter_main.h" + +namespace firebase { +namespace firestore { + +class FilterInternal { + public: + + static Filter ArrayContains(const FieldPath &field, const FieldValue &value) { + return UnaryFilter(field, UnaryOperator::ArrayContains, value); + } + + static Filter ArrayContainsAny(const FieldPath &field, const std::vector &values) { + return UnaryFilter(field, UnaryOperator::ArrayContainsAny, values); + } + + static Filter EqualTo(const FieldPath &field, const FieldValue &value) { + return UnaryFilter(field, UnaryOperator::Equal, value); + } + + static Filter NotEqualTo(const FieldPath &field, const FieldValue &value) { + return UnaryFilter(field, UnaryOperator::NotEqual, value); + } + + static Filter GreaterThan(const FieldPath &field, const FieldValue &value) { + return UnaryFilter(field, UnaryOperator::GreaterThan, value); + } + + static Filter GreaterThanOrEqualTo(const FieldPath &field, const FieldValue &value) { + return UnaryFilter(field, UnaryOperator::GreaterThanOrEqual, value); + } + + static Filter LessThan(const FieldPath &field, const FieldValue &value) { + return UnaryFilter(field, UnaryOperator::LessThan, value); + } + + static Filter LessThanOrEqualTo(const FieldPath &field, const FieldValue &value) { + return UnaryFilter(field, UnaryOperator::LessThanOrEqual, value); + } + + static Filter In(const FieldPath &field, const std::vector &values) { + return UnaryFilter(field, UnaryOperator::In, values); + } + + static Filter NotIn(const FieldPath &field, const std::vector &values) { + return UnaryFilter(field, UnaryOperator::NotIn, values); + } + + virtual core::Filter filter_core(const api::Query& query, const UserDataConverter& user_data_converter) const = 0; + + template + static Filter Or(const Filter& filter, const Filters& ... filters) { + return CompositeFilter(CompositeOperator::Or, filter, filters...); + } + + template + static Filter And(const Filter& filter, const Filters& ... filters) { + return CompositeFilter(CompositeOperator::And, filter, filters...); + }; + + virtual ~FilterInternal() = default; + + friend bool operator==(const FilterInternal& lhs, const FilterInternal& rhs); + + protected: + enum FilterType { + Unary, Composite + }; + + explicit FilterInternal(FilterType filterType); + + const FilterType filter_type_; + + private: + + friend class Filter; + friend class QueryInternal; + + virtual FilterInternal* clone() = 0; + + using UnaryOperator = core::FieldFilter::Operator; + using CompositeOperator = core::CompositeFilter::Operator; + + static Filter UnaryFilter(const FieldPath& field_path, + UnaryOperator op, const FieldValue& value); + static Filter UnaryFilter(const FieldPath& field_path, + UnaryOperator op, const std::vector& values); + + static Filter CompositeFilter(CompositeOperator op, const Filter& filter) { + return filter; + } + + template + static Filter CompositeFilter(CompositeOperator op, const Filter& filter, const Filters& ... filters); +}; + +inline bool operator!=(const FilterInternal& lhs, const FilterInternal& rhs) { + return !(lhs == rhs); +} + +} // namespace firestore +} // namespace firebase + +#endif // FIREBASE_FIRESTORE_SRC_MAIN_FILTER_MAIN_H_ diff --git a/firestore/src/main/query_main.cc b/firestore/src/main/query_main.cc index ffed058c9e..03b51afffd 100644 --- a/firestore/src/main/query_main.cc +++ b/firestore/src/main/query_main.cc @@ -37,6 +37,7 @@ #include "firestore/src/main/aggregate_query_main.h" #include "firestore/src/main/converter_main.h" #include "firestore/src/main/document_snapshot_main.h" +#include "firestore/src/main/filter_main.h" #include "firestore/src/main/listener_main.h" #include "firestore/src/main/promise_main.h" #include "firestore/src/main/set_options_main.h" @@ -98,6 +99,12 @@ Future QueryInternal::Get(Source source) { AggregateQuery QueryInternal::Count() { return MakePublic(query_.Count()); } +Query QueryInternal::Where(const Filter& filter) const { + core::Filter core_filter = GetInternal(&filter)->filter_core(query_, user_data_converter_); + api::Query decorated = query_.AddNewFilter(std::move(core_filter)); + return MakePublic(std::move(decorated)); +} + Query QueryInternal::Where(const FieldPath& field_path, Operator op, const FieldValue& value) const { @@ -114,14 +121,14 @@ Query QueryInternal::Where(const FieldPath& field_path, Query QueryInternal::Where(const FieldPath& field_path, Operator op, const std::vector& values) const { + //return Where(field_path, op, FieldValue::Array(values)); const model::FieldPath& path = GetInternal(field_path); auto array_value = FieldValue::Array(values); Message parsed = user_data_converter_.ParseQueryValue(array_value, true); auto describer = [&array_value] { return Describe(array_value.type()); }; - api::Query decorated = query_.AddNewFilter( - query_.ParseFieldFilter(path, op, std::move(parsed), describer)); + api::Query decorated = query_.AddNewFilter(query_.ParseFieldFilter(path, op, std::move(parsed), describer)); return MakePublic(std::move(decorated)); } diff --git a/firestore/src/main/query_main.h b/firestore/src/main/query_main.h index 958df81f03..8cc38b7eed 100644 --- a/firestore/src/main/query_main.h +++ b/firestore/src/main/query_main.h @@ -27,6 +27,7 @@ #include "Firestore/core/src/core/order_by.h" #include "Firestore/core/src/core/query.h" #include "Firestore/core/src/nanopb/message.h" +#include "firestore/src/include/firebase/firestore/filter.h" #include "firestore/src/include/firebase/firestore/field_path.h" #include "firestore/src/include/firebase/firestore/query.h" #include "firestore/src/main/firestore_main.h" @@ -68,6 +69,7 @@ class QueryInternal { callback); // Delegating methods + Query Where(const Filter& filter) const; Query WhereEqualTo(const FieldPath& field, const FieldValue& value) const { return Where(field, Operator::Equal, value); diff --git a/firestore/src/main/unary_filter_main.cc b/firestore/src/main/unary_filter_main.cc new file mode 100644 index 0000000000..ec04eb705c --- /dev/null +++ b/firestore/src/main/unary_filter_main.cc @@ -0,0 +1,53 @@ +/* +* 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. + */ + +#include "firestore/src/main/unary_filter_main.h" + +#include "Firestore/core/src/nanopb/message.h" +#include "firestore/src/main/converter_main.h" + +namespace firebase { +namespace firestore { + +using nanopb::Message; + +UnaryFilterInternal::UnaryFilterInternal(FieldPath field_path, core::FieldFilter::Operator op, FieldValue value) + : FilterInternal(FilterType::Unary), path_(std::move(field_path)), op_(op), value_(std::move(value)){} + +UnaryFilterInternal::UnaryFilterInternal(FieldPath field_path, core::FieldFilter::Operator op, const std::vector& values) + : FilterInternal(FilterType::Unary), allow_arrays_(true), path_(std::move(field_path)), op_(op), value_(FieldValue::Array(values)){} + +UnaryFilterInternal* UnaryFilterInternal::clone() { + return new UnaryFilterInternal(*this); +} + +core::Filter UnaryFilterInternal::filter_core( + const api::Query& query, + const UserDataConverter& user_data_converter) const { + const model::FieldPath& path = GetInternal(path_); + Message parsed = + user_data_converter.ParseQueryValue(value_, allow_arrays_); + auto describer = [this] { return Describe(value_.type()); }; + + return query.ParseFieldFilter(path, op_, std::move(parsed), describer); +} + +bool operator==(const UnaryFilterInternal& lhs, const UnaryFilterInternal& rhs) { + return lhs.op_ == rhs.op_ && lhs.path_ == rhs.path_ && lhs.value_ == rhs.value_; +} + +} // namespace firestore +} // namespace firebase diff --git a/firestore/src/main/unary_filter_main.h b/firestore/src/main/unary_filter_main.h new file mode 100644 index 0000000000..ff3f528215 --- /dev/null +++ b/firestore/src/main/unary_filter_main.h @@ -0,0 +1,54 @@ +/* +* 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. + */ + +#ifndef FIREBASE_FIRESTORE_SRC_MAIN_UNARY_FILTER_MAIN_H_ +#define FIREBASE_FIRESTORE_SRC_MAIN_UNARY_FILTER_MAIN_H_ + +#if defined(__ANDROID__) +#error "This header should not be used on Android." +#endif + +#include "Firestore/core/src/api/query_core.h" +#include "firestore/src/main/filter_main.h" + +namespace firebase { +namespace firestore { + +class UnaryFilterInternal final : public FilterInternal { + public: + UnaryFilterInternal(FieldPath field_path, core::FieldFilter::Operator op, FieldValue value); + UnaryFilterInternal(FieldPath field_path, core::FieldFilter::Operator op, const std::vector& values); + + core::Filter filter_core(const api::Query& query, const UserDataConverter& user_data_converter) const override; + + friend bool operator==(const UnaryFilterInternal& lhs, const UnaryFilterInternal& rhs); + private: + UnaryFilterInternal* clone() override; + + const bool allow_arrays_ = false; + const FieldPath path_; + const core::FieldFilter::Operator op_; + const FieldValue value_; +}; + +inline bool operator!=(const UnaryFilterInternal& lhs, const UnaryFilterInternal& rhs) { + return !(lhs == rhs); +} + +} // namespace firestore +} // namespace firebase + +#endif // FIREBASE_FIRESTORE_SRC_MAIN_UNARY_FILTER_MAIN_H_ From e2623f642b97b15c27c004626a63feba2fcf21c1 Mon Sep 17 00:00:00 2001 From: Tom Andersen Date: Mon, 29 May 2023 16:47:34 -0400 Subject: [PATCH 02/25] Pretty --- .../src/filter_test.cc | 75 ++++++----- firestore/src/common/filter.cc | 116 ++++++++++-------- firestore/src/common/query.cc | 2 +- .../src/include/firebase/firestore/filter.h | 95 +++++++------- firestore/src/main/composite_filter_main.cc | 40 +++--- firestore/src/main/composite_filter_main.h | 43 ++++--- firestore/src/main/filter_main.cc | 52 ++++---- firestore/src/main/filter_main.h | 85 +++++++------ firestore/src/main/query_main.cc | 8 +- firestore/src/main/query_main.h | 2 +- firestore/src/main/unary_filter_main.cc | 55 +++++---- firestore/src/main/unary_filter_main.h | 45 ++++--- 12 files changed, 347 insertions(+), 271 deletions(-) diff --git a/firestore/integration_test_internal/src/filter_test.cc b/firestore/integration_test_internal/src/filter_test.cc index d946d71fa5..e448dc85c9 100644 --- a/firestore/integration_test_internal/src/filter_test.cc +++ b/firestore/integration_test_internal/src/filter_test.cc @@ -1,18 +1,18 @@ /* -* 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. -*/ + * 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. + */ #include "firebase/firestore.h" #include "firestore_integration_test.h" @@ -29,8 +29,10 @@ TEST_F(FilterTest, IdenticalShouldBeEqual) { Filter filter1a = Filter::ArrayContains("foo", FieldValue::Integer(42)); Filter filter1b = Filter::ArrayContains(foo_path, FieldValue::Integer(42)); - Filter filter2a = Filter::ArrayContainsAny("foo", std::vector{FieldValue::Integer(42)}); - Filter filter2b = Filter::ArrayContainsAny(foo_path, std::vector{FieldValue::Integer(42)}); + Filter filter2a = Filter::ArrayContainsAny( + "foo", std::vector{FieldValue::Integer(42)}); + Filter filter2b = Filter::ArrayContainsAny( + foo_path, std::vector{FieldValue::Integer(42)}); Filter filter3a = Filter::EqualTo("foo", FieldValue::Integer(42)); Filter filter3b = Filter::EqualTo(foo_path, FieldValue::Integer(42)); @@ -41,20 +43,27 @@ TEST_F(FilterTest, IdenticalShouldBeEqual) { Filter filter5a = Filter::GreaterThan("foo", FieldValue::Integer(42)); Filter filter5b = Filter::GreaterThan(foo_path, FieldValue::Integer(42)); - Filter filter6a = Filter::GreaterThanOrEqualTo("foo", FieldValue::Integer(42)); - Filter filter6b = Filter::GreaterThanOrEqualTo(foo_path, FieldValue::Integer(42)); + Filter filter6a = + Filter::GreaterThanOrEqualTo("foo", FieldValue::Integer(42)); + Filter filter6b = + Filter::GreaterThanOrEqualTo(foo_path, FieldValue::Integer(42)); Filter filter7a = Filter::LessThan("foo", FieldValue::Integer(42)); Filter filter7b = Filter::LessThan(foo_path, FieldValue::Integer(42)); Filter filter8a = Filter::LessThanOrEqualTo("foo", FieldValue::Integer(42)); - Filter filter8b = Filter::LessThanOrEqualTo(foo_path, FieldValue::Integer(42)); + Filter filter8b = + Filter::LessThanOrEqualTo(foo_path, FieldValue::Integer(42)); - Filter filter9a = Filter::In("foo", std::vector{FieldValue::Integer(42)}); - Filter filter9b = Filter::In(foo_path, std::vector{FieldValue::Integer(42)}); + Filter filter9a = + Filter::In("foo", std::vector{FieldValue::Integer(42)}); + Filter filter9b = + Filter::In(foo_path, std::vector{FieldValue::Integer(42)}); - Filter filter10a = Filter::NotIn("foo", std::vector{FieldValue::Integer(42)}); - Filter filter10b = Filter::NotIn(foo_path, std::vector{FieldValue::Integer(42)}); + Filter filter10a = + Filter::NotIn("foo", std::vector{FieldValue::Integer(42)}); + Filter filter10b = + Filter::NotIn(foo_path, std::vector{FieldValue::Integer(42)}); EXPECT_TRUE(filter1a == filter1a); EXPECT_TRUE(filter2a == filter2a); @@ -160,8 +169,10 @@ TEST_F(FilterTest, DifferentValuesAreNotEqual) { Filter filter4a = Filter::GreaterThan("foo", FieldValue::Integer(24)); Filter filter4b = Filter::GreaterThan("foo", FieldValue::Integer(42)); - Filter filter5a = Filter::GreaterThanOrEqualTo("foo", FieldValue::Integer(24)); - Filter filter5b = Filter::GreaterThanOrEqualTo("foo", FieldValue::Integer(42)); + Filter filter5a = + Filter::GreaterThanOrEqualTo("foo", FieldValue::Integer(24)); + Filter filter5b = + Filter::GreaterThanOrEqualTo("foo", FieldValue::Integer(42)); Filter filter6a = Filter::LessThan("foo", FieldValue::Integer(24)); Filter filter6b = Filter::LessThan("foo", FieldValue::Integer(42)); @@ -187,14 +198,10 @@ TEST_F(FilterTest, DifferentValuesAreNotEqual) { } TEST_F(FilterTest, DifferentOrderOfValuesAreNotEqual) { - const std::vector& valueOrderA = std::vector{ - FieldValue::Integer(1), - FieldValue::Integer(2) - }; - const std::vector& valueOrderB = std::vector{ - FieldValue::Integer(2), - FieldValue::Integer(1) - }; + const std::vector& valueOrderA = + std::vector{FieldValue::Integer(1), FieldValue::Integer(2)}; + const std::vector& valueOrderB = + std::vector{FieldValue::Integer(2), FieldValue::Integer(1)}; { Filter filter1 = Filter::ArrayContainsAny("foo", valueOrderA); @@ -218,7 +225,7 @@ TEST_F(FilterTest, DifferentOrderOfValuesAreNotEqual) { } } -} +} // namespace } // namespace firestore } // namespace firebase diff --git a/firestore/src/common/filter.cc b/firestore/src/common/filter.cc index 30f11cbf2e..38a194d58f 100644 --- a/firestore/src/common/filter.cc +++ b/firestore/src/common/filter.cc @@ -1,17 +1,17 @@ /* -* 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. + * 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. */ #include "firebase/firestore/filter.h" @@ -28,9 +28,7 @@ namespace firebase { namespace firestore { -Filter::Filter(const Filter& other) { - internal_ = other.internal_->clone(); -} +Filter::Filter(const Filter& other) { internal_ = other.internal_->clone(); } Filter::Filter(Filter&& other) noexcept { std::swap(internal_, other.internal_); @@ -64,93 +62,105 @@ Filter& Filter::operator=(Filter&& other) noexcept { return *this; } -Filter Filter::ArrayContains(const std::string &field, const FieldValue & value) { - return ArrayContains(FieldPath::FromDotSeparatedString(field), value); +Filter Filter::ArrayContains(const std::string& field, + const FieldValue& value) { + return ArrayContains(FieldPath::FromDotSeparatedString(field), value); } -Filter Filter::ArrayContainsAny(const std::string &field, const std::vector &values) { +Filter Filter::ArrayContainsAny(const std::string& field, + const std::vector& values) { return ArrayContainsAny(FieldPath::FromDotSeparatedString(field), values); } -Filter Filter::EqualTo(const std::string& field, const firebase::firestore::FieldValue& value) { +Filter Filter::EqualTo(const std::string& field, + const firebase::firestore::FieldValue& value) { return EqualTo(FieldPath::FromDotSeparatedString(field), value); } -Filter Filter::NotEqualTo(const std::string &field, const FieldValue &value) { +Filter Filter::NotEqualTo(const std::string& field, const FieldValue& value) { return NotEqualTo(FieldPath::FromDotSeparatedString(field), value); } -Filter Filter::GreaterThan(const std::string &field, const FieldValue &value) { +Filter Filter::GreaterThan(const std::string& field, const FieldValue& value) { return GreaterThan(FieldPath::FromDotSeparatedString(field), value); } -Filter Filter::GreaterThanOrEqualTo(const std::string &field, const FieldValue &value) { +Filter Filter::GreaterThanOrEqualTo(const std::string& field, + const FieldValue& value) { return GreaterThanOrEqualTo(FieldPath::FromDotSeparatedString(field), value); } -Filter Filter::LessThan(const std::string &field, const FieldValue &value) { +Filter Filter::LessThan(const std::string& field, const FieldValue& value) { return LessThan(FieldPath::FromDotSeparatedString(field), value); } -Filter Filter::LessThanOrEqualTo(const std::string &field, const FieldValue &value) { - return LessThanOrEqualTo(FieldPath::FromDotSeparatedString(field), value); +Filter Filter::LessThanOrEqualTo(const std::string& field, + const FieldValue& value) { + return LessThanOrEqualTo(FieldPath::FromDotSeparatedString(field), value); } -Filter Filter::In(const std::string &field, const std::vector &values) { - return In(FieldPath::FromDotSeparatedString(field), values); +Filter Filter::In(const std::string& field, + const std::vector& values) { + return In(FieldPath::FromDotSeparatedString(field), values); } -Filter Filter::NotIn(const std::string &field, const std::vector &values) { - return NotIn(FieldPath::FromDotSeparatedString(field), values); +Filter Filter::NotIn(const std::string& field, + const std::vector& values) { + return NotIn(FieldPath::FromDotSeparatedString(field), values); } -Filter Filter::ArrayContains(const FieldPath &field, const FieldValue &value) { - return FilterInternal::ArrayContains(field, value); +Filter Filter::ArrayContains(const FieldPath& field, const FieldValue& value) { + return FilterInternal::ArrayContains(field, value); } -Filter Filter::ArrayContainsAny(const FieldPath &field, const std::vector &values) { - return FilterInternal::ArrayContainsAny(field, values); +Filter Filter::ArrayContainsAny(const FieldPath& field, + const std::vector& values) { + return FilterInternal::ArrayContainsAny(field, values); } -Filter Filter::EqualTo(const FieldPath &field, const FieldValue &value) { - return FilterInternal::EqualTo(field, value); +Filter Filter::EqualTo(const FieldPath& field, const FieldValue& value) { + return FilterInternal::EqualTo(field, value); } -Filter Filter::NotEqualTo(const FieldPath &field, const FieldValue &value) { - return FilterInternal::NotEqualTo(field, value); +Filter Filter::NotEqualTo(const FieldPath& field, const FieldValue& value) { + return FilterInternal::NotEqualTo(field, value); } -Filter Filter::GreaterThan(const FieldPath &field, const FieldValue &value) { - return FilterInternal::GreaterThan(field, value); +Filter Filter::GreaterThan(const FieldPath& field, const FieldValue& value) { + return FilterInternal::GreaterThan(field, value); } -Filter Filter::GreaterThanOrEqualTo(const FieldPath &field, const FieldValue &value) { - return FilterInternal::GreaterThanOrEqualTo(field, value); +Filter Filter::GreaterThanOrEqualTo(const FieldPath& field, + const FieldValue& value) { + return FilterInternal::GreaterThanOrEqualTo(field, value); } -Filter Filter::LessThan(const FieldPath &field, const FieldValue &value) { - return FilterInternal::LessThan(field, value); +Filter Filter::LessThan(const FieldPath& field, const FieldValue& value) { + return FilterInternal::LessThan(field, value); } -Filter Filter::LessThanOrEqualTo(const FieldPath &field, const FieldValue &value) { - return FilterInternal::LessThanOrEqualTo(field, value); +Filter Filter::LessThanOrEqualTo(const FieldPath& field, + const FieldValue& value) { + return FilterInternal::LessThanOrEqualTo(field, value); } -Filter Filter::In(const FieldPath &field, const std::vector &values) { - return FilterInternal::In(field, values); +Filter Filter::In(const FieldPath& field, + const std::vector& values) { + return FilterInternal::In(field, values); } -Filter Filter::NotIn(const FieldPath &field, const std::vector &values) { +Filter Filter::NotIn(const FieldPath& field, + const std::vector& values) { return FilterInternal::NotIn(field, values); } -template -Filter Filter::Or(const Filter& filter, const Filters& ... filters) { +template +Filter Filter::Or(const Filter& filter, const Filters&... filters) { return FilterInternal::Or(filter, filters...); } -template -Filter Filter::And(const Filter& filter, const Filters& ... filters) { +template +Filter Filter::And(const Filter& filter, const Filters&... filters) { return FilterInternal::And(filter, filters...); } diff --git a/firestore/src/common/query.cc b/firestore/src/common/query.cc index 08f3381b48..04bd301432 100644 --- a/firestore/src/common/query.cc +++ b/firestore/src/common/query.cc @@ -25,9 +25,9 @@ #include "firestore/src/common/util.h" #include "firestore/src/include/firebase/firestore/aggregate_query.h" #include "firestore/src/include/firebase/firestore/document_snapshot.h" -#include "firestore/src/include/firebase/firestore/filter.h" #include "firestore/src/include/firebase/firestore/field_path.h" #include "firestore/src/include/firebase/firestore/field_value.h" +#include "firestore/src/include/firebase/firestore/filter.h" #include "firestore/src/include/firebase/firestore/listener_registration.h" #include "firestore/src/include/firebase/firestore/query_snapshot.h" #if defined(__ANDROID__) diff --git a/firestore/src/include/firebase/firestore/filter.h b/firestore/src/include/firebase/firestore/filter.h index 6a25955c54..e9e7557681 100644 --- a/firestore/src/include/firebase/firestore/filter.h +++ b/firestore/src/include/firebase/firestore/filter.h @@ -27,48 +27,59 @@ namespace firestore { class FilterInternal; class Filter { - public: - static Filter ArrayContains(const std::string &field, const FieldValue & value); - static Filter ArrayContainsAny(const std::string &field, const std::vector &values); - static Filter EqualTo(const std::string &field, const FieldValue &value); - static Filter NotEqualTo(const std::string &field, const FieldValue &value); - static Filter GreaterThan(const std::string &field, const FieldValue &value); - static Filter GreaterThanOrEqualTo(const std::string &field, const FieldValue &value); - static Filter LessThan(const std::string &field, const FieldValue &value); - static Filter LessThanOrEqualTo(const std::string &field, const FieldValue &value); - static Filter In(const std::string &field, const std::vector &values); - static Filter NotIn(const std::string &field, const std::vector &values); - - static Filter ArrayContains(const FieldPath &field, const FieldValue &value); - static Filter ArrayContainsAny(const FieldPath &field, const std::vector &values); - static Filter EqualTo(const FieldPath &field, const FieldValue &value); - static Filter NotEqualTo(const FieldPath &field, const FieldValue &value); - static Filter GreaterThan(const FieldPath &field, const FieldValue &value); - static Filter GreaterThanOrEqualTo(const FieldPath &field, const FieldValue &value); - static Filter LessThan(const FieldPath &field, const FieldValue &value); - static Filter LessThanOrEqualTo(const FieldPath &field, const FieldValue &value); - static Filter In(const FieldPath &field, const std::vector &values); - static Filter NotIn(const FieldPath &field, const std::vector &values); - - template - static Filter Or(const Filter& filter, const Filters & ... filters); - - template - static Filter And(const Filter & filter, const Filters & ... filters); - - Filter(const Filter& other); - Filter(Filter&& other) noexcept; - Filter& operator=(const Filter& other); - Filter& operator=(Filter&& other) noexcept; - - ~Filter(); - - private: - friend bool operator==(const Filter& lhs, const Filter& rhs); - friend struct ConverterImpl; - - explicit Filter(FilterInternal* internal); - FilterInternal* internal_; + public: + static Filter ArrayContains(const std::string& field, + const FieldValue& value); + static Filter ArrayContainsAny(const std::string& field, + const std::vector& values); + static Filter EqualTo(const std::string& field, const FieldValue& value); + static Filter NotEqualTo(const std::string& field, const FieldValue& value); + static Filter GreaterThan(const std::string& field, const FieldValue& value); + static Filter GreaterThanOrEqualTo(const std::string& field, + const FieldValue& value); + static Filter LessThan(const std::string& field, const FieldValue& value); + static Filter LessThanOrEqualTo(const std::string& field, + const FieldValue& value); + static Filter In(const std::string& field, + const std::vector& values); + static Filter NotIn(const std::string& field, + const std::vector& values); + + static Filter ArrayContains(const FieldPath& field, const FieldValue& value); + static Filter ArrayContainsAny(const FieldPath& field, + const std::vector& values); + static Filter EqualTo(const FieldPath& field, const FieldValue& value); + static Filter NotEqualTo(const FieldPath& field, const FieldValue& value); + static Filter GreaterThan(const FieldPath& field, const FieldValue& value); + static Filter GreaterThanOrEqualTo(const FieldPath& field, + const FieldValue& value); + static Filter LessThan(const FieldPath& field, const FieldValue& value); + static Filter LessThanOrEqualTo(const FieldPath& field, + const FieldValue& value); + static Filter In(const FieldPath& field, + const std::vector& values); + static Filter NotIn(const FieldPath& field, + const std::vector& values); + + template + static Filter Or(const Filter& filter, const Filters&... filters); + + template + static Filter And(const Filter& filter, const Filters&... filters); + + Filter(const Filter& other); + Filter(Filter&& other) noexcept; + Filter& operator=(const Filter& other); + Filter& operator=(Filter&& other) noexcept; + + ~Filter(); + + private: + friend bool operator==(const Filter& lhs, const Filter& rhs); + friend struct ConverterImpl; + + explicit Filter(FilterInternal* internal); + FilterInternal* internal_; }; /** Checks `lhs` and `rhs` for equality. */ diff --git a/firestore/src/main/composite_filter_main.cc b/firestore/src/main/composite_filter_main.cc index 49a7b9680b..5cf2f063a8 100644 --- a/firestore/src/main/composite_filter_main.cc +++ b/firestore/src/main/composite_filter_main.cc @@ -1,17 +1,17 @@ /* -* 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. + * Copyright 2023 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ #if defined(__ANDROID__) @@ -24,11 +24,12 @@ namespace firebase { namespace firestore { -template +template CompositeFilterInternal::CompositeFilterInternal( - core::CompositeFilter::Operator op, - const Filter& filter, Ts... filters) - : FilterInternal(FilterType::Composite), op_(op), filters_(filter, filters...) {} + core::CompositeFilter::Operator op, const Filter& filter, Ts... filters) + : FilterInternal(FilterType::Composite), + op_(op), + filters_(filter, filters...) {} CompositeFilterInternal* CompositeFilterInternal::clone() { return new CompositeFilterInternal(*this); @@ -44,9 +45,10 @@ core::Filter CompositeFilterInternal::filter_core( return core::CompositeFilter::Create(std::move(core_filters), op_); } -bool operator==(const CompositeFilterInternal& lhs, const CompositeFilterInternal& rhs) { +bool operator==(const CompositeFilterInternal& lhs, + const CompositeFilterInternal& rhs) { return lhs.op_ == rhs.op_ && lhs.filters_ == rhs.filters_; } -} // namespace firestore +} // namespace firestore } // namespace firebase diff --git a/firestore/src/main/composite_filter_main.h b/firestore/src/main/composite_filter_main.h index 43bd945e7d..1a92cf9f5f 100644 --- a/firestore/src/main/composite_filter_main.h +++ b/firestore/src/main/composite_filter_main.h @@ -1,17 +1,17 @@ /* -* 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. + * 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. */ #ifndef FIREBASE_FIRESTORE_SRC_MAIN_COMPOSITE_FILTER_MAIN_H_ @@ -29,12 +29,18 @@ namespace firestore { class CompositeFilterInternal : public FilterInternal { public: - template - CompositeFilterInternal(core::CompositeFilter::Operator op, const Filter& filter, Ts... filters); + template + CompositeFilterInternal(core::CompositeFilter::Operator op, + const Filter& filter, + Ts... filters); - core::Filter filter_core(const api::Query& query, const UserDataConverter& user_data_converter) const override; + core::Filter filter_core( + const api::Query& query, + const UserDataConverter& user_data_converter) const override; + + friend bool operator==(const CompositeFilterInternal& lhs, + const CompositeFilterInternal& rhs); - friend bool operator==(const CompositeFilterInternal& lhs, const CompositeFilterInternal& rhs); private: CompositeFilterInternal* clone() override; @@ -42,7 +48,8 @@ class CompositeFilterInternal : public FilterInternal { const std::vector> filters_; }; -inline bool operator!=(const CompositeFilterInternal& lhs, const CompositeFilterInternal& rhs) { +inline bool operator!=(const CompositeFilterInternal& lhs, + const CompositeFilterInternal& rhs) { return !(lhs == rhs); } diff --git a/firestore/src/main/filter_main.cc b/firestore/src/main/filter_main.cc index 96253a1142..b66b5bed44 100644 --- a/firestore/src/main/filter_main.cc +++ b/firestore/src/main/filter_main.cc @@ -1,40 +1,46 @@ /* -* 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. + * 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. */ -#include "firestore/src/main/converter_main.h" #include "firestore/src/main/filter_main.h" -#include "firestore/src/main/unary_filter_main.h" #include "firestore/src/main/composite_filter_main.h" +#include "firestore/src/main/converter_main.h" +#include "firestore/src/main/unary_filter_main.h" namespace firebase { namespace firestore { -FilterInternal::FilterInternal(FilterInternal::FilterType filter_type) : filter_type_(filter_type) {} +FilterInternal::FilterInternal(FilterInternal::FilterType filter_type) + : filter_type_(filter_type) {} Filter FilterInternal::UnaryFilter(const FieldPath& field_path, - UnaryOperator op, const FieldValue& value) { + UnaryOperator op, + const FieldValue& value) { return MakePublic(UnaryFilterInternal(field_path, op, value)); } -Filter FilterInternal::UnaryFilter(const FieldPath& field_path, UnaryOperator op, const std::vector& values) { +Filter FilterInternal::UnaryFilter(const FieldPath& field_path, + UnaryOperator op, + const std::vector& values) { return MakePublic(UnaryFilterInternal(field_path, op, values)); } -template -Filter FilterInternal::CompositeFilter(core::CompositeFilter::Operator op, const Filter& filter, const Filters&... filters) { +template +Filter FilterInternal::CompositeFilter(core::CompositeFilter::Operator op, + const Filter& filter, + const Filters&... filters) { return MakePublic(CompositeFilterInternal(op, filter, filters...)); } @@ -42,9 +48,11 @@ bool operator==(const FilterInternal& lhs, const FilterInternal& rhs) { if (lhs.filter_type_ == rhs.filter_type_) { switch (lhs.filter_type_) { case FilterInternal::Composite: - return *static_cast(&lhs) == *static_cast(&rhs); + return *static_cast(&lhs) == + *static_cast(&rhs); case FilterInternal::Unary: - return *static_cast(&lhs) == *static_cast(&rhs); + return *static_cast(&lhs) == + *static_cast(&rhs); } } return false; diff --git a/firestore/src/main/filter_main.h b/firestore/src/main/filter_main.h index ce75b8b8c1..94bd57f572 100644 --- a/firestore/src/main/filter_main.h +++ b/firestore/src/main/filter_main.h @@ -1,18 +1,18 @@ /* -* 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. -*/ + * 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. + */ #ifndef FIREBASE_FIRESTORE_SRC_MAIN_FILTER_MAIN_H_ #define FIREBASE_FIRESTORE_SRC_MAIN_FILTER_MAIN_H_ @@ -22,8 +22,8 @@ #endif #include "Firestore/core/src/core/composite_filter.h" -#include "Firestore/core/src/core/filter.h" #include "Firestore/core/src/core/field_filter.h" +#include "Firestore/core/src/core/filter.h" #include "firestore/src/include/firebase/firestore/filter.h" #include "firestore/src/main/user_data_converter_main.h" @@ -32,56 +32,62 @@ namespace firestore { class FilterInternal { public: - - static Filter ArrayContains(const FieldPath &field, const FieldValue &value) { + static Filter ArrayContains(const FieldPath& field, const FieldValue& value) { return UnaryFilter(field, UnaryOperator::ArrayContains, value); } - static Filter ArrayContainsAny(const FieldPath &field, const std::vector &values) { + static Filter ArrayContainsAny(const FieldPath& field, + const std::vector& values) { return UnaryFilter(field, UnaryOperator::ArrayContainsAny, values); } - static Filter EqualTo(const FieldPath &field, const FieldValue &value) { + static Filter EqualTo(const FieldPath& field, const FieldValue& value) { return UnaryFilter(field, UnaryOperator::Equal, value); } - static Filter NotEqualTo(const FieldPath &field, const FieldValue &value) { + static Filter NotEqualTo(const FieldPath& field, const FieldValue& value) { return UnaryFilter(field, UnaryOperator::NotEqual, value); } - static Filter GreaterThan(const FieldPath &field, const FieldValue &value) { + static Filter GreaterThan(const FieldPath& field, const FieldValue& value) { return UnaryFilter(field, UnaryOperator::GreaterThan, value); } - static Filter GreaterThanOrEqualTo(const FieldPath &field, const FieldValue &value) { + static Filter GreaterThanOrEqualTo(const FieldPath& field, + const FieldValue& value) { return UnaryFilter(field, UnaryOperator::GreaterThanOrEqual, value); } - static Filter LessThan(const FieldPath &field, const FieldValue &value) { + static Filter LessThan(const FieldPath& field, const FieldValue& value) { return UnaryFilter(field, UnaryOperator::LessThan, value); } - static Filter LessThanOrEqualTo(const FieldPath &field, const FieldValue &value) { + static Filter LessThanOrEqualTo(const FieldPath& field, + const FieldValue& value) { return UnaryFilter(field, UnaryOperator::LessThanOrEqual, value); } - static Filter In(const FieldPath &field, const std::vector &values) { + static Filter In(const FieldPath& field, + const std::vector& values) { return UnaryFilter(field, UnaryOperator::In, values); } - static Filter NotIn(const FieldPath &field, const std::vector &values) { + static Filter NotIn(const FieldPath& field, + const std::vector& values) { return UnaryFilter(field, UnaryOperator::NotIn, values); } - virtual core::Filter filter_core(const api::Query& query, const UserDataConverter& user_data_converter) const = 0; + virtual core::Filter filter_core( + const api::Query& query, + const UserDataConverter& user_data_converter) const = 0; - template - static Filter Or(const Filter& filter, const Filters& ... filters) { + template + static Filter Or(const Filter& filter, const Filters&... filters) { return CompositeFilter(CompositeOperator::Or, filter, filters...); } - template - static Filter And(const Filter& filter, const Filters& ... filters) { + template + static Filter And(const Filter& filter, const Filters&... filters) { return CompositeFilter(CompositeOperator::And, filter, filters...); }; @@ -90,16 +96,13 @@ class FilterInternal { friend bool operator==(const FilterInternal& lhs, const FilterInternal& rhs); protected: - enum FilterType { - Unary, Composite - }; + enum FilterType { Unary, Composite }; explicit FilterInternal(FilterType filterType); const FilterType filter_type_; private: - friend class Filter; friend class QueryInternal; @@ -109,16 +112,20 @@ class FilterInternal { using CompositeOperator = core::CompositeFilter::Operator; static Filter UnaryFilter(const FieldPath& field_path, - UnaryOperator op, const FieldValue& value); + UnaryOperator op, + const FieldValue& value); static Filter UnaryFilter(const FieldPath& field_path, - UnaryOperator op, const std::vector& values); + UnaryOperator op, + const std::vector& values); static Filter CompositeFilter(CompositeOperator op, const Filter& filter) { return filter; } - template - static Filter CompositeFilter(CompositeOperator op, const Filter& filter, const Filters& ... filters); + template + static Filter CompositeFilter(CompositeOperator op, + const Filter& filter, + const Filters&... filters); }; inline bool operator!=(const FilterInternal& lhs, const FilterInternal& rhs) { diff --git a/firestore/src/main/query_main.cc b/firestore/src/main/query_main.cc index 03b51afffd..7eeea2da66 100644 --- a/firestore/src/main/query_main.cc +++ b/firestore/src/main/query_main.cc @@ -100,7 +100,8 @@ Future QueryInternal::Get(Source source) { AggregateQuery QueryInternal::Count() { return MakePublic(query_.Count()); } Query QueryInternal::Where(const Filter& filter) const { - core::Filter core_filter = GetInternal(&filter)->filter_core(query_, user_data_converter_); + core::Filter core_filter = + GetInternal(&filter)->filter_core(query_, user_data_converter_); api::Query decorated = query_.AddNewFilter(std::move(core_filter)); return MakePublic(std::move(decorated)); } @@ -121,14 +122,15 @@ Query QueryInternal::Where(const FieldPath& field_path, Query QueryInternal::Where(const FieldPath& field_path, Operator op, const std::vector& values) const { - //return Where(field_path, op, FieldValue::Array(values)); + // return Where(field_path, op, FieldValue::Array(values)); const model::FieldPath& path = GetInternal(field_path); auto array_value = FieldValue::Array(values); Message parsed = user_data_converter_.ParseQueryValue(array_value, true); auto describer = [&array_value] { return Describe(array_value.type()); }; - api::Query decorated = query_.AddNewFilter(query_.ParseFieldFilter(path, op, std::move(parsed), describer)); + api::Query decorated = query_.AddNewFilter( + query_.ParseFieldFilter(path, op, std::move(parsed), describer)); return MakePublic(std::move(decorated)); } diff --git a/firestore/src/main/query_main.h b/firestore/src/main/query_main.h index 8cc38b7eed..ddf773f846 100644 --- a/firestore/src/main/query_main.h +++ b/firestore/src/main/query_main.h @@ -27,8 +27,8 @@ #include "Firestore/core/src/core/order_by.h" #include "Firestore/core/src/core/query.h" #include "Firestore/core/src/nanopb/message.h" -#include "firestore/src/include/firebase/firestore/filter.h" #include "firestore/src/include/firebase/firestore/field_path.h" +#include "firestore/src/include/firebase/firestore/filter.h" #include "firestore/src/include/firebase/firestore/query.h" #include "firestore/src/main/firestore_main.h" #include "firestore/src/main/promise_factory_main.h" diff --git a/firestore/src/main/unary_filter_main.cc b/firestore/src/main/unary_filter_main.cc index ec04eb705c..d08063a74d 100644 --- a/firestore/src/main/unary_filter_main.cc +++ b/firestore/src/main/unary_filter_main.cc @@ -1,17 +1,17 @@ /* -* 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. + * 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. */ #include "firestore/src/main/unary_filter_main.h" @@ -24,11 +24,22 @@ namespace firestore { using nanopb::Message; -UnaryFilterInternal::UnaryFilterInternal(FieldPath field_path, core::FieldFilter::Operator op, FieldValue value) - : FilterInternal(FilterType::Unary), path_(std::move(field_path)), op_(op), value_(std::move(value)){} +UnaryFilterInternal::UnaryFilterInternal(FieldPath field_path, + core::FieldFilter::Operator op, + FieldValue value) + : FilterInternal(FilterType::Unary), + path_(std::move(field_path)), + op_(op), + value_(std::move(value)) {} -UnaryFilterInternal::UnaryFilterInternal(FieldPath field_path, core::FieldFilter::Operator op, const std::vector& values) - : FilterInternal(FilterType::Unary), allow_arrays_(true), path_(std::move(field_path)), op_(op), value_(FieldValue::Array(values)){} +UnaryFilterInternal::UnaryFilterInternal(FieldPath field_path, + core::FieldFilter::Operator op, + const std::vector& values) + : FilterInternal(FilterType::Unary), + allow_arrays_(true), + path_(std::move(field_path)), + op_(op), + value_(FieldValue::Array(values)) {} UnaryFilterInternal* UnaryFilterInternal::clone() { return new UnaryFilterInternal(*this); @@ -45,9 +56,11 @@ core::Filter UnaryFilterInternal::filter_core( return query.ParseFieldFilter(path, op_, std::move(parsed), describer); } -bool operator==(const UnaryFilterInternal& lhs, const UnaryFilterInternal& rhs) { - return lhs.op_ == rhs.op_ && lhs.path_ == rhs.path_ && lhs.value_ == rhs.value_; +bool operator==(const UnaryFilterInternal& lhs, + const UnaryFilterInternal& rhs) { + return lhs.op_ == rhs.op_ && lhs.path_ == rhs.path_ && + lhs.value_ == rhs.value_; } -} // namespace firestore -} // namespace firebase +} // namespace firestore +} // namespace firebase diff --git a/firestore/src/main/unary_filter_main.h b/firestore/src/main/unary_filter_main.h index ff3f528215..a43eda9ccd 100644 --- a/firestore/src/main/unary_filter_main.h +++ b/firestore/src/main/unary_filter_main.h @@ -1,17 +1,17 @@ /* -* 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. + * 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. */ #ifndef FIREBASE_FIRESTORE_SRC_MAIN_UNARY_FILTER_MAIN_H_ @@ -29,12 +29,20 @@ namespace firestore { class UnaryFilterInternal final : public FilterInternal { public: - UnaryFilterInternal(FieldPath field_path, core::FieldFilter::Operator op, FieldValue value); - UnaryFilterInternal(FieldPath field_path, core::FieldFilter::Operator op, const std::vector& values); + UnaryFilterInternal(FieldPath field_path, + core::FieldFilter::Operator op, + FieldValue value); + UnaryFilterInternal(FieldPath field_path, + core::FieldFilter::Operator op, + const std::vector& values); - core::Filter filter_core(const api::Query& query, const UserDataConverter& user_data_converter) const override; + core::Filter filter_core( + const api::Query& query, + const UserDataConverter& user_data_converter) const override; + + friend bool operator==(const UnaryFilterInternal& lhs, + const UnaryFilterInternal& rhs); - friend bool operator==(const UnaryFilterInternal& lhs, const UnaryFilterInternal& rhs); private: UnaryFilterInternal* clone() override; @@ -44,7 +52,8 @@ class UnaryFilterInternal final : public FilterInternal { const FieldValue value_; }; -inline bool operator!=(const UnaryFilterInternal& lhs, const UnaryFilterInternal& rhs) { +inline bool operator!=(const UnaryFilterInternal& lhs, + const UnaryFilterInternal& rhs) { return !(lhs == rhs); } From aa2a04544a202920ef20352090871a57b4bdd12b Mon Sep 17 00:00:00 2001 From: Tom Andersen Date: Tue, 13 Jun 2023 15:45:40 -0400 Subject: [PATCH 03/25] Add includes --- firestore/src/include/firebase/firestore/filter.h | 1 + firestore/src/main/composite_filter_main.cc | 3 +++ firestore/src/main/composite_filter_main.h | 3 +++ firestore/src/main/filter_main.cc | 2 ++ firestore/src/main/filter_main.h | 4 +++- firestore/src/main/unary_filter_main.cc | 3 +++ 6 files changed, 15 insertions(+), 1 deletion(-) diff --git a/firestore/src/include/firebase/firestore/filter.h b/firestore/src/include/firebase/firestore/filter.h index e9e7557681..e920aa187c 100644 --- a/firestore/src/include/firebase/firestore/filter.h +++ b/firestore/src/include/firebase/firestore/filter.h @@ -17,6 +17,7 @@ #ifndef FIREBASE_FIRESTORE_SRC_INCLUDE_FIREBASE_FIRESTORE_FILTER_H_ #define FIREBASE_FIRESTORE_SRC_INCLUDE_FIREBASE_FIRESTORE_FILTER_H_ +#include #include #include "firebase/firestore/field_value.h" diff --git a/firestore/src/main/composite_filter_main.cc b/firestore/src/main/composite_filter_main.cc index 5cf2f063a8..b78a9586fa 100644 --- a/firestore/src/main/composite_filter_main.cc +++ b/firestore/src/main/composite_filter_main.cc @@ -18,6 +18,9 @@ #error "This header should not be used on Android." #endif +#include +#include + #include "firestore/src/main/composite_filter_main.h" #include "Firestore/core/src/core/composite_filter.h" diff --git a/firestore/src/main/composite_filter_main.h b/firestore/src/main/composite_filter_main.h index 1a92cf9f5f..a99854bd17 100644 --- a/firestore/src/main/composite_filter_main.h +++ b/firestore/src/main/composite_filter_main.h @@ -21,6 +21,9 @@ #error "This header should not be used on Android." #endif +#include +#include + #include "Firestore/core/src/api/query_core.h" #include "firestore/src/main/filter_main.h" diff --git a/firestore/src/main/filter_main.cc b/firestore/src/main/filter_main.cc index b66b5bed44..89e7828d5e 100644 --- a/firestore/src/main/filter_main.cc +++ b/firestore/src/main/filter_main.cc @@ -14,6 +14,8 @@ * limitations under the License. */ +#include + #include "firestore/src/main/filter_main.h" #include "firestore/src/main/composite_filter_main.h" #include "firestore/src/main/converter_main.h" diff --git a/firestore/src/main/filter_main.h b/firestore/src/main/filter_main.h index 94bd57f572..75bfe330be 100644 --- a/firestore/src/main/filter_main.h +++ b/firestore/src/main/filter_main.h @@ -21,6 +21,8 @@ #error "This header should not be used on Android." #endif +#include + #include "Firestore/core/src/core/composite_filter.h" #include "Firestore/core/src/core/field_filter.h" #include "Firestore/core/src/core/filter.h" @@ -89,7 +91,7 @@ class FilterInternal { template static Filter And(const Filter& filter, const Filters&... filters) { return CompositeFilter(CompositeOperator::And, filter, filters...); - }; + } virtual ~FilterInternal() = default; diff --git a/firestore/src/main/unary_filter_main.cc b/firestore/src/main/unary_filter_main.cc index d08063a74d..db94382818 100644 --- a/firestore/src/main/unary_filter_main.cc +++ b/firestore/src/main/unary_filter_main.cc @@ -14,6 +14,9 @@ * limitations under the License. */ +#include +#include + #include "firestore/src/main/unary_filter_main.h" #include "Firestore/core/src/nanopb/message.h" From 516ff3926d61a5ce77259616a96ae46851c851c2 Mon Sep 17 00:00:00 2001 From: Tom Andersen Date: Tue, 13 Jun 2023 16:32:00 -0400 Subject: [PATCH 04/25] Fix from PR feedback --- firestore/src/common/filter.cc | 4 +++- firestore/src/main/filter_main.cc | 4 ++-- firestore/src/main/filter_main.h | 27 +++++++++++++------------- firestore/src/main/unary_filter_main.h | 2 ++ 4 files changed, 21 insertions(+), 16 deletions(-) diff --git a/firestore/src/common/filter.cc b/firestore/src/common/filter.cc index 38a194d58f..0aeb0930fb 100644 --- a/firestore/src/common/filter.cc +++ b/firestore/src/common/filter.cc @@ -25,6 +25,8 @@ #include "firestore/src/main/filter_main.h" #endif // defined(__ANDROID__) +#include "firestore/src/common/util.h" + namespace firebase { namespace firestore { @@ -165,7 +167,7 @@ Filter Filter::And(const Filter& filter, const Filters&... filters) { } bool operator==(const Filter& lhs, const Filter& rhs) { - return &lhs == &rhs || *lhs.internal_ == *rhs.internal_; + return EqualityCompare(lhs.internal_, rhs.internal_); } } // namespace firestore diff --git a/firestore/src/main/filter_main.cc b/firestore/src/main/filter_main.cc index 89e7828d5e..e131acee0a 100644 --- a/firestore/src/main/filter_main.cc +++ b/firestore/src/main/filter_main.cc @@ -28,13 +28,13 @@ FilterInternal::FilterInternal(FilterInternal::FilterType filter_type) : filter_type_(filter_type) {} Filter FilterInternal::UnaryFilter(const FieldPath& field_path, - UnaryOperator op, + FieldFilterOperator op, const FieldValue& value) { return MakePublic(UnaryFilterInternal(field_path, op, value)); } Filter FilterInternal::UnaryFilter(const FieldPath& field_path, - UnaryOperator op, + FieldFilterOperator op, const std::vector& values) { return MakePublic(UnaryFilterInternal(field_path, op, values)); } diff --git a/firestore/src/main/filter_main.h b/firestore/src/main/filter_main.h index 75bfe330be..f33f7f6d6b 100644 --- a/firestore/src/main/filter_main.h +++ b/firestore/src/main/filter_main.h @@ -26,6 +26,7 @@ #include "Firestore/core/src/core/composite_filter.h" #include "Firestore/core/src/core/field_filter.h" #include "Firestore/core/src/core/filter.h" +#include "Firestore/core/src/api/query_core.h" #include "firestore/src/include/firebase/firestore/filter.h" #include "firestore/src/main/user_data_converter_main.h" @@ -35,48 +36,48 @@ namespace firestore { class FilterInternal { public: static Filter ArrayContains(const FieldPath& field, const FieldValue& value) { - return UnaryFilter(field, UnaryOperator::ArrayContains, value); + return UnaryFilter(field, FieldFilterOperator::ArrayContains, value); } static Filter ArrayContainsAny(const FieldPath& field, const std::vector& values) { - return UnaryFilter(field, UnaryOperator::ArrayContainsAny, values); + return UnaryFilter(field, FieldFilterOperator::ArrayContainsAny, values); } static Filter EqualTo(const FieldPath& field, const FieldValue& value) { - return UnaryFilter(field, UnaryOperator::Equal, value); + return UnaryFilter(field, FieldFilterOperator::Equal, value); } static Filter NotEqualTo(const FieldPath& field, const FieldValue& value) { - return UnaryFilter(field, UnaryOperator::NotEqual, value); + return UnaryFilter(field, FieldFilterOperator::NotEqual, value); } static Filter GreaterThan(const FieldPath& field, const FieldValue& value) { - return UnaryFilter(field, UnaryOperator::GreaterThan, value); + return UnaryFilter(field, FieldFilterOperator::GreaterThan, value); } static Filter GreaterThanOrEqualTo(const FieldPath& field, const FieldValue& value) { - return UnaryFilter(field, UnaryOperator::GreaterThanOrEqual, value); + return UnaryFilter(field, FieldFilterOperator::GreaterThanOrEqual, value); } static Filter LessThan(const FieldPath& field, const FieldValue& value) { - return UnaryFilter(field, UnaryOperator::LessThan, value); + return UnaryFilter(field, FieldFilterOperator::LessThan, value); } static Filter LessThanOrEqualTo(const FieldPath& field, const FieldValue& value) { - return UnaryFilter(field, UnaryOperator::LessThanOrEqual, value); + return UnaryFilter(field, FieldFilterOperator::LessThanOrEqual, value); } static Filter In(const FieldPath& field, const std::vector& values) { - return UnaryFilter(field, UnaryOperator::In, values); + return UnaryFilter(field, FieldFilterOperator::In, values); } static Filter NotIn(const FieldPath& field, const std::vector& values) { - return UnaryFilter(field, UnaryOperator::NotIn, values); + return UnaryFilter(field, FieldFilterOperator::NotIn, values); } virtual core::Filter filter_core( @@ -110,14 +111,14 @@ class FilterInternal { virtual FilterInternal* clone() = 0; - using UnaryOperator = core::FieldFilter::Operator; + using FieldFilterOperator = core::FieldFilter::Operator; using CompositeOperator = core::CompositeFilter::Operator; static Filter UnaryFilter(const FieldPath& field_path, - UnaryOperator op, + FieldFilterOperator op, const FieldValue& value); static Filter UnaryFilter(const FieldPath& field_path, - UnaryOperator op, + FieldFilterOperator op, const std::vector& values); static Filter CompositeFilter(CompositeOperator op, const Filter& filter) { diff --git a/firestore/src/main/unary_filter_main.h b/firestore/src/main/unary_filter_main.h index a43eda9ccd..72d4588703 100644 --- a/firestore/src/main/unary_filter_main.h +++ b/firestore/src/main/unary_filter_main.h @@ -21,6 +21,8 @@ #error "This header should not be used on Android." #endif +#include + #include "Firestore/core/src/api/query_core.h" #include "firestore/src/main/filter_main.h" From f858b7ba3026533c2cdf13f1593115a20c572e50 Mon Sep 17 00:00:00 2001 From: Tom Andersen Date: Thu, 15 Jun 2023 17:55:49 -0400 Subject: [PATCH 05/25] Fix variadic parameters --- .../src/filter_test.cc | 134 ++++++++++++++---- firestore/src/common/filter.cc | 12 +- firestore/src/common/query.cc | 5 + .../src/include/firebase/firestore/filter.h | 23 ++- firestore/src/main/composite_filter_main.cc | 15 +- firestore/src/main/composite_filter_main.h | 20 +-- firestore/src/main/filter_main.cc | 76 +++++++++- firestore/src/main/filter_main.h | 80 +++-------- firestore/src/main/query_main.cc | 23 +-- firestore/src/main/unary_filter_main.cc | 5 +- firestore/src/main/unary_filter_main.h | 11 +- 11 files changed, 268 insertions(+), 136 deletions(-) diff --git a/firestore/integration_test_internal/src/filter_test.cc b/firestore/integration_test_internal/src/filter_test.cc index e448dc85c9..40f9d522d5 100644 --- a/firestore/integration_test_internal/src/filter_test.cc +++ b/firestore/integration_test_internal/src/filter_test.cc @@ -159,70 +159,152 @@ TEST_F(FilterTest, IdenticalShouldBeEqual) { TEST_F(FilterTest, DifferentValuesAreNotEqual) { Filter filter1a = Filter::ArrayContains("foo", FieldValue::Integer(24)); Filter filter1b = Filter::ArrayContains("foo", FieldValue::Integer(42)); + Filter filter1c = Filter::ArrayContains("bar", FieldValue::Integer(42)); Filter filter2a = Filter::EqualTo("foo", FieldValue::Integer(24)); Filter filter2b = Filter::EqualTo("foo", FieldValue::Integer(42)); + Filter filter2c = Filter::EqualTo("bar", FieldValue::Integer(42)); Filter filter3a = Filter::NotEqualTo("foo", FieldValue::Integer(24)); Filter filter3b = Filter::NotEqualTo("foo", FieldValue::Integer(42)); + Filter filter3c = Filter::NotEqualTo("bar", FieldValue::Integer(42)); Filter filter4a = Filter::GreaterThan("foo", FieldValue::Integer(24)); Filter filter4b = Filter::GreaterThan("foo", FieldValue::Integer(42)); + Filter filter4c = Filter::GreaterThan("bar", FieldValue::Integer(42)); Filter filter5a = Filter::GreaterThanOrEqualTo("foo", FieldValue::Integer(24)); Filter filter5b = Filter::GreaterThanOrEqualTo("foo", FieldValue::Integer(42)); + Filter filter5c = + Filter::GreaterThanOrEqualTo("bar", FieldValue::Integer(42)); Filter filter6a = Filter::LessThan("foo", FieldValue::Integer(24)); Filter filter6b = Filter::LessThan("foo", FieldValue::Integer(42)); + Filter filter6c = Filter::LessThan("bar", FieldValue::Integer(42)); Filter filter7a = Filter::LessThanOrEqualTo("foo", FieldValue::Integer(24)); Filter filter7b = Filter::LessThanOrEqualTo("foo", FieldValue::Integer(42)); + Filter filter7c = Filter::LessThanOrEqualTo("bar", FieldValue::Integer(42)); EXPECT_FALSE(filter1a == filter1b); + EXPECT_FALSE(filter1b == filter1c); EXPECT_FALSE(filter2a == filter2b); + EXPECT_FALSE(filter2b == filter2c); EXPECT_FALSE(filter3a == filter3b); + EXPECT_FALSE(filter3b == filter3c); EXPECT_FALSE(filter4a == filter4b); + EXPECT_FALSE(filter4b == filter4c); EXPECT_FALSE(filter5a == filter5b); + EXPECT_FALSE(filter5b == filter5c); EXPECT_FALSE(filter6a == filter6b); + EXPECT_FALSE(filter6b == filter6c); EXPECT_FALSE(filter7a == filter7b); + EXPECT_FALSE(filter7b == filter7c); EXPECT_TRUE(filter1a != filter1b); + EXPECT_TRUE(filter1b != filter1c); EXPECT_TRUE(filter2a != filter2b); + EXPECT_TRUE(filter2b != filter2c); EXPECT_TRUE(filter3a != filter3b); + EXPECT_TRUE(filter3b != filter3c); EXPECT_TRUE(filter4a != filter4b); + EXPECT_TRUE(filter4b != filter4c); EXPECT_TRUE(filter5a != filter5b); + EXPECT_TRUE(filter5b != filter5c); EXPECT_TRUE(filter6a != filter6b); + EXPECT_TRUE(filter6b != filter6c); EXPECT_TRUE(filter7a != filter7b); + EXPECT_TRUE(filter7b != filter7c); } -TEST_F(FilterTest, DifferentOrderOfValuesAreNotEqual) { - const std::vector& valueOrderA = - std::vector{FieldValue::Integer(1), FieldValue::Integer(2)}; - const std::vector& valueOrderB = - std::vector{FieldValue::Integer(2), FieldValue::Integer(1)}; - - { - Filter filter1 = Filter::ArrayContainsAny("foo", valueOrderA); - Filter filter2 = Filter::ArrayContainsAny("foo", valueOrderB); - EXPECT_FALSE(filter1 == filter2); - EXPECT_TRUE(filter1 != filter2); - } - - { - Filter filter1 = Filter::In("foo", valueOrderA); - Filter filter2 = Filter::In("foo", valueOrderB); - EXPECT_FALSE(filter1 == filter2); - EXPECT_TRUE(filter1 != filter2); - } - - { - Filter filter1 = Filter::NotIn("foo", valueOrderA); - Filter filter2 = Filter::NotIn("foo", valueOrderB); - EXPECT_FALSE(filter1 == filter2); - EXPECT_TRUE(filter1 != filter2); - } +TEST_F(FilterTest, CompositesWithOneFilterAreTheSameAsFilter) { + Filter filter1 = Filter::EqualTo("foo", FieldValue::Integer(42)); + Filter filter2 = Filter::Or(filter1); + Filter filter3 = Filter::And(filter1); + + EXPECT_TRUE(filter1 == filter2); + EXPECT_TRUE(filter1 == filter3); + + EXPECT_FALSE(filter1 != filter2); + EXPECT_FALSE(filter1 != filter3); +} + +TEST_F(FilterTest, EmptyCompositeIsIgnored) { + Filter filter1 = Filter::And(); + Filter filter2 = Filter::And(Filter::And(), Filter::And()); + Filter filter3 = Filter::And(Filter::Or(), Filter::Or()); + Filter filter4 = Filter::Or(); + Filter filter5 = Filter::Or(Filter::Or(), Filter::Or()); + Filter filter6 = Filter::Or(Filter::And(), Filter::And()); + + CollectionReference collection = Collection(); + + EXPECT_EQ(filter1, filter2); + EXPECT_EQ(filter1, filter3); + EXPECT_EQ(filter4, filter5); + EXPECT_EQ(filter4, filter6); + + Query query1 = collection.Where(filter1); + Query query2 = collection.Where(filter2); + Query query3 = collection.Where(filter3); + Query query4 = collection.Where(filter4); + Query query5 = collection.Where(filter5); + Query query6 = collection.Where(filter6); + + EXPECT_EQ(collection, query1); + EXPECT_EQ(collection, query2); + EXPECT_EQ(collection, query3); + EXPECT_EQ(collection, query4); + EXPECT_EQ(collection, query5); + EXPECT_EQ(collection, query6); +} + +TEST_F(FilterTest, CompositeComparison) { + Filter filter1 = Filter::ArrayContains("foo", FieldValue::Integer(42)); + Filter filter2 = Filter::EqualTo("foo", FieldValue::Integer(42)); + Filter filter3 = Filter::NotEqualTo("foo", FieldValue::Integer(42)); + Filter filter4 = Filter::GreaterThan("foo", FieldValue::Integer(42)); + + Filter and1 = Filter::And(filter1); + Filter and2 = Filter::And(filter1, filter2); + Filter and3 = Filter::And(filter1, filter2, filter3); + Filter and4 = Filter::And(filter1, filter2, filter3, filter4); + + Filter or1 = Filter::Or(filter1); + Filter or2 = Filter::Or(filter1, filter2); + Filter or3 = Filter::Or(filter1, filter2, filter3); + Filter or4 = Filter::Or(filter1, filter2, filter3, filter4); + + EXPECT_EQ(and1, and1); + EXPECT_EQ(and2, and2); + EXPECT_EQ(and3, and3); + EXPECT_EQ(and4, and4); + + EXPECT_EQ(or1, or1); + EXPECT_EQ(or2, or2); + EXPECT_EQ(or3, or3); + EXPECT_EQ(or4, or4); + + EXPECT_EQ(and1, or1); + EXPECT_NE(and2, or2); + EXPECT_NE(and3, or3); + EXPECT_NE(and4, or4); + + EXPECT_NE(and1, and2); + EXPECT_NE(and1, and3); + EXPECT_NE(and1, and4); + EXPECT_NE(and2, and3); + EXPECT_NE(and2, and4); + EXPECT_NE(and3, and4); + + EXPECT_NE(or1, or2); + EXPECT_NE(or1, or3); + EXPECT_NE(or1, or4); + EXPECT_NE(or2, or3); + EXPECT_NE(or2, or4); + EXPECT_NE(or3, or4); } } // namespace diff --git a/firestore/src/common/filter.cc b/firestore/src/common/filter.cc index 0aeb0930fb..129d9da2a8 100644 --- a/firestore/src/common/filter.cc +++ b/firestore/src/common/filter.cc @@ -156,19 +156,19 @@ Filter Filter::NotIn(const FieldPath& field, return FilterInternal::NotIn(field, values); } -template -Filter Filter::Or(const Filter& filter, const Filters&... filters) { - return FilterInternal::Or(filter, filters...); +Filter Filter::And(const std::vector& filters) { + return FilterInternal::And(filters); } -template -Filter Filter::And(const Filter& filter, const Filters&... filters) { - return FilterInternal::And(filter, filters...); +Filter Filter::Or(const std::vector& filters) { + return FilterInternal::Or(filters); } bool operator==(const Filter& lhs, const Filter& rhs) { return EqualityCompare(lhs.internal_, rhs.internal_); } +bool Filter::IsEmpty() const { return internal_->IsEmpty(); } + } // namespace firestore } // namespace firebase diff --git a/firestore/src/common/query.cc b/firestore/src/common/query.cc index 04bd301432..248460ab62 100644 --- a/firestore/src/common/query.cc +++ b/firestore/src/common/query.cc @@ -115,6 +115,11 @@ AggregateQuery Query::Count() const { Query Query::Where(const Filter& filter) const { if (!internal_) return {}; + if (filter.IsEmpty()) { + // Return the existing query if not adding any more filters (e.g. an empty + // composite filter). + return *this; + } return internal_->Where(filter); } diff --git a/firestore/src/include/firebase/firestore/filter.h b/firestore/src/include/firebase/firestore/filter.h index e920aa187c..16ec7a8906 100644 --- a/firestore/src/include/firebase/firestore/filter.h +++ b/firestore/src/include/firebase/firestore/filter.h @@ -21,6 +21,7 @@ #include #include "firebase/firestore/field_value.h" +#include "firestore/src/main/filter_main.h" namespace firebase { namespace firestore { @@ -62,11 +63,23 @@ class Filter { static Filter NotIn(const FieldPath& field, const std::vector& values); - template - static Filter Or(const Filter& filter, const Filters&... filters); + static Filter And(const Filter filter) { return filter; } template - static Filter And(const Filter& filter, const Filters&... filters); + static Filter And(const Filters&... filters) { + return And(std::vector({filters...})); + } + + static Filter And(const std::vector& filters); + + static Filter Or(const Filter filter) { return filter; } + + template + static Filter Or(const Filters&... filters) { + return Or(std::vector({filters...})); + } + + static Filter Or(const std::vector& filters); Filter(const Filter& other); Filter(Filter&& other) noexcept; @@ -76,9 +89,13 @@ class Filter { ~Filter(); private: + friend class Query; + friend class QueryInternal; friend bool operator==(const Filter& lhs, const Filter& rhs); friend struct ConverterImpl; + bool IsEmpty() const; + explicit Filter(FilterInternal* internal); FilterInternal* internal_; }; diff --git a/firestore/src/main/composite_filter_main.cc b/firestore/src/main/composite_filter_main.cc index b78a9586fa..fe06086be6 100644 --- a/firestore/src/main/composite_filter_main.cc +++ b/firestore/src/main/composite_filter_main.cc @@ -21,29 +21,32 @@ #include #include -#include "firestore/src/main/composite_filter_main.h" #include "Firestore/core/src/core/composite_filter.h" +#include "firestore/src/main/composite_filter_main.h" +#include "firestore/src/main/converter_main.h" namespace firebase { namespace firestore { -template CompositeFilterInternal::CompositeFilterInternal( - core::CompositeFilter::Operator op, const Filter& filter, Ts... filters) + core::CompositeFilter::Operator op, std::vector&& filters) : FilterInternal(FilterType::Composite), op_(op), - filters_(filter, filters...) {} + filters_(std::move(filters)) {} CompositeFilterInternal* CompositeFilterInternal::clone() { return new CompositeFilterInternal(*this); } -core::Filter CompositeFilterInternal::filter_core( +bool CompositeFilterInternal::IsEmpty() const { return filters_.empty(); } + +core::Filter CompositeFilterInternal::ToCoreFilter( const api::Query& query, const firebase::firestore::UserDataConverter& user_data_converter) const { std::vector core_filters; for (auto& filter : filters_) { - core_filters.push_back(filter->filter_core(query, user_data_converter)); + core_filters.push_back( + GetInternal(&filter)->ToCoreFilter(query, user_data_converter)); } return core::CompositeFilter::Create(std::move(core_filters), op_); } diff --git a/firestore/src/main/composite_filter_main.h b/firestore/src/main/composite_filter_main.h index a99854bd17..663548f61c 100644 --- a/firestore/src/main/composite_filter_main.h +++ b/firestore/src/main/composite_filter_main.h @@ -32,25 +32,29 @@ namespace firestore { class CompositeFilterInternal : public FilterInternal { public: - template - CompositeFilterInternal(core::CompositeFilter::Operator op, - const Filter& filter, - Ts... filters); + explicit CompositeFilterInternal(core::CompositeFilter::Operator op, + std::vector&& filters); - core::Filter filter_core( - const api::Query& query, - const UserDataConverter& user_data_converter) const override; + core::Filter ToCoreFilter(const api::Query& query, + const firebase::firestore::UserDataConverter& + user_data_converter) const override; friend bool operator==(const CompositeFilterInternal& lhs, const CompositeFilterInternal& rhs); + protected: + bool IsEmpty() const override; + private: CompositeFilterInternal* clone() override; const core::CompositeFilter::Operator op_; - const std::vector> filters_; + const std::vector filters_; }; +bool operator==(const CompositeFilterInternal& lhs, + const CompositeFilterInternal& rhs); + inline bool operator!=(const CompositeFilterInternal& lhs, const CompositeFilterInternal& rhs) { return !(lhs == rhs); diff --git a/firestore/src/main/filter_main.cc b/firestore/src/main/filter_main.cc index e131acee0a..b303d6da55 100644 --- a/firestore/src/main/filter_main.cc +++ b/firestore/src/main/filter_main.cc @@ -16,14 +16,72 @@ #include -#include "firestore/src/main/filter_main.h" #include "firestore/src/main/composite_filter_main.h" #include "firestore/src/main/converter_main.h" +#include "firestore/src/main/filter_main.h" #include "firestore/src/main/unary_filter_main.h" namespace firebase { namespace firestore { +Filter FilterInternal::ArrayContains(const FieldPath& field, + const FieldValue& value) { + return UnaryFilter(field, FieldFilterOperator::ArrayContains, value); +} + +Filter FilterInternal::ArrayContainsAny(const FieldPath& field, + const std::vector& values) { + return UnaryFilter(field, FieldFilterOperator::ArrayContainsAny, values); +} + +Filter FilterInternal::EqualTo(const FieldPath& field, + const FieldValue& value) { + return UnaryFilter(field, FieldFilterOperator::Equal, value); +} + +Filter FilterInternal::NotEqualTo(const FieldPath& field, + const FieldValue& value) { + return UnaryFilter(field, FieldFilterOperator::NotEqual, value); +} + +Filter FilterInternal::GreaterThan(const FieldPath& field, + const FieldValue& value) { + return UnaryFilter(field, FieldFilterOperator::GreaterThan, value); +} + +Filter FilterInternal::GreaterThanOrEqualTo(const FieldPath& field, + const FieldValue& value) { + return UnaryFilter(field, FieldFilterOperator::GreaterThanOrEqual, value); +} + +Filter FilterInternal::LessThan(const FieldPath& field, + const FieldValue& value) { + return UnaryFilter(field, FieldFilterOperator::LessThan, value); +} + +Filter FilterInternal::LessThanOrEqualTo(const FieldPath& field, + const FieldValue& value) { + return UnaryFilter(field, FieldFilterOperator::LessThanOrEqual, value); +} + +Filter FilterInternal::In(const FieldPath& field, + const std::vector& values) { + return UnaryFilter(field, FieldFilterOperator::In, values); +} + +Filter FilterInternal::NotIn(const FieldPath& field, + const std::vector& values) { + return UnaryFilter(field, FieldFilterOperator::NotIn, values); +} + +Filter FilterInternal::Or(const std::vector& filters) { + return CompositeFilter(CompositeOperator::Or, filters); +} + +Filter FilterInternal::And(const std::vector& filters) { + return CompositeFilter(CompositeOperator::And, filters); +} + FilterInternal::FilterInternal(FilterInternal::FilterType filter_type) : filter_type_(filter_type) {} @@ -39,11 +97,17 @@ Filter FilterInternal::UnaryFilter(const FieldPath& field_path, return MakePublic(UnaryFilterInternal(field_path, op, values)); } -template -Filter FilterInternal::CompositeFilter(core::CompositeFilter::Operator op, - const Filter& filter, - const Filters&... filters) { - return MakePublic(CompositeFilterInternal(op, filter, filters...)); +Filter FilterInternal::CompositeFilter( + core::CompositeFilter::Operator op, + const std::vector& filters) { + std::vector nonEmptyFilters; + std::copy_if(filters.begin(), filters.end(), + std::back_inserter(nonEmptyFilters), + [](Filter filter) { return !GetInternal(&filter)->IsEmpty(); }); + if (nonEmptyFilters.size() == 1) { + return filters[0]; + } + return MakePublic(CompositeFilterInternal(op, std::move(nonEmptyFilters))); } bool operator==(const FilterInternal& lhs, const FilterInternal& rhs) { diff --git a/firestore/src/main/filter_main.h b/firestore/src/main/filter_main.h index f33f7f6d6b..392eb00fa3 100644 --- a/firestore/src/main/filter_main.h +++ b/firestore/src/main/filter_main.h @@ -23,76 +23,44 @@ #include +#include "Firestore/core/src/api/query_core.h" #include "Firestore/core/src/core/composite_filter.h" #include "Firestore/core/src/core/field_filter.h" #include "Firestore/core/src/core/filter.h" -#include "Firestore/core/src/api/query_core.h" #include "firestore/src/include/firebase/firestore/filter.h" #include "firestore/src/main/user_data_converter_main.h" namespace firebase { namespace firestore { +class Filter; + class FilterInternal { public: - static Filter ArrayContains(const FieldPath& field, const FieldValue& value) { - return UnaryFilter(field, FieldFilterOperator::ArrayContains, value); - } - + static Filter ArrayContains(const FieldPath& field, const FieldValue& value); static Filter ArrayContainsAny(const FieldPath& field, - const std::vector& values) { - return UnaryFilter(field, FieldFilterOperator::ArrayContainsAny, values); - } - - static Filter EqualTo(const FieldPath& field, const FieldValue& value) { - return UnaryFilter(field, FieldFilterOperator::Equal, value); - } - - static Filter NotEqualTo(const FieldPath& field, const FieldValue& value) { - return UnaryFilter(field, FieldFilterOperator::NotEqual, value); - } - - static Filter GreaterThan(const FieldPath& field, const FieldValue& value) { - return UnaryFilter(field, FieldFilterOperator::GreaterThan, value); - } - + const std::vector& values); + static Filter EqualTo(const FieldPath& field, const FieldValue& value); + static Filter NotEqualTo(const FieldPath& field, const FieldValue& value); + static Filter GreaterThan(const FieldPath& field, const FieldValue& value); static Filter GreaterThanOrEqualTo(const FieldPath& field, - const FieldValue& value) { - return UnaryFilter(field, FieldFilterOperator::GreaterThanOrEqual, value); - } - - static Filter LessThan(const FieldPath& field, const FieldValue& value) { - return UnaryFilter(field, FieldFilterOperator::LessThan, value); - } - + const FieldValue& value); + static Filter LessThan(const FieldPath& field, const FieldValue& value); static Filter LessThanOrEqualTo(const FieldPath& field, - const FieldValue& value) { - return UnaryFilter(field, FieldFilterOperator::LessThanOrEqual, value); - } - + const FieldValue& value); static Filter In(const FieldPath& field, - const std::vector& values) { - return UnaryFilter(field, FieldFilterOperator::In, values); - } - + const std::vector& values); static Filter NotIn(const FieldPath& field, - const std::vector& values) { - return UnaryFilter(field, FieldFilterOperator::NotIn, values); - } + const std::vector& values); - virtual core::Filter filter_core( + virtual core::Filter ToCoreFilter( const api::Query& query, - const UserDataConverter& user_data_converter) const = 0; + const firebase::firestore::UserDataConverter& user_data_converter) + const = 0; - template - static Filter Or(const Filter& filter, const Filters&... filters) { - return CompositeFilter(CompositeOperator::Or, filter, filters...); - } + static Filter Or(const std::vector& filters); - template - static Filter And(const Filter& filter, const Filters&... filters) { - return CompositeFilter(CompositeOperator::And, filter, filters...); - } + static Filter And(const std::vector& filters); virtual ~FilterInternal() = default; @@ -105,6 +73,8 @@ class FilterInternal { const FilterType filter_type_; + virtual bool IsEmpty() const = 0; + private: friend class Filter; friend class QueryInternal; @@ -121,16 +91,12 @@ class FilterInternal { FieldFilterOperator op, const std::vector& values); - static Filter CompositeFilter(CompositeOperator op, const Filter& filter) { - return filter; - } - - template static Filter CompositeFilter(CompositeOperator op, - const Filter& filter, - const Filters&... filters); + const std::vector& filters); }; +bool operator==(const FilterInternal& lhs, const FilterInternal& rhs); + inline bool operator!=(const FilterInternal& lhs, const FilterInternal& rhs) { return !(lhs == rhs); } diff --git a/firestore/src/main/query_main.cc b/firestore/src/main/query_main.cc index 7eeea2da66..6dab91109a 100644 --- a/firestore/src/main/query_main.cc +++ b/firestore/src/main/query_main.cc @@ -100,8 +100,9 @@ Future QueryInternal::Get(Source source) { AggregateQuery QueryInternal::Count() { return MakePublic(query_.Count()); } Query QueryInternal::Where(const Filter& filter) const { + SIMPLE_HARD_ASSERT(!filter.IsEmpty()); core::Filter core_filter = - GetInternal(&filter)->filter_core(query_, user_data_converter_); + GetInternal(&filter)->ToCoreFilter(query_, user_data_converter_); api::Query decorated = query_.AddNewFilter(std::move(core_filter)); return MakePublic(std::move(decorated)); } @@ -109,29 +110,13 @@ Query QueryInternal::Where(const Filter& filter) const { Query QueryInternal::Where(const FieldPath& field_path, Operator op, const FieldValue& value) const { - const model::FieldPath& path = GetInternal(field_path); - Message parsed = - user_data_converter_.ParseQueryValue(value); - auto describer = [&value] { return Describe(value.type()); }; - - api::Query decorated = query_.AddNewFilter( - query_.ParseFieldFilter(path, op, std::move(parsed), describer)); - return MakePublic(std::move(decorated)); + return Where(UnaryFilterInternal::UnaryFilter(field_path, op, value)); } Query QueryInternal::Where(const FieldPath& field_path, Operator op, const std::vector& values) const { - // return Where(field_path, op, FieldValue::Array(values)); - const model::FieldPath& path = GetInternal(field_path); - auto array_value = FieldValue::Array(values); - Message parsed = - user_data_converter_.ParseQueryValue(array_value, true); - auto describer = [&array_value] { return Describe(array_value.type()); }; - - api::Query decorated = query_.AddNewFilter( - query_.ParseFieldFilter(path, op, std::move(parsed), describer)); - return MakePublic(std::move(decorated)); + return Where(UnaryFilterInternal::UnaryFilter(field_path, op, values)); } Query QueryInternal::WithBound(BoundPosition bound_pos, diff --git a/firestore/src/main/unary_filter_main.cc b/firestore/src/main/unary_filter_main.cc index db94382818..3561ba6f60 100644 --- a/firestore/src/main/unary_filter_main.cc +++ b/firestore/src/main/unary_filter_main.cc @@ -31,6 +31,7 @@ UnaryFilterInternal::UnaryFilterInternal(FieldPath field_path, core::FieldFilter::Operator op, FieldValue value) : FilterInternal(FilterType::Unary), + allow_arrays_(false), path_(std::move(field_path)), op_(op), value_(std::move(value)) {} @@ -48,9 +49,9 @@ UnaryFilterInternal* UnaryFilterInternal::clone() { return new UnaryFilterInternal(*this); } -core::Filter UnaryFilterInternal::filter_core( +core::Filter UnaryFilterInternal::ToCoreFilter( const api::Query& query, - const UserDataConverter& user_data_converter) const { + const firebase::firestore::UserDataConverter& user_data_converter) const { const model::FieldPath& path = GetInternal(path_); Message parsed = user_data_converter.ParseQueryValue(value_, allow_arrays_); diff --git a/firestore/src/main/unary_filter_main.h b/firestore/src/main/unary_filter_main.h index 72d4588703..e23d0c9481 100644 --- a/firestore/src/main/unary_filter_main.h +++ b/firestore/src/main/unary_filter_main.h @@ -38,13 +38,16 @@ class UnaryFilterInternal final : public FilterInternal { core::FieldFilter::Operator op, const std::vector& values); - core::Filter filter_core( - const api::Query& query, - const UserDataConverter& user_data_converter) const override; + core::Filter ToCoreFilter(const api::Query& query, + const firebase::firestore::UserDataConverter& + user_data_converter) const override; friend bool operator==(const UnaryFilterInternal& lhs, const UnaryFilterInternal& rhs); + protected: + bool IsEmpty() const override { return false; } + private: UnaryFilterInternal* clone() override; @@ -54,6 +57,8 @@ class UnaryFilterInternal final : public FilterInternal { const FieldValue value_; }; +bool operator==(const UnaryFilterInternal& lhs, const UnaryFilterInternal& rhs); + inline bool operator!=(const UnaryFilterInternal& lhs, const UnaryFilterInternal& rhs) { return !(lhs == rhs); From 9a0f88ac7e789c2114a570a5a65c42a4d2fe85c0 Mon Sep 17 00:00:00 2001 From: Tom Andersen Date: Fri, 16 Jun 2023 13:10:11 -0400 Subject: [PATCH 06/25] Add and fix tests --- .../integration_test_internal/src/filter_test.cc | 4 ++-- firestore/src/include/firebase/firestore/filter.h | 1 + firestore/src/main/composite_filter_main.cc | 13 +++++++------ firestore/src/main/composite_filter_main.h | 6 +++--- firestore/src/main/filter_main.cc | 15 +++++++++------ 5 files changed, 22 insertions(+), 17 deletions(-) diff --git a/firestore/integration_test_internal/src/filter_test.cc b/firestore/integration_test_internal/src/filter_test.cc index 40f9d522d5..04fdd31f18 100644 --- a/firestore/integration_test_internal/src/filter_test.cc +++ b/firestore/integration_test_internal/src/filter_test.cc @@ -239,13 +239,13 @@ TEST_F(FilterTest, EmptyCompositeIsIgnored) { Filter filter5 = Filter::Or(Filter::Or(), Filter::Or()); Filter filter6 = Filter::Or(Filter::And(), Filter::And()); - CollectionReference collection = Collection(); - EXPECT_EQ(filter1, filter2); EXPECT_EQ(filter1, filter3); EXPECT_EQ(filter4, filter5); EXPECT_EQ(filter4, filter6); + CollectionReference collection = Collection(); + Query query1 = collection.Where(filter1); Query query2 = collection.Where(filter2); Query query3 = collection.Where(filter3); diff --git a/firestore/src/include/firebase/firestore/filter.h b/firestore/src/include/firebase/firestore/filter.h index 16ec7a8906..79da28657e 100644 --- a/firestore/src/include/firebase/firestore/filter.h +++ b/firestore/src/include/firebase/firestore/filter.h @@ -91,6 +91,7 @@ class Filter { private: friend class Query; friend class QueryInternal; + friend class FilterInternal; friend bool operator==(const Filter& lhs, const Filter& rhs); friend struct ConverterImpl; diff --git a/firestore/src/main/composite_filter_main.cc b/firestore/src/main/composite_filter_main.cc index fe06086be6..014c5f54f3 100644 --- a/firestore/src/main/composite_filter_main.cc +++ b/firestore/src/main/composite_filter_main.cc @@ -29,10 +29,12 @@ namespace firebase { namespace firestore { CompositeFilterInternal::CompositeFilterInternal( - core::CompositeFilter::Operator op, std::vector&& filters) - : FilterInternal(FilterType::Composite), - op_(op), - filters_(std::move(filters)) {} + core::CompositeFilter::Operator op, std::vector& filters) + : FilterInternal(FilterType::Composite), op_(op) { + for (FilterInternal* filter_internal : filters) { + filters_.emplace_back(std::shared_ptr(filter_internal)); + } +} CompositeFilterInternal* CompositeFilterInternal::clone() { return new CompositeFilterInternal(*this); @@ -45,8 +47,7 @@ core::Filter CompositeFilterInternal::ToCoreFilter( const firebase::firestore::UserDataConverter& user_data_converter) const { std::vector core_filters; for (auto& filter : filters_) { - core_filters.push_back( - GetInternal(&filter)->ToCoreFilter(query, user_data_converter)); + core_filters.push_back(filter->ToCoreFilter(query, user_data_converter)); } return core::CompositeFilter::Create(std::move(core_filters), op_); } diff --git a/firestore/src/main/composite_filter_main.h b/firestore/src/main/composite_filter_main.h index 663548f61c..4eb1ee5af8 100644 --- a/firestore/src/main/composite_filter_main.h +++ b/firestore/src/main/composite_filter_main.h @@ -32,8 +32,8 @@ namespace firestore { class CompositeFilterInternal : public FilterInternal { public: - explicit CompositeFilterInternal(core::CompositeFilter::Operator op, - std::vector&& filters); + CompositeFilterInternal(core::CompositeFilter::Operator op, + std::vector& filters); core::Filter ToCoreFilter(const api::Query& query, const firebase::firestore::UserDataConverter& @@ -49,7 +49,7 @@ class CompositeFilterInternal : public FilterInternal { CompositeFilterInternal* clone() override; const core::CompositeFilter::Operator op_; - const std::vector filters_; + std::vector> filters_; }; bool operator==(const CompositeFilterInternal& lhs, diff --git a/firestore/src/main/filter_main.cc b/firestore/src/main/filter_main.cc index b303d6da55..e11cd03cf5 100644 --- a/firestore/src/main/filter_main.cc +++ b/firestore/src/main/filter_main.cc @@ -100,14 +100,17 @@ Filter FilterInternal::UnaryFilter(const FieldPath& field_path, Filter FilterInternal::CompositeFilter( core::CompositeFilter::Operator op, const std::vector& filters) { - std::vector nonEmptyFilters; - std::copy_if(filters.begin(), filters.end(), - std::back_inserter(nonEmptyFilters), - [](Filter filter) { return !GetInternal(&filter)->IsEmpty(); }); + std::vector nonEmptyFilters; + for (const Filter& filter : filters) { + FilterInternal* filterInternal = GetInternal(&filter); + if (!filterInternal->IsEmpty()) { + nonEmptyFilters.push_back(filterInternal->clone()); + } + } if (nonEmptyFilters.size() == 1) { - return filters[0]; + return Filter(nonEmptyFilters[0]); } - return MakePublic(CompositeFilterInternal(op, std::move(nonEmptyFilters))); + return MakePublic(CompositeFilterInternal(op, nonEmptyFilters)); } bool operator==(const FilterInternal& lhs, const FilterInternal& rhs) { From fd4e5ddc19c42a33f887a6c1692944d96c098f61 Mon Sep 17 00:00:00 2001 From: Tom Andersen Date: Mon, 19 Jun 2023 10:45:34 -0400 Subject: [PATCH 07/25] Add/fix method descriptions. --- .../src/include/firebase/firestore/filter.h | 216 ++++++++++++++++++ .../src/include/firebase/firestore/query.h | 8 +- 2 files changed, 220 insertions(+), 4 deletions(-) diff --git a/firestore/src/include/firebase/firestore/filter.h b/firestore/src/include/firebase/firestore/filter.h index 79da28657e..02b9634962 100644 --- a/firestore/src/include/firebase/firestore/filter.h +++ b/firestore/src/include/firebase/firestore/filter.h @@ -30,41 +30,248 @@ class FilterInternal; class Filter { public: + /** + * @brief Creates a new filter for checking that the given array field + * contains the given value. + * + * @param[in] field The name of the field containing an array to search. + * @param[in] value The value that must be contained in the array. + * + * @return The newly created filter. + */ static Filter ArrayContains(const std::string& field, const FieldValue& value); + + /** + * @brief Creates a new filter for checking that the given array field + * contains any of the given values. + * + * @param[in] field The name of the field containing an array to search. + * @param[in] values The list of values to match. + * + * @return The newly created filter. + */ static Filter ArrayContainsAny(const std::string& field, const std::vector& values); + + /** + * @brief Creates a new filter for checking that the given field is equal to + * the given value. + * + * @param[in] field The name of the field to compare. + * @param[in] value The value for comparison + * + * @return The newly created filter. + */ static Filter EqualTo(const std::string& field, const FieldValue& value); + + /** + * @brief Creates a new filter for checking that the given field is not equal + * to the given value. + * + * @param[in] field The name of the field to compare. + * @param[in] value The value for comparison + * + * @return The newly created filter. + */ static Filter NotEqualTo(const std::string& field, const FieldValue& value); + + /** + * @brief Creates a new filter for checking that the given field is greater + * than the given value. + * + * @param[in] field The name of the field to compare. + * @param[in] value The value for comparison + * + * @return The newly created filter. + */ static Filter GreaterThan(const std::string& field, const FieldValue& value); + + /** + * @brief Creates a new filter for checking that the given field is greater + * than or equal to the given value. + * + * @param[in] field The name of the field to compare. + * @param[in] value The value for comparison + * + * @return The newly created filter. + */ static Filter GreaterThanOrEqualTo(const std::string& field, const FieldValue& value); + + /** + * @brief Creates a new filter for checking that the given field is less than + * the given value. + * + * @param[in] field The name of the field to compare. + * @param[in] value The value for comparison + * + * @return The newly created filter. + */ static Filter LessThan(const std::string& field, const FieldValue& value); + + /** + * @brief Creates a new filter for checking that the given field is less than + * or equal to the given value. + * + * @param[in] field The name of the field to compare. + * @param[in] value The value for comparison + * + * @return The newly created filter. + */ static Filter LessThanOrEqualTo(const std::string& field, const FieldValue& value); + + /** + * @brief Creates a new filter for checking that the given field equals any of + * the given values. + * + * @param[in] field The name of the field to compare. + * @param[in] values The list of values to match. + * + * @return The newly created filter. + */ static Filter In(const std::string& field, const std::vector& values); + + /** + * @brief Creates a new filter for checking that the given field does not + * equal any of the given values. + * + * @param[in] field The name of the field to compare. + * @param[in] values The list of values to match. + * + * @return The newly created filter. + */ static Filter NotIn(const std::string& field, const std::vector& values); + /** + * @brief Creates a new filter for checking that the given array field + * contains the given value. + * + * @param[in] field The path of the field containing an array to search. + * @param[in] value The value that must be contained in the array. + * + * @return The newly created filter. + */ static Filter ArrayContains(const FieldPath& field, const FieldValue& value); + + /** + * @brief Creates a new filter for checking that the given array field + * contains any of the given values. + * + * @param[in] field The path of the field containing an array to search. + * @param[in] values The list of values to match. + * + * @return The newly created filter. + */ static Filter ArrayContainsAny(const FieldPath& field, const std::vector& values); + + /** + * @brief Creates a new filter for checking that the given field is equal to + * the given value. + * + * @param[in] field The path of the field to compare. + * @param[in] value The value for comparison + * + * @return The newly created filter. + */ static Filter EqualTo(const FieldPath& field, const FieldValue& value); + + /** + * @brief Creates a new filter for checking that the given field is not equal + * to the given value. + * + * @param[in] field The path of the field to compare. + * @param[in] value The value for comparison + * + * @return The newly created filter. + */ static Filter NotEqualTo(const FieldPath& field, const FieldValue& value); + + /** + * @brief Creates a new filter for checking that the given field is greater + * than the given value. + * + * @param[in] field The path of the field to compare. + * @param[in] value The value for comparison + * + * @return The newly created filter. + */ static Filter GreaterThan(const FieldPath& field, const FieldValue& value); + + /** + * @brief Creates a new filter for checking that the given field is greater + * than or equal to the given value. + * + * @param[in] field The path of the field to compare. + * @param[in] value The value for comparison + * + * @return The newly created filter. + */ static Filter GreaterThanOrEqualTo(const FieldPath& field, const FieldValue& value); + + /** + * @brief Creates a new filter for checking that the given field is less than + * the given value. + * + * @param[in] field The path of the field to compare. + * @param[in] value The value for comparison + * + * @return The newly created filter. + */ static Filter LessThan(const FieldPath& field, const FieldValue& value); + + /** + * @brief Creates a new filter for checking that the given field is less than + * or equal to the given value. + * + * @param[in] field The path of the field to compare. + * @param[in] value The value for comparison + * + * @return The newly created filter. + */ static Filter LessThanOrEqualTo(const FieldPath& field, const FieldValue& value); + + /** + * @brief Creates a new filter for checking that the given field equals any of + * the given values. + * + * @param[in] field The path of the field to compare. + * @param[in] values The list of values to match. + * + * @return The newly created filter. + */ static Filter In(const FieldPath& field, const std::vector& values); + + /** + * @brief Creates a new filter for checking that the given field does not + * equal any of the given values. + * + * @param[in] field The path of the field to compare. + * @param[in] values The list of values to match. + * + * @return The newly created filter. + */ static Filter NotIn(const FieldPath& field, const std::vector& values); static Filter And(const Filter filter) { return filter; } + /** + * @brief Creates a new filter that is a conjunction of the given filters. A + * conjunction filter includes a document if it satisfies all of the + * given filters. + * + * @param[in] filters The filters to perform a conjunction for. + * + * @return The newly created filter. + */ template static Filter And(const Filters&... filters) { return And(std::vector({filters...})); @@ -74,6 +281,15 @@ class Filter { static Filter Or(const Filter filter) { return filter; } + /** + * @brief Creates a new filter that is a disjunction of the given filters. A + * disjunction filter includes a document if it satisfies any of the + * given filters. + * + * @param[in] filters The filters to perform a disjunction for. + * + * @return The newly created filter. + */ template static Filter Or(const Filters&... filters) { return Or(std::vector({filters...})); diff --git a/firestore/src/include/firebase/firestore/query.h b/firestore/src/include/firebase/firestore/query.h index 6666cf2ee3..ec5b75d1c8 100644 --- a/firestore/src/include/firebase/firestore/query.h +++ b/firestore/src/include/firebase/firestore/query.h @@ -404,7 +404,7 @@ class Query { * A Query can have only one `WhereIn()` filter and it cannot be * combined with `WhereArrayContainsAny()`. * - * @param[in] field The name of the field containing an array to search. + * @param[in] field The name of the field to compare. * @param[in] values The list that contains the values to match. * * @return The created Query. @@ -420,7 +420,7 @@ class Query { * A Query can have only one `WhereIn()` filter and it cannot be * combined with `WhereArrayContainsAny()`. * - * @param[in] field The path of the field containing an array to search. + * @param[in] field The path of the field to compare. * @param[in] values The list that contains the values to match. * * @return The created Query. @@ -442,7 +442,7 @@ class Query { * combined with `WhereArrayContains()`, `WhereArrayContainsAny()`, * `WhereIn()`, or `WhereNotEqualTo()`. * - * @param[in] field The name of the field containing an array to search. + * @param[in] field The name of the field to compare. * @param[in] values The list that contains the values to match. * * @return The created Query. @@ -464,7 +464,7 @@ class Query { * combined with `WhereArrayContains()`, `WhereArrayContainsAny()`, * `WhereIn()`, or `WhereNotEqualTo()`. * - * @param[in] field The path of the field containing an array to search. + * @param[in] field The path of the field to compare. * @param[in] values The list that contains the values to match. * * @return The created Query. From 602a46349bba949336ddc02d79fe5b42c80769c6 Mon Sep 17 00:00:00 2001 From: Tom Andersen Date: Mon, 19 Jun 2023 11:21:23 -0400 Subject: [PATCH 08/25] Add/fix constructor and class descriptions. --- .../src/include/firebase/firestore/filter.h | 35 +++++++++++++++++++ .../src/include/firebase/firestore/query.h | 6 ++-- 2 files changed, 37 insertions(+), 4 deletions(-) diff --git a/firestore/src/include/firebase/firestore/filter.h b/firestore/src/include/firebase/firestore/filter.h index 02b9634962..358cc83010 100644 --- a/firestore/src/include/firebase/firestore/filter.h +++ b/firestore/src/include/firebase/firestore/filter.h @@ -28,6 +28,10 @@ namespace firestore { class FilterInternal; +/** + * @brief A Filter represents a restriction on one or more field values and can + * be used to refine the results of a Query. + */ class Filter { public: /** @@ -297,9 +301,40 @@ class Filter { static Filter Or(const std::vector& filters); + /** + * @brief Copy constructor. + * + * `Filter` is immutable and can be efficiently copied. + * + * @param[in] other `Filter` to copy from. + */ Filter(const Filter& other); + + /** + * @brief Move constructor. + * + * @param[in] other `Filter` to move data from. + */ Filter(Filter&& other) noexcept; + + /** + * @brief Copy assignment operator. + * + * `Filter` is immutable and can be efficiently copied. + * + * @param[in] other `Filter` to copy from. + * + * @return Reference to the destination `Filter`. + */ Filter& operator=(const Filter& other); + + /** + * @brief Move assignment operator. + * + * @param[in] other `Filter` to move data from. + * + * @return Reference to the destination `Filter`. + */ Filter& operator=(Filter&& other) noexcept; ~Filter(); diff --git a/firestore/src/include/firebase/firestore/query.h b/firestore/src/include/firebase/firestore/query.h index ec5b75d1c8..d696492146 100644 --- a/firestore/src/include/firebase/firestore/query.h +++ b/firestore/src/include/firebase/firestore/query.h @@ -84,8 +84,7 @@ class Query { /** * @brief Copy constructor. * - * `Query` is immutable and can be efficiently copied (no deep copy is - * performed). + * `Query` is immutable and can be efficiently copied. * * @param[in] other `Query` to copy from. */ @@ -106,8 +105,7 @@ class Query { /** * @brief Copy assignment operator. * - * `Query` is immutable and can be efficiently copied (no deep copy is - * performed). + * `Query` is immutable and can be efficiently copied. * * @param[in] other `Query` to copy from. * From 959f53b377b8995856e7cf26392a832200060d8a Mon Sep 17 00:00:00 2001 From: Tom Andersen Date: Mon, 19 Jun 2023 11:36:48 -0400 Subject: [PATCH 09/25] Add method description to disjunction/conjunction. --- .../src/include/firebase/firestore/filter.h | 25 ++++++++++++++----- 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/firestore/src/include/firebase/firestore/filter.h b/firestore/src/include/firebase/firestore/filter.h index 358cc83010..f9dd664ee9 100644 --- a/firestore/src/include/firebase/firestore/filter.h +++ b/firestore/src/include/firebase/firestore/filter.h @@ -265,12 +265,19 @@ class Filter { static Filter NotIn(const FieldPath& field, const std::vector& values); + /** + * @brief Conjunction of a single filter will simply return original filter. + * + * @param[in] filter Single filter for conjunction. + * + * @return Same as filter passed in as parameter. + */ static Filter And(const Filter filter) { return filter; } /** * @brief Creates a new filter that is a conjunction of the given filters. A - * conjunction filter includes a document if it satisfies all of the - * given filters. + * conjunction filter includes a document if it satisfies all of the given + * filters. * * @param[in] filters The filters to perform a conjunction for. * @@ -281,8 +288,13 @@ class Filter { return And(std::vector({filters...})); } - static Filter And(const std::vector& filters); - + /** + * @brief Disjunction of a single filter will simply return original filter. + * + * @param[in] filter Single filter for disjunction. + * + * @return Same as filter passed in as parameter. + */ static Filter Or(const Filter filter) { return filter; } /** @@ -299,8 +311,6 @@ class Filter { return Or(std::vector({filters...})); } - static Filter Or(const std::vector& filters); - /** * @brief Copy constructor. * @@ -346,6 +356,9 @@ class Filter { friend bool operator==(const Filter& lhs, const Filter& rhs); friend struct ConverterImpl; + static Filter And(const std::vector& filters); + static Filter Or(const std::vector& filters); + bool IsEmpty() const; explicit Filter(FilterInternal* internal); From 0f3e62f10df8ae5b27c4cd1b1ae9e94a38578c8e Mon Sep 17 00:00:00 2001 From: Tom Andersen Date: Tue, 20 Jun 2023 12:22:09 -0400 Subject: [PATCH 10/25] Add tests. Revealed bugs to be fixed. --- .../src/filter_test.cc | 154 ++++++++++++++++-- .../src/include/firebase/firestore/filter.h | 2 +- firestore/src/main/composite_filter_main.cc | 11 +- firestore/src/main/composite_filter_main.h | 2 + firestore/src/main/unary_filter_main.h | 2 + 5 files changed, 155 insertions(+), 16 deletions(-) diff --git a/firestore/integration_test_internal/src/filter_test.cc b/firestore/integration_test_internal/src/filter_test.cc index 04fdd31f18..e06efd5b03 100644 --- a/firestore/integration_test_internal/src/filter_test.cc +++ b/firestore/integration_test_internal/src/filter_test.cc @@ -23,16 +23,109 @@ namespace { using FilterTest = FirestoreIntegrationTest; -TEST_F(FilterTest, IdenticalShouldBeEqual) { +TEST_F(FilterTest, CopyConstructorReturnsEqualObject) { + const Filter filter1a = Filter::EqualTo("foo", FieldValue::Integer(42)); + const Filter filter2a = Filter::ArrayContainsAny( + "bar", {FieldValue::Integer(4), FieldValue::Integer(2)}); + const Filter filter3a = Filter::And(filter1a, filter2a); + + const Filter filter1b(filter1a); + const Filter filter2b(filter2a); + const Filter filter3b(filter3a); + + EXPECT_EQ(filter1a, filter1b); + EXPECT_EQ(filter2a, filter2b); + EXPECT_EQ(filter3a, filter3b); +} + +TEST_F(FilterTest, CopyAssignementReturnsEqualObject) { + const Filter filter1 = Filter::EqualTo("foo", FieldValue::Integer(42)); + const Filter filter2 = Filter::ArrayContainsAny( + "bar", {FieldValue::Integer(4), FieldValue::Integer(2)}); + const Filter filter3 = Filter::And(filter1, filter2); + + Filter filter = Filter::And(); + + EXPECT_NE(filter, filter1); + EXPECT_NE(filter, filter2); + EXPECT_NE(filter, filter3); + + filter = filter1; + + EXPECT_EQ(filter, filter1); + EXPECT_NE(filter, filter2); + EXPECT_NE(filter, filter3); + + filter = filter2; + + EXPECT_NE(filter, filter1); + EXPECT_EQ(filter, filter2); + EXPECT_NE(filter, filter3); + + filter = filter3; + + EXPECT_NE(filter, filter1); + EXPECT_NE(filter, filter2); + EXPECT_EQ(filter, filter3); +} + +TEST_F(FilterTest, MoveConstructorReturnsEqualObject) { + Filter filter1a = Filter::EqualTo("foo", FieldValue::Integer(42)); + Filter filter2a = Filter::ArrayContainsAny( + "bar", {FieldValue::Integer(4), FieldValue::Integer(2)}); + Filter filter3a = Filter::And(filter1a, filter2a); + + Filter filter1b(std::move(filter1a)); + EXPECT_EQ(filter1b, Filter::EqualTo("foo", FieldValue::Integer(42))); + + Filter filter2b(std::move(filter2a)); + EXPECT_EQ(filter2b, Filter::ArrayContainsAny("bar", {FieldValue::Integer(4), FieldValue::Integer(2)})); + + Filter filter3b(std::move(filter3a)); + EXPECT_EQ(filter3b, Filter::And(filter1b, filter2b)); +} + +TEST_F(FilterTest, MoveAssignmentReturnsEqualObject) { + Filter filter1a = Filter::EqualTo("foo", FieldValue::Integer(42)); + Filter filter2a = Filter::ArrayContainsAny( + "bar", {FieldValue::Integer(4), FieldValue::Integer(2)}); + Filter filter3a = Filter::And(filter1a, filter2a); + + Filter filter1b = std::move(filter1a); + EXPECT_EQ(filter1b, Filter::EqualTo("foo", FieldValue::Integer(42))); + + Filter filter2b = std::move(filter2a); + EXPECT_EQ(filter2b, Filter::ArrayContainsAny("bar", {FieldValue::Integer(4), FieldValue::Integer(2)})); + + Filter filter3b = std::move(filter3a); + EXPECT_EQ(filter3b, Filter::And(filter1b, filter2b)); +} + +TEST_F(FilterTest, MoveAssignmentAppliedToSelfReturnsEqualObject) { + Filter filter1 = Filter::EqualTo("foo", FieldValue::Integer(42)); + Filter filter2 = Filter::ArrayContainsAny( + "bar", {FieldValue::Integer(4), FieldValue::Integer(2)}); + Filter filter3 = Filter::And(filter1, filter2); + + filter1 = std::move(filter1); + EXPECT_EQ(filter1, Filter::EqualTo("foo", FieldValue::Integer(42))); + + filter2 = std::move(filter2); + EXPECT_EQ(filter2, Filter::ArrayContainsAny("bar", {FieldValue::Integer(4), FieldValue::Integer(2)})); + + filter3 = std::move(filter3); + EXPECT_EQ(filter3, Filter::And(filter1, filter2)); +} + +TEST_F(FilterTest, IdenticalFilterShouldBeEqual) { FieldPath foo_path{std::vector{"foo"}}; Filter filter1a = Filter::ArrayContains("foo", FieldValue::Integer(42)); Filter filter1b = Filter::ArrayContains(foo_path, FieldValue::Integer(42)); - Filter filter2a = Filter::ArrayContainsAny( - "foo", std::vector{FieldValue::Integer(42)}); - Filter filter2b = Filter::ArrayContainsAny( - foo_path, std::vector{FieldValue::Integer(42)}); + Filter filter2a = Filter::ArrayContainsAny("foo", {FieldValue::Integer(42)}); + Filter filter2b = + Filter::ArrayContainsAny(foo_path, {FieldValue::Integer(42)}); Filter filter3a = Filter::EqualTo("foo", FieldValue::Integer(42)); Filter filter3b = Filter::EqualTo(foo_path, FieldValue::Integer(42)); @@ -55,15 +148,17 @@ TEST_F(FilterTest, IdenticalShouldBeEqual) { Filter filter8b = Filter::LessThanOrEqualTo(foo_path, FieldValue::Integer(42)); - Filter filter9a = - Filter::In("foo", std::vector{FieldValue::Integer(42)}); - Filter filter9b = - Filter::In(foo_path, std::vector{FieldValue::Integer(42)}); + Filter filter9a = Filter::In("foo", {FieldValue::Integer(42)}); + Filter filter9b = Filter::In(foo_path, {FieldValue::Integer(42)}); + + Filter filter10a = Filter::NotIn("foo", {FieldValue::Integer(42)}); + Filter filter10b = Filter::NotIn(foo_path, {FieldValue::Integer(42)}); - Filter filter10a = - Filter::NotIn("foo", std::vector{FieldValue::Integer(42)}); - Filter filter10b = - Filter::NotIn(foo_path, std::vector{FieldValue::Integer(42)}); + Filter filter11a = Filter::And(filter1a, filter2a); + Filter filter11b = Filter::And(filter1b, filter2b); + + Filter filter12a = Filter::Or(filter3a, filter4a, filter5a, filter6a, filter7a); + Filter filter12b = Filter::Or(filter3b, filter4b, filter5b, filter6b, filter7b); EXPECT_TRUE(filter1a == filter1a); EXPECT_TRUE(filter2a == filter2a); @@ -75,6 +170,8 @@ TEST_F(FilterTest, IdenticalShouldBeEqual) { EXPECT_TRUE(filter8a == filter8a); EXPECT_TRUE(filter9a == filter9a); EXPECT_TRUE(filter10a == filter10a); + EXPECT_TRUE(filter11a == filter11a); + EXPECT_TRUE(filter12a == filter12a); EXPECT_TRUE(filter1a == filter1b); EXPECT_TRUE(filter2a == filter2b); @@ -86,6 +183,8 @@ TEST_F(FilterTest, IdenticalShouldBeEqual) { EXPECT_TRUE(filter8a == filter8b); EXPECT_TRUE(filter9a == filter9b); EXPECT_TRUE(filter10a == filter10b); + EXPECT_TRUE(filter11a == filter11b); + EXPECT_TRUE(filter12a == filter12b); EXPECT_FALSE(filter1a != filter1a); EXPECT_FALSE(filter2a != filter2a); @@ -97,6 +196,8 @@ TEST_F(FilterTest, IdenticalShouldBeEqual) { EXPECT_FALSE(filter8a != filter8a); EXPECT_FALSE(filter9a != filter9a); EXPECT_FALSE(filter10a != filter10a); + EXPECT_FALSE(filter11a != filter11a); + EXPECT_FALSE(filter12a != filter12a); EXPECT_FALSE(filter1a != filter1b); EXPECT_FALSE(filter2a != filter2b); @@ -108,6 +209,8 @@ TEST_F(FilterTest, IdenticalShouldBeEqual) { EXPECT_FALSE(filter8a != filter8b); EXPECT_FALSE(filter9a != filter9b); EXPECT_FALSE(filter10a != filter10b); + EXPECT_FALSE(filter11a != filter11b); + EXPECT_FALSE(filter12a != filter12b); EXPECT_TRUE(filter1a != filter2a); EXPECT_TRUE(filter1a != filter3a); @@ -118,6 +221,8 @@ TEST_F(FilterTest, IdenticalShouldBeEqual) { EXPECT_TRUE(filter1a != filter8a); EXPECT_TRUE(filter1a != filter9a); EXPECT_TRUE(filter1a != filter10a); + EXPECT_TRUE(filter1a != filter11a); + EXPECT_TRUE(filter1a != filter12a); EXPECT_TRUE(filter2a != filter3a); EXPECT_TRUE(filter2a != filter4a); EXPECT_TRUE(filter2a != filter5a); @@ -126,6 +231,8 @@ TEST_F(FilterTest, IdenticalShouldBeEqual) { EXPECT_TRUE(filter2a != filter8a); EXPECT_TRUE(filter2a != filter9a); EXPECT_TRUE(filter2a != filter10a); + EXPECT_TRUE(filter2a != filter11a); + EXPECT_TRUE(filter2a != filter12a); EXPECT_TRUE(filter3a != filter4a); EXPECT_TRUE(filter3a != filter5a); EXPECT_TRUE(filter3a != filter6a); @@ -133,27 +240,44 @@ TEST_F(FilterTest, IdenticalShouldBeEqual) { EXPECT_TRUE(filter3a != filter8a); EXPECT_TRUE(filter3a != filter9a); EXPECT_TRUE(filter3a != filter10a); + EXPECT_TRUE(filter3a != filter11a); + EXPECT_TRUE(filter3a != filter12a); EXPECT_TRUE(filter4a != filter5a); EXPECT_TRUE(filter4a != filter6a); EXPECT_TRUE(filter4a != filter7a); EXPECT_TRUE(filter4a != filter8a); EXPECT_TRUE(filter4a != filter9a); EXPECT_TRUE(filter4a != filter10a); + EXPECT_TRUE(filter4a != filter11a); + EXPECT_TRUE(filter4a != filter12a); EXPECT_TRUE(filter5a != filter6a); EXPECT_TRUE(filter5a != filter7a); EXPECT_TRUE(filter5a != filter8a); EXPECT_TRUE(filter5a != filter9a); EXPECT_TRUE(filter5a != filter10a); + EXPECT_TRUE(filter5a != filter11a); + EXPECT_TRUE(filter5a != filter12a); EXPECT_TRUE(filter6a != filter7a); EXPECT_TRUE(filter6a != filter8a); EXPECT_TRUE(filter6a != filter9a); EXPECT_TRUE(filter6a != filter10a); + EXPECT_TRUE(filter6a != filter11a); + EXPECT_TRUE(filter6a != filter12a); EXPECT_TRUE(filter7a != filter8a); EXPECT_TRUE(filter7a != filter9a); EXPECT_TRUE(filter7a != filter10a); + EXPECT_TRUE(filter7a != filter11a); + EXPECT_TRUE(filter7a != filter12a); EXPECT_TRUE(filter8a != filter9a); EXPECT_TRUE(filter8a != filter10a); + EXPECT_TRUE(filter8a != filter11a); + EXPECT_TRUE(filter8a != filter12a); EXPECT_TRUE(filter9a != filter10a); + EXPECT_TRUE(filter9a != filter11a); + EXPECT_TRUE(filter9a != filter12a); + EXPECT_TRUE(filter10a != filter11a); + EXPECT_TRUE(filter10a != filter12a); + EXPECT_TRUE(filter11a != filter12a); } TEST_F(FilterTest, DifferentValuesAreNotEqual) { @@ -231,7 +355,7 @@ TEST_F(FilterTest, CompositesWithOneFilterAreTheSameAsFilter) { EXPECT_FALSE(filter1 != filter3); } -TEST_F(FilterTest, EmptyCompositeIsIgnored) { +TEST_F(FilterTest, EmptyCompositeIsIgnoredByCompositesAndQueries) { Filter filter1 = Filter::And(); Filter filter2 = Filter::And(Filter::And(), Filter::And()); Filter filter3 = Filter::And(Filter::Or(), Filter::Or()); @@ -287,7 +411,9 @@ TEST_F(FilterTest, CompositeComparison) { EXPECT_EQ(or3, or3); EXPECT_EQ(or4, or4); + // Is equal because single filter composite is same as filter itself. EXPECT_EQ(and1, or1); + EXPECT_NE(and2, or2); EXPECT_NE(and3, or3); EXPECT_NE(and4, or4); diff --git a/firestore/src/include/firebase/firestore/filter.h b/firestore/src/include/firebase/firestore/filter.h index f9dd664ee9..c07a304ab8 100644 --- a/firestore/src/include/firebase/firestore/filter.h +++ b/firestore/src/include/firebase/firestore/filter.h @@ -362,7 +362,7 @@ class Filter { bool IsEmpty() const; explicit Filter(FilterInternal* internal); - FilterInternal* internal_; + FilterInternal* internal_ = nullptr; }; /** Checks `lhs` and `rhs` for equality. */ diff --git a/firestore/src/main/composite_filter_main.cc b/firestore/src/main/composite_filter_main.cc index 014c5f54f3..83b3a03a2f 100644 --- a/firestore/src/main/composite_filter_main.cc +++ b/firestore/src/main/composite_filter_main.cc @@ -24,6 +24,7 @@ #include "Firestore/core/src/core/composite_filter.h" #include "firestore/src/main/composite_filter_main.h" #include "firestore/src/main/converter_main.h" +#include "absl/algorithm/container.h" namespace firebase { namespace firestore { @@ -54,7 +55,15 @@ core::Filter CompositeFilterInternal::ToCoreFilter( bool operator==(const CompositeFilterInternal& lhs, const CompositeFilterInternal& rhs) { - return lhs.op_ == rhs.op_ && lhs.filters_ == rhs.filters_; + if (lhs.op_ != rhs.op_) return false; + const std::vector>& lhs_filters = lhs.filters_; + const std::vector>& rhs_filters = rhs.filters_; + const unsigned long size = lhs_filters.size(); + if (size != rhs_filters.size()) return false; + for (int i = 0; i < size; i++) { + if (lhs_filters[i] != rhs_filters[i] && *lhs_filters[i] != *rhs_filters[i]) return false; + } + return true; } } // namespace firestore diff --git a/firestore/src/main/composite_filter_main.h b/firestore/src/main/composite_filter_main.h index 4eb1ee5af8..c6b7876b8f 100644 --- a/firestore/src/main/composite_filter_main.h +++ b/firestore/src/main/composite_filter_main.h @@ -35,6 +35,8 @@ class CompositeFilterInternal : public FilterInternal { CompositeFilterInternal(core::CompositeFilter::Operator op, std::vector& filters); + ~CompositeFilterInternal() override = default; + core::Filter ToCoreFilter(const api::Query& query, const firebase::firestore::UserDataConverter& user_data_converter) const override; diff --git a/firestore/src/main/unary_filter_main.h b/firestore/src/main/unary_filter_main.h index e23d0c9481..30674eb2d2 100644 --- a/firestore/src/main/unary_filter_main.h +++ b/firestore/src/main/unary_filter_main.h @@ -38,6 +38,8 @@ class UnaryFilterInternal final : public FilterInternal { core::FieldFilter::Operator op, const std::vector& values); + ~UnaryFilterInternal() override = default; + core::Filter ToCoreFilter(const api::Query& query, const firebase::firestore::UserDataConverter& user_data_converter) const override; From 95b2a8c537c260c82a7867111101254d23df355d Mon Sep 17 00:00:00 2001 From: Tom Andersen Date: Tue, 20 Jun 2023 12:25:24 -0400 Subject: [PATCH 11/25] Fix type --- firestore/src/main/composite_filter_main.cc | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/firestore/src/main/composite_filter_main.cc b/firestore/src/main/composite_filter_main.cc index 83b3a03a2f..f098d3ff70 100644 --- a/firestore/src/main/composite_filter_main.cc +++ b/firestore/src/main/composite_filter_main.cc @@ -58,9 +58,8 @@ bool operator==(const CompositeFilterInternal& lhs, if (lhs.op_ != rhs.op_) return false; const std::vector>& lhs_filters = lhs.filters_; const std::vector>& rhs_filters = rhs.filters_; - const unsigned long size = lhs_filters.size(); - if (size != rhs_filters.size()) return false; - for (int i = 0; i < size; i++) { + if (lhs_filters.size() != rhs_filters.size()) return false; + for (int i = 0; i < lhs_filters.size(); i++) { if (lhs_filters[i] != rhs_filters[i] && *lhs_filters[i] != *rhs_filters[i]) return false; } return true; From 787ec3cdfa477fe3ed8a125d564a668af46f7940 Mon Sep 17 00:00:00 2001 From: Tom Andersen Date: Tue, 20 Jun 2023 16:34:14 -0400 Subject: [PATCH 12/25] Add test --- .../src/filter_test.cc | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/firestore/integration_test_internal/src/filter_test.cc b/firestore/integration_test_internal/src/filter_test.cc index e06efd5b03..baf114c56e 100644 --- a/firestore/integration_test_internal/src/filter_test.cc +++ b/firestore/integration_test_internal/src/filter_test.cc @@ -433,6 +433,29 @@ TEST_F(FilterTest, CompositeComparison) { EXPECT_NE(or3, or4); } +TEST_F(FilterTest, QueryWhereComposite) { + MapFieldValue doc_aa = {{"x", FieldValue::String("a")}, {"y", FieldValue::String("a")}}; + MapFieldValue doc_ab = {{"x", FieldValue::String("a")}, {"y", FieldValue::String("b")}}; + MapFieldValue doc_ba = {{"x", FieldValue::String("b")}, {"y", FieldValue::String("a")}}; + MapFieldValue doc_bb = {{"x", FieldValue::String("b")}, {"y", FieldValue::String("b")}}; + CollectionReference collection = + Collection({{"aa", doc_aa}, + {"ab", doc_ab}, + {"ba", doc_ba}, + {"bb", doc_bb}}); + + Filter filter_xa = Filter::EqualTo("x", FieldValue::String("a")); + Filter filter_yb = Filter::EqualTo("y", FieldValue::String("b")); + + QuerySnapshot snapshot1 = + ReadDocuments(collection.Where(Filter::And(filter_xa, filter_yb))); + EXPECT_EQ(std::vector({doc_ab}), QuerySnapshotToValues(snapshot1)); + + QuerySnapshot snapshot2 = + ReadDocuments(collection.Where(Filter::Or(filter_xa, filter_yb))); + EXPECT_EQ(std::vector({doc_aa, doc_ab, doc_bb}), QuerySnapshotToValues(snapshot2)); +} + } // namespace } // namespace firestore From 56f15c2b81601bf536fd0e265cf940e0ac5ff302 Mon Sep 17 00:00:00 2001 From: Tom Andersen Date: Thu, 22 Jun 2023 11:46:03 -0400 Subject: [PATCH 13/25] Android implementation --- firestore/CMakeLists.txt | 2 + .../project.pbxproj | 24 ++ .../src/aggregate_count_test.cc | 16 -- .../src/aggregate_query_test.cc | 15 ++ firestore/src/android/filter_android.cc | 208 ++++++++++++++++++ firestore/src/android/filter_android.h | 92 ++++++++ firestore/src/android/query_android.cc | 12 + firestore/src/android/query_android.h | 2 + firestore/src/android/wrapper.cc | 2 +- firestore/src/android/wrapper.h | 2 +- .../src/include/firebase/firestore/filter.h | 1 - firestore/src/main/composite_filter_main.cc | 16 +- 12 files changed, 367 insertions(+), 25 deletions(-) create mode 100644 firestore/src/android/filter_android.cc create mode 100644 firestore/src/android/filter_android.h diff --git a/firestore/CMakeLists.txt b/firestore/CMakeLists.txt index bc39b48609..c237a753c9 100644 --- a/firestore/CMakeLists.txt +++ b/firestore/CMakeLists.txt @@ -98,6 +98,8 @@ set(android_SRCS src/android/field_path_portable.h src/android/field_value_android.cc src/android/field_value_android.h + src/android/filter_android.cc + src/android/filter_android.h src/android/firestore_android.cc src/android/firestore_android.h src/android/firestore_exceptions_android.h diff --git a/firestore/integration_test_internal/integration_test.xcodeproj/project.pbxproj b/firestore/integration_test_internal/integration_test.xcodeproj/project.pbxproj index 4fc6d0ca75..415b4bcff8 100644 --- a/firestore/integration_test_internal/integration_test.xcodeproj/project.pbxproj +++ b/firestore/integration_test_internal/integration_test.xcodeproj/project.pbxproj @@ -21,6 +21,14 @@ 12CCF1E928FDBD9F00C24941 /* set_options_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 12CCF1DF28FDBD9F00C24941 /* set_options_test.cc */; }; 12D513142684C8C200A83FAA /* bundle_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 12D513132684C8C200A83FAA /* bundle_test.cc */; }; 12D5131A2684C8D100A83FAA /* bundle_builder.cc in Sources */ = {isa = PBXBuildFile; fileRef = 12D513182684C8D100A83FAA /* bundle_builder.cc */; }; + 1BAFACA32A449C2B00834979 /* aggregate_query_snapshot_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 1BAFACA02A449C2B00834979 /* aggregate_query_snapshot_test.cc */; }; + 1BAFACA42A449C2B00834979 /* aggregate_query_snapshot_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 1BAFACA02A449C2B00834979 /* aggregate_query_snapshot_test.cc */; }; + 1BAFACA52A449C2B00834979 /* aggregate_count_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 1BAFACA12A449C2B00834979 /* aggregate_count_test.cc */; }; + 1BAFACA62A449C2B00834979 /* aggregate_count_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 1BAFACA12A449C2B00834979 /* aggregate_count_test.cc */; }; + 1BAFACA72A449C2B00834979 /* aggregate_query_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 1BAFACA22A449C2B00834979 /* aggregate_query_test.cc */; }; + 1BAFACA82A449C2B00834979 /* aggregate_query_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 1BAFACA22A449C2B00834979 /* aggregate_query_test.cc */; }; + 1BAFACAA2A449CBD00834979 /* filter_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 1BAFACA92A449CBD00834979 /* filter_test.cc */; }; + 1BAFACAB2A449CBD00834979 /* filter_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 1BAFACA92A449CBD00834979 /* filter_test.cc */; }; 520BC0391C869159008CFBC3 /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 520BC0381C869159008CFBC3 /* GoogleService-Info.plist */; }; 5270BB448DF5ECE860FDD68B /* firebase_firestore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = EAFAF9474EC412ADCC65F2CC /* firebase_firestore.framework */; }; 529226D61C85F68000C89379 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 529226D51C85F68000C89379 /* Foundation.framework */; }; @@ -123,6 +131,10 @@ 12D513182684C8D100A83FAA /* bundle_builder.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = bundle_builder.cc; path = src/util/bundle_builder.cc; sourceTree = ""; }; 12D513192684C8D100A83FAA /* bundle_builder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = bundle_builder.h; path = src/util/bundle_builder.h; sourceTree = ""; }; 1B3D64B35A22073C76B376D5 /* libPods-integration_test_tvos.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-integration_test_tvos.a"; sourceTree = BUILT_PRODUCTS_DIR; }; + 1BAFACA02A449C2B00834979 /* aggregate_query_snapshot_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = aggregate_query_snapshot_test.cc; path = src/aggregate_query_snapshot_test.cc; sourceTree = ""; }; + 1BAFACA12A449C2B00834979 /* aggregate_count_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = aggregate_count_test.cc; path = src/aggregate_count_test.cc; sourceTree = ""; }; + 1BAFACA22A449C2B00834979 /* aggregate_query_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = aggregate_query_test.cc; path = src/aggregate_query_test.cc; sourceTree = ""; }; + 1BAFACA92A449CBD00834979 /* filter_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = filter_test.cc; path = src/filter_test.cc; sourceTree = ""; }; 3DE393E827F88B06CD3C39CD /* Pods-integration_test_tvos.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-integration_test_tvos.release.xcconfig"; path = "Target Support Files/Pods-integration_test_tvos/Pods-integration_test_tvos.release.xcconfig"; sourceTree = ""; }; 4AAFA3E3DA9641C2E3C46C9D /* Pods_integration_test.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_integration_test.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 520BC0381C869159008CFBC3 /* GoogleService-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "GoogleService-Info.plist"; sourceTree = ""; }; @@ -281,6 +293,10 @@ 5292271D1C85FB5500C89379 /* src */ = { isa = PBXGroup; children = ( + 1BAFACA92A449CBD00834979 /* filter_test.cc */, + 1BAFACA12A449C2B00834979 /* aggregate_count_test.cc */, + 1BAFACA02A449C2B00834979 /* aggregate_query_snapshot_test.cc */, + 1BAFACA22A449C2B00834979 /* aggregate_query_test.cc */, 12CCF1DF28FDBD9F00C24941 /* set_options_test.cc */, 12CCF1DB28FDBD9E00C24941 /* settings_test.cc */, 12CCF1DC28FDBD9F00C24941 /* source_test.cc */, @@ -576,12 +592,14 @@ D62CCBC022F367140099BE9F /* gmock-all.cc in Sources */, D61CFBC126091C3B0035CB2A /* integration_test.cc in Sources */, D6AAAD532606C22D0025C53B /* includes_test.cc in Sources */, + 1BAFACA52A449C2B00834979 /* aggregate_count_test.cc in Sources */, D6AAAD502606C22D0025C53B /* numeric_transforms_test.cc in Sources */, D6ED33BE2606CD890058CBF9 /* integration_test_util.cc in Sources */, D6C179EA22CB322900C2651A /* ios_firebase_test_framework.mm in Sources */, 12CCF1E228FDBD9F00C24941 /* source_test.cc in Sources */, D6AAAD4C2606C22D0025C53B /* server_timestamp_test.cc in Sources */, D6AAAD4E2606C22D0025C53B /* firestore_test.cc in Sources */, + 1BAFACAA2A449CBD00834979 /* filter_test.cc in Sources */, D6AAAD452606C22D0025C53B /* document_change_test.cc in Sources */, D6AAAD472606C22D0025C53B /* document_snapshot_test.cc in Sources */, D6C179E922CB322900C2651A /* ios_app_framework.mm in Sources */, @@ -591,7 +609,9 @@ EDEEC7632800CD0000EFBAAF /* leveldb_snappy_test.cc in Sources */, 12CCF1E828FDBD9F00C24941 /* set_options_test.cc in Sources */, D6AAAD562606C22D0025C53B /* query_network_test.cc in Sources */, + 1BAFACA72A449C2B00834979 /* aggregate_query_test.cc in Sources */, D6AAAD552606C22D0025C53B /* listener_registration_test.cc in Sources */, + 1BAFACA32A449C2B00834979 /* aggregate_query_snapshot_test.cc in Sources */, 12D5131A2684C8D100A83FAA /* bundle_builder.cc in Sources */, D6AAAD4A2606C22D0025C53B /* fields_test.cc in Sources */, D6AAAD462606C22D0025C53B /* query_test.cc in Sources */, @@ -610,6 +630,8 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 1BAFACAB2A449CBD00834979 /* filter_test.cc in Sources */, + 1BAFACA62A449C2B00834979 /* aggregate_count_test.cc in Sources */, BC1D6850267B00EB005DC2DA /* app_framework.cc in Sources */, BC1D6853267B00EB005DC2DA /* transaction_extra_test.cc in Sources */, BC1D683E267B00EB005DC2DA /* integration_test_util.cc in Sources */, @@ -623,6 +645,7 @@ BC1D6848267B00EB005DC2DA /* sanity_test.cc in Sources */, 12CCF1E728FDBD9F00C24941 /* write_batch_test.cc in Sources */, 12CCF1E128FDBD9F00C24941 /* settings_test.cc in Sources */, + 1BAFACA82A449C2B00834979 /* aggregate_query_test.cc in Sources */, BC1D6856267B00EE005DC2DA /* ios_app_framework.mm in Sources */, BC1D6843267B00EB005DC2DA /* numeric_transforms_test.cc in Sources */, BC1D6844267B00EB005DC2DA /* array_transform_test.cc in Sources */, @@ -632,6 +655,7 @@ BC1D684E267B00EB005DC2DA /* includes_test.cc in Sources */, BC1D684C267B00EB005DC2DA /* document_change_test.cc in Sources */, BC1D6851267B00EB005DC2DA /* firestore_integration_test.cc in Sources */, + 1BAFACA42A449C2B00834979 /* aggregate_query_snapshot_test.cc in Sources */, BC1D6838267B00EB005DC2DA /* future_test_util.cc in Sources */, 12CCF1E528FDBD9F00C24941 /* validation_test.cc in Sources */, BC1D6839267B00EB005DC2DA /* type_test.cc in Sources */, diff --git a/firestore/integration_test_internal/src/aggregate_count_test.cc b/firestore/integration_test_internal/src/aggregate_count_test.cc index dc58961fc3..7f3f462a1f 100644 --- a/firestore/integration_test_internal/src/aggregate_count_test.cc +++ b/firestore/integration_test_internal/src/aggregate_count_test.cc @@ -28,15 +28,9 @@ #include "firestore_integration_test.h" #include "util/event_accumulator.h" -#if defined(__ANDROID__) -#include "firestore/src/android/query_android.h" -#include "firestore/src/common/wrapper_assertions.h" -#endif // defined(__ANDROID__) - #include "Firestore/core/src/util/firestore_exceptions.h" #include "firebase/firestore/firestore_errors.h" #include "firebase_test_framework.h" -#include "gmock/gmock.h" #include "gtest/gtest.h" namespace firebase { @@ -757,15 +751,5 @@ TEST_F(AggregateCountTest, EXPECT_EQ(aggregate_query2, aggregate_snapshot2.query()); } -#if defined(__ANDROID__) -TEST(QueryTestAndroidStub, Construction) { - testutil::AssertWrapperConstructionContract(); -} - -TEST(QueryTestAndroidStub, Assignment) { - testutil::AssertWrapperAssignmentContract(); -} -#endif // defined(__ANDROID__) - } // namespace firestore } // namespace firebase diff --git a/firestore/integration_test_internal/src/aggregate_query_test.cc b/firestore/integration_test_internal/src/aggregate_query_test.cc index 4a52be9790..4810e5e96f 100644 --- a/firestore/integration_test_internal/src/aggregate_query_test.cc +++ b/firestore/integration_test_internal/src/aggregate_query_test.cc @@ -17,6 +17,11 @@ #include "firebase/firestore.h" #include "firestore_integration_test.h" +#if defined(__ANDROID__) +#include "firestore/src/android/aggregate_query_android.h" +#include "firestore/src/common/wrapper_assertions.h" +#endif // defined(__ANDROID__) + #include "gtest/gtest.h" namespace firebase { @@ -332,6 +337,16 @@ TEST_F(AggregateQueryTest, TestHashCode) { AggregateQueryHash(query1.Count())); } +#if defined(__ANDROID__) +TEST(QueryTestAndroidStub, Construction) { + testutil::AssertWrapperConstructionContract(); +} + +TEST(QueryTestAndroidStub, Assignment) { + testutil::AssertWrapperAssignmentContract(); +} +#endif // defined(__ANDROID__) + } // namespace } // namespace firestore } // namespace firebase diff --git a/firestore/src/android/filter_android.cc b/firestore/src/android/filter_android.cc new file mode 100644 index 0000000000..eed2540a27 --- /dev/null +++ b/firestore/src/android/filter_android.cc @@ -0,0 +1,208 @@ +/* + * 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. + */ + +#include "firestore/src/android/filter_android.h" + +#include "firestore/src/android/converter_android.h" +#include "firestore/src/android/firestore_android.h" +#include "firestore/src/android/field_path_android.h" +#include "firestore/src/android/field_value_android.h" + +#include "firestore/src/jni/array.h" +#include "firestore/src/jni/array_list.h" +#include "firestore/src/jni/compare.h" +#include "firestore/src/jni/env.h" +#include "firestore/src/jni/loader.h" + +namespace firebase { +namespace firestore { +namespace { + +using jni::Array; +using jni::ArrayList; +using jni::Env; +using jni::Local; +using jni::StaticMethod; +using jni::Object; + +constexpr char kClassName[] = + PROGUARD_KEEP_CLASS "com/google/firebase/firestore/Filter"; +StaticMethod kEqualTo( + "equalTo", + "(Lcom/google/firebase/firestore/FieldPath;Ljava/lang/Object;)" + "Lcom/google/firebase/firestore/Filter;"); +StaticMethod kNotEqualTo( + "notEqualTo", + "(Lcom/google/firebase/firestore/FieldPath;Ljava/lang/Object;)" + "Lcom/google/firebase/firestore/Filter;"); +StaticMethod kLessThan( + "lessThan", + "(Lcom/google/firebase/firestore/FieldPath;Ljava/lang/Object;)" + "Lcom/google/firebase/firestore/Filter;"); +StaticMethod kLessThanOrEqualTo( + "lessThanOrEqualTo", + "(Lcom/google/firebase/firestore/FieldPath;Ljava/lang/Object;)" + "Lcom/google/firebase/firestore/Filter;"); +StaticMethod kGreaterThan( + "greaterThan", + "(Lcom/google/firebase/firestore/FieldPath;Ljava/lang/Object;)" + "Lcom/google/firebase/firestore/Filter;"); +StaticMethod kGreaterThanOrEqualTo( + "greaterThanOrEqualTo", + "(Lcom/google/firebase/firestore/FieldPath;Ljava/lang/Object;)" + "Lcom/google/firebase/firestore/Filter;"); +StaticMethod kArrayContains( + "arrayContains", + "(Lcom/google/firebase/firestore/FieldPath;Ljava/lang/Object;)" + "Lcom/google/firebase/firestore/Filter;"); +StaticMethod kArrayContainsAny( + "arrayContainsAny", + "(Lcom/google/firebase/firestore/FieldPath;Ljava/util/List;)" + "Lcom/google/firebase/firestore/Filter;"); +StaticMethod kIn("in", + "(Lcom/google/firebase/firestore/FieldPath;Ljava/util/List;)" + "Lcom/google/firebase/firestore/Filter;"); +StaticMethod kNotIn( + "notIn", + "(Lcom/google/firebase/firestore/FieldPath;Ljava/util/List;)" + "Lcom/google/firebase/firestore/Filter;"); +StaticMethod kAnd( + "and", + "([Lcom/google/firebase/firestore/Filter;)" + "Lcom/google/firebase/firestore/Filter;"); +StaticMethod kOr( + "or", + "([Lcom/google/firebase/firestore/Filter;)" + "Lcom/google/firebase/firestore/Filter;"); +} + +void FilterInternal::Initialize(jni::Loader& loader) { + loader.LoadClass( + kClassName, kEqualTo, kNotEqualTo, kLessThan, kLessThanOrEqualTo, + kGreaterThan, kGreaterThanOrEqualTo, kArrayContains, kArrayContainsAny, + kIn, kNotIn, kAnd, kOr); +} + +FilterInternal::FilterInternal(jni::Object&& object, bool is_empty) + : object_(object), is_empty_(is_empty) {} + +Filter FilterInternal::EqualTo(const FieldPath& field, + const FieldValue& value) { + return Where(field, kEqualTo, value); +} + +Filter FilterInternal::NotEqualTo(const FieldPath& field, + const FieldValue& value) { + return Where(field, kNotEqualTo, value); +} + +Filter FilterInternal::LessThan(const FieldPath& field, + const FieldValue& value) { + return Where(field, kLessThan, value); +} + +Filter FilterInternal::LessThanOrEqualTo(const FieldPath& field, + const FieldValue& value) { + return Where(field, kLessThanOrEqualTo, value); +} + +Filter FilterInternal::GreaterThan(const FieldPath& field, + const FieldValue& value) { + return Where(field, kGreaterThan, value); +} + +Filter FilterInternal::GreaterThanOrEqualTo(const FieldPath& field, + const FieldValue& value) { + return Where(field, kGreaterThanOrEqualTo, value); +} + +Filter FilterInternal::ArrayContains(const FieldPath& field, + const FieldValue& value) { + return Where(field, kArrayContains, value); +} + +Filter FilterInternal::ArrayContainsAny( + const FieldPath& field, const std::vector& values) { + return Where(field, kArrayContainsAny, values); +} + +Filter FilterInternal::In(const FieldPath& field, + const std::vector& values) { + return Where(field, kIn, values); +} + +Filter FilterInternal::NotIn(const FieldPath& field, + const std::vector& values) { + return Where(field, kNotIn, values); +} + +Filter FilterInternal::And(const std::vector& filters) { + return Where(kAnd, filters); +} + +Filter FilterInternal::Or(const std::vector& filters) { + return Where(kOr, filters); +} + +Env FilterInternal::GetEnv() { return FirestoreInternal::GetEnv(); } + +Filter FilterInternal::Where(const FieldPath& field, + const StaticMethod& method, + const FieldValue& value) { + Env env = GetEnv(); + Local java_field = FieldPathConverter::Create(env, field); + Object filter = env.Call(method, java_field, FieldValueInternal::ToJava(value)); + return Filter(new FilterInternal(std::move(filter), false)); +} + +Filter FilterInternal::Where(const FieldPath& field, + const jni::StaticMethod& method, + const std::vector& values) { + Env env = GetEnv(); + size_t size = values.size(); + Local java_values = ArrayList::Create(env, size); + for (size_t i = 0; i < size; ++i) { + java_values.Add(env, FieldValueInternal::ToJava(values[i])); + } + + Local java_field = FieldPathConverter::Create(env, field); + Object filter = env.Call(method, java_field, java_values); + return Filter(new FilterInternal(std::move(filter), false)); +} + +Filter FilterInternal::Where(const StaticMethod& method, + const std::vector& filters) { + Env env = GetEnv(); + size_t size = filters.size(); + Local> java_filters = env.NewArray(size, Object::GetClass()); + bool is_empty = true; + for (int i = 0; i < size; ++i) { + FilterInternal* internal_filter = filters[i].internal_; + if (!internal_filter->IsEmpty()) { + is_empty = false; + } + java_filters.Set(env, i, internal_filter->object_); + } + Object filter = env.Call(method, java_filters); + return Filter(new FilterInternal(std::move(filter), is_empty)); +} + +bool operator==(const FilterInternal& lhs, const FilterInternal& rhs) { + return jni::EqualityCompareJni(lhs, rhs); +} + +} // namespace firestore +} // namespace firebase diff --git a/firestore/src/android/filter_android.h b/firestore/src/android/filter_android.h new file mode 100644 index 0000000000..d080cad213 --- /dev/null +++ b/firestore/src/android/filter_android.h @@ -0,0 +1,92 @@ +/* + * 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. + */ + +#ifndef FIREBASE_FIRESTORE_SRC_ANDROID_FILTER_ANDROID_H_ +#define FIREBASE_FIRESTORE_SRC_ANDROID_FILTER_ANDROID_H_ + +#include + +#include "firestore/src/android/wrapper.h" +#include "firestore/src/include/firebase/firestore/field_path.h" +#include "firestore/src/include/firebase/firestore/field_value.h" +#include "firestore/src/include/firebase/firestore/filter.h" + +namespace firebase { +namespace firestore { + +class FilterInternal final { + public: + static void Initialize(jni::Loader& loader); + + FilterInternal(jni::Object&& object, bool is_empty); + + static Filter ArrayContains(const FieldPath& field, const FieldValue& value); + static Filter ArrayContainsAny(const FieldPath& field, + const std::vector& values); + static Filter EqualTo(const FieldPath& field, const FieldValue& value); + static Filter NotEqualTo(const FieldPath& field, const FieldValue& value); + static Filter GreaterThan(const FieldPath& field, const FieldValue& value); + static Filter GreaterThanOrEqualTo(const FieldPath& field, + const FieldValue& value); + static Filter LessThan(const FieldPath& field, const FieldValue& value); + static Filter LessThanOrEqualTo(const FieldPath& field, + const FieldValue& value); + static Filter In(const FieldPath& field, + const std::vector& values); + static Filter NotIn(const FieldPath& field, + const std::vector& values); + static Filter Or(const std::vector& filters); + static Filter And(const std::vector& filters); + + const jni::Global& ToJava() const { return object_; } + + private: + friend class Filter; + friend class FirestoreInternal; + + FilterInternal* clone() { + return new FilterInternal(*this); + } + + bool IsEmpty() const { return is_empty_; } + + static jni::Env GetEnv(); + + jni::Global object_; + const bool is_empty_; + + // A generalized function for all WhereFoo calls. + static Filter Where(const FieldPath& field, + const jni::StaticMethod& method, + const FieldValue& value); + static Filter Where(const FieldPath& field, + const jni::StaticMethod& method, + const std::vector& values); + static Filter Where(const jni::StaticMethod& method, + const std::vector& filters); + +}; + +bool operator==(const FilterInternal& lhs, const FilterInternal& rhs); + +inline bool operator!=(const FilterInternal& lhs, const FilterInternal& rhs) { + return !(lhs == rhs); +} + +} // namespace firestore +} // namespace firebase + +#endif // FIREBASE_FIRESTORE_SRC_ANDROID_FILTER_ANDROID_H_ diff --git a/firestore/src/android/query_android.cc b/firestore/src/android/query_android.cc index 81fdd418e0..7ba01494ec 100644 --- a/firestore/src/android/query_android.cc +++ b/firestore/src/android/query_android.cc @@ -21,6 +21,7 @@ #include "firestore/src/android/direction_android.h" #include "firestore/src/android/document_snapshot_android.h" #include "firestore/src/android/event_listener_android.h" +#include "firestore/src/android/filter_android.h" #include "firestore/src/android/field_path_android.h" #include "firestore/src/android/field_value_android.h" #include "firestore/src/android/firestore_android.h" @@ -53,6 +54,10 @@ constexpr char kClassName[] = PROGUARD_KEEP_CLASS "com/google/firebase/firestore/Query"; Method kCount("count", "()Lcom/google/firebase/firestore/AggregateQuery;"); +Method kWhere( + "where", + "(Lcom/google/firebase/firestore/Filter;)" + "Lcom/google/firebase/firestore/Query;"); Method kEqualTo( "whereEqualTo", "(Lcom/google/firebase/firestore/FieldPath;Ljava/lang/Object;)" @@ -156,6 +161,13 @@ AggregateQuery QueryInternal::Count() const { return firestore_->NewAggregateQuery(env, aggregate_query); } +Query QueryInternal::Where(const firebase::firestore::Filter& filter) const { + Env env = GetEnv(); + Local query = env.Call(obj_, kWhere, filter.internal_->ToJava()); + return firestore_->NewQuery(env, query); + +} + Query QueryInternal::WhereEqualTo(const FieldPath& field, const FieldValue& value) const { return Where(field, kEqualTo, value); diff --git a/firestore/src/android/query_android.h b/firestore/src/android/query_android.h index abb3dea8e3..b4429f946a 100644 --- a/firestore/src/android/query_android.h +++ b/firestore/src/android/query_android.h @@ -71,6 +71,8 @@ class QueryInternal : public Wrapper { */ virtual AggregateQuery Count() const; + Query Where(const Filter& filter) const; + /** * @brief Creates and returns a new Query with the additional filter that * documents must contain the specified field and the value should be equal to diff --git a/firestore/src/android/wrapper.cc b/firestore/src/android/wrapper.cc index c4304abe29..6fd031ac8a 100644 --- a/firestore/src/android/wrapper.cc +++ b/firestore/src/android/wrapper.cc @@ -56,7 +56,7 @@ Wrapper::Wrapper(Wrapper* rhs) : Wrapper() { Wrapper::~Wrapper() = default; -jni::Env Wrapper::GetEnv() const { return firestore_->GetEnv(); } +jni::Env Wrapper::GetEnv() { return FirestoreInternal::GetEnv(); } Object Wrapper::ToJava(const FieldValue& value) { return FieldValueInternal::ToJava(value); diff --git a/firestore/src/android/wrapper.h b/firestore/src/android/wrapper.h index b1da5fce65..fdbf79bf04 100644 --- a/firestore/src/android/wrapper.h +++ b/firestore/src/android/wrapper.h @@ -56,7 +56,7 @@ class Wrapper { // Similar to a copy constructor, but can handle the case where `rhs` is null. explicit Wrapper(Wrapper* rhs); - jni::Env GetEnv() const; + static jni::Env GetEnv(); FirestoreInternal* firestore_ = nullptr; // not owning jni::Global obj_; diff --git a/firestore/src/include/firebase/firestore/filter.h b/firestore/src/include/firebase/firestore/filter.h index c07a304ab8..be8417b00d 100644 --- a/firestore/src/include/firebase/firestore/filter.h +++ b/firestore/src/include/firebase/firestore/filter.h @@ -21,7 +21,6 @@ #include #include "firebase/firestore/field_value.h" -#include "firestore/src/main/filter_main.h" namespace firebase { namespace firestore { diff --git a/firestore/src/main/composite_filter_main.cc b/firestore/src/main/composite_filter_main.cc index f098d3ff70..1069600cc4 100644 --- a/firestore/src/main/composite_filter_main.cc +++ b/firestore/src/main/composite_filter_main.cc @@ -22,9 +22,9 @@ #include #include "Firestore/core/src/core/composite_filter.h" +#include "absl/algorithm/container.h" #include "firestore/src/main/composite_filter_main.h" #include "firestore/src/main/converter_main.h" -#include "absl/algorithm/container.h" namespace firebase { namespace firestore { @@ -56,11 +56,15 @@ core::Filter CompositeFilterInternal::ToCoreFilter( bool operator==(const CompositeFilterInternal& lhs, const CompositeFilterInternal& rhs) { if (lhs.op_ != rhs.op_) return false; - const std::vector>& lhs_filters = lhs.filters_; - const std::vector>& rhs_filters = rhs.filters_; - if (lhs_filters.size() != rhs_filters.size()) return false; - for (int i = 0; i < lhs_filters.size(); i++) { - if (lhs_filters[i] != rhs_filters[i] && *lhs_filters[i] != *rhs_filters[i]) return false; + const std::vector>& lhs_filters = + lhs.filters_; + const std::vector>& rhs_filters = + rhs.filters_; + size_t size = lhs_filters.size(); + if (size != rhs_filters.size()) return false; + for (int i = 0; i < size; i++) { + if (lhs_filters[i] != rhs_filters[i] && *lhs_filters[i] != *rhs_filters[i]) + return false; } return true; } From 1a6d116d0ba778bb39655455d19b0e6c79cdd892 Mon Sep 17 00:00:00 2001 From: Tom Andersen Date: Thu, 22 Jun 2023 12:31:19 -0400 Subject: [PATCH 14/25] Pretty --- .../src/filter_test.cc | 42 ++++++++++++------- firestore/src/android/filter_android.cc | 4 +- firestore/src/android/filter_android.h | 1 - firestore/src/main/filter_main.h | 8 ++-- 4 files changed, 32 insertions(+), 23 deletions(-) diff --git a/firestore/integration_test_internal/src/filter_test.cc b/firestore/integration_test_internal/src/filter_test.cc index baf114c56e..d4a7330ab0 100644 --- a/firestore/integration_test_internal/src/filter_test.cc +++ b/firestore/integration_test_internal/src/filter_test.cc @@ -79,7 +79,9 @@ TEST_F(FilterTest, MoveConstructorReturnsEqualObject) { EXPECT_EQ(filter1b, Filter::EqualTo("foo", FieldValue::Integer(42))); Filter filter2b(std::move(filter2a)); - EXPECT_EQ(filter2b, Filter::ArrayContainsAny("bar", {FieldValue::Integer(4), FieldValue::Integer(2)})); + EXPECT_EQ(filter2b, + Filter::ArrayContainsAny( + "bar", {FieldValue::Integer(4), FieldValue::Integer(2)})); Filter filter3b(std::move(filter3a)); EXPECT_EQ(filter3b, Filter::And(filter1b, filter2b)); @@ -95,7 +97,9 @@ TEST_F(FilterTest, MoveAssignmentReturnsEqualObject) { EXPECT_EQ(filter1b, Filter::EqualTo("foo", FieldValue::Integer(42))); Filter filter2b = std::move(filter2a); - EXPECT_EQ(filter2b, Filter::ArrayContainsAny("bar", {FieldValue::Integer(4), FieldValue::Integer(2)})); + EXPECT_EQ(filter2b, + Filter::ArrayContainsAny( + "bar", {FieldValue::Integer(4), FieldValue::Integer(2)})); Filter filter3b = std::move(filter3a); EXPECT_EQ(filter3b, Filter::And(filter1b, filter2b)); @@ -111,7 +115,8 @@ TEST_F(FilterTest, MoveAssignmentAppliedToSelfReturnsEqualObject) { EXPECT_EQ(filter1, Filter::EqualTo("foo", FieldValue::Integer(42))); filter2 = std::move(filter2); - EXPECT_EQ(filter2, Filter::ArrayContainsAny("bar", {FieldValue::Integer(4), FieldValue::Integer(2)})); + EXPECT_EQ(filter2, Filter::ArrayContainsAny("bar", {FieldValue::Integer(4), + FieldValue::Integer(2)})); filter3 = std::move(filter3); EXPECT_EQ(filter3, Filter::And(filter1, filter2)); @@ -157,8 +162,10 @@ TEST_F(FilterTest, IdenticalFilterShouldBeEqual) { Filter filter11a = Filter::And(filter1a, filter2a); Filter filter11b = Filter::And(filter1b, filter2b); - Filter filter12a = Filter::Or(filter3a, filter4a, filter5a, filter6a, filter7a); - Filter filter12b = Filter::Or(filter3b, filter4b, filter5b, filter6b, filter7b); + Filter filter12a = + Filter::Or(filter3a, filter4a, filter5a, filter6a, filter7a); + Filter filter12b = + Filter::Or(filter3b, filter4b, filter5b, filter6b, filter7b); EXPECT_TRUE(filter1a == filter1a); EXPECT_TRUE(filter2a == filter2a); @@ -434,26 +441,29 @@ TEST_F(FilterTest, CompositeComparison) { } TEST_F(FilterTest, QueryWhereComposite) { - MapFieldValue doc_aa = {{"x", FieldValue::String("a")}, {"y", FieldValue::String("a")}}; - MapFieldValue doc_ab = {{"x", FieldValue::String("a")}, {"y", FieldValue::String("b")}}; - MapFieldValue doc_ba = {{"x", FieldValue::String("b")}, {"y", FieldValue::String("a")}}; - MapFieldValue doc_bb = {{"x", FieldValue::String("b")}, {"y", FieldValue::String("b")}}; - CollectionReference collection = - Collection({{"aa", doc_aa}, - {"ab", doc_ab}, - {"ba", doc_ba}, - {"bb", doc_bb}}); + MapFieldValue doc_aa = {{"x", FieldValue::String("a")}, + {"y", FieldValue::String("a")}}; + MapFieldValue doc_ab = {{"x", FieldValue::String("a")}, + {"y", FieldValue::String("b")}}; + MapFieldValue doc_ba = {{"x", FieldValue::String("b")}, + {"y", FieldValue::String("a")}}; + MapFieldValue doc_bb = {{"x", FieldValue::String("b")}, + {"y", FieldValue::String("b")}}; + CollectionReference collection = Collection( + {{"aa", doc_aa}, {"ab", doc_ab}, {"ba", doc_ba}, {"bb", doc_bb}}); Filter filter_xa = Filter::EqualTo("x", FieldValue::String("a")); Filter filter_yb = Filter::EqualTo("y", FieldValue::String("b")); QuerySnapshot snapshot1 = ReadDocuments(collection.Where(Filter::And(filter_xa, filter_yb))); - EXPECT_EQ(std::vector({doc_ab}), QuerySnapshotToValues(snapshot1)); + EXPECT_EQ(std::vector({doc_ab}), + QuerySnapshotToValues(snapshot1)); QuerySnapshot snapshot2 = ReadDocuments(collection.Where(Filter::Or(filter_xa, filter_yb))); - EXPECT_EQ(std::vector({doc_aa, doc_ab, doc_bb}), QuerySnapshotToValues(snapshot2)); + EXPECT_EQ(std::vector({doc_aa, doc_ab, doc_bb}), + QuerySnapshotToValues(snapshot2)); } } // namespace diff --git a/firestore/src/android/filter_android.cc b/firestore/src/android/filter_android.cc index eed2540a27..06da8d1ae1 100644 --- a/firestore/src/android/filter_android.cc +++ b/firestore/src/android/filter_android.cc @@ -14,6 +14,8 @@ * limitations under the License. */ +#include + #include "firestore/src/android/filter_android.h" #include "firestore/src/android/converter_android.h" @@ -202,7 +204,7 @@ Filter FilterInternal::Where(const StaticMethod& method, bool operator==(const FilterInternal& lhs, const FilterInternal& rhs) { return jni::EqualityCompareJni(lhs, rhs); -} +} // namespace } // namespace firestore } // namespace firebase diff --git a/firestore/src/android/filter_android.h b/firestore/src/android/filter_android.h index d080cad213..3e0b3fa6b3 100644 --- a/firestore/src/android/filter_android.h +++ b/firestore/src/android/filter_android.h @@ -77,7 +77,6 @@ class FilterInternal final { const std::vector& values); static Filter Where(const jni::StaticMethod& method, const std::vector& filters); - }; bool operator==(const FilterInternal& lhs, const FilterInternal& rhs); diff --git a/firestore/src/main/filter_main.h b/firestore/src/main/filter_main.h index 392eb00fa3..2712d201be 100644 --- a/firestore/src/main/filter_main.h +++ b/firestore/src/main/filter_main.h @@ -25,8 +25,8 @@ #include "Firestore/core/src/api/query_core.h" #include "Firestore/core/src/core/composite_filter.h" -#include "Firestore/core/src/core/field_filter.h" #include "Firestore/core/src/core/filter.h" +#include "Firestore/core/src/model/field_path.h" #include "firestore/src/include/firebase/firestore/filter.h" #include "firestore/src/main/user_data_converter_main.h" @@ -52,16 +52,14 @@ class FilterInternal { const std::vector& values); static Filter NotIn(const FieldPath& field, const std::vector& values); + static Filter Or(const std::vector& filters); + static Filter And(const std::vector& filters); virtual core::Filter ToCoreFilter( const api::Query& query, const firebase::firestore::UserDataConverter& user_data_converter) const = 0; - static Filter Or(const std::vector& filters); - - static Filter And(const std::vector& filters); - virtual ~FilterInternal() = default; friend bool operator==(const FilterInternal& lhs, const FilterInternal& rhs); From a26cf80940db686e5bbeb8d881ccf8c6828b4f1b Mon Sep 17 00:00:00 2001 From: Tom Andersen Date: Thu, 22 Jun 2023 12:46:39 -0400 Subject: [PATCH 15/25] Pretty --- firestore/src/android/filter_android.cc | 4 ++-- firestore/src/android/query_android.cc | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/firestore/src/android/filter_android.cc b/firestore/src/android/filter_android.cc index 06da8d1ae1..6c96662687 100644 --- a/firestore/src/android/filter_android.cc +++ b/firestore/src/android/filter_android.cc @@ -89,7 +89,7 @@ StaticMethod kOr( "or", "([Lcom/google/firebase/firestore/Filter;)" "Lcom/google/firebase/firestore/Filter;"); -} +} // namespace void FilterInternal::Initialize(jni::Loader& loader) { loader.LoadClass( @@ -204,7 +204,7 @@ Filter FilterInternal::Where(const StaticMethod& method, bool operator==(const FilterInternal& lhs, const FilterInternal& rhs) { return jni::EqualityCompareJni(lhs, rhs); -} // namespace +} } // namespace firestore } // namespace firebase diff --git a/firestore/src/android/query_android.cc b/firestore/src/android/query_android.cc index 7ba01494ec..47e82b8aa9 100644 --- a/firestore/src/android/query_android.cc +++ b/firestore/src/android/query_android.cc @@ -165,7 +165,6 @@ Query QueryInternal::Where(const firebase::firestore::Filter& filter) const { Env env = GetEnv(); Local query = env.Call(obj_, kWhere, filter.internal_->ToJava()); return firestore_->NewQuery(env, query); - } Query QueryInternal::WhereEqualTo(const FieldPath& field, From 62fcf27b4ed48c95d701f0bf56486ab80057419a Mon Sep 17 00:00:00 2001 From: Tom Andersen Date: Thu, 22 Jun 2023 12:58:54 -0400 Subject: [PATCH 16/25] Pretty --- firestore/src/android/filter_android.cc | 57 ++++++++++++------------- firestore/src/android/filter_android.h | 14 +++--- firestore/src/android/query_android.cc | 9 ++-- 3 files changed, 38 insertions(+), 42 deletions(-) diff --git a/firestore/src/android/filter_android.cc b/firestore/src/android/filter_android.cc index 6c96662687..166131c3e3 100644 --- a/firestore/src/android/filter_android.cc +++ b/firestore/src/android/filter_android.cc @@ -19,9 +19,9 @@ #include "firestore/src/android/filter_android.h" #include "firestore/src/android/converter_android.h" -#include "firestore/src/android/firestore_android.h" #include "firestore/src/android/field_path_android.h" #include "firestore/src/android/field_value_android.h" +#include "firestore/src/android/firestore_android.h" #include "firestore/src/jni/array.h" #include "firestore/src/jni/array_list.h" @@ -37,8 +37,8 @@ using jni::Array; using jni::ArrayList; using jni::Env; using jni::Local; -using jni::StaticMethod; using jni::Object; +using jni::StaticMethod; constexpr char kClassName[] = PROGUARD_KEEP_CLASS "com/google/firebase/firestore/Filter"; @@ -74,80 +74,78 @@ StaticMethod kArrayContainsAny( "arrayContainsAny", "(Lcom/google/firebase/firestore/FieldPath;Ljava/util/List;)" "Lcom/google/firebase/firestore/Filter;"); -StaticMethod kIn("in", - "(Lcom/google/firebase/firestore/FieldPath;Ljava/util/List;)" - "Lcom/google/firebase/firestore/Filter;"); +StaticMethod kIn( + "in", + "(Lcom/google/firebase/firestore/FieldPath;Ljava/util/List;)" + "Lcom/google/firebase/firestore/Filter;"); StaticMethod kNotIn( "notIn", "(Lcom/google/firebase/firestore/FieldPath;Ljava/util/List;)" "Lcom/google/firebase/firestore/Filter;"); -StaticMethod kAnd( - "and", - "([Lcom/google/firebase/firestore/Filter;)" - "Lcom/google/firebase/firestore/Filter;"); -StaticMethod kOr( - "or", - "([Lcom/google/firebase/firestore/Filter;)" - "Lcom/google/firebase/firestore/Filter;"); +StaticMethod kAnd("and", + "([Lcom/google/firebase/firestore/Filter;)" + "Lcom/google/firebase/firestore/Filter;"); +StaticMethod kOr("or", + "([Lcom/google/firebase/firestore/Filter;)" + "Lcom/google/firebase/firestore/Filter;"); } // namespace void FilterInternal::Initialize(jni::Loader& loader) { - loader.LoadClass( - kClassName, kEqualTo, kNotEqualTo, kLessThan, kLessThanOrEqualTo, - kGreaterThan, kGreaterThanOrEqualTo, kArrayContains, kArrayContainsAny, - kIn, kNotIn, kAnd, kOr); + loader.LoadClass(kClassName, kEqualTo, kNotEqualTo, kLessThan, + kLessThanOrEqualTo, kGreaterThan, kGreaterThanOrEqualTo, + kArrayContains, kArrayContainsAny, kIn, kNotIn, kAnd, kOr); } FilterInternal::FilterInternal(jni::Object&& object, bool is_empty) : object_(object), is_empty_(is_empty) {} Filter FilterInternal::EqualTo(const FieldPath& field, - const FieldValue& value) { + const FieldValue& value) { return Where(field, kEqualTo, value); } Filter FilterInternal::NotEqualTo(const FieldPath& field, - const FieldValue& value) { + const FieldValue& value) { return Where(field, kNotEqualTo, value); } Filter FilterInternal::LessThan(const FieldPath& field, - const FieldValue& value) { + const FieldValue& value) { return Where(field, kLessThan, value); } Filter FilterInternal::LessThanOrEqualTo(const FieldPath& field, - const FieldValue& value) { + const FieldValue& value) { return Where(field, kLessThanOrEqualTo, value); } Filter FilterInternal::GreaterThan(const FieldPath& field, - const FieldValue& value) { + const FieldValue& value) { return Where(field, kGreaterThan, value); } Filter FilterInternal::GreaterThanOrEqualTo(const FieldPath& field, - const FieldValue& value) { + const FieldValue& value) { return Where(field, kGreaterThanOrEqualTo, value); } Filter FilterInternal::ArrayContains(const FieldPath& field, - const FieldValue& value) { + const FieldValue& value) { return Where(field, kArrayContains, value); } -Filter FilterInternal::ArrayContainsAny( - const FieldPath& field, const std::vector& values) { +Filter FilterInternal::ArrayContainsAny(const FieldPath& field, + const std::vector& values) { return Where(field, kArrayContainsAny, values); } Filter FilterInternal::In(const FieldPath& field, - const std::vector& values) { + const std::vector& values) { return Where(field, kIn, values); } Filter FilterInternal::NotIn(const FieldPath& field, - const std::vector& values) { + const std::vector& values) { return Where(field, kNotIn, values); } @@ -166,7 +164,8 @@ Filter FilterInternal::Where(const FieldPath& field, const FieldValue& value) { Env env = GetEnv(); Local java_field = FieldPathConverter::Create(env, field); - Object filter = env.Call(method, java_field, FieldValueInternal::ToJava(value)); + Object filter = + env.Call(method, java_field, FieldValueInternal::ToJava(value)); return Filter(new FilterInternal(std::move(filter), false)); } diff --git a/firestore/src/android/filter_android.h b/firestore/src/android/filter_android.h index 3e0b3fa6b3..565a115696 100644 --- a/firestore/src/android/filter_android.h +++ b/firestore/src/android/filter_android.h @@ -57,9 +57,7 @@ class FilterInternal final { friend class Filter; friend class FirestoreInternal; - FilterInternal* clone() { - return new FilterInternal(*this); - } + FilterInternal* clone() { return new FilterInternal(*this); } bool IsEmpty() const { return is_empty_; } @@ -70,13 +68,13 @@ class FilterInternal final { // A generalized function for all WhereFoo calls. static Filter Where(const FieldPath& field, - const jni::StaticMethod& method, - const FieldValue& value); + const jni::StaticMethod& method, + const FieldValue& value); static Filter Where(const FieldPath& field, - const jni::StaticMethod& method, - const std::vector& values); + const jni::StaticMethod& method, + const std::vector& values); static Filter Where(const jni::StaticMethod& method, - const std::vector& filters); + const std::vector& filters); }; bool operator==(const FilterInternal& lhs, const FilterInternal& rhs); diff --git a/firestore/src/android/query_android.cc b/firestore/src/android/query_android.cc index 47e82b8aa9..99082b78aa 100644 --- a/firestore/src/android/query_android.cc +++ b/firestore/src/android/query_android.cc @@ -21,9 +21,9 @@ #include "firestore/src/android/direction_android.h" #include "firestore/src/android/document_snapshot_android.h" #include "firestore/src/android/event_listener_android.h" -#include "firestore/src/android/filter_android.h" #include "firestore/src/android/field_path_android.h" #include "firestore/src/android/field_value_android.h" +#include "firestore/src/android/filter_android.h" #include "firestore/src/android/firestore_android.h" #include "firestore/src/android/lambda_event_listener.h" #include "firestore/src/android/listener_registration_android.h" @@ -54,10 +54,9 @@ constexpr char kClassName[] = PROGUARD_KEEP_CLASS "com/google/firebase/firestore/Query"; Method kCount("count", "()Lcom/google/firebase/firestore/AggregateQuery;"); -Method kWhere( - "where", - "(Lcom/google/firebase/firestore/Filter;)" - "Lcom/google/firebase/firestore/Query;"); +Method kWhere("where", + "(Lcom/google/firebase/firestore/Filter;)" + "Lcom/google/firebase/firestore/Query;"); Method kEqualTo( "whereEqualTo", "(Lcom/google/firebase/firestore/FieldPath;Ljava/lang/Object;)" From bc3cba0ed7330bd59839dba8acff381ff02267e6 Mon Sep 17 00:00:00 2001 From: Tom Andersen Date: Thu, 22 Jun 2023 15:52:46 -0400 Subject: [PATCH 17/25] Remove const --- firestore/src/android/filter_android.cc | 6 +++--- firestore/src/android/filter_android.h | 6 +++--- firestore/src/common/filter.cc | 4 ++-- firestore/src/include/firebase/firestore/filter.h | 8 ++++---- firestore/src/main/filter_main.cc | 6 +++--- firestore/src/main/filter_main.h | 6 +++--- 6 files changed, 18 insertions(+), 18 deletions(-) diff --git a/firestore/src/android/filter_android.cc b/firestore/src/android/filter_android.cc index 166131c3e3..e81cd3f926 100644 --- a/firestore/src/android/filter_android.cc +++ b/firestore/src/android/filter_android.cc @@ -149,11 +149,11 @@ Filter FilterInternal::NotIn(const FieldPath& field, return Where(field, kNotIn, values); } -Filter FilterInternal::And(const std::vector& filters) { +Filter FilterInternal::And(const std::vector& filters) { return Where(kAnd, filters); } -Filter FilterInternal::Or(const std::vector& filters) { +Filter FilterInternal::Or(const std::vector& filters) { return Where(kOr, filters); } @@ -185,7 +185,7 @@ Filter FilterInternal::Where(const FieldPath& field, } Filter FilterInternal::Where(const StaticMethod& method, - const std::vector& filters) { + const std::vector& filters) { Env env = GetEnv(); size_t size = filters.size(); Local> java_filters = env.NewArray(size, Object::GetClass()); diff --git a/firestore/src/android/filter_android.h b/firestore/src/android/filter_android.h index 565a115696..c69984c537 100644 --- a/firestore/src/android/filter_android.h +++ b/firestore/src/android/filter_android.h @@ -48,8 +48,8 @@ class FilterInternal final { const std::vector& values); static Filter NotIn(const FieldPath& field, const std::vector& values); - static Filter Or(const std::vector& filters); - static Filter And(const std::vector& filters); + static Filter Or(const std::vector& filters); + static Filter And(const std::vector& filters); const jni::Global& ToJava() const { return object_; } @@ -74,7 +74,7 @@ class FilterInternal final { const jni::StaticMethod& method, const std::vector& values); static Filter Where(const jni::StaticMethod& method, - const std::vector& filters); + const std::vector& filters); }; bool operator==(const FilterInternal& lhs, const FilterInternal& rhs); diff --git a/firestore/src/common/filter.cc b/firestore/src/common/filter.cc index 129d9da2a8..77ae208beb 100644 --- a/firestore/src/common/filter.cc +++ b/firestore/src/common/filter.cc @@ -156,11 +156,11 @@ Filter Filter::NotIn(const FieldPath& field, return FilterInternal::NotIn(field, values); } -Filter Filter::And(const std::vector& filters) { +Filter Filter::And(const std::vector& filters) { return FilterInternal::And(filters); } -Filter Filter::Or(const std::vector& filters) { +Filter Filter::Or(const std::vector& filters) { return FilterInternal::Or(filters); } diff --git a/firestore/src/include/firebase/firestore/filter.h b/firestore/src/include/firebase/firestore/filter.h index be8417b00d..6dfba0e9d6 100644 --- a/firestore/src/include/firebase/firestore/filter.h +++ b/firestore/src/include/firebase/firestore/filter.h @@ -284,7 +284,7 @@ class Filter { */ template static Filter And(const Filters&... filters) { - return And(std::vector({filters...})); + return And(std::vector({filters...})); } /** @@ -307,7 +307,7 @@ class Filter { */ template static Filter Or(const Filters&... filters) { - return Or(std::vector({filters...})); + return Or(std::vector({filters...})); } /** @@ -355,8 +355,8 @@ class Filter { friend bool operator==(const Filter& lhs, const Filter& rhs); friend struct ConverterImpl; - static Filter And(const std::vector& filters); - static Filter Or(const std::vector& filters); + static Filter And(const std::vector& filters); + static Filter Or(const std::vector& filters); bool IsEmpty() const; diff --git a/firestore/src/main/filter_main.cc b/firestore/src/main/filter_main.cc index e11cd03cf5..236ecd0f74 100644 --- a/firestore/src/main/filter_main.cc +++ b/firestore/src/main/filter_main.cc @@ -74,11 +74,11 @@ Filter FilterInternal::NotIn(const FieldPath& field, return UnaryFilter(field, FieldFilterOperator::NotIn, values); } -Filter FilterInternal::Or(const std::vector& filters) { +Filter FilterInternal::Or(const std::vector& filters) { return CompositeFilter(CompositeOperator::Or, filters); } -Filter FilterInternal::And(const std::vector& filters) { +Filter FilterInternal::And(const std::vector& filters) { return CompositeFilter(CompositeOperator::And, filters); } @@ -99,7 +99,7 @@ Filter FilterInternal::UnaryFilter(const FieldPath& field_path, Filter FilterInternal::CompositeFilter( core::CompositeFilter::Operator op, - const std::vector& filters) { + const std::vector& filters) { std::vector nonEmptyFilters; for (const Filter& filter : filters) { FilterInternal* filterInternal = GetInternal(&filter); diff --git a/firestore/src/main/filter_main.h b/firestore/src/main/filter_main.h index 2712d201be..fbe1f4b728 100644 --- a/firestore/src/main/filter_main.h +++ b/firestore/src/main/filter_main.h @@ -52,8 +52,8 @@ class FilterInternal { const std::vector& values); static Filter NotIn(const FieldPath& field, const std::vector& values); - static Filter Or(const std::vector& filters); - static Filter And(const std::vector& filters); + static Filter Or(const std::vector& filters); + static Filter And(const std::vector& filters); virtual core::Filter ToCoreFilter( const api::Query& query, @@ -90,7 +90,7 @@ class FilterInternal { const std::vector& values); static Filter CompositeFilter(CompositeOperator op, - const std::vector& filters); + const std::vector& filters); }; bool operator==(const FilterInternal& lhs, const FilterInternal& rhs); From fe5b6e820c33cf8c5304ae44be2619a1dbd7fdf5 Mon Sep 17 00:00:00 2001 From: Tom Andersen Date: Thu, 22 Jun 2023 17:01:46 -0400 Subject: [PATCH 18/25] Pretty --- firestore/src/main/filter_main.cc | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/firestore/src/main/filter_main.cc b/firestore/src/main/filter_main.cc index 236ecd0f74..2d57f4e9a5 100644 --- a/firestore/src/main/filter_main.cc +++ b/firestore/src/main/filter_main.cc @@ -97,9 +97,8 @@ Filter FilterInternal::UnaryFilter(const FieldPath& field_path, return MakePublic(UnaryFilterInternal(field_path, op, values)); } -Filter FilterInternal::CompositeFilter( - core::CompositeFilter::Operator op, - const std::vector& filters) { +Filter FilterInternal::CompositeFilter(core::CompositeFilter::Operator op, + const std::vector& filters) { std::vector nonEmptyFilters; for (const Filter& filter : filters) { FilterInternal* filterInternal = GetInternal(&filter); From a232d5062c7acff2dfb7d90536bb4611d15f75ad Mon Sep 17 00:00:00 2001 From: Tom Andersen Date: Wed, 28 Jun 2023 16:33:34 -0400 Subject: [PATCH 19/25] Fixes from code review --- .../src/filter_test.cc | 106 +++++++++++++++--- firestore/src/android/query_android.cc | 2 +- firestore/src/android/query_android.h | 6 + firestore/src/android/wrapper.cc | 2 +- firestore/src/android/wrapper.h | 2 +- .../src/include/firebase/firestore/filter.h | 67 ++++++++--- firestore/src/main/composite_filter_main.cc | 23 ++-- firestore/src/main/composite_filter_main.h | 2 - firestore/src/main/filter_main.cc | 2 +- firestore/src/main/unary_filter_main.h | 2 - 10 files changed, 162 insertions(+), 52 deletions(-) diff --git a/firestore/integration_test_internal/src/filter_test.cc b/firestore/integration_test_internal/src/filter_test.cc index d4a7330ab0..e3806943d0 100644 --- a/firestore/integration_test_internal/src/filter_test.cc +++ b/firestore/integration_test_internal/src/filter_test.cc @@ -441,29 +441,107 @@ TEST_F(FilterTest, CompositeComparison) { } TEST_F(FilterTest, QueryWhereComposite) { - MapFieldValue doc_aa = {{"x", FieldValue::String("a")}, - {"y", FieldValue::String("a")}}; - MapFieldValue doc_ab = {{"x", FieldValue::String("a")}, - {"y", FieldValue::String("b")}}; - MapFieldValue doc_ba = {{"x", FieldValue::String("b")}, - {"y", FieldValue::String("a")}}; - MapFieldValue doc_bb = {{"x", FieldValue::String("b")}, - {"y", FieldValue::String("b")}}; - CollectionReference collection = Collection( - {{"aa", doc_aa}, {"ab", doc_ab}, {"ba", doc_ba}, {"bb", doc_bb}}); + MapFieldValue doc_aaa = {{"x", FieldValue::String("a")}, + {"y", FieldValue::String("a")}, + {"z", FieldValue::String("a")}}; + MapFieldValue doc_aab = {{"x", FieldValue::String("a")}, + {"y", FieldValue::String("a")}, + {"z", FieldValue::String("b")}}; + MapFieldValue doc_aba = {{"x", FieldValue::String("a")}, + {"y", FieldValue::String("b")}, + {"z", FieldValue::String("a")}}; + MapFieldValue doc_abb = {{"x", FieldValue::String("a")}, + {"y", FieldValue::String("b")}, + {"z", FieldValue::String("b")}}; + MapFieldValue doc_baa = {{"x", FieldValue::String("b")}, + {"y", FieldValue::String("a")}, + {"z", FieldValue::String("a")}}; + MapFieldValue doc_bab = {{"x", FieldValue::String("b")}, + {"y", FieldValue::String("a")}, + {"z", FieldValue::String("b")}}; + MapFieldValue doc_bba = {{"x", FieldValue::String("b")}, + {"y", FieldValue::String("b")}, + {"z", FieldValue::String("a")}}; + MapFieldValue doc_bbb = {{"x", FieldValue::String("b")}, + {"y", FieldValue::String("b")}, + {"z", FieldValue::String("b")}}; + CollectionReference collection = Collection({{"aaa", doc_aaa}, + {"aab", doc_aab}, + {"aba", doc_aba}, + {"abb", doc_abb}, + {"baa", doc_baa}, + {"bab", doc_bab}, + {"bba", doc_bba}, + {"bbb", doc_bbb}}); Filter filter_xa = Filter::EqualTo("x", FieldValue::String("a")); + Filter filter_ya = Filter::EqualTo("y", FieldValue::String("a")); Filter filter_yb = Filter::EqualTo("y", FieldValue::String("b")); + Filter filter_za = Filter::EqualTo("z", FieldValue::String("a")); + // And(x=a) QuerySnapshot snapshot1 = - ReadDocuments(collection.Where(Filter::And(filter_xa, filter_yb))); - EXPECT_EQ(std::vector({doc_ab}), + ReadDocuments(collection.Where(Filter::And(filter_xa))); + EXPECT_EQ(std::vector({doc_aaa, doc_aab, doc_aba, doc_abb}), QuerySnapshotToValues(snapshot1)); + // And(x=a, y=b) QuerySnapshot snapshot2 = - ReadDocuments(collection.Where(Filter::Or(filter_xa, filter_yb))); - EXPECT_EQ(std::vector({doc_aa, doc_ab, doc_bb}), + ReadDocuments(collection.Where(Filter::And(filter_xa, filter_yb))); + EXPECT_EQ(std::vector({doc_aba, doc_abb}), QuerySnapshotToValues(snapshot2)); + + // And(Or(And(x=a)),Or(And(Or())) + QuerySnapshot snapshot3 = ReadDocuments( + collection.Where(Filter::And(Filter::Or(Filter::And(filter_xa)), + Filter::Or(Filter::And(Filter::Or()))))); + EXPECT_EQ(std::vector({doc_aaa, doc_aab, doc_aba, doc_abb}), + QuerySnapshotToValues(snapshot3)); + + // Or(x=a) + QuerySnapshot snapshot4 = + ReadDocuments(collection.Where(Filter::Or(filter_xa))); + EXPECT_EQ(std::vector({doc_aaa, doc_aab, doc_aba, doc_abb}), + QuerySnapshotToValues(snapshot4)); + + // Or(x=a, y=b) + QuerySnapshot snapshot5 = + ReadDocuments(collection.Where(Filter::Or(filter_xa, filter_yb))); + EXPECT_EQ(std::vector( + {doc_aaa, doc_aab, doc_aba, doc_abb, doc_bba, doc_bbb}), + QuerySnapshotToValues(snapshot5)); + + // Or(And(Or(x=a)),And(Or(And())) + QuerySnapshot snapshot6 = ReadDocuments( + collection.Where(Filter::Or(Filter::And(Filter::Or(filter_xa)), + Filter::And(Filter::Or(Filter::And()))))); + EXPECT_EQ(std::vector({doc_aaa, doc_aab, doc_aba, doc_abb}), + QuerySnapshotToValues(snapshot6)); + + // And(x=b, Or(y=a, And(y=b, z=a))) + QuerySnapshot snapshot7 = ReadDocuments(collection.Where(Filter::And( + filter_xa, Filter::Or(filter_ya, Filter::And(filter_yb, filter_za))))); + EXPECT_EQ(std::vector({doc_aaa, doc_aab, doc_aba}), + QuerySnapshotToValues(snapshot7)); +} + +TEST_F(FilterTest, QueryEmptyWhereComposite) { + MapFieldValue doc = {{"foo", FieldValue::String("bar")}}; + CollectionReference collection = Collection({{"x", doc}}); + + QuerySnapshot s1 = ReadDocuments(collection.Where(Filter::And())); + EXPECT_EQ(std::vector({doc}), QuerySnapshotToValues(s1)); + + QuerySnapshot s2 = + ReadDocuments(collection.Where(Filter::And(Filter::Or(), Filter::Or()))); + EXPECT_EQ(std::vector({doc}), QuerySnapshotToValues(s2)); + + QuerySnapshot s3 = ReadDocuments(collection.Where(Filter::Or())); + EXPECT_EQ(std::vector({doc}), QuerySnapshotToValues(s3)); + + QuerySnapshot s4 = + ReadDocuments(collection.Where(Filter::Or(Filter::And(), Filter::And()))); + EXPECT_EQ(std::vector({doc}), QuerySnapshotToValues(s4)); } } // namespace diff --git a/firestore/src/android/query_android.cc b/firestore/src/android/query_android.cc index 99082b78aa..eb22027f50 100644 --- a/firestore/src/android/query_android.cc +++ b/firestore/src/android/query_android.cc @@ -146,7 +146,7 @@ void QueryInternal::Initialize(jni::Loader& loader) { kGreaterThan, kGreaterThanOrEqualTo, kArrayContains, kArrayContainsAny, kIn, kNotIn, kOrderBy, kLimit, kLimitToLast, kStartAtSnapshot, kStartAt, kStartAfterSnapshot, kStartAfter, kEndBeforeSnapshot, kEndBefore, - kEndAtSnapshot, kEndAt, kGet, kAddSnapshotListener, kHashCode); + kEndAtSnapshot, kEndAt, kGet, kAddSnapshotListener, kHashCode, kWhere); } Firestore* QueryInternal::firestore() { diff --git a/firestore/src/android/query_android.h b/firestore/src/android/query_android.h index b4429f946a..a325e561e4 100644 --- a/firestore/src/android/query_android.h +++ b/firestore/src/android/query_android.h @@ -71,6 +71,12 @@ class QueryInternal : public Wrapper { */ virtual AggregateQuery Count() const; + /** + * @brief Creates and returns a new Query with the additional filter. + * + * @param filter The new filter to apply to the existing query. + * @return The created Query. + */ Query Where(const Filter& filter) const; /** diff --git a/firestore/src/android/wrapper.cc b/firestore/src/android/wrapper.cc index 6fd031ac8a..c4304abe29 100644 --- a/firestore/src/android/wrapper.cc +++ b/firestore/src/android/wrapper.cc @@ -56,7 +56,7 @@ Wrapper::Wrapper(Wrapper* rhs) : Wrapper() { Wrapper::~Wrapper() = default; -jni::Env Wrapper::GetEnv() { return FirestoreInternal::GetEnv(); } +jni::Env Wrapper::GetEnv() const { return firestore_->GetEnv(); } Object Wrapper::ToJava(const FieldValue& value) { return FieldValueInternal::ToJava(value); diff --git a/firestore/src/android/wrapper.h b/firestore/src/android/wrapper.h index fdbf79bf04..b1da5fce65 100644 --- a/firestore/src/android/wrapper.h +++ b/firestore/src/android/wrapper.h @@ -56,7 +56,7 @@ class Wrapper { // Similar to a copy constructor, but can handle the case where `rhs` is null. explicit Wrapper(Wrapper* rhs); - static jni::Env GetEnv(); + jni::Env GetEnv() const; FirestoreInternal* firestore_ = nullptr; // not owning jni::Global obj_; diff --git a/firestore/src/include/firebase/firestore/filter.h b/firestore/src/include/firebase/firestore/filter.h index 6dfba0e9d6..ff1471acc3 100644 --- a/firestore/src/include/firebase/firestore/filter.h +++ b/firestore/src/include/firebase/firestore/filter.h @@ -264,52 +264,74 @@ class Filter { static Filter NotIn(const FieldPath& field, const std::vector& values); - /** - * @brief Conjunction of a single filter will simply return original filter. - * - * @param[in] filter Single filter for conjunction. - * - * @return Same as filter passed in as parameter. - */ - static Filter And(const Filter filter) { return filter; } - /** * @brief Creates a new filter that is a conjunction of the given filters. A * conjunction filter includes a document if it satisfies all of the given * filters. * + * If no filter is given, the composite filter is a no-op, and if only one + * filter is given, the composite filter has the same behavior as the + * underlying filter. + * * @param[in] filters The filters to perform a conjunction for. * * @return The newly created filter. */ template static Filter And(const Filters&... filters) { - return And(std::vector({filters...})); + return AndInternal(filters...); } /** - * @brief Disjunction of a single filter will simply return original filter. + * @brief Creates a new filter that is a conjunction of the given filters. A + * conjunction filter includes a document if it satisfies all of the given + * filters. * - * @param[in] filter Single filter for disjunction. + * If no filter is given, the composite filter is a no-op, and if only one + * filter is given, the composite filter has the same behavior as the + * underlying filter. * - * @return Same as filter passed in as parameter. + * @param[in] filters The list that contains filters to perform a conjunction + * for. + * + * @return The newly created filter. */ - static Filter Or(const Filter filter) { return filter; } + static Filter And(const std::vector& filters); /** * @brief Creates a new filter that is a disjunction of the given filters. A * disjunction filter includes a document if it satisfies any of the * given filters. * + * If no filter is given, the composite filter is a no-op, and if only one + * filter is given, the composite filter has the same behavior as the + * underlying filter. + * * @param[in] filters The filters to perform a disjunction for. * * @return The newly created filter. */ template static Filter Or(const Filters&... filters) { - return Or(std::vector({filters...})); + return OrInternal(filters...); } + /** + * @brief Creates a new filter that is a disjunction of the given filters. A + * disjunction filter includes a document if it satisfies any of the + * given filters. + * + * If no filter is given, the composite filter is a no-op, and if only one + * filter is given, the composite filter has the same behavior as the + * underlying filter. + * + * @param[in] filters The list that contains filters to perform a disjunction + * for. + * + * @return The newly created filter. + */ + static Filter Or(const std::vector& filters); + /** * @brief Copy constructor. * @@ -355,8 +377,19 @@ class Filter { friend bool operator==(const Filter& lhs, const Filter& rhs); friend struct ConverterImpl; - static Filter And(const std::vector& filters); - static Filter Or(const std::vector& filters); + static inline Filter AndInternal(const Filter& filter) { return filter; } + + template + static inline Filter AndInternal(const Filters&... filters) { + return And(std::vector({filters...})); + } + + static inline Filter OrInternal(const Filter& filter) { return filter; } + + template + static inline Filter OrInternal(const Filters&... filters) { + return Or(std::vector({filters...})); + } bool IsEmpty() const; diff --git a/firestore/src/main/composite_filter_main.cc b/firestore/src/main/composite_filter_main.cc index 1069600cc4..82666c528b 100644 --- a/firestore/src/main/composite_filter_main.cc +++ b/firestore/src/main/composite_filter_main.cc @@ -23,6 +23,7 @@ #include "Firestore/core/src/core/composite_filter.h" #include "absl/algorithm/container.h" +#include "firestore/src/common/util.h" #include "firestore/src/main/composite_filter_main.h" #include "firestore/src/main/converter_main.h" @@ -46,7 +47,7 @@ bool CompositeFilterInternal::IsEmpty() const { return filters_.empty(); } core::Filter CompositeFilterInternal::ToCoreFilter( const api::Query& query, const firebase::firestore::UserDataConverter& user_data_converter) const { - std::vector core_filters; + std::vector core_filters{}; for (auto& filter : filters_) { core_filters.push_back(filter->ToCoreFilter(query, user_data_converter)); } @@ -55,18 +56,14 @@ core::Filter CompositeFilterInternal::ToCoreFilter( bool operator==(const CompositeFilterInternal& lhs, const CompositeFilterInternal& rhs) { - if (lhs.op_ != rhs.op_) return false; - const std::vector>& lhs_filters = - lhs.filters_; - const std::vector>& rhs_filters = - rhs.filters_; - size_t size = lhs_filters.size(); - if (size != rhs_filters.size()) return false; - for (int i = 0; i < size; i++) { - if (lhs_filters[i] != rhs_filters[i] && *lhs_filters[i] != *rhs_filters[i]) - return false; - } - return true; + return lhs.op_ == rhs.op_ && lhs.filters_.size() == rhs.filters_.size() && + std::equal(lhs.filters_.begin(), lhs.filters_.end(), + rhs.filters_.begin(), rhs.filters_.end(), + [](const std::shared_ptr& lhs_filter, + const std::shared_ptr& rhs_filter) { + return EqualityCompare(lhs_filter.get(), + rhs_filter.get()); + }); } } // namespace firestore diff --git a/firestore/src/main/composite_filter_main.h b/firestore/src/main/composite_filter_main.h index c6b7876b8f..4eb1ee5af8 100644 --- a/firestore/src/main/composite_filter_main.h +++ b/firestore/src/main/composite_filter_main.h @@ -35,8 +35,6 @@ class CompositeFilterInternal : public FilterInternal { CompositeFilterInternal(core::CompositeFilter::Operator op, std::vector& filters); - ~CompositeFilterInternal() override = default; - core::Filter ToCoreFilter(const api::Query& query, const firebase::firestore::UserDataConverter& user_data_converter) const override; diff --git a/firestore/src/main/filter_main.cc b/firestore/src/main/filter_main.cc index 2d57f4e9a5..bbc3afbcb1 100644 --- a/firestore/src/main/filter_main.cc +++ b/firestore/src/main/filter_main.cc @@ -99,7 +99,7 @@ Filter FilterInternal::UnaryFilter(const FieldPath& field_path, Filter FilterInternal::CompositeFilter(core::CompositeFilter::Operator op, const std::vector& filters) { - std::vector nonEmptyFilters; + std::vector nonEmptyFilters{}; for (const Filter& filter : filters) { FilterInternal* filterInternal = GetInternal(&filter); if (!filterInternal->IsEmpty()) { diff --git a/firestore/src/main/unary_filter_main.h b/firestore/src/main/unary_filter_main.h index 30674eb2d2..e23d0c9481 100644 --- a/firestore/src/main/unary_filter_main.h +++ b/firestore/src/main/unary_filter_main.h @@ -38,8 +38,6 @@ class UnaryFilterInternal final : public FilterInternal { core::FieldFilter::Operator op, const std::vector& values); - ~UnaryFilterInternal() override = default; - core::Filter ToCoreFilter(const api::Query& query, const firebase::firestore::UserDataConverter& user_data_converter) const override; From d6961a7d23f6db21a88eeedc265e1a226ef296d8 Mon Sep 17 00:00:00 2001 From: Tom Andersen Date: Thu, 29 Jun 2023 12:36:18 -0400 Subject: [PATCH 20/25] Release notes --- release_build_files/readme.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/release_build_files/readme.md b/release_build_files/readme.md index cc162d6479..4054f92f1f 100644 --- a/release_build_files/readme.md +++ b/release_build_files/readme.md @@ -644,6 +644,8 @@ code. time zone name in the current system language contains an accented character or apostrophe. This adds a requirement for applications using Remote Config on Windows desktop to link the "icu.dll" system library. + - Firestore: Add support for disjunctions in queries (OR queries) + ([#1335](https://github.com/firebase/firebase-cpp-sdk/pull/1335)). ### 11.1.0 - Changes From 6f3fc73fad559be814fe295e3090373f5d5c2738 Mon Sep 17 00:00:00 2001 From: Tom Andersen Date: Thu, 29 Jun 2023 12:40:02 -0400 Subject: [PATCH 21/25] Release notes --- release_build_files/readme.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/release_build_files/readme.md b/release_build_files/readme.md index 4054f92f1f..03fe3f367e 100644 --- a/release_build_files/readme.md +++ b/release_build_files/readme.md @@ -631,6 +631,8 @@ code. - Changes - Auth (Android): Fixed an issue where VerifyPhoneNumber's internal builder failed to create PhoneAuthOptions with certain compiler settings. + - Firestore: Add support for disjunctions in queries (OR queries) + ([#1335](https://github.com/firebase/firebase-cpp-sdk/pull/1335)). ### 11.2.0 - Changes @@ -644,8 +646,6 @@ code. time zone name in the current system language contains an accented character or apostrophe. This adds a requirement for applications using Remote Config on Windows desktop to link the "icu.dll" system library. - - Firestore: Add support for disjunctions in queries (OR queries) - ([#1335](https://github.com/firebase/firebase-cpp-sdk/pull/1335)). ### 11.1.0 - Changes From 156ea40ff7d12c24cfc3574eceddb88d65a19a64 Mon Sep 17 00:00:00 2001 From: Tom Andersen Date: Thu, 21 Sep 2023 10:13:49 -0400 Subject: [PATCH 22/25] Fix Android OR Query --- firestore/src/android/filter_android.cc | 48 ++++++++++++++-------- firestore/src/android/filter_android.h | 6 +-- firestore/src/android/firestore_android.cc | 2 + 3 files changed, 35 insertions(+), 21 deletions(-) diff --git a/firestore/src/android/filter_android.cc b/firestore/src/android/filter_android.cc index e81cd3f926..d6bcd422b2 100644 --- a/firestore/src/android/filter_android.cc +++ b/firestore/src/android/filter_android.cc @@ -40,6 +40,7 @@ using jni::Local; using jni::Object; using jni::StaticMethod; +jclass filter_class = nullptr; constexpr char kClassName[] = PROGUARD_KEEP_CLASS "com/google/firebase/firestore/Filter"; StaticMethod kEqualTo( @@ -75,11 +76,11 @@ StaticMethod kArrayContainsAny( "(Lcom/google/firebase/firestore/FieldPath;Ljava/util/List;)" "Lcom/google/firebase/firestore/Filter;"); StaticMethod kIn( - "in", + "inArray", "(Lcom/google/firebase/firestore/FieldPath;Ljava/util/List;)" "Lcom/google/firebase/firestore/Filter;"); StaticMethod kNotIn( - "notIn", + "notInArray", "(Lcom/google/firebase/firestore/FieldPath;Ljava/util/List;)" "Lcom/google/firebase/firestore/Filter;"); StaticMethod kAnd("and", @@ -91,13 +92,17 @@ StaticMethod kOr("or", } // namespace void FilterInternal::Initialize(jni::Loader& loader) { + filter_class = loader.LoadClass(kClassName); loader.LoadClass(kClassName, kEqualTo, kNotEqualTo, kLessThan, kLessThanOrEqualTo, kGreaterThan, kGreaterThanOrEqualTo, kArrayContains, kArrayContainsAny, kIn, kNotIn, kAnd, kOr); } -FilterInternal::FilterInternal(jni::Object&& object, bool is_empty) - : object_(object), is_empty_(is_empty) {} +FilterInternal::FilterInternal(const jni::Object& obj, bool is_empty) + : is_empty_(is_empty) { + Env env = GetEnv(); + obj_.reset(env, obj); +} Filter FilterInternal::EqualTo(const FieldPath& field, const FieldValue& value) { @@ -164,9 +169,9 @@ Filter FilterInternal::Where(const FieldPath& field, const FieldValue& value) { Env env = GetEnv(); Local java_field = FieldPathConverter::Create(env, field); - Object filter = + Local filter = env.Call(method, java_field, FieldValueInternal::ToJava(value)); - return Filter(new FilterInternal(std::move(filter), false)); + return Filter(new FilterInternal(filter, false)); } Filter FilterInternal::Where(const FieldPath& field, @@ -180,25 +185,32 @@ Filter FilterInternal::Where(const FieldPath& field, } Local java_field = FieldPathConverter::Create(env, field); - Object filter = env.Call(method, java_field, java_values); - return Filter(new FilterInternal(std::move(filter), false)); + Local filter = env.Call(method, java_field, java_values); + return Filter(new FilterInternal(filter, false)); } Filter FilterInternal::Where(const StaticMethod& method, const std::vector& filters) { Env env = GetEnv(); - size_t size = filters.size(); - Local> java_filters = env.NewArray(size, Object::GetClass()); - bool is_empty = true; - for (int i = 0; i < size; ++i) { - FilterInternal* internal_filter = filters[i].internal_; - if (!internal_filter->IsEmpty()) { - is_empty = false; + std::vector non_empty_indexes; + size_t filters_size = filters.size(); + for (int i = 0; i < filters_size; ++i) { + if (!filters[i].internal_->IsEmpty()) { + non_empty_indexes.push_back(i); } - java_filters.Set(env, i, internal_filter->object_); } - Object filter = env.Call(method, java_filters); - return Filter(new FilterInternal(std::move(filter), is_empty)); + size_t non_empty_size = non_empty_indexes.size(); + Local> java_filters = env.NewArray(non_empty_size, filter_class); + for (int i = 0; i < non_empty_size; ++i) { + java_filters.Set(env, i, filters[non_empty_indexes[i]].internal_->ToJava()); + } + Local filter = env.Call(method, java_filters); + return Filter(new FilterInternal(filter, non_empty_size == 0)); +} + +Local FilterInternal::ToJava() const { + Env env = GetEnv(); + return obj_.get(env); } bool operator==(const FilterInternal& lhs, const FilterInternal& rhs) { diff --git a/firestore/src/android/filter_android.h b/firestore/src/android/filter_android.h index c69984c537..c180b1650b 100644 --- a/firestore/src/android/filter_android.h +++ b/firestore/src/android/filter_android.h @@ -31,7 +31,7 @@ class FilterInternal final { public: static void Initialize(jni::Loader& loader); - FilterInternal(jni::Object&& object, bool is_empty); + FilterInternal(const jni::Object& object, bool is_empty); static Filter ArrayContains(const FieldPath& field, const FieldValue& value); static Filter ArrayContainsAny(const FieldPath& field, @@ -51,7 +51,7 @@ class FilterInternal final { static Filter Or(const std::vector& filters); static Filter And(const std::vector& filters); - const jni::Global& ToJava() const { return object_; } + jni::Local ToJava() const; private: friend class Filter; @@ -63,7 +63,7 @@ class FilterInternal final { static jni::Env GetEnv(); - jni::Global object_; + jni::ArenaRef obj_; const bool is_empty_; // A generalized function for all WhereFoo calls. diff --git a/firestore/src/android/firestore_android.cc b/firestore/src/android/firestore_android.cc index be94023a9c..67937725d5 100644 --- a/firestore/src/android/firestore_android.cc +++ b/firestore/src/android/firestore_android.cc @@ -37,6 +37,7 @@ #include "firestore/src/android/exception_android.h" #include "firestore/src/android/field_path_android.h" #include "firestore/src/android/field_value_android.h" +#include "firestore/src/android/filter_android.h" #include "firestore/src/android/geo_point_android.h" #include "firestore/src/android/jni_runnable_android.h" #include "firestore/src/android/lambda_event_listener.h" @@ -339,6 +340,7 @@ bool FirestoreInternal::Initialize(App* app) { ExceptionInternal::Initialize(loader); FieldPathConverter::Initialize(loader); FieldValueInternal::Initialize(loader); + FilterInternal::Initialize(loader); GeoPointInternal::Initialize(loader); JniRunnableBase::Initialize(loader); ListenerRegistrationInternal::Initialize(loader); From ab93d434e17dbe6f7a1f59dd3f11cc1244e6c6e9 Mon Sep 17 00:00:00 2001 From: Tom Andersen Date: Thu, 21 Sep 2023 10:19:36 -0400 Subject: [PATCH 23/25] Release notes. --- release_build_files/readme.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/release_build_files/readme.md b/release_build_files/readme.md index cbb32a536e..8c6b0559f3 100644 --- a/release_build_files/readme.md +++ b/release_build_files/readme.md @@ -637,6 +637,8 @@ code. - Auth: Add Firebase Auth Emulator support. Set the environment variable USE_AUTH_EMULATOR=yes (and optionally AUTH_EMULATOR_PORT, default 9099) to connect to the local Firebase Auth Emulator. + - Firestore: Add support for disjunctions in queries (OR queries) + ([#1453](https://github.com/firebase/firebase-cpp-sdk/pull/1453)). ### 11.4.0 - Changes @@ -645,8 +647,6 @@ code. - General (iOS): 32-bit iOS builds (i386 and armv7) are no longer supported. - General: Add FirebaseApp.GetApps(), to return the list of `firebase::App` instances. - GMA (Android): Fixed a crash when initializing GMA without a Firebase App. - - Firestore: Add support for disjunctions in queries (OR queries) - ([#1335](https://github.com/firebase/firebase-cpp-sdk/pull/1335)). ### 11.3.0 - Changes From bda2909cfc395f6c2fec5694e4f5e1dbb19a8add Mon Sep 17 00:00:00 2001 From: Tom Andersen Date: Thu, 21 Sep 2023 10:27:42 -0400 Subject: [PATCH 24/25] Fix release notes. --- release_build_files/readme.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/release_build_files/readme.md b/release_build_files/readme.md index 508138368b..2481549478 100644 --- a/release_build_files/readme.md +++ b/release_build_files/readme.md @@ -643,6 +643,8 @@ code. - Auth: Add Firebase Auth Emulator support. Set the environment variable USE_AUTH_EMULATOR=yes (and optionally AUTH_EMULATOR_PORT, default 9099) to connect to the local Firebase Auth Emulator. + - GMA (iOS): Updated dependency to Google-Mobile-Ads-SDK version 10.10.0. + - GMA (Android): Updated dependency to play-services-ads version 22.3.0. ### 11.4.0 - Changes From d7555dac59db8c7ca55cdfbb53c4f96bc926b678 Mon Sep 17 00:00:00 2001 From: Tom Andersen Date: Thu, 21 Sep 2023 10:32:33 -0400 Subject: [PATCH 25/25] Format --- firestore/src/android/filter_android.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/firestore/src/android/filter_android.cc b/firestore/src/android/filter_android.cc index d6bcd422b2..70f91d5848 100644 --- a/firestore/src/android/filter_android.cc +++ b/firestore/src/android/filter_android.cc @@ -200,7 +200,8 @@ Filter FilterInternal::Where(const StaticMethod& method, } } size_t non_empty_size = non_empty_indexes.size(); - Local> java_filters = env.NewArray(non_empty_size, filter_class); + Local> java_filters = + env.NewArray(non_empty_size, filter_class); for (int i = 0; i < non_empty_size; ++i) { java_filters.Set(env, i, filters[non_empty_indexes[i]].internal_->ToJava()); }