Skip to content

Commit cc9c626

Browse files
cherylEnkiduwu-hui
andauthored
Add setIndexConfiguration for client side indexing (#10090)
* Add setIndexConfiguration for client side indexing * Address feedback * Templates in headers Co-authored-by: Wu-Hui <[email protected]>
1 parent 160accf commit cc9c626

30 files changed

+1228
-462
lines changed

Firestore/CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
# Unreleased
2+
- [added] Expose client side indexing feature with `FIRFirestore.setIndexConfigurationFromJSON` and
3+
`FIRFirestore.setIndexConfigurationFromStream` (#10090).
4+
15
# 9.5.0
26
- [fixed] Fixed an intermittent crash if `ListenerRegistration::Remove()` was
37
invoked concurrently (#10065).

Firestore/Example/Firestore.xcodeproj/project.pbxproj

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -707,6 +707,7 @@
707707
71719F9F1E33DC2100824A3D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 71719F9D1E33DC2100824A3D /* LaunchScreen.storyboard */; };
708708
71E2B154C4FB63F7B7CC4B50 /* target_id_generator_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = AB380CF82019382300D97691 /* target_id_generator_test.cc */; };
709709
722F9A798F39F7D1FE7CF270 /* CodableGeoPointTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5495EB022040E90200EBA509 /* CodableGeoPointTests.swift */; };
710+
7264B73291F7F1EB454C45B1 /* FIRIndexingTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 795AA8FC31D2AF6864B07D39 /* FIRIndexingTests.mm */; };
710711
7281C2F04838AFFDF6A762DF /* memory_remote_document_cache_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 1CA9800A53669EFBFFB824E3 /* memory_remote_document_cache_test.cc */; };
711712
72AD91671629697074F2545B /* ordered_code_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = AB380D03201BC6E400D97691 /* ordered_code_test.cc */; };
712713
72B25B2D698E4746143D5B74 /* memory_lru_garbage_collector_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 9765D47FA12FA283F4EFAD02 /* memory_lru_garbage_collector_test.cc */; };
@@ -1077,6 +1078,7 @@
10771078
C09BDBA73261578F9DA74CEE /* firebase_auth_credentials_provider_test.mm in Sources */ = {isa = PBXBuildFile; fileRef = F869D85E900E5AF6CD02E2FC /* firebase_auth_credentials_provider_test.mm */; };
10781079
C0AD8DB5A84CAAEE36230899 /* status_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 54A0352C20A3B3D7003E0143 /* status_test.cc */; };
10791080
C0EFC5FB79517679C377C252 /* schedule_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 9B0B005A79E765AF02793DCE /* schedule_test.cc */; };
1081+
C10417B067155BE78E19807D /* FIRIndexingTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 795AA8FC31D2AF6864B07D39 /* FIRIndexingTests.mm */; };
10801082
C1237EE2A74F174A3DF5978B /* memory_target_cache_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 2286F308EFB0534B1BDE05B9 /* memory_target_cache_test.cc */; };
10811083
C15F5F1E7427738F20C2D789 /* offline_spec_test.json in Resources */ = {isa = PBXBuildFile; fileRef = 54DA12A11F315EE100DD57A1 /* offline_spec_test.json */; };
10821084
C19214F5B43AA745A7FC2FC1 /* maybe_document.pb.cc in Sources */ = {isa = PBXBuildFile; fileRef = 618BBE7E20B89AAC00B5BCE7 /* maybe_document.pb.cc */; };
@@ -1292,6 +1294,7 @@
12921294
F0EA84FB66813F2BC164EF7C /* token_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = A082AFDD981B07B5AD78FDE8 /* token_test.cc */; };
12931295
F10A3E4E164A5458DFF7EDE6 /* leveldb_remote_document_cache_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 0840319686A223CC4AD3FAB1 /* leveldb_remote_document_cache_test.cc */; };
12941296
F19B749671F2552E964422F7 /* FIRListenerRegistrationTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5492E06B202154D500B64F25 /* FIRListenerRegistrationTests.mm */; };
1297+
F1EAEE9DF819C017A9506AEB /* FIRIndexingTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 795AA8FC31D2AF6864B07D39 /* FIRIndexingTests.mm */; };
12951298
F272A8C41D2353700A11D1FB /* field_mask_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 549CCA5320A36E1F00BCEB75 /* field_mask_test.cc */; };
12961299
F27347560A963E8162C56FF3 /* target_index_matcher_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 63136A2371C0C013EC7A540C /* target_index_matcher_test.cc */; };
12971300
F2AB7EACA1B9B1A7046D3995 /* FSTSyncEngineTestDriver.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5492E02E20213FFC00B64F25 /* FSTSyncEngineTestDriver.mm */; };
@@ -1642,6 +1645,7 @@
16421645
776530F066E788C355B78457 /* FIRBundlesTests.mm */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.objcpp; path = FIRBundlesTests.mm; sourceTree = "<group>"; };
16431646
78EE0BFC7E60C4929458A0EA /* resource.pb.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = resource.pb.h; sourceTree = "<group>"; };
16441647
79507DF8378D3C42F5B36268 /* string_win_test.cc */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; path = string_win_test.cc; sourceTree = "<group>"; };
1648+
795AA8FC31D2AF6864B07D39 /* FIRIndexingTests.mm */ = {isa = PBXFileReference; includeInIndex = 1; path = FIRIndexingTests.mm; sourceTree = "<group>"; };
16451649
79D4CD6A707ED3F7A6D2ECF5 /* view_testing.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = view_testing.h; sourceTree = "<group>"; };
16461650
79EAA9F7B1B9592B5F053923 /* bundle_spec_test.json */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.json; path = bundle_spec_test.json; sourceTree = "<group>"; };
16471651
7B65C996438B84DBC7616640 /* CodableTimestampTests.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = CodableTimestampTests.swift; sourceTree = "<group>"; };
@@ -2636,6 +2640,7 @@
26362640
5492E06C202154D500B64F25 /* FIRDatabaseTests.mm */,
26372641
5492E06A202154D500B64F25 /* FIRFieldsTests.mm */,
26382642
6161B5012047140400A99DBB /* FIRFirestoreSourceTests.mm */,
2643+
795AA8FC31D2AF6864B07D39 /* FIRIndexingTests.mm */,
26392644
5492E06B202154D500B64F25 /* FIRListenerRegistrationTests.mm */,
26402645
D5B25E7E7D6873CBA4571841 /* FIRNumericTransformTests.mm */,
26412646
5492E069202154D500B64F25 /* FIRQueryTests.mm */,
@@ -3982,6 +3987,7 @@
39823987
BC2D0A8EA272A0058F6C2B9E /* FIRFirestoreSourceTests.mm in Sources */,
39833988
CBC1C0459C73BB4B06998401 /* FIRFirestoreTests.mm in Sources */,
39843989
61D35E0DE04E70D3BC243A65 /* FIRGeoPointTests.mm in Sources */,
3990+
7264B73291F7F1EB454C45B1 /* FIRIndexingTests.mm in Sources */,
39853991
F19B749671F2552E964422F7 /* FIRListenerRegistrationTests.mm in Sources */,
39863992
08F44F7DF9A3EF0D35C8FB57 /* FIRNumericTransformTests.mm in Sources */,
39873993
6DBB3DB3FD6B4981B7F26A55 /* FIRQuerySnapshotTests.mm in Sources */,
@@ -4201,6 +4207,7 @@
42014207
8A6C809B9F81C30B7333FCAA /* FIRFirestoreSourceTests.mm in Sources */,
42024208
457171CE2510EEA46F7D8A30 /* FIRFirestoreTests.mm in Sources */,
42034209
4809D7ACAA9414E3192F04FF /* FIRGeoPointTests.mm in Sources */,
4210+
C10417B067155BE78E19807D /* FIRIndexingTests.mm in Sources */,
42044211
E2B15548A3B6796CE5A01975 /* FIRListenerRegistrationTests.mm in Sources */,
42054212
B03F286F3AEC3781C386C646 /* FIRNumericTransformTests.mm in Sources */,
42064213
BB894A81FDF56EEC19CC29F8 /* FIRQuerySnapshotTests.mm in Sources */,
@@ -4654,6 +4661,7 @@
46544661
6161B5032047140C00A99DBB /* FIRFirestoreSourceTests.mm in Sources */,
46554662
25C167BAA4284FC951206E1F /* FIRFirestoreTests.mm in Sources */,
46564663
1B6E74BA33B010D76DB1E2F9 /* FIRGeoPointTests.mm in Sources */,
4664+
F1EAEE9DF819C017A9506AEB /* FIRIndexingTests.mm in Sources */,
46574665
5492E074202154D600B64F25 /* FIRListenerRegistrationTests.mm in Sources */,
46584666
D5B252EE3F4037405DB1ECE3 /* FIRNumericTransformTests.mm in Sources */,
46594667
6C143182916AC638707DB854 /* FIRQuerySnapshotTests.mm in Sources */,
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
/*
2+
* Copyright 2022 Google LLC
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
#import <FirebaseFirestore/FirebaseFirestore.h>
18+
19+
#import <XCTest/XCTest.h>
20+
21+
#import "Firestore/Example/Tests/Util/FSTIntegrationTestCase.h"
22+
23+
@interface FIRIndexingTests : FSTIntegrationTestCase
24+
@end
25+
26+
@implementation FIRIndexingTests
27+
28+
// Clears persistence for each test method to have a clean start.
29+
- (void)setUp {
30+
[super setUp];
31+
self.db = [self firestore];
32+
XCTestExpectation* exp = [self expectationWithDescription:@"clear persistence"];
33+
[self.db clearPersistenceWithCompletion:^(NSError*) {
34+
[exp fulfill];
35+
}];
36+
[self awaitExpectation:exp];
37+
}
38+
39+
- (void)testCanConfigureIndexes {
40+
NSString* json = @"{\n"
41+
"\t\"indexes\": [{\n"
42+
"\t\t\t\"collectionGroup\": \"restaurants\",\n"
43+
"\t\t\t\"queryScope\": \"COLLECTION\",\n"
44+
"\t\t\t\"fields\": [{\n"
45+
"\t\t\t\t\t\"fieldPath\": \"price\",\n"
46+
"\t\t\t\t\t\"order\": \"ASCENDING\"\n"
47+
"\t\t\t\t},\n"
48+
"\t\t\t\t{\n"
49+
"\t\t\t\t\t\"fieldPath\": \"avgRating\",\n"
50+
"\t\t\t\t\t\"order\": \"DESCENDING\"\n"
51+
"\t\t\t\t}\n"
52+
"\t\t\t]\n"
53+
"\t\t},\n"
54+
"\t\t{\n"
55+
"\t\t\t\"collectionGroup\": \"restaurants\",\n"
56+
"\t\t\t\"queryScope\": \"COLLECTION\",\n"
57+
"\t\t\t\"fields\": [{\n"
58+
"\t\t\t\t\"fieldPath\": \"price\",\n"
59+
"\t\t\t\t\"order\": \"ASCENDING\"\n"
60+
"\t\t\t}]\n"
61+
"\t\t}\n"
62+
"\t],\n"
63+
"\t\"fieldOverrides\": []\n"
64+
"}";
65+
66+
[self.db setIndexConfigurationFromJSON:json
67+
completion:^(NSError* error) {
68+
XCTAssertNil(error);
69+
}];
70+
}
71+
72+
- (void)testBadJsonDoesNotCrashClient {
73+
[self.db setIndexConfigurationFromJSON:@"{,"
74+
completion:^(NSError* error) {
75+
XCTAssertNotNil(error);
76+
XCTAssertEqualObjects(error.domain, FIRFirestoreErrorDomain);
77+
XCTAssertEqual(error.code, FIRFirestoreErrorCodeInvalidArgument);
78+
}];
79+
}
80+
81+
- (void)testBadIndexDoesNotCrashClient {
82+
NSString* json = @"{\n"
83+
"\t\"indexes\": [{\n"
84+
"\t\t\"collectionGroup\": \"restaurants\",\n"
85+
"\t\t\"queryScope\": \"COLLECTION\",\n"
86+
"\t\t\"fields\": [{\n"
87+
"\t\t\t\"fieldPath\": \"price\",\n"
88+
"\t\t\t\"order\": \"ASCENDING\",\n"
89+
"\t\t]}\n"
90+
"\t}],\n"
91+
"\t\"fieldOverrides\": []\n"
92+
"}";
93+
94+
[self.db setIndexConfigurationFromJSON:json
95+
completion:^(NSError* error) {
96+
XCTAssertNotNil(error);
97+
XCTAssertEqualObjects(error.domain, FIRFirestoreErrorDomain);
98+
XCTAssertEqual(error.code, FIRFirestoreErrorCodeInvalidArgument);
99+
}];
100+
}
101+
102+
@end

Firestore/Source/API/FIRFirestore.mm

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@
8787
using firebase::firestore::util::ThrowInvalidArgument;
8888
using firebase::firestore::util::kLogLevelDebug;
8989
using firebase::firestore::util::kLogLevelNotice;
90+
using firebase::firestore::util::StreamReadResult;
9091

9192
using UserUpdateBlock = id _Nullable (^)(FIRTransaction *, NSError **);
9293
using UserTransactionCompletion = void (^)(id _Nullable, NSError *_Nullable);
@@ -206,6 +207,31 @@ - (void)setSettings:(FIRFirestoreSettings *)settings {
206207
}
207208
}
208209

210+
- (void)setIndexConfigurationFromJSON:(NSString *)json
211+
completion:(nullable void (^)(NSError *_Nullable error))completion {
212+
_firestore->SetIndexConfiguration(MakeString(json), MakeCallback(completion));
213+
}
214+
215+
- (void)setIndexConfigurationFromStream:(NSInputStream *)stream
216+
completion:(nullable void (^)(NSError *_Nullable error))completion {
217+
auto input = absl::make_unique<ByteStreamApple>(stream);
218+
auto callback = MakeCallback(completion);
219+
220+
std::string json;
221+
bool eof = false;
222+
while (!eof) {
223+
StreamReadResult result = input->Read(1024ul);
224+
if (!result.ok()) {
225+
callback(result.status());
226+
return;
227+
}
228+
eof = result.eof();
229+
json.append(std::move(result).ValueOrDie());
230+
}
231+
232+
_firestore->SetIndexConfiguration(json, callback);
233+
}
234+
209235
- (FIRCollectionReference *)collectionWithPath:(NSString *)collectionPath {
210236
if (!collectionPath) {
211237
ThrowInvalidArgument("Collection path cannot be nil.");

Firestore/Source/Public/FirebaseFirestore/FIRFirestore.h

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,53 @@ NS_SWIFT_NAME(Firestore)
7272
*/
7373
@property(strong, nonatomic, readonly) FIRApp *app;
7474

