2 * Copyright (c) 2019 Samsung Electronics Co., Ltd All Rights Reserved
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 #include "common/json-filter.h"
21 std::vector<std::string> SplitString(std::string text, char delimiter) {
23 std::vector<std::string> parts;
24 std::string word = "";
28 parts.push_back(word);
36 parts.push_back(word);
41 picojson::value GetAttribute(std::string attribute, picojson::value json) {
43 for (auto node : SplitString(attribute, kAttributeSeparator)) {
44 if (!json.is<picojson::object>()) {
45 throw "filtered attribute not found";
48 auto obj = json.get<picojson::object>();
49 if (obj.find(node) == obj.end()) {
50 throw "filtered attribute not found";
58 } // namespace internal
62 JsonFilter::JsonFilter(picojson::value filter) : filter(filter) {
64 operators = {{"$AND", &JsonFilter::AndOperator},
65 {"$OR", &JsonFilter::OrOperator},
66 {"$EXACTLY", &JsonFilter::EqualsOperator},
67 {"$CONTAINS", &JsonFilter::ContainsOperator}};
70 JsonFilter::~JsonFilter() {
74 picojson::array JsonFilter::Filter(const picojson::array& records) const {
76 picojson::array filtered;
77 for (const auto& record : records) {
78 if (IsMatch(record)) {
79 filtered.push_back(record);
85 bool JsonFilter::IsMatch(picojson::value record) const {
86 if (!filter.is<picojson::object>()) {
87 throw "filter is not a json object";
89 return EvaluateNode(filter.get<picojson::object>(), record);
92 bool JsonFilter::AndOperator(picojson::array args, picojson::value record) const {
95 for (const auto& value : args) {
96 if (value.is<picojson::object>()) {
97 result = result && EvaluateNode(value.get<picojson::object>(), record);
98 } else if (value.is<std::string>()) {
99 auto attribute = internal::GetAttribute(value.get<std::string>(), record);
100 result = result && attribute.evaluate_as_boolean();
102 result = result && value.evaluate_as_boolean();
108 bool JsonFilter::OrOperator(picojson::array args, picojson::value record) const {
111 for (const auto& value : args) {
112 if (value.is<picojson::object>()) {
113 result = result || EvaluateNode(value.get<picojson::object>(), record);
114 } else if (value.is<std::string>()) {
115 auto attribute = internal::GetAttribute(value.get<std::string>(), record);
116 result = result || attribute.evaluate_as_boolean();
118 result = result || value.evaluate_as_boolean();
124 bool JsonFilter::EqualsOperator(picojson::array args, picojson::value record) const {
126 if (args.size() != 2) {
127 throw "equals operator takes exactly 2 arguments";
130 if (!args[0].is<std::string>()) {
131 throw "equals operator first argument must be a string (attribute path)";
134 auto attribute = internal::GetAttribute(args[0].get<std::string>(), record);
135 return args[1].serialize() == attribute.serialize();
138 bool JsonFilter::ContainsOperator(picojson::array args, picojson::value record) const {
140 if (args.size() != 2) {
141 throw "contains operator takes exactly 2 arguments";
144 if (!args[0].is<std::string>() || !args[1].is<std::string>()) {
145 throw "contains operator arguments must be a string";
148 auto attribute = internal::GetAttribute(args[0].get<std::string>(), record);
149 if (!attribute.is<std::string>()) {
150 throw "attribute for contains operator must have a string value type";
153 return attribute.get<std::string>().find(args[1].get<std::string>()) != std::string::npos;
156 bool JsonFilter::IsOperator(std::string identifier) const {
158 return operators.find(identifier) != operators.end();
161 bool JsonFilter::EvaluateOperator(std::string opType, picojson::value arguments,
162 picojson::value record) const {
164 if (!arguments.is<picojson::array>()) {
165 throw "Operator requires an array of arguments";
167 return (this->*(operators.at(opType)))(arguments.get<picojson::array>(), record);
170 bool JsonFilter::EvaluateNode(picojson::object node, picojson::value record) const {
173 for (const auto& attr : node) {
174 if (IsOperator(attr.first)) {
175 bool value = EvaluateOperator(attr.first, attr.second, record);
176 result = result && value;
182 } // namespace common