2 * ============LICENSE_START=======================================================
3 * ONAP : ccsdk features
4 * ================================================================================
5 * Copyright (C) 2021 highstreet technologies GmbH Intellectual Property.
7 * ================================================================================
8 * Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
12 * http://www.apache.org/licenses/LICENSE-2.0
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
19 * ============LICENSE_END=========================================================
22 package org.onap.ccsdk.features.sdnr.wt.dataprovider.database.sqldb.query;
24 import java.util.ArrayList;
25 import java.util.Arrays;
26 import java.util.Calendar;
27 import java.util.Collection;
28 import java.util.Date;
29 import java.util.List;
31 import java.util.TimeZone;
32 import java.util.stream.Collectors;
33 import org.eclipse.jdt.annotation.Nullable;
34 import org.onap.ccsdk.features.sdnr.wt.common.database.data.DbFilter;
35 import org.onap.ccsdk.features.sdnr.wt.dataprovider.database.sqldb.database.SqlDBMapper;
36 import org.onap.ccsdk.features.sdnr.wt.dataprovider.database.sqldb.query.filters.DBFilterKeyValuePair;
37 import org.onap.ccsdk.features.sdnr.wt.dataprovider.database.sqldb.query.filters.RangeSqlDBFilter;
38 import org.onap.ccsdk.features.sdnr.wt.dataprovider.database.sqldb.query.filters.RegexSqlDBFilter;
39 import org.onap.ccsdk.features.sdnr.wt.dataprovider.database.sqldb.query.filters.SqlDBSearchFilter;
40 import org.onap.ccsdk.features.sdnr.wt.dataprovider.model.NetconfTimeStamp;
41 import org.onap.ccsdk.features.sdnr.wt.dataprovider.model.types.NetconfTimeStampImpl;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.rev201110.entity.input.Filter;
43 import io.netty.util.internal.StringUtil;
45 public interface SqlQuery {
49 static final List<String> TIMESTAMPPROPERTYNAMES = Arrays.asList("timestamp", "time-stamp", "start", "end");
50 static final String MARIADB_TIMESTAMP_REPLACER = "0000-00-00 00:00:00.000";
51 static final String NETCONF_TIMESTAMP_REPLACER = "0000-00-00T00:00:00.000Z";
52 static final String MARIADB_TIMESTAMP_REPLACER_MIN = "0000-00-00 00:00:00";
53 static final int MARIADB_TIMESTAMP_REPLACER_MIN_LENGTH = MARIADB_TIMESTAMP_REPLACER_MIN.length();
54 static final int MARIADB_TIMESTAMP_REPLACER_MAX_LENGTH = MARIADB_TIMESTAMP_REPLACER.length();
55 static final boolean DEFAULT_IGNORE_CONTROLLERID = false;
56 static final boolean DEFAULT_IGNORE_ID_FIELD = false;
58 public static String getWhereExpression(Collection<Filter> filters) {
59 return getWhereExpression(filters, null);
61 public static String getWhereExpression(Collection<Filter> filters, String controllerId) {
62 return getWhereExpression(filters, controllerId, null);
64 public static String getWhereExpression(Collection<Filter> filters, String controllerId, SqlDBSearchFilter allPropertyFilter) {
65 if (filters == null && controllerId == null) {
68 StringBuilder sb = new StringBuilder();
69 List<String> filters2 =
71 ? filters.stream().filter(e -> !isFilterEmpty(e)).map(e -> getFilterExpression(e))
72 .collect(Collectors.toList())
74 if (controllerId != null) {
75 filters2.add(getFilterExpression(SqlDBMapper.ODLID_DBCOL, controllerId));
77 if(allPropertyFilter!=null){
78 filters2.add(allPropertyFilter.getFilterExpression(true));
80 if (!filters2.isEmpty()) {
82 sb.append(StringUtil.join(" AND ", filters2));
87 private static String getFilterExpression(Filter filter) {
88 String property = filter.getProperty();
89 List<String> values = collectValues(filter.getFiltervalue(), filter.getFiltervalues()).stream()
90 .filter(e -> !"*".equals(e)).collect(Collectors.toList());
91 if (values.size() == 1) {
92 return getFilterExpression(property, values.get(0));
93 } else if (values.size() > 1) {
94 StringBuilder sb = new StringBuilder();
95 sb.append(getFilterExpression(property, values.get(0)));
96 for (int i = 1; i < values.size(); i++) {
98 sb.append(getFilterExpression(property, values.get(i)));
100 return sb.toString();
105 private static String getFilterExpression(String property, String value) {
106 String filter = null;
107 if (DbFilter.hasSearchParams(value)) {
108 if (TIMESTAMPPROPERTYNAMES.contains(property.toLowerCase())) {
109 if (DbFilter.isComparisonValid(value)) {
110 filter = getComparisonFilter(property, value, true);
112 filter = fromTimestampSearchFilter(property, value);
114 if (filter != null) {
118 return new RegexSqlDBFilter(property, value).getFilterExpression();
119 } else if (DbFilter.isComparisonValid(value)) {
120 filter = getComparisonFilter(property, value, TIMESTAMPPROPERTYNAMES.contains(property.toLowerCase()));
121 if (filter != null) {
125 return new DBFilterKeyValuePair(property, value).getFilterExpression();
128 private static List<String> collectValues(String filtervalue, Set<String> filtervalues) {
129 if (filtervalues == null) {
130 return Arrays.asList(filtervalue);
132 List<String> values = new ArrayList<>();
133 if (filtervalue != null) {
134 values.add(filtervalue);
136 values.addAll(filtervalues);
140 private static String getComparisonFilter(String property, String filtervalue, boolean asTimeStamp) {
141 filtervalue = filtervalue.trim();
142 String comparator = null;
144 if (filtervalue.startsWith(">=")) {
146 filtervalue = filtervalue.substring(2).trim();
148 filtervalue = netconfToMariaDBTimestamp(fillTimeStamp(
149 filtervalue.endsWith("*") ? filtervalue : (filtervalue + "*"), MARIADB_TIMESTAMP_REPLACER));
151 } else if (filtervalue.startsWith(">")) {
153 filtervalue = filtervalue.substring(1).trim();
155 if (isFullTimestamp(filtervalue)) {
156 filtervalue = netconfToMariaDBTimestamp(filtervalue);
159 filtervalue = netconfToMariaDBTimestamp(
160 fillTimeStamp(filtervalue.endsWith("*") ? filtervalue : (filtervalue + "*"),
161 NETCONF_TIMESTAMP_REPLACER, true));
164 } else if (filtervalue.startsWith("<=")) {
166 filtervalue = filtervalue.substring(2).trim();
168 if (isFullTimestamp(filtervalue)) {
169 filtervalue = netconfToMariaDBTimestamp(filtervalue);
172 filtervalue = netconfToMariaDBTimestamp(
173 fillTimeStamp(filtervalue.endsWith("*") ? filtervalue : (filtervalue + "*"),
174 NETCONF_TIMESTAMP_REPLACER, true));
177 } else if (filtervalue.startsWith("<")) {
179 filtervalue = filtervalue.substring(1).trim();
181 filtervalue = netconfToMariaDBTimestamp(fillTimeStamp(
182 filtervalue.endsWith("*") ? filtervalue : (filtervalue + "*"), MARIADB_TIMESTAMP_REPLACER));
188 return new RangeSqlDBFilter(property, value, comparator).getFilterExpression();
191 static boolean isFullTimestamp(String v) {
192 return v.length() >= MARIADB_TIMESTAMP_REPLACER_MIN_LENGTH;
196 * Convert timestamp beginning filter expression like 2017* to a full qualified timestamp like '2017-01-01
199 * @param value filter input value
200 * @return fully qualified timestamp
202 private static String fillTimeStamp(String value) {
203 return fillTimeStamp(value, NETCONF_TIMESTAMP_REPLACER);
206 private static String fillTimeStamp(String value, String replacer) {
207 return fillTimeStamp(value, replacer, false);
210 private static String fillTimeStamp(String value, String replacer, boolean useUpperEnd) {
211 int idx = value.lastIndexOf("*");
213 if (idx > replacer.length()) {
214 s = value.substring(0, replacer.length());
216 s = value.substring(0, idx) + replacer.substring(idx);
218 //if month is zero => set to 1
219 if (Integer.parseInt(s.substring(5, 7)) == 0) {
220 s = s.substring(0, 5) + "01-" + s.substring(8);
222 //if day is zero => set to 1
223 if (Integer.parseInt(s.substring(8, 10)) == 0) {
224 s = s.substring(0, 8) + "01" + s.substring(10);
227 s = getTimestampUpperLimit(s, idx);
233 * convert timestamp with ending placeholder in filter to elasticsearch filter e.g. 2017* => gte: 2017-01-01
234 * 00:00:00, lt:2018-01-01 00:00:00Z
236 * 201* => 2010-01... 2020 .. 2018-* => 2018-01... <=> 2019-01
239 private static @Nullable String fromTimestampSearchFilter(String property, String value) {
240 if (!value.endsWith("*")) {
243 int idx = value.lastIndexOf("*");
244 String lowerEnd = fillTimeStamp(value);
245 String upperEnd = getTimestampUpperLimit(fillTimeStamp(value, "0000-00-00T00:00:00.0Z"), idx);
246 return RangeSqlDBFilter.between(property, netconfToMariaDBTimestamp(lowerEnd), true,
247 netconfToMariaDBTimestamp(upperEnd), false);
250 private static String netconfToMariaDBTimestamp(String ts) {
254 String v = ts.replace("T", " ").replace("Z", "");
255 return v.length() > MARIADB_TIMESTAMP_REPLACER_MAX_LENGTH
256 ? v.substring(0, MARIADB_TIMESTAMP_REPLACER_MAX_LENGTH)
260 private static String getTimestampUpperLimit(String lowerEnd, int idx) {
262 String upperEnd = null;
263 NetconfTimeStamp converter = NetconfTimeStampImpl.getConverter();
266 dt = converter.getDateFromNetconf(lowerEnd);
267 } catch (Exception e) {
274 Calendar c = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
279 c.set(Calendar.YEAR, c.get(Calendar.YEAR) + 1000);
280 upperEnd = converter.getTimeStampAsNetconfString(c.getTime());
283 c.set(Calendar.YEAR, c.get(Calendar.YEAR) + 100);
284 upperEnd = converter.getTimeStampAsNetconfString(c.getTime());
287 c.set(Calendar.YEAR, c.get(Calendar.YEAR) + 10);
288 upperEnd = converter.getTimeStampAsNetconfString(c.getTime());
292 c.set(Calendar.YEAR, c.get(Calendar.YEAR) + 1);
293 upperEnd = converter.getTimeStampAsNetconfString(c.getTime());
295 case 6: // switch 10 months (2000-0* or 2000-1*)
296 tmpvalue = c.get(Calendar.MONTH);
298 c.set(Calendar.MONTH, 9);
300 c.set(Calendar.YEAR, c.get(Calendar.YEAR) + 1);
301 c.set(Calendar.MONTH, 0);
303 upperEnd = converter.getTimeStampAsNetconfString(c.getTime());
306 case 7: // switch one month (2018-01* or 2018-01-*)
308 c.add(Calendar.MONTH, 1);
309 upperEnd = converter.getTimeStampAsNetconfString(c.getTime());
311 case 9: // (2018-01-0*)
312 tmpvalue = c.get(Calendar.DAY_OF_MONTH);
314 c.set(Calendar.DAY_OF_MONTH, 10);
315 } else if (tmpvalue == 10) {
316 c.set(Calendar.DAY_OF_MONTH, 20);
317 } else if (tmpvalue == 20) {
318 if (c.getActualMaximum(Calendar.DAY_OF_MONTH) < 30) {
319 c.set(Calendar.DAY_OF_MONTH, 1);
320 c.add(Calendar.MONTH, 1);
322 c.set(Calendar.DAY_OF_MONTH, 30);
324 } else if (tmpvalue == 30) {
325 c.set(Calendar.DAY_OF_MONTH, 1);
326 c.add(Calendar.MONTH, 1);
330 upperEnd = converter.getTimeStampAsNetconfString(c.getTime());
332 case 10: // (2018-01-01*)
333 case 11: // (2018-01-01T*)
334 c.add(Calendar.DAY_OF_MONTH, 1);
335 upperEnd = converter.getTimeStampAsNetconfString(c.getTime());
337 case 12: // (2018-01-01T1*)
338 tmpvalue = c.get(Calendar.HOUR_OF_DAY);
339 if (tmpvalue == 20) {
340 c.set(Calendar.HOUR_OF_DAY, 0);
341 c.add(Calendar.DAY_OF_MONTH, 1);
343 c.add(Calendar.HOUR_OF_DAY, 10);
345 upperEnd = converter.getTimeStampAsNetconfString(c.getTime());
347 case 13: // (2018-01-01T11*)
348 case 14: // (2018-01-01T11-*)
349 c.add(Calendar.HOUR_OF_DAY, 1);
350 upperEnd = converter.getTimeStampAsNetconfString(c.getTime());
352 case 15: // (2018-01-01T11-3*)
353 c.add(Calendar.MINUTE, 10);
354 upperEnd = converter.getTimeStampAsNetconfString(c.getTime());
356 case 16: // (2018-01-01T11-32*)
357 case 17: // (2018-01-01T11-32-*)
358 c.add(Calendar.MINUTE, 1);
359 upperEnd = converter.getTimeStampAsNetconfString(c.getTime());
361 case 18: // (2018-01-01T11-32-1*)
362 c.add(Calendar.SECOND, 10);
363 upperEnd = converter.getTimeStampAsNetconfString(c.getTime());
365 case 19: // (2018-01-01T11-32-11*)
366 case 20: // (2018-01-01T11-32-11.*)
367 c.add(Calendar.SECOND, 1);
368 upperEnd = converter.getTimeStampAsNetconfString(c.getTime());
378 private static boolean isFilterEmpty(Filter filter) {
379 @Nullable Set<String> filtervalues = filter.getFiltervalues();
380 @Nullable String filtervalue = filter.getFiltervalue();
382 List<String> allValues = filtervalues == null ? new ArrayList<>() : new ArrayList<>(filtervalues);
383 if (filtervalue != null) {
384 allValues.add(filtervalue);
387 return allValues.isEmpty() || allValues.contains("*");