75+
#pragma mark - Configure FieldIndexes
76+
77+
/**
78+
* This method is in preview. API signature and functionality are subject to change.
79+
*
80+
* Configures indexing for local query execution. Any previous index configuration is overridden.
81+
*
82+
* The index entries themselves are created asynchronously. You can continue to use queries
83+
* that require indexing even if the indices are not yet available. Query execution will
84+
* automatically start using the index once the index entries have been written.
85+
*
86+
* The method accepts the JSON format exported by the Firebase CLI (`firebase
87+
* firestore:indexes`). If the JSON format is invalid, the completion block will be
88+
* invoked with a NSError.
89+
*
90+
* @param json The JSON format exported by the Firebase CLI.
91+
* @param completion A block to execute when setting is in a final state. The `error` parameter
92+
* will be set if the block is invoked due to an error.
93+
*/
94+
- (void)setIndexConfigurationFromJSON:(NSString *)json
95+
completion:(nullable void (^)(NSError *_Nullable error))completion
96+
NS_SWIFT_NAME(setIndexConfiguration(_:completion:));
97+
98+
/**
99+
* This method is in preview. API signature and functionality are subject to change.
100+
*
101+
* Configures indexing for local query execution. Any previous index configuration is overridden.
102+
*
103+
* The index entries themselves are created asynchronously. You can continue to use queries
104+
* that require indexing even if the indices are not yet available. Query execution will
105+
* automatically start using the index once the index entries have been written.
106+
*
107+
* Indexes are only supported with LevelDB persistence. Invoke `set_persistence_enabled(true)`
108+
* before setting an index configuration. If LevelDB is not enabled, any index configuration
109+
* will be rejected.
110+
*
111+
* The method accepts the JSON format exported by the Firebase CLI (`firebase
112+
* firestore:indexes`). If the JSON format is invalid, this method ignores the changes.
113+
*
114+
* @param stream An input stream from which the configuration can be read.
115+
* @param completion A block to execute when setting is in a final state. The `error` parameter
116+
* will be set if the block is invoked due to an error.
117+
*/
118+
- (void)setIndexConfigurationFromStream:(NSInputStream *)stream
119+
completion:(nullable void (^)(NSError *_Nullable error))completion
120+
NS_SWIFT_NAME(setIndexConfiguration(_:completion:));
121+
75122
#pragma mark - Collections and Documents
76123

