2 * Copyright (c) 2015 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 "content/content_filter.h"
21 #include "common/converter.h"
22 #include "common/logger.h"
23 #include "common/tools.h"
25 using common::AttributeMatchFlag;
26 using common::CompositeFilterType;
27 using common::ErrorCode;
28 using common::JsonCast;
29 using common::PlatformResult;
36 std::map<std::string, std::string> const attributeNameMap = {
38 {"type", "MEDIA_TYPE"},
39 {"mimeType", "MEDIA_MIME_TYPE"},
40 {"name", "MEDIA_DISPLAY_NAME"},
41 {"title", "MEDIA_TITLE"},
42 {"contentURI", "MEDIA_PATH"},
43 {"thumbnailURIs", "MEDIA_THUMBNAIL_PATH"},
44 {"description", "MEDIA_DESCRIPTION"},
45 {"rating", "MEDIA_RATING"},
46 {"createdDate", "MEDIA_ADDED_TIME"},
47 {"releaseDate", "MEDIA_DATETAKEN"},
48 {"modifiedDate", "MEDIA_MODIFIED_TIME"},
49 {"geolocation.latitude",
50 "MEDIA_LATITUDE"}, // Deprecated since 9.0 //TODO remove after 2 versions
51 {"geolocation.longitude",
52 "MEDIA_LONGITUDE"}, // Deprecated since 9.0 //TODO remove after 2 versions
54 "MEDIA_DURATION"}, // Deprecated since 9.0 //TODO remove after 2 versions
55 {"album", "MEDIA_ALBUM"},
56 {"artists", "MEDIA_ARTIST"},
57 {"width", "MEDIA_WIDTH"},
58 {"height", "MEDIA_HEIGHT"},
59 {"genres", "MEDIA_GENRE"},
60 {"size", "MEDIA_SIZE"},
63 std::string escapeValueString(const std::string& data) {
66 // If string won't be resized, then it will be faster
67 out.reserve(data.size());
87 PlatformResult ContentFilter::MapField(const std::string& name, std::string* result) {
89 auto it = attributeNameMap.find(name);
90 if (it != attributeNameMap.end()) {
91 if (name == "rating" || name == "description" ||
92 name == "geolocation.latitude" || name == "geolocation.longitude" ||
94 std::string warning = "Filtering by attribute '" + name + "'";
95 common::tools::PrintDeprecationWarningFor(warning.c_str());
99 return LogAndCreateResult(ErrorCode::INVALID_VALUES_ERR);
101 return PlatformResult(ErrorCode::NO_ERROR);
104 PlatformResult ContentFilter::BuildQuery(const picojson::object& jsFilter,
105 std::string* queryToCall) {
107 std::vector<std::vector<std::string>> partialqueries;
108 partialqueries.push_back(std::vector<std::string>());
110 visitor.SetOnAttributeFilter([&](const std::string& name, AttributeMatchFlag match_flag,
111 const picojson::value& match_value) {
112 ScopeLogger("Entered into asynchronous function, visitor.SetOnAttributeFilter's argument");
115 std::string matchValue;
117 PlatformResult result = MapField(name, &query);
118 if (!result) return result;
120 if (AttributeMatchFlag::kExactly == match_flag ||
121 AttributeMatchFlag::kFullString == match_flag) {
123 } else if (AttributeMatchFlag::kContains == match_flag ||
124 AttributeMatchFlag::kStartsWith == match_flag ||
125 AttributeMatchFlag::kEndsWith == match_flag) {
127 } else if (AttributeMatchFlag::kExists == match_flag) {
128 query += " IS NOT NULL ";
130 return LogAndCreateResult(ErrorCode::INVALID_VALUES_ERR);
132 if (AttributeMatchFlag::kExists != match_flag) {
134 matchValue = escapeValueString(JsonCast<std::string>(match_value));
135 if (name == "type") {
136 if (matchValue == "IMAGE") {
138 } else if (matchValue == "VIDEO") {
140 } else if (matchValue == "AUDIO") {
145 } else if (name == "contentURI") {
146 const char* uri_prefix = "file://";
147 size_t found = matchValue.find(uri_prefix);
148 if (found != std::string::npos) {
149 // simple convertion of URI to globalpath
150 matchValue = matchValue.substr(found + strlen(uri_prefix));
153 switch (match_flag) {
154 case AttributeMatchFlag::kStartsWith:
155 query += matchValue + "%";
157 case AttributeMatchFlag::kEndsWith:
158 query += "%" + matchValue;
160 case AttributeMatchFlag::kContains:
161 query += "%" + matchValue + "%";
169 partialqueries.back().push_back(query);
174 visitor.SetOnCompositeFilterBegin([&](CompositeFilterType type) {
175 ScopeLogger("Entered into asynchronous function, visitor.SetOnCompositeFilterBegin's argument");
176 partialqueries.push_back(std::vector<std::string>());
177 return PlatformResult(ErrorCode::NO_ERROR);
180 visitor.SetOnCompositeFilterEnd([&](CompositeFilterType calType) {
181 ScopeLogger("Entered into asynchronous function, visitor.SetOnCompositeFilterEnd's argument");
182 std::string finalQuery;
183 std::string separator;
185 if (CompositeFilterType::kUnion == calType)
190 if (partialqueries.back().empty()) {
191 partialqueries.pop_back();
192 return PlatformResult(ErrorCode::NO_ERROR);
194 if (partialqueries.back().size() != 1) finalQuery.append("(");
196 for (unsigned long i = 0; i < partialqueries.back().size(); i++) {
197 finalQuery += partialqueries.back().at(i);
198 if (i != partialqueries.back().size() - 1) {
199 finalQuery += separator;
203 if (partialqueries.back().size() != 1) finalQuery.append(")");
204 partialqueries.pop_back();
205 partialqueries.back().push_back(finalQuery);
207 return PlatformResult(ErrorCode::NO_ERROR);
210 visitor.SetOnAttributeRangeFilter([&](const std::string& name,
211 const picojson::value& initial_value,
212 const picojson::value& end_value) {
213 ScopeLogger("Entered into asynchronous function, visitor.SetOnAttributeRangeFilter's argument");
215 std::string query = "";
216 std::string paramName;
217 PlatformResult result = MapField(name, ¶mName);
218 if (!result) return result;
220 std::string initialValue = escapeValueString(JsonCast<std::string>(initial_value));
221 std::string endValue = escapeValueString(JsonCast<std::string>(end_value));
224 query += initialValue;
230 partialqueries.back().push_back(query);
235 if (!visitor.Visit(jsFilter)) {
236 return LogAndCreateResult(ErrorCode::INVALID_VALUES_ERR);
239 if (partialqueries.empty()) {
240 return LogAndCreateResult(ErrorCode::SYNTAX_ERR);
242 if (partialqueries.back().empty()) {
243 LoggerD("Resolved to empty string!");
245 return PlatformResult(ErrorCode::NO_ERROR);
248 *queryToCall = partialqueries.back().front();
249 return PlatformResult(ErrorCode::NO_ERROR);
252 } // namespace content
253 } // namespace extension