Build fixes for new toolchain
[platform/core/api/webapi-plugins.git] / src / common / json-filter.cc
1 /*
2  * Copyright (c) 2019 Samsung Electronics Co., Ltd All Rights Reserved
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 "common/json-filter.h"
18
19 namespace internal {
20
21 std::vector<std::string> SplitString(std::string text, char delimiter) {
22   ScopeLogger();
23   std::vector<std::string> parts;
24   std::string word = "";
25   for (char c : text) {
26     if (c == delimiter) {
27       if (!word.empty()) {
28         parts.push_back(word);
29         word.clear();
30       }
31     } else {
32       word.push_back(c);
33     }
34   }
35   if (!word.empty()) {
36     parts.push_back(word);
37   }
38   return parts;
39 }
40
41 picojson::value GetAttribute(std::string attribute, picojson::value json) {
42   ScopeLogger();
43   for (auto node : SplitString(attribute, kAttributeSeparator)) {
44     if (!json.is<picojson::object>()) {
45       throw "filtered attribute not found";
46     }
47
48     auto obj = json.get<picojson::object>();
49     if (obj.find(node) == obj.end()) {
50       throw "filtered attribute not found";
51     }
52
53     json = obj.at(node);
54   }
55   return json;
56 }
57
58 }  // namespace internal
59
60 namespace common {
61
62 JsonFilter::JsonFilter(picojson::value filter) : filter(filter) {
63   ScopeLogger();
64   operators = {{"$AND", &JsonFilter::AndOperator},
65                {"$OR", &JsonFilter::OrOperator},
66                {"$EXACTLY", &JsonFilter::EqualsOperator},
67                {"$CONTAINS", &JsonFilter::ContainsOperator}};
68 }
69
70 JsonFilter::~JsonFilter() {
71   ScopeLogger();
72 }
73
74 picojson::array JsonFilter::Filter(const picojson::array& records) const {
75   ScopeLogger();
76   picojson::array filtered;
77   for (const auto& record : records) {
78     if (IsMatch(record)) {
79       filtered.push_back(record);
80     }
81   }
82   return filtered;
83 }
84
85 bool JsonFilter::IsMatch(picojson::value record) const {
86   if (!filter.is<picojson::object>()) {
87     throw "filter is not a json object";
88   }
89   return EvaluateNode(filter.get<picojson::object>(), record);
90 }
91
92 bool JsonFilter::AndOperator(picojson::array args, picojson::value record) const {
93   ScopeLogger();
94   bool result = true;
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();
101     } else {
102       result = result && value.evaluate_as_boolean();
103     }
104   }
105   return result;
106 }
107
108 bool JsonFilter::OrOperator(picojson::array args, picojson::value record) const {
109   ScopeLogger();
110   bool result = false;
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();
117     } else {
118       result = result || value.evaluate_as_boolean();
119     }
120   }
121   return result;
122 }
123
124 bool JsonFilter::EqualsOperator(picojson::array args, picojson::value record) const {
125   ScopeLogger();
126   if (args.size() != 2) {
127     throw "equals operator takes exactly 2 arguments";
128   }
129
130   if (!args[0].is<std::string>()) {
131     throw "equals operator first argument must be a string (attribute path)";
132   }
133
134   auto attribute = internal::GetAttribute(args[0].get<std::string>(), record);
135   return args[1].serialize() == attribute.serialize();
136 }
137
138 bool JsonFilter::ContainsOperator(picojson::array args, picojson::value record) const {
139   ScopeLogger();
140   if (args.size() != 2) {
141     throw "contains operator takes exactly 2 arguments";
142   }
143
144   if (!args[0].is<std::string>() || !args[1].is<std::string>()) {
145     throw "contains operator arguments must be a string";
146   }
147
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";
151   }
152
153   return attribute.get<std::string>().find(args[1].get<std::string>()) != std::string::npos;
154 }
155
156 bool JsonFilter::IsOperator(std::string identifier) const {
157   ScopeLogger();
158   return operators.find(identifier) != operators.end();
159 }
160
161 bool JsonFilter::EvaluateOperator(std::string opType, picojson::value arguments,
162                                   picojson::value record) const {
163   ScopeLogger();
164   if (!arguments.is<picojson::array>()) {
165     throw "Operator requires an array of arguments";
166   }
167   return (this->*(operators.at(opType)))(arguments.get<picojson::array>(), record);
168 }
169
170 bool JsonFilter::EvaluateNode(picojson::object node, picojson::value record) const {
171   ScopeLogger();
172   bool result = true;
173   for (const auto& attr : node) {
174     if (IsOperator(attr.first)) {
175       bool value = EvaluateOperator(attr.first, attr.second, record);
176       result = result && value;
177     }
178   }
179   return result;
180 }
181
182 }  // namespace common