Skip to content

Commit 96a4345

Browse files
committed
[realppl 6] offline ppl evaluation and tests
1 parent d7e061b commit 96a4345

30 files changed

+8714
-64
lines changed

Firestore/Example/Firestore.xcodeproj/project.pbxproj

Lines changed: 189 additions & 3 deletions
Large diffs are not rendered by default.

Firestore/Source/API/FIRPipelineBridge+Internal.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ NS_ASSUME_NONNULL_BEGIN
3737

3838
@interface FIROrderingBridge (Internal)
3939

40-
- (std::shared_ptr<api::Ordering>)cppOrderingWithReader:(FSTUserDataReader *)reader;
40+
- (api::Ordering)cppOrderingWithReader:(FSTUserDataReader *)reader;
4141

4242
@end
4343

Firestore/Source/API/FIRPipelineBridge.mm

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -184,7 +184,7 @@ - (nonnull id)initWithName:(NSString *)name Args:(nonnull NSArray<FIRExprBridge
184184
@end
185185

186186
@implementation FIROrderingBridge {
187-
std::shared_ptr<Ordering> cpp_ordering;
187+
std::unique_ptr<Ordering> cpp_ordering;
188188
NSString *_direction;
189189
FIRExprBridge *_expr;
190190
Boolean isUserDataRead;
@@ -197,14 +197,14 @@ - (nonnull id)initWithExpr:(FIRExprBridge *)expr Direction:(NSString *)direction
197197
return self;
198198
}
199199

200-
- (std::shared_ptr<Ordering>)cppOrderingWithReader:(FSTUserDataReader *)reader {
200+
- (Ordering)cppOrderingWithReader:(FSTUserDataReader *)reader {
201201
if (!isUserDataRead) {
202-
cpp_ordering = std::make_shared<Ordering>(
202+
cpp_ordering = std::make_unique<Ordering>(
203203
[_expr cppExprWithReader:reader], Ordering::DirectionFromString(MakeString(_direction)));
204204
}
205205

206206
isUserDataRead = YES;
207-
return cpp_ordering;
207+
return *cpp_ordering;
208208
}
209209

210210
@end
@@ -610,7 +610,7 @@ - (id)initWithOrderings:(NSArray<id> *)orderings {
610610

611611
- (std::shared_ptr<api::Stage>)cppStageWithReader:(FSTUserDataReader *)reader {
612612
if (!isUserDataRead) {
613-
std::vector<std::shared_ptr<Ordering>> cpp_orderings;
613+
std::vector<Ordering> cpp_orderings;
614614
for (FIROrderingBridge *ordering in _orderings) {
615615
cpp_orderings.push_back([ordering cppOrderingWithReader:reader]);
616616
}

Firestore/core/src/api/expressions.cc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ namespace api {
2929

3030
Field::Field(std::string name) {
3131
field_path_ = model::FieldPath::FromDotSeparatedString(name);
32+
alias_ = field_path_.CanonicalString();
3233
}
3334

3435
google_firestore_v1_Value Field::to_proto() const {

Firestore/core/src/api/ordering.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,14 @@ class Ordering {
4545
: expr_(expr), direction_(direction) {
4646
}
4747

48+
const Expr* expr() const {
49+
return expr_.get();
50+
}
51+
52+
Direction direction() const {
53+
return direction_;
54+
}
55+
4856
google_firestore_v1_Value to_proto() const;
4957

5058
private:

Firestore/core/src/api/realtime_pipeline.cc

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,16 @@ const std::vector<std::shared_ptr<EvaluableStage>>& RealtimePipeline::stages()
4444
return this->stages_;
4545
}
4646

47+
const std::vector<std::shared_ptr<EvaluableStage>>&
48+
RealtimePipeline::rewritten_stages() const {
49+
return this->rewritten_stages_;
50+
}
51+
52+
void RealtimePipeline::SetRewrittentStages(
53+
std::vector<std::shared_ptr<EvaluableStage>> stages) {
54+
this->rewritten_stages_ = std::move(stages);
55+
}
56+
4757
EvaluateContext RealtimePipeline::evaluate_context() {
4858
return EvaluateContext(&serializer_);
4959
}

Firestore/core/src/api/realtime_pipeline.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,11 +38,15 @@ class RealtimePipeline {
3838
RealtimePipeline AddingStage(std::shared_ptr<EvaluableStage> stage);
3939

4040
const std::vector<std::shared_ptr<EvaluableStage>>& stages() const;
41+
const std::vector<std::shared_ptr<EvaluableStage>>& rewritten_stages() const;
42+
43+
void SetRewrittentStages(std::vector<std::shared_ptr<EvaluableStage>>);
4144

4245
EvaluateContext evaluate_context();
4346

4447
private:
4548
std::vector<std::shared_ptr<EvaluableStage>> stages_;
49+
std::vector<std::shared_ptr<EvaluableStage>> rewritten_stages_;
4650
remote::Serializer serializer_;
4751
};
4852

Firestore/core/src/api/stages.cc

Lines changed: 55 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,10 @@ namespace firebase {
4141
namespace firestore {
4242
namespace api {
4343

44+
CollectionSource::CollectionSource(std::string path)
45+
: path_(model::ResourcePath::FromStringView(path)) {
46+
}
47+
4448
google_firestore_v1_Pipeline_Stage CollectionSource::to_proto() const {
4549
google_firestore_v1_Pipeline_Stage result;
4650

@@ -50,7 +54,9 @@ google_firestore_v1_Pipeline_Stage CollectionSource::to_proto() const {
5054
result.args = nanopb::MakeArray<google_firestore_v1_Value>(1);
5155
result.args[0].which_value_type =
5256
google_firestore_v1_Value_reference_value_tag;
53-
result.args[0].reference_value = nanopb::MakeBytesArray(this->path_);
57+
// TODO: use EncodeResourceName instead
58+
result.args[0].reference_value =
59+
nanopb::MakeBytesArray(this->path_.CanonicalString());
5460

5561
result.options_count = 0;
5662
result.options = nullptr;
@@ -275,7 +281,7 @@ google_firestore_v1_Pipeline_Stage SortStage::to_proto() const {
275281
result.args = nanopb::MakeArray<google_firestore_v1_Value>(result.args_count);
276282

277283
for (size_t i = 0; i < orders_.size(); ++i) {
278-
result.args[i] = orders_[i]->to_proto();
284+
result.args[i] = orders_[i].to_proto();
279285
}
280286

281287
result.options_count = 0;
@@ -443,7 +449,20 @@ model::PipelineInputOutputVector CollectionSource::Evaluate(
443449
std::copy_if(inputs.begin(), inputs.end(), std::back_inserter(results),
444450
[this](const model::MutableDocument& doc) {
445451
return doc.is_found_document() &&
446-
doc.key().path().PopLast().CanonicalString() == path_;
452+
doc.key().path().PopLast().CanonicalString() ==
453+
path_.CanonicalString();
454+
});
455+
return results;
456+
}
457+
458+
model::PipelineInputOutputVector CollectionGroupSource::Evaluate(
459+
const EvaluateContext& /*context*/,
460+
const model::PipelineInputOutputVector& inputs) const {
461+
model::PipelineInputOutputVector results;
462+
std::copy_if(inputs.begin(), inputs.end(), std::back_inserter(results),
463+
[this](const model::MutableDocument& doc) {
464+
return doc.is_found_document() &&
465+
doc.key().GetCollectionGroup() == collection_id_;
447466
});
448467
return results;
449468
}
@@ -492,6 +511,39 @@ model::PipelineInputOutputVector LimitStage::Evaluate(
492511
inputs.begin() + count);
493512
}
494513

514+
model::PipelineInputOutputVector SortStage::Evaluate(
515+
const EvaluateContext& context,
516+
const model::PipelineInputOutputVector& inputs) const {
517+
model::PipelineInputOutputVector input_copy = inputs;
518+
std::sort(
519+
input_copy.begin(), input_copy.end(),
520+
[this, &context](const model::PipelineInputOutput& left,
521+
const model::PipelineInputOutput& right) -> bool {
522+
for (const auto& ordering : this->orders_) {
523+
const auto left_result =
524+
ordering.expr()->ToEvaluable()->Evaluate(context, left);
525+
const auto right_result =
526+
ordering.expr()->ToEvaluable()->Evaluate(context, right);
527+
528+
auto left_val = left_result.IsErrorOrUnset() ? model::MinValue()
529+
: *left_result.value();
530+
auto right_val = right_result.IsErrorOrUnset()
531+
? model::MinValue()
532+
: *right_result.value();
533+
const auto compare_result = model::Compare(left_val, right_val);
534+
if (compare_result != util::ComparisonResult::Same) {
535+
return ordering.direction() == Ordering::ASCENDING
536+
? compare_result == util::ComparisonResult::Ascending
537+
: compare_result == util::ComparisonResult::Descending;
538+
}
539+
}
540+
541+
return false;
542+
});
543+
544+
return input_copy;
545+
}
546+
495547
} // namespace api
496548
} // namespace firestore
497549
} // namespace firebase

Firestore/core/src/api/stages.h

Lines changed: 51 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
#include "Firestore/core/src/api/expressions.h"
3030
#include "Firestore/core/src/api/ordering.h"
3131
#include "Firestore/core/src/model/model_fwd.h"
32+
#include "Firestore/core/src/model/resource_path.h"
3233
#include "Firestore/core/src/nanopb/message.h"
3334
#include "absl/types/optional.h"
3435

@@ -67,25 +68,29 @@ class EvaluableStage : public Stage {
6768
EvaluableStage() = default;
6869
virtual ~EvaluableStage() = default;
6970

71+
virtual absl::string_view name() const = 0;
7072
virtual model::PipelineInputOutputVector Evaluate(
7173
const EvaluateContext& context,
7274
const model::PipelineInputOutputVector& inputs) const = 0;
7375
};
7476

7577
class CollectionSource : public EvaluableStage {
7678
public:
77-
explicit CollectionSource(std::string path) : path_(std::move(path)) {
78-
}
79+
explicit CollectionSource(std::string path);
7980
~CollectionSource() override = default;
8081

8182
google_firestore_v1_Pipeline_Stage to_proto() const override;
8283

84+
absl::string_view name() const override {
85+
return "collection";
86+
}
87+
8388
model::PipelineInputOutputVector Evaluate(
8489
const EvaluateContext& context,
8590
const model::PipelineInputOutputVector& inputs) const override;
8691

8792
private:
88-
std::string path_;
93+
model::ResourcePath path_;
8994
};
9095

9196
class DatabaseSource : public EvaluableStage {
@@ -94,12 +99,17 @@ class DatabaseSource : public EvaluableStage {
9499
~DatabaseSource() override = default;
95100

96101
google_firestore_v1_Pipeline_Stage to_proto() const override;
102+
103+
absl::string_view name() const override {
104+
return "database";
105+
}
106+
97107
model::PipelineInputOutputVector Evaluate(
98108
const EvaluateContext& context,
99109
const model::PipelineInputOutputVector& inputs) const override;
100110
};
101111

102-
class CollectionGroupSource : public Stage {
112+
class CollectionGroupSource : public EvaluableStage {
103113
public:
104114
explicit CollectionGroupSource(std::string collection_id)
105115
: collection_id_(std::move(collection_id)) {
@@ -108,6 +118,14 @@ class CollectionGroupSource : public Stage {
108118

109119
google_firestore_v1_Pipeline_Stage to_proto() const override;
110120

121+
absl::string_view name() const override {
122+
return "collection_group";
123+
}
124+
125+
model::PipelineInputOutputVector Evaluate(
126+
const EvaluateContext& context,
127+
const model::PipelineInputOutputVector& inputs) const override;
128+
111129
private:
112130
std::string collection_id_;
113131
};
@@ -121,6 +139,10 @@ class DocumentsSource : public Stage {
121139

122140
google_firestore_v1_Pipeline_Stage to_proto() const override;
123141

142+
absl::string_view name() const {
143+
return "documents";
144+
}
145+
124146
private:
125147
std::vector<std::string> documents_;
126148
};
@@ -163,6 +185,11 @@ class Where : public EvaluableStage {
163185
~Where() override = default;
164186

165187
google_firestore_v1_Pipeline_Stage to_proto() const override;
188+
189+
absl::string_view name() const override {
190+
return "where";
191+
}
192+
166193
model::PipelineInputOutputVector Evaluate(
167194
const EvaluateContext& context,
168195
const model::PipelineInputOutputVector& inputs) const override;
@@ -218,6 +245,11 @@ class LimitStage : public EvaluableStage {
218245
~LimitStage() override = default;
219246

220247
google_firestore_v1_Pipeline_Stage to_proto() const override;
248+
249+
absl::string_view name() const override {
250+
return "limit";
251+
}
252+
221253
model::PipelineInputOutputVector Evaluate(
222254
const EvaluateContext& context,
223255
const model::PipelineInputOutputVector& inputs) const override;
@@ -252,17 +284,29 @@ class SelectStage : public Stage {
252284
std::unordered_map<std::string, std::shared_ptr<Expr>> fields_;
253285
};
254286

255-
class SortStage : public Stage {
287+
class SortStage : public EvaluableStage {
256288
public:
257-
explicit SortStage(std::vector<std::shared_ptr<Ordering>> orders)
289+
explicit SortStage(std::vector<Ordering> orders)
258290
: orders_(std::move(orders)) {
259291
}
260292
~SortStage() override = default;
261293

262294
google_firestore_v1_Pipeline_Stage to_proto() const override;
263295

296+
absl::string_view name() const override {
297+
return "sort";
298+
}
299+
300+
model::PipelineInputOutputVector Evaluate(
301+
const EvaluateContext& context,
302+
const model::PipelineInputOutputVector& inputs) const override;
303+
304+
const std::vector<Ordering>& orders() const {
305+
return orders_;
306+
}
307+
264308
private:
265-
std::vector<std::shared_ptr<Ordering>> orders_;
309+
std::vector<Ordering> orders_;
266310
};
267311

268312
class DistinctStage : public Stage {

Firestore/core/src/core/expressions_eval.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,7 @@
2424

2525
#include "Firestore/core/src/api/expressions.h"
2626
#include "Firestore/core/src/api/stages.h"
27-
#include "Firestore/core/src/model/value_util.h"
2827
#include "Firestore/core/src/nanopb/message.h"
29-
#include "Firestore/core/src/util/hard_assert.h"
3028
#include "absl/types/optional.h"
3129

3230
namespace firebase {

Firestore/core/src/core/pipeline_run.cc

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include "Firestore/core/src/api/stages.h"
2222
#include "Firestore/core/src/model/mutable_document.h"
2323
#include "Firestore/core/src/remote/serializer.h"
24+
#include "pipeline_util.h"
2425

2526
namespace firebase {
2627
namespace firestore {
@@ -29,8 +30,12 @@ namespace core {
2930
std::vector<model::MutableDocument> RunPipeline(
3031
api::RealtimePipeline& pipeline,
3132
const std::vector<model::MutableDocument>& inputs) {
32-
auto& current = const_cast<std::vector<model::MutableDocument>&>(inputs);
33-
for (const auto& stage : pipeline.stages()) {
33+
if (pipeline.rewritten_stages().empty()) {
34+
pipeline.SetRewrittentStages(RewriteStages(pipeline.stages()));
35+
}
36+
37+
auto current = std::vector<model::MutableDocument>(inputs);
38+
for (const auto& stage : pipeline.rewritten_stages()) {
3439
current = stage->Evaluate(pipeline.evaluate_context(), current);
3540
}
3641

0 commit comments

Comments
 (0)