Skip to content

Commit f7cc868

Browse files
committed
[realppl 2] Minimalistic ppl offline evaluation
1 parent 757acda commit f7cc868

20 files changed

+1193
-247
lines changed

Firestore/Example/Firestore.xcodeproj/project.pbxproj

Lines changed: 289 additions & 226 deletions
Large diffs are not rendered by default.

Firestore/core/src/api/expressions.cc

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,40 +19,58 @@
1919
#include <memory>
2020

2121
#include "Firestore/Protos/nanopb/google/firestore/v1/document.nanopb.h"
22+
#include "Firestore/core/src/core/expressions_eval.h"
2223
#include "Firestore/core/src/model/value_util.h"
2324
#include "Firestore/core/src/nanopb/nanopb_util.h"
2425

2526
namespace firebase {
2627
namespace firestore {
2728
namespace api {
2829

30+
Field::Field(std::string name) {
31+
field_path_ = model::FieldPath::FromDotSeparatedString(name);
32+
}
33+
2934
google_firestore_v1_Value Field::to_proto() const {
3035
google_firestore_v1_Value result;
3136

3237
result.which_value_type = google_firestore_v1_Value_field_reference_value_tag;
33-
result.field_reference_value = nanopb::MakeBytesArray(this->name_);
38+
result.field_reference_value = nanopb::MakeBytesArray(this->alias());
3439

3540
return result;
3641
}
3742

43+
std::unique_ptr<core::EvaluableExpr> Field::ToEvaluable() const {
44+
return std::make_unique<core::CoreField>(std::make_unique<Field>(*this));
45+
}
46+
3847
google_firestore_v1_Value Constant::to_proto() const {
3948
// Return a copy of the value proto to avoid double delete.
4049
return *model::DeepClone(*value_).release();
4150
}
4251

52+
std::unique_ptr<core::EvaluableExpr> Constant::ToEvaluable() const {
53+
return std::make_unique<core::CoreConstant>(
54+
std::make_unique<Constant>(*this));
55+
}
56+
4357
google_firestore_v1_Value FunctionExpr::to_proto() const {
4458
google_firestore_v1_Value result;
4559

4660
result.which_value_type = google_firestore_v1_Value_function_value_tag;
4761
result.function_value = google_firestore_v1_Function{};
4862
result.function_value.name = nanopb::MakeBytesArray(name_);
4963
nanopb::SetRepeatedField(
50-
&result.function_value.args, &result.function_value.args_count, args_,
64+
&result.function_value.args, &result.function_value.args_count, params_,
5165
[](const std::shared_ptr<Expr>& arg) { return arg->to_proto(); });
5266

5367
return result;
5468
}
5569

70+
std::unique_ptr<core::EvaluableExpr> FunctionExpr::ToEvaluable() const {
71+
return core::FunctionToEvaluable(*this);
72+
}
73+
5674
} // namespace api
5775
} // namespace firestore
5876
} // namespace firebase

Firestore/core/src/api/expressions.h

Lines changed: 37 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -23,36 +23,54 @@
2323
#include <vector>
2424

2525
#include "Firestore/Protos/nanopb/google/firestore/v1/document.nanopb.h"
26+
#include "Firestore/core/src/model/field_path.h"
2627
#include "Firestore/core/src/nanopb/message.h"
2728

2829
namespace firebase {
2930
namespace firestore {
31+
namespace core {
32+
class EvaluableExpr;
33+
} // namespace core
3034
namespace api {
3135

3236
class Expr {
3337
public:
3438
Expr() = default;
3539
virtual ~Expr() = default;
3640
virtual google_firestore_v1_Value to_proto() const = 0;
41+
virtual std::unique_ptr<core::EvaluableExpr> ToEvaluable() const = 0;
3742
};
3843

3944
class Selectable : public Expr {
4045
public:
41-
virtual ~Selectable() = default;
46+
~Selectable() override = default;
4247
virtual const std::string& alias() const = 0;
4348
};
4449

4550
class Field : public Selectable {
4651
public:
47-
explicit Field(std::string name) : name_(std::move(name)) {
52+
explicit Field(model::FieldPath field_path)
53+
: field_path_(std::move(field_path)),
54+
alias_(field_path_.CanonicalString()) {
4855
}
56+
~Field() override = default;
57+
58+
explicit Field(std::string name);
59+
4960
google_firestore_v1_Value to_proto() const override;
61+
5062
const std::string& alias() const override {
51-
return name_;
63+
return alias_;
5264
}
65+
const model::FieldPath& field_path() const {
66+
return field_path_;
67+
}
68+
69+
std::unique_ptr<core::EvaluableExpr> ToEvaluable() const override;
5370

5471
private:
55-
std::string name_;
72+
model::FieldPath field_path_;
73+
std::string alias_;
5674
};
5775

5876
class Constant : public Expr {
@@ -62,21 +80,33 @@ class Constant : public Expr {
6280
}
6381
google_firestore_v1_Value to_proto() const override;
6482

83+
std::unique_ptr<core::EvaluableExpr> ToEvaluable() const override;
84+
6585
private:
6686
nanopb::SharedMessage<google_firestore_v1_Value> value_;
6787
};
6888

6989
class FunctionExpr : public Expr {
7090
public:
71-
FunctionExpr(std::string name, std::vector<std::shared_ptr<Expr>> args)
72-
: name_(std::move(name)), args_(std::move(args)) {
91+
FunctionExpr(std::string name, std::vector<std::shared_ptr<Expr>> params)
92+
: name_(std::move(name)), params_(std::move(params)) {
7393
}
7494

7595
google_firestore_v1_Value to_proto() const override;
7696

97+
std::unique_ptr<core::EvaluableExpr> ToEvaluable() const override;
98+
99+
const std::string& name() const {
100+
return name_;
101+
}
102+
103+
const std::vector<std::shared_ptr<Expr>>& params() const {
104+
return params_;
105+
}
106+
77107
private:
78108
std::string name_;
79-
std::vector<std::shared_ptr<Expr>> args_;
109+
std::vector<std::shared_ptr<Expr>> params_;
80110
};
81111

82112
} // namespace api

Firestore/core/src/api/ordering.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ google_firestore_v1_Value Ordering::to_proto() const {
3131
result.map_value.fields =
3232
nanopb::MakeArray<google_firestore_v1_MapValue_FieldsEntry>(2);
3333
result.map_value.fields[0].key = nanopb::MakeBytesArray("expression");
34-
result.map_value.fields[0].value = field_.to_proto();
34+
result.map_value.fields[0].value = expr_->to_proto();
3535
result.map_value.fields[1].key = nanopb::MakeBytesArray("direction");
3636
google_firestore_v1_Value direction;
3737
direction.which_value_type = google_firestore_v1_Value_string_value_tag;

Firestore/core/src/api/ordering.h

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,14 +34,22 @@ class Ordering {
3434
DESCENDING,
3535
};
3636

37-
Ordering(Field field, Direction direction)
38-
: field_(std::move(field)), direction_(direction) {
37+
Ordering(std::unique_ptr<Expr> expr, Direction direction)
38+
: expr_(std::move(expr)), direction_(direction) {
39+
}
40+
41+
const Expr& expr() const {
42+
return *expr_;
43+
}
44+
45+
Direction direction() const {
46+
return direction_;
3947
}
4048

4149
google_firestore_v1_Value to_proto() const;
4250

4351
private:
44-
Field field_;
52+
std::unique_ptr<Expr> expr_;
4553
Direction direction_;
4654
};
4755

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
/*
2+
* Copyright 2025 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+
#include "Firestore/core/src/api/realtime_pipeline.h"
18+
19+
#include <memory>
20+
#include <utility>
21+
22+
#include "Firestore/core/src/remote/serializer.h"
23+
24+
namespace firebase {
25+
namespace firestore {
26+
namespace api {
27+
28+
RealtimePipeline::RealtimePipeline(
29+
std::vector<std::shared_ptr<EvaluableStage>> stages,
30+
remote::Serializer serializer)
31+
: stages_(std::move(stages)),
32+
serializer_(serializer) {
33+
}
34+
35+
RealtimePipeline RealtimePipeline::AddingStage(
36+
std::shared_ptr<EvaluableStage> stage) {
37+
auto copy = std::vector<std::shared_ptr<EvaluableStage>>(this->stages_);
38+
copy.push_back(stage);
39+
40+
return {copy, serializer_};
41+
}
42+
43+
const std::vector<std::shared_ptr<EvaluableStage>>& RealtimePipeline::stages()
44+
const {
45+
return this->stages_;
46+
}
47+
48+
EvaluateContext RealtimePipeline::evaluate_context() {
49+
return EvaluateContext(&serializer_);
50+
}
51+
52+
} // namespace api
53+
} // namespace firestore
54+
} // namespace firebase
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
/*
2+
* Copyright 2025 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+
#ifndef FIRESTORE_CORE_SRC_API_REALTIME_PIPELINE_H_
18+
#define FIRESTORE_CORE_SRC_API_REALTIME_PIPELINE_H_
19+
20+
#include <memory>
21+
#include <utility>
22+
#include <vector>
23+
24+
#include "Firestore/core/src/api/firestore.h"
25+
#include "Firestore/core/src/api/pipeline_snapshot.h"
26+
#include "Firestore/core/src/api/stages.h"
27+
#include "Firestore/core/src/remote/serializer.h"
28+
29+
namespace firebase {
30+
namespace firestore {
31+
namespace api {
32+
33+
class RealtimePipeline {
34+
public:
35+
RealtimePipeline(std::vector<std::shared_ptr<EvaluableStage>> stages,
36+
remote::Serializer serializer);
37+
38+
RealtimePipeline AddingStage(std::shared_ptr<EvaluableStage> stage);
39+
40+
const std::vector<std::shared_ptr<EvaluableStage>>& stages() const;
41+
42+
EvaluateContext evaluate_context();
43+
44+
private:
45+
std::vector<std::shared_ptr<EvaluableStage>> stages_;
46+
remote::Serializer serializer_;
47+
};
48+
49+
} // namespace api
50+
} // namespace firestore
51+
} // namespace firebase
52+
53+
#endif // FIRESTORE_CORE_SRC_API_REALTIME_PIPELINE_H_

Firestore/core/src/api/stages.cc

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,25 @@
1616

1717
#include "Firestore/core/src/api/stages.h"
1818

19+
#include <algorithm>
20+
#include <memory>
21+
#include <stdexcept>
1922
#include <unordered_map>
23+
#include <unordered_set>
2024
#include <utility>
25+
#include <vector>
2126

2227
#include "Firestore/Protos/nanopb/google/firestore/v1/document.nanopb.h"
28+
#include "Firestore/core/src/core/expressions_eval.h"
29+
#include "Firestore/core/src/model/document.h"
30+
#include "Firestore/core/src/model/document_key.h"
31+
#include "Firestore/core/src/model/mutable_document.h"
32+
#include "Firestore/core/src/model/resource_path.h"
33+
#include "Firestore/core/src/model/value_util.h"
2334
#include "Firestore/core/src/nanopb/message.h"
2435
#include "Firestore/core/src/nanopb/nanopb_util.h"
36+
#include "Firestore/core/src/util/comparison.h"
37+
#include "Firestore/core/src/util/hard_assert.h"
2538

2639
namespace firebase {
2740
namespace firestore {
@@ -304,6 +317,62 @@ google_firestore_v1_Pipeline_Stage RemoveFieldsStage::to_proto() const {
304317
return result;
305318
}
306319

320+
model::PipelineInputOutputVector CollectionSource::Evaluate(
321+
const EvaluateContext& /*context*/,
322+
const model::PipelineInputOutputVector& inputs) const {
323+
model::PipelineInputOutputVector results;
324+
std::copy_if(inputs.begin(), inputs.end(), std::back_inserter(results),
325+
[this](const model::MutableDocument& doc) {
326+
return doc.is_found_document() &&
327+
doc.key().path().PopLast().CanonicalString() == path_;
328+
});
329+
return results;
330+
}
331+
332+
model::PipelineInputOutputVector DatabaseSource::Evaluate(
333+
const EvaluateContext& /*context*/,
334+
const model::PipelineInputOutputVector& inputs) const {
335+
model::PipelineInputOutputVector results;
336+
std::copy_if(inputs.begin(), inputs.end(), std::back_inserter(results),
337+
[](const model::MutableDocument& doc) {
338+
return doc.is_found_document();
339+
});
340+
return results;
341+
}
342+
343+
model::PipelineInputOutputVector Where::Evaluate(
344+
const EvaluateContext& context,
345+
const model::PipelineInputOutputVector& inputs) const {
346+
model::PipelineInputOutputVector results;
347+
const auto evaluable_expr = expr_->ToEvaluable();
348+
const auto true_value = model::TrueValue();
349+
350+
for (const auto& doc : inputs) {
351+
auto result = evaluable_expr->Evaluate(context, doc);
352+
if (!result.IsErrorOrUnset() &&
353+
model::Equals(*result.value(), true_value)) {
354+
results.push_back(doc);
355+
}
356+
}
357+
358+
return results;
359+
}
360+
361+
model::PipelineInputOutputVector LimitStage::Evaluate(
362+
const EvaluateContext& /*context*/,
363+
const model::PipelineInputOutputVector& inputs) const {
364+
if (limit_ < 0) {
365+
// Or handle as error? Assuming non-negative limit.
366+
return {};
367+
}
368+
size_t count = static_cast<size_t>(limit_);
369+
if (count > inputs.size()) {
370+
count = inputs.size();
371+
}
372+
return model::PipelineInputOutputVector(inputs.begin(),
373+
inputs.begin() + count);
374+
}
375+
307376
} // namespace api
308377
} // namespace firestore
309378
} // namespace firebase

0 commit comments

Comments
 (0)