77124
/**

Firestore/core/src/api/firestore.cc

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include "Firestore/core/src/api/firestore.h"
1818

1919
#include <utility>
20+
#include <vector>
2021

2122
#include "Firestore/core/src/api/collection_reference.h"
2223
#include "Firestore/core/src/api/document_reference.h"
@@ -31,13 +32,18 @@
3132
#include "Firestore/core/src/credentials/empty_credentials_provider.h"
3233
#include "Firestore/core/src/local/leveldb_persistence.h"
3334
#include "Firestore/core/src/model/document_key.h"
35+
#include "Firestore/core/src/model/field_path.h"
3436
#include "Firestore/core/src/model/resource_path.h"
3537
#include "Firestore/core/src/remote/firebase_metadata_provider.h"
3638
#include "Firestore/core/src/remote/grpc_connection.h"
3739
#include "Firestore/core/src/util/async_queue.h"
40+
#include "Firestore/core/src/util/exception.h"
3841
#include "Firestore/core/src/util/executor.h"
3942
#include "Firestore/core/src/util/hard_assert.h"
43+
#include "Firestore/core/src/util/json_reader.h"
44+
#include "Firestore/core/src/util/log.h"
4045
#include "Firestore/core/src/util/status.h"
46+
#include "Firestore/third_party/nlohmann_json/json.hpp"
4147
#include "absl/memory/memory.h"
4248

4349
namespace firebase {
@@ -49,13 +55,18 @@ using core::DatabaseInfo;
4955
using core::FirestoreClient;
5056
using credentials::AuthCredentialsProvider;
5157
using local::LevelDbPersistence;
58+
using model::FieldIndex;
59+
using model::FieldPath;
5260
using model::ResourcePath;
61+
using model::Segment;
62+
using nlohmann::json;
5363
using remote::FirebaseMetadataProvider;
5464
using remote::GrpcConnection;
5565
using util::AsyncQueue;
5666
using util::Empty;
5767
using util::Executor;
5868
using util::Status;
69+
using util::ThrowInvalidArgument;
5970

6071
const int kDefaultTransactionMaxAttempts = 5;
6172

@@ -242,6 +253,70 @@ DatabaseInfo Firestore::MakeDatabaseInfo() const {
242253
settings_.ssl_enabled());
243254
}
244255

256+
void Firestore::SetIndexConfiguration(const std::string& config,
257+
const util::StatusCallback& callback) {
258+
EnsureClientConfigured();
259+
260+
util::JsonReader reader;
261+
if (!settings_.persistence_enabled()) {
262+
LOG_DEBUG("Cannot enable indexes when persistence is disabled.");
263+
callback(util::Status::OK());
264+
return;
265+
}
266+
267+
auto json_object =
268+
nlohmann::json::parse(config.begin(), config.end(),
269+
/*callback=*/nullptr, /*allow_exceptions=*/false);
270+
if (json_object.is_discarded()) {
271+
callback(Status(Error::kErrorInvalidArgument, "Invalid Json format."));
272+
return;
273+
}
274+
275+
std::vector<FieldIndex> parsed_indexes;
276+
const std::vector<json> default_vector;
277+
const auto& json_indexes =
278+
reader.OptionalArray("indexes", json_object, default_vector);
279+
for (const auto& json_index : json_indexes) {
280+
const std::string& collection_group =
281+
reader.RequiredString("collectionGroup", json_index);
282+
std::vector<Segment> segments;
283+
const auto& json_fields =
284+
reader.OptionalArray("fields", json_index, default_vector);
285+
for (const auto& json_field : json_fields) {
286+
FieldPath field_path = FieldPath::FromServerFormat(
287+
reader.RequiredString("fieldPath", json_field))
288+
.ValueOrDie();
289+
std::string default_string;
290+
if ("CONTAINS" ==
291+
reader.OptionalString("arrayConfig", json_field, default_string)) {
292+
segments.emplace_back(
293+
Segment(std::move(field_path), Segment::Kind::kContains));
294+
} else if ("ASCENDING" ==
295+
reader.OptionalString("order", json_field, default_string)) {
296+
segments.emplace_back(
297+
Segment(std::move(field_path), Segment::Kind::kAscending));
298+
} else {
299+
segments.emplace_back(
300+
Segment(std::move(field_path), Segment::Kind::kDescending));
301+
}
302+
}
303+
304+
if (reader.status() != util::Status::OK()) {
305+
callback(reader.status());
306+
return;
307+
}
308+
309+
parsed_indexes.emplace_back(
310+
FieldIndex(FieldIndex::UnknownId(), collection_group,
311+
std::move(segments), FieldIndex::InitialState()));
312+
}
313+
314+
client_->ConfigureFieldIndexes(std::move(parsed_indexes));
315+
316+
callback(util::Status::OK());
317+
return;
318+
}
319+
245320
std::shared_ptr<LoadBundleTask> Firestore::LoadBundle(
246321
std::unique_ptr<util::ByteStream> bundle_data) {
247322
EnsureClientConfigured();

Firestore/core/src/api/firestore.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,9 @@ class Firestore : public std::enable_shared_from_this<Firestore> {
107107
void EnableNetwork(util::StatusCallback callback);
108108
void DisableNetwork(util::StatusCallback callback);
109109

110+
void SetIndexConfiguration(const std::string& config,
111+
const util::StatusCallback& callback);
112+
110113
std::shared_ptr<api::LoadBundleTask> LoadBundle(
111114
std::unique_ptr<util::ByteStream> bundle_data);
112115
void GetNamedQuery(const std::string& name, api::QueryCallback callback);

0 commit comments

Comments
 (0)