Skip to content

Commit

Permalink
Implement FHIRPath's skip() and take() functions.
Browse files Browse the repository at this point in the history
PiperOrigin-RevId: 313840420
  • Loading branch information
aaronnash authored and nickgeorge committed Jun 15, 2020
1 parent 1e9dc2c commit 30409c0
Show file tree
Hide file tree
Showing 2 changed files with 104 additions and 2 deletions.
60 changes: 58 additions & 2 deletions cc/google/fhir/fhir_path/fhir_path.cc
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@

#include "google/fhir/fhir_path/fhir_path.h"

#include <algorithm>
#include <iterator>
#include <utility>

#include "google/protobuf/any.pb.h"
Expand Down Expand Up @@ -1307,6 +1309,60 @@ class TailFunction : public ZeroParameterFunctionNode {
const Descriptor* ReturnType() const override { return child_->ReturnType(); }
};

class SkipFunction : public SingleValueFunctionNode {
public:
explicit SkipFunction(
const std::shared_ptr<ExpressionNode>& child,
const std::vector<std::shared_ptr<ExpressionNode>>& params)
: SingleValueFunctionNode(child, params) {}

Status EvaluateWithParam(
WorkSpace* work_space, const WorkspaceMessage& param,
std::vector<WorkspaceMessage>* results) const override {
std::vector<WorkspaceMessage> child_results;
FHIR_RETURN_IF_ERROR(child_->Evaluate(work_space, &child_results));
FHIR_ASSIGN_OR_RETURN(
int num,
ToSystemInteger(work_space->GetPrimitiveHandler(), *param.Message()));

auto start = child_results.begin();
std::advance(start, std::min(num < 0 ? 0 : static_cast<size_t>(num),
child_results.size()));
results->insert(results->begin(), start, child_results.end());

return absl::OkStatus();
}

const Descriptor* ReturnType() const override { return child_->ReturnType(); }
};

class TakeFunction : public SingleValueFunctionNode {
public:
explicit TakeFunction(
const std::shared_ptr<ExpressionNode>& child,
const std::vector<std::shared_ptr<ExpressionNode>>& params)
: SingleValueFunctionNode(child, params) {}

Status EvaluateWithParam(
WorkSpace* work_space, const WorkspaceMessage& param,
std::vector<WorkspaceMessage>* results) const override {
std::vector<WorkspaceMessage> child_results;
FHIR_RETURN_IF_ERROR(child_->Evaluate(work_space, &child_results));
FHIR_ASSIGN_OR_RETURN(
int num,
ToSystemInteger(work_space->GetPrimitiveHandler(), *param.Message()));

auto end = child_results.begin();
std::advance(end, std::min(num < 0 ? 0 : static_cast<size_t>(num),
child_results.size()));
results->insert(results->begin(), child_results.begin(), end);

return absl::OkStatus();
}

const Descriptor* ReturnType() const override { return child_->ReturnType(); }
};

// Implements the FHIRPath .trace() function.
class TraceFunction : public SingleValueFunctionNode {
public:
Expand Down Expand Up @@ -3604,8 +3660,8 @@ class FhirPathCompilerVisitor : public FhirPathBaseVisitor {
{"repeat", UnimplementedFunction},
{"single", FunctionNode::Create<SingleFunction>},
{"last", FunctionNode::Create<LastFunction>},
{"skip", UnimplementedFunction},
{"take", UnimplementedFunction},
{"skip", FunctionNode::Create<SkipFunction>},
{"take", FunctionNode::Create<TakeFunction>},
{"exclude", UnimplementedFunction},
{"union", UnimplementedFunction},
{"convertsToBoolean", UnimplementedFunction},
Expand Down
46 changes: 46 additions & 0 deletions cc/google/fhir/fhir_path/fhir_path_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -818,6 +818,52 @@ FHIR_VERSION_TEST(FhirPathTest, TestFunctionTail, {
EXPECT_THAT(Evaluate("true.combine(true).tail()"), EvalsToTrue());
})

FHIR_VERSION_TEST(FhirPathTest, TestFunctionSkip, {
EXPECT_THAT(Evaluate("{}.skip(-1)"), EvalsToEmpty());
EXPECT_THAT(Evaluate("{}.skip(0)"), EvalsToEmpty());
EXPECT_THAT(Evaluate("{}.skip(1)"), EvalsToEmpty());

EXPECT_THAT(Evaluate("(true).skip(-1)"), EvalsToTrue());
EXPECT_THAT(Evaluate("(true).skip(0)"), EvalsToTrue());
EXPECT_THAT(Evaluate("(true).skip(1)"), EvalsToEmpty());

EXPECT_THAT(Evaluate("true.combine(true).skip(-1) = true.combine(true)"),
EvalsToTrue());
EXPECT_THAT(Evaluate("true.combine(true).skip(0) = true.combine(true)"),
EvalsToTrue());
EXPECT_THAT(Evaluate("true.combine(true).skip(1)"), EvalsToTrue());
EXPECT_THAT(Evaluate("true.combine(true).skip(2)"), EvalsToEmpty());

EXPECT_THAT(Evaluate("(true).skip()"),
HasStatusCode(StatusCode::kInvalidArgument));
EXPECT_THAT(Evaluate("(true).skip('1')"),
HasStatusCode(StatusCode::kInvalidArgument));
})

FHIR_VERSION_TEST(FhirPathTest, TestFunctionTake, {
EXPECT_THAT(Evaluate("{}.take(-1)"), EvalsToEmpty());
EXPECT_THAT(Evaluate("{}.take(0)"), EvalsToEmpty());
EXPECT_THAT(Evaluate("{}.take(1)"), EvalsToEmpty());

EXPECT_THAT(Evaluate("(true).take(-1)"), EvalsToEmpty());
EXPECT_THAT(Evaluate("(true).take(0)"), EvalsToEmpty());
EXPECT_THAT(Evaluate("(true).take(1)"), EvalsToTrue());
EXPECT_THAT(Evaluate("(true).take(2)"), EvalsToTrue());

EXPECT_THAT(Evaluate("true.combine(true).take(-1)"), EvalsToEmpty());
EXPECT_THAT(Evaluate("true.combine(true).take(0)"), EvalsToEmpty());
EXPECT_THAT(Evaluate("true.combine(true).take(1)"), EvalsToTrue());
EXPECT_THAT(Evaluate("true.combine(true).take(2) = true.combine(true)"),
EvalsToTrue());
EXPECT_THAT(Evaluate("true.combine(true).take(3) = true.combine(true)"),
EvalsToTrue());

EXPECT_THAT(Evaluate("(true).take()"),
HasStatusCode(StatusCode::kInvalidArgument));
EXPECT_THAT(Evaluate("(true).take('1')"),
HasStatusCode(StatusCode::kInvalidArgument));
})

FHIR_VERSION_TEST(FhirPathTest, TestFunctionOfTypePrimitives, {
EXPECT_THAT(Evaluate("{}.ofType(Boolean)"), EvalsToEmpty());

Expand Down

0 comments on commit 30409c0

Please sign in to comment.