Fix 'frequency' statistics for the trigger to emit proper results
[platform/core/context/statistics-context-provider.git] / src / shared / db_handle_base.cpp
1 /*
2  * Copyright (c) 2015 Samsung Electronics Co., Ltd.
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 <sstream>
18 #include <types_internal.h>
19 #include <context_mgr.h>
20 #include <db_mgr.h>
21 #include "common_types.h"
22 #include "db_handle_base.h"
23
24 #define DAY_OF_WEEK(SECOND) "CAST(strftime('%w', " SECOND ", 'unixepoch') AS INTEGER)"
25 #define HOUR_OF_DAY(SECOND) "CAST(strftime('%H', " SECOND ", 'unixepoch') AS INTEGER)"
26
27 ctx::stats_db_handle_base::stats_db_handle_base(const char* zone)
28         : is_trigger_item(false)
29         , req_zone(zone)
30 {
31 }
32
33 ctx::stats_db_handle_base::~stats_db_handle_base()
34 {
35 }
36
37 int ctx::stats_db_handle_base::generate_qid()
38 {
39         static int qid = 0;
40
41         if (qid++ < 0) qid = 1;
42         return qid;
43 }
44
45 bool ctx::stats_db_handle_base::execute_query(const char* subject, ctx::json filter, const char* query)
46 {
47         bool ret = db_manager::execute(generate_qid(), query, this);
48         IF_FAIL_RETURN(ret, false);
49
50         req_subject = subject;
51         req_filter = filter;
52
53         return true;
54 }
55
56 std::string ctx::stats_db_handle_base::create_where_clause(ctx::json filter)
57 {
58         std::stringstream where_clause;
59         int week = 0;
60         int start = 0;
61         int end = 0;
62         int timespan = DEFAULT_TIMESPAN;
63         std::string app_id;
64         std::string week_str;
65         std::string time_of_day;
66
67         if (filter.get(NULL, STATS_DAY_OF_WEEK, &week_str)) {
68                 // In case of string (from Trigger)
69                 if (week_str == STATS_WEEKDAY) {
70                         week = STATS_DAY_OF_WEEK_WEEKDAY;
71
72                 } else if (week_str == STATS_WEEKEND) {
73                         week = STATS_DAY_OF_WEEK_WEEKEND;
74
75                 } else if (week_str == STATS_SUN) {
76                         week = STATS_DAY_OF_WEEK_SUN;
77
78                 } else if (week_str == STATS_MON) {
79                         week = STATS_DAY_OF_WEEK_MON;
80
81                 } else if (week_str == STATS_TUE) {
82                         week = STATS_DAY_OF_WEEK_TUE;
83
84                 } else if (week_str == STATS_WED) {
85                         week = STATS_DAY_OF_WEEK_WED;
86
87                 } else if (week_str == STATS_THU) {
88                         week = STATS_DAY_OF_WEEK_THU;
89
90                 } else if (week_str == STATS_FRI) {
91                         week = STATS_DAY_OF_WEEK_FRI;
92
93                 } else if (week_str == STATS_SAT) {
94                         week = STATS_DAY_OF_WEEK_SAT;
95                 }
96         } else {
97                 // In case of integer (from History)
98                 filter.get(NULL, STATS_DAY_OF_WEEK, &week);
99         }
100
101         switch(week) {
102         case STATS_DAY_OF_WEEK_WEEKDAY:
103                 where_clause << "(" DAY_OF_WEEK(STATS_LOCAL_TIME) " > 0 AND " DAY_OF_WEEK(STATS_LOCAL_TIME) " < 6) AND ";
104                 break;
105         case STATS_DAY_OF_WEEK_WEEKEND:
106                 where_clause << "(" DAY_OF_WEEK(STATS_LOCAL_TIME) " = 0 OR " DAY_OF_WEEK(STATS_LOCAL_TIME) " = 6) AND ";
107                 break;
108         case STATS_DAY_OF_WEEK_SUN:
109         case STATS_DAY_OF_WEEK_MON:
110         case STATS_DAY_OF_WEEK_TUE:
111         case STATS_DAY_OF_WEEK_WED:
112         case STATS_DAY_OF_WEEK_THU:
113         case STATS_DAY_OF_WEEK_FRI:
114         case STATS_DAY_OF_WEEK_SAT:
115                 where_clause << DAY_OF_WEEK(STATS_LOCAL_TIME) " = " << week - STATS_DAY_OF_WEEK_SUN << " AND ";
116                 break;
117         default:
118                 break;
119         }
120
121         if (filter.get(NULL, STATS_APP_ID, &app_id))
122                 where_clause << STATS_APP_ID " = '" << app_id << "' AND ";
123
124         if (filter.get(NULL, STATS_START_TIME, &start))
125                 where_clause << STATS_UNIV_TIME " >= " << start << " AND ";
126
127         if (filter.get(NULL, STATS_END_TIME, &end))
128                 where_clause << STATS_UNIV_TIME " <= " << end << " AND ";
129
130         if (filter.get(NULL, STATS_TIME_OF_DAY, &time_of_day)) {
131                 size_t pivot = time_of_day.find('-');
132                 if (pivot != std::string::npos) {
133                         std::string from = time_of_day.substr(0, pivot);
134                         std::string to = time_of_day.substr(pivot + 1);
135                         where_clause << "(" HOUR_OF_DAY(STATS_LOCAL_TIME) " >= " << from \
136                                 << " AND " HOUR_OF_DAY(STATS_LOCAL_TIME) " < " << to << ") AND ";
137                 }
138         }
139
140         filter.get(NULL, STATS_TIMESPAN, &timespan);
141         where_clause << STATS_UNIV_TIME " > strftime('%s', 'now', '-" << timespan <<" day')";
142
143         return where_clause.str();
144 }
145
146 std::string ctx::stats_db_handle_base::create_sql_peak_time(ctx::json filter, const char* table_name, std::string where_clause)
147 {
148         std::stringstream query;
149         int limit = DEFAULT_LIMIT;
150
151         filter.get(NULL, STATS_RESULT_SIZE, &limit);
152
153         query <<
154                 "SELECT " \
155                         HOUR_OF_DAY(STATS_LOCAL_TIME) " AS " STATS_HOUR_OF_DAY ", COUNT(*) AS " STATS_TOTAL_COUNT \
156                 " FROM " << table_name << \
157                 " WHERE " << where_clause << \
158                 " GROUP BY " HOUR_OF_DAY(STATS_LOCAL_TIME) \
159                 " ORDER BY " STATS_TOTAL_COUNT " DESC" \
160                 " LIMIT " << limit;
161
162         return query.str();
163 }
164
165 std::string ctx::stats_db_handle_base::create_sql_common_setting(ctx::json filter, const char* table_name, std::string where_clause)
166 {
167         std::stringstream query;
168
169         query <<
170                 "SELECT ( SELECT " STATS_AUDIO_JACK \
171                                 " FROM " << table_name << \
172                                 " WHERE " << where_clause << \
173                                 " GROUP BY " STATS_AUDIO_JACK \
174                                 " ORDER BY count(" STATS_AUDIO_JACK ") DESC" \
175                                 " LIMIT 1 ) AS " STATS_AUDIO_JACK \
176                         ", ( SELECT " STATS_SYSTEM_VOLUME \
177                                 " FROM " << table_name << \
178                                 " WHERE " << where_clause << \
179                                 " GROUP BY " STATS_SYSTEM_VOLUME \
180                                 " ORDER BY count(" STATS_SYSTEM_VOLUME ") DESC" \
181                                 " LIMIT 1 ) AS " STATS_SYSTEM_VOLUME \
182                         ", ( SELECT " STATS_MEDIA_VOLUME \
183                                 " FROM " << table_name << \
184                                 " WHERE " << where_clause << \
185                                 " GROUP BY " STATS_MEDIA_VOLUME \
186                                 " ORDER BY count(" STATS_MEDIA_VOLUME ") DESC" \
187                                 " LIMIT 1 ) AS " STATS_MEDIA_VOLUME;
188
189         return query.str();
190 }
191
192 void ctx::stats_db_handle_base::on_creation_result_received(unsigned int query_id, int error)
193 {
194 }
195
196 void ctx::stats_db_handle_base::on_insertion_result_received(unsigned int query_id, int error, int64_t row_id)
197 {
198         delete this;
199 }
200
201 void ctx::stats_db_handle_base::json_vector_to_array(std::vector<json> &vec_json, ctx::json &json_result)
202 {
203         std::vector<json>::iterator json_vec_end = vec_json.end();
204
205         for(std::vector<json>::iterator json_vec_pos = vec_json.begin(); json_vec_pos != json_vec_end; ++json_vec_pos) {
206                 json origin_j = *json_vec_pos;
207                 json_result.array_append(NULL, STATS_QUERY_RESULT, origin_j);
208         }
209 }
210
211 void ctx::stats_db_handle_base::on_query_result_received(unsigned int query_id, int error, std::vector<json>& records)
212 {
213         if (is_trigger_item) {
214                 if (records.size() == 1) {
215                         context_manager::reply_to_read(req_subject.c_str(), req_filter, error, records[0], req_zone.c_str());
216                 } else {
217                         _E("Invalid query result");
218                         json dummy;
219                         context_manager::reply_to_read(req_subject.c_str(), req_filter, ERR_OPERATION_FAILED, dummy, req_zone.c_str());
220                 }
221         } else {
222                 json results = "{\"" STATS_QUERY_RESULT "\":[]}";
223                 json_vector_to_array(records, results);
224                 context_manager::reply_to_read(req_subject.c_str(), req_filter, error, results, req_zone.c_str());
225         }
226
227         delete this;
228 }