Skip to content

[realppl 2] Minimalistic ppl offline evaluation #14827

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: wuandy/RealPpl_1
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
515 changes: 289 additions & 226 deletions Firestore/Example/Firestore.xcodeproj/project.pbxproj

Large diffs are not rendered by default.

22 changes: 20 additions & 2 deletions Firestore/core/src/api/expressions.cc
Original file line number Diff line number Diff line change
Expand Up @@ -19,40 +19,58 @@
#include <memory>

#include "Firestore/Protos/nanopb/google/firestore/v1/document.nanopb.h"
#include "Firestore/core/src/core/expressions_eval.h"
#include "Firestore/core/src/model/value_util.h"
#include "Firestore/core/src/nanopb/nanopb_util.h"

namespace firebase {
namespace firestore {
namespace api {

Field::Field(std::string name) {
field_path_ = model::FieldPath::FromDotSeparatedString(name);
}

google_firestore_v1_Value Field::to_proto() const {
google_firestore_v1_Value result;

result.which_value_type = google_firestore_v1_Value_field_reference_value_tag;
result.field_reference_value = nanopb::MakeBytesArray(this->name_);
result.field_reference_value = nanopb::MakeBytesArray(this->alias());

return result;
}

std::unique_ptr<core::EvaluableExpr> Field::ToEvaluable() const {
return std::make_unique<core::CoreField>(std::make_unique<Field>(*this));
}

google_firestore_v1_Value Constant::to_proto() const {
// Return a copy of the value proto to avoid double delete.
return *model::DeepClone(*value_).release();
}

std::unique_ptr<core::EvaluableExpr> Constant::ToEvaluable() const {
return std::make_unique<core::CoreConstant>(
std::make_unique<Constant>(*this));
}

google_firestore_v1_Value FunctionExpr::to_proto() const {
google_firestore_v1_Value result;

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

return result;
}

std::unique_ptr<core::EvaluableExpr> FunctionExpr::ToEvaluable() const {
return core::FunctionToEvaluable(*this);
}

} // namespace api
} // namespace firestore
} // namespace firebase
52 changes: 44 additions & 8 deletions Firestore/core/src/api/expressions.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,30 +23,54 @@
#include <vector>

#include "Firestore/Protos/nanopb/google/firestore/v1/document.nanopb.h"
#include "Firestore/core/src/model/field_path.h"
#include "Firestore/core/src/nanopb/message.h"

namespace firebase {
namespace firestore {
namespace core {
class EvaluableExpr;
} // namespace core
namespace api {

class Expr {
public:
Expr() = default;
virtual ~Expr() = default;
virtual google_firestore_v1_Value to_proto() const = 0;
virtual std::unique_ptr<core::EvaluableExpr> ToEvaluable() const = 0;
};

class Field : public Expr {
class Selectable : public Expr {
public:
explicit Field(std::string name) : name_(std::move(name)) {
~Selectable() override = default;
virtual const std::string& alias() const = 0;
};

class Field : public Selectable {
public:
explicit Field(model::FieldPath field_path)
: field_path_(std::move(field_path)),
alias_(field_path_.CanonicalString()) {
}
~Field() override = default;

explicit Field(std::string name);

google_firestore_v1_Value to_proto() const override;
const std::string& alias() const {
return name_;

const std::string& alias() const override {
return alias_;
}
const model::FieldPath& field_path() const {
return field_path_;
}

std::unique_ptr<core::EvaluableExpr> ToEvaluable() const override;

private:
std::string name_;
model::FieldPath field_path_;
std::string alias_;
};

class Constant : public Expr {
Expand All @@ -56,21 +80,33 @@ class Constant : public Expr {
}
google_firestore_v1_Value to_proto() const override;

std::unique_ptr<core::EvaluableExpr> ToEvaluable() const override;

private:
nanopb::SharedMessage<google_firestore_v1_Value> value_;
};

class FunctionExpr : public Expr {
public:
FunctionExpr(std::string name, std::vector<std::shared_ptr<Expr>> args)
: name_(std::move(name)), args_(std::move(args)) {
FunctionExpr(std::string name, std::vector<std::shared_ptr<Expr>> params)
: name_(std::move(name)), params_(std::move(params)) {
}

google_firestore_v1_Value to_proto() const override;

std::unique_ptr<core::EvaluableExpr> ToEvaluable() const override;

const std::string& name() const {
return name_;
}

const std::vector<std::shared_ptr<Expr>>& params() const {
return params_;
}

private:
std::string name_;
std::vector<std::shared_ptr<Expr>> args_;
std::vector<std::shared_ptr<Expr>> params_;
};

} // namespace api
Expand Down
53 changes: 53 additions & 0 deletions Firestore/core/src/api/realtime_pipeline.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/*
* Copyright 2025 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#include "Firestore/core/src/api/realtime_pipeline.h"

#include <memory>
#include <utility>

#include "Firestore/core/src/remote/serializer.h"

namespace firebase {
namespace firestore {
namespace api {

RealtimePipeline::RealtimePipeline(
std::vector<std::shared_ptr<EvaluableStage>> stages,
remote::Serializer serializer)
: stages_(std::move(stages)), serializer_(serializer) {
}

RealtimePipeline RealtimePipeline::AddingStage(
std::shared_ptr<EvaluableStage> stage) {
auto copy = std::vector<std::shared_ptr<EvaluableStage>>(this->stages_);
copy.push_back(stage);

return {copy, serializer_};
}

const std::vector<std::shared_ptr<EvaluableStage>>& RealtimePipeline::stages()
const {
return this->stages_;
}

EvaluateContext RealtimePipeline::evaluate_context() {
return EvaluateContext(&serializer_);
}

} // namespace api
} // namespace firestore
} // namespace firebase
53 changes: 53 additions & 0 deletions Firestore/core/src/api/realtime_pipeline.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/*
* Copyright 2025 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#ifndef FIRESTORE_CORE_SRC_API_REALTIME_PIPELINE_H_
#define FIRESTORE_CORE_SRC_API_REALTIME_PIPELINE_H_

#include <memory>
#include <utility>
#include <vector>

#include "Firestore/core/src/api/firestore.h"
#include "Firestore/core/src/api/pipeline_snapshot.h"
#include "Firestore/core/src/api/stages.h"
#include "Firestore/core/src/remote/serializer.h"

namespace firebase {
namespace firestore {
namespace api {

class RealtimePipeline {
public:
RealtimePipeline(std::vector<std::shared_ptr<EvaluableStage>> stages,
remote::Serializer serializer);

RealtimePipeline AddingStage(std::shared_ptr<EvaluableStage> stage);

const std::vector<std::shared_ptr<EvaluableStage>>& stages() const;

EvaluateContext evaluate_context();

private:
std::vector<std::shared_ptr<EvaluableStage>> stages_;
remote::Serializer serializer_;
};

} // namespace api
} // namespace firestore
} // namespace firebase

#endif // FIRESTORE_CORE_SRC_API_REALTIME_PIPELINE_H_
69 changes: 69 additions & 0 deletions Firestore/core/src/api/stages.cc
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,26 @@

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

#include <algorithm>
#include <memory>
#include <stdexcept>
#include <unordered_map>
#include <unordered_set>
#include <utility>
#include <vector>

#include "Firestore/Protos/nanopb/google/firestore/v1/document.nanopb.h"
#include "Firestore/core/src/api/pipeline.h"
#include "Firestore/core/src/core/expressions_eval.h"
#include "Firestore/core/src/model/document.h"
#include "Firestore/core/src/model/document_key.h"
#include "Firestore/core/src/model/mutable_document.h"
#include "Firestore/core/src/model/resource_path.h"
#include "Firestore/core/src/model/value_util.h"
#include "Firestore/core/src/nanopb/message.h"
#include "Firestore/core/src/nanopb/nanopb_util.h"
#include "Firestore/core/src/util/comparison.h"
#include "Firestore/core/src/util/hard_assert.h"

namespace firebase {
namespace firestore {
Expand Down Expand Up @@ -423,6 +436,62 @@ google_firestore_v1_Pipeline_Stage GenericStage::to_proto() const {
return result;
}

model::PipelineInputOutputVector CollectionSource::Evaluate(
const EvaluateContext& /*context*/,
const model::PipelineInputOutputVector& inputs) const {
model::PipelineInputOutputVector results;
std::copy_if(inputs.begin(), inputs.end(), std::back_inserter(results),
[this](const model::MutableDocument& doc) {
return doc.is_found_document() &&
doc.key().path().PopLast().CanonicalString() == path_;
});
return results;
}

model::PipelineInputOutputVector DatabaseSource::Evaluate(
const EvaluateContext& /*context*/,
const model::PipelineInputOutputVector& inputs) const {
model::PipelineInputOutputVector results;
std::copy_if(inputs.begin(), inputs.end(), std::back_inserter(results),
[](const model::MutableDocument& doc) {
return doc.is_found_document();
});
return results;
}

model::PipelineInputOutputVector Where::Evaluate(
const EvaluateContext& context,
const model::PipelineInputOutputVector& inputs) const {
model::PipelineInputOutputVector results;
const auto evaluable_expr = expr_->ToEvaluable();
const auto true_value = model::TrueValue();

for (const auto& doc : inputs) {
auto result = evaluable_expr->Evaluate(context, doc);
if (!result.IsErrorOrUnset() &&
model::Equals(*result.value(), true_value)) {
results.push_back(doc);
}
}

return results;
}

model::PipelineInputOutputVector LimitStage::Evaluate(
const EvaluateContext& /*context*/,
const model::PipelineInputOutputVector& inputs) const {
if (limit_ < 0) {
// Or handle as error? Assuming non-negative limit.
return {};
}
size_t count = static_cast<size_t>(limit_);
if (count > inputs.size()) {
count = inputs.size();
}
return model::PipelineInputOutputVector(inputs.begin(),
inputs.begin() + count);
}

} // namespace api
} // namespace firestore
} // namespace firebase
Loading
Loading