#include #include #include #include #include #include #include #include #include #include #include #include static int db_update_insert(relay_t *relay, sqlite3_stmt *stmt) { int rc; sqlite3_bind_int(stmt, 1, relay->id); sqlite3_bind_int(stmt, 2, relay->number); sqlite3_bind_text(stmt, 3, relay->name, -1, SQLITE_STATIC); sqlite3_bind_int(stmt, 4, relay->controller_id); rc = sqlite3_step(stmt); sqlite3_finalize(stmt); return rc != SQLITE_DONE; } static relay_t* relay_db_select_mapper(sqlite3_stmt *stmt) { relay_t *new_relay = malloc(sizeof(relay_t)); for(int i = 0; i < sqlite3_column_count(stmt); i++) { const char *name = sqlite3_column_name(stmt, i); switch(name[0]) { case 'c': // controller_id new_relay->controller_id = sqlite3_column_int(stmt, i); break; case 'i': new_relay->id = sqlite3_column_int(stmt, i); break; case 'n': switch(name[1]) { case 'a': // name strncpy(new_relay->name, (const char*)sqlite3_column_text(stmt, i), 127); break; case 'u': // number new_relay->number = sqlite3_column_int(stmt, i); break; default: break; } break; default: // ignore columns not implemented break; } } schedule_t **schedules = schedule_get_relay_weekdays(new_relay->id); for(int i = 0; i < 7; ++i) { if(schedules[i] == NULL) { LOG_ERROR("got only %d/7 schedules for relay_id %d\n", i, new_relay->id); relay_free(new_relay); free(schedules); return NULL; } new_relay->schedules[i] = schedules[i]; } free(schedules); // don't free list, because contents are kept in relay->schedules relay_reload_active_schedule(new_relay); return new_relay; } static relay_t** relay_db_select(sqlite3_stmt *stmt) { relay_t **all_relays = malloc(sizeof(relay_t*)); int row = 0; while(true) { int s; s = sqlite3_step(stmt); if (s == SQLITE_ROW) { relay_t *new_relay = relay_db_select_mapper(stmt); row++; all_relays = (relay_t**)realloc(all_relays, sizeof(relay_t*) * (row + 1)); all_relays[row - 1] = new_relay; } else { if(s == SQLITE_DONE) { break; } else { LOG_ERROR("error selecting relays from database: %s\n", sqlite3_errstr(s)); break; } } } sqlite3_finalize(stmt); all_relays[row] = NULL; return all_relays; } int relay_save(relay_t *relay) { sqlite3_stmt *stmt; if(relay->id) { sqlite3_prepare_v2(global_database, "UPDATE relays set number = ?2, name = ?3, controller_id = ?4 WHERE id = ?1;", -1, &stmt, NULL); } else { sqlite3_prepare_v2(global_database, "INSERT INTO relays(number, name, controller_id) values (?2, ?3, ?4);", -1, &stmt, NULL); } int result = db_update_insert(relay, stmt); if(result) { if(relay->id) { LOG_ERROR("error inserting data: %s\n", sqlite3_errmsg(global_database)); } else { LOG_ERROR("error updating data: %s\n", sqlite3_errmsg(global_database)); } } else { if(relay->id == 0) { relay->id = sqlite3_last_insert_rowid(global_database); } } junction_relay_schedule_remove_for_relay(relay->id); for(int i = 0; i < 7; ++i) { junction_relay_schedule_insert(i, relay->id, relay->schedules[i]->id); } return result; } int relay_remove(relay_t *relay) { sqlite3_stmt *stmt; if(!relay->id) { return 0; } sqlite3_prepare_v2(global_database, "DELETE FROM relays WHERE id=?1;", -1, &stmt, NULL); sqlite3_bind_int(stmt, 1, relay->id); int rc = sqlite3_step(stmt); sqlite3_finalize(stmt); return rc != SQLITE_DONE; } void relay_reload_active_schedule(relay_t *relay) { time_t timestamp = time(NULL); struct tm *time_struct = localtime(×tamp); relay->active_schedule = relay->schedules[helper_get_weekday(time_struct)]; } void relay_free(relay_t *relay) { for(int i = 0; i < 7; ++i) { schedule_free(relay->schedules[i]); } free(relay); } void relay_free_list(relay_t **relays) { for(int i = 0; relays[i] != NULL; ++i) { relay_free(relays[i]); } free(relays); } cJSON* relay_to_json(relay_t *relay) { relay_reload_active_schedule(relay); cJSON *json = cJSON_CreateObject(); cJSON *json_number = cJSON_CreateNumber(relay->number); if(json_number == NULL) { LOG_DEBUG("failed to make number\n"); cJSON_Delete(json); return NULL; } cJSON_AddItemToObject(json, "number", json_number); cJSON *json_name = cJSON_CreateString(relay->name); if(json_name == NULL) { LOG_DEBUG("failed to make name\n"); cJSON_Delete(json); return NULL; } cJSON_AddItemToObject(json, "name", json_name); controller_t *controller = controller_get_by_id(relay->controller_id); if(!controller) { LOG_WARN("failed to get controller\n"); cJSON_Delete(json); return NULL; } char uuid_str[UUID_STR_LEN]; uuid_unparse(controller->uid, uuid_str); cJSON *json_controller_id = cJSON_CreateString(uuid_str); if(json_controller_id == NULL) { LOG_DEBUG("failed to make controller id\n"); cJSON_Delete(json); return NULL; } cJSON_AddItemToObject(json, "controller_id", json_controller_id); controller_free(controller); cJSON_AddItemToObject(json, "active_schedule", schedule_to_json(relay->active_schedule)); cJSON *json_schedules = cJSON_CreateArray(); for(int i = 0; i < 7; ++i) { cJSON_AddItemToArray(json_schedules, schedule_to_json(relay->schedules[i])); } cJSON_AddItemToObject(json, "schedules", json_schedules); cJSON *json_tags = cJSON_CreateArray(); int *tags_ids = junction_tag_get_tags_for_relay_id(relay->id); if(tags_ids != NULL) { for(int i = 0; tags_ids[i] != 0; ++i) { char *tag = tag_get_tag(tags_ids[i]); if(tag == NULL) { continue; } cJSON *json_tag = cJSON_CreateString(tag); if (json_tag == NULL) { LOG_DEBUG("failed to add tag from string '%s'\n", tag); free(tag); continue; } cJSON_AddItemToArray(json_tags, json_tag); free(tag); } free(tags_ids); } cJSON_AddItemToObject(json, "tags", json_tags); return json; } relay_t* relay_get_by_id(int id) { sqlite3_stmt *stmt; sqlite3_prepare_v2(global_database, "SELECT * FROM relays WHERE id = ?1;", -1, &stmt, NULL); sqlite3_bind_int(stmt, 1, id); relay_t **sql_result = relay_db_select(stmt); relay_t *result = sql_result[0]; free(sql_result); return result; } relay_t* relay_get_by_uid(uuid_t uid) { sqlite3_stmt *stmt; sqlite3_prepare_v2(global_database, "SELECT * FROM relays WHERE uid = ?1;", -1, &stmt, NULL); sqlite3_bind_blob(stmt, 1, uid, sizeof(uuid_t), SQLITE_STATIC); relay_t **sql_result = relay_db_select(stmt); relay_t *result = sql_result[0]; free(sql_result); return result; } relay_t** relay_get_all() { sqlite3_stmt *stmt; sqlite3_prepare_v2(global_database, "SELECT * FROM relays;", -1, &stmt, NULL); return relay_db_select(stmt); } relay_t** relay_get_with_schedule(int schedule_id) { sqlite3_stmt *stmt; sqlite3_prepare_v2(global_database, "SELECT DISTINCT relays.* FROM relays INNER JOIN junction_relay_schedule ON relays.id == junction_relay_schedule.relay_id WHERE junction_relay_schedule.schedule_id = ?1;", -1, &stmt, NULL); sqlite3_bind_int(stmt, 1, schedule_id); return relay_db_select(stmt); } relay_t* relay_get_for_controller(int controller_id, int relay_num) { sqlite3_stmt *stmt; sqlite3_prepare_v2(global_database, "SELECT * FROM relays WHERE controller_id = ?1 AND number = ?2;", -1, &stmt, NULL); sqlite3_bind_int(stmt, 1, controller_id); sqlite3_bind_int(stmt, 2, relay_num); relay_t **sql_result = relay_db_select(stmt); relay_t *result = sql_result[0]; free(sql_result); return result; } relay_t** relay_get_by_controller_id(int controller_id) { sqlite3_stmt *stmt; sqlite3_prepare_v2(global_database, "SELECT * FROM relays WHERE controller_id = ?1;", -1, &stmt, NULL); sqlite3_bind_int(stmt, 1, controller_id); return relay_db_select(stmt); }