package edu.vanderbilt.vm.guide.util;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteException;
import edu.vanderbilt.vm.guide.annotations.NeedsTesting;
import edu.vanderbilt.vm.guide.container.Agenda;
import edu.vanderbilt.vm.guide.container.Place;
import edu.vanderbilt.vm.guide.container.Tour;
import edu.vanderbilt.vm.guide.db.GuideDBConstants;
import edu.vanderbilt.vm.guide.db.GuideDBConstants.TourTable;
/**
* Static helper methods to make querying the database easier
*
* @author nick
*/
@NeedsTesting(lastModifiedDate = "12/22/12")
public class DBUtils {
private static final Logger logger = LoggerFactory.getLogger("util.DBUtils");
/**
* Queries db for the place with the given uniqueId and creates a Place
* object to hold the result of the query.
*
* @param uniqueId The unique id of the place
* @param db The database to query
* @return The Place with the given uniqueId
*/
public static Place getPlaceById(int uniqueId, SQLiteDatabase db) {
Cursor cursor = db.query(GuideDBConstants.PlaceTable.PLACE_TABLE_NAME, null,
GuideDBConstants.PlaceTable.ID_COL + "=" + uniqueId, null, null, null, null);
if (!cursor.moveToFirst()) {
logger.warn("Got an empty cursor");
return null;
}
Place place = getPlaceFromCursor(cursor);
if (place == null) {
logger.warn("Could not find place with id {}", uniqueId);
}
return place;
}
public static String getPlaceNameById(int uniqueId, SQLiteDatabase db) {
Cursor cursor = db.query(GuideDBConstants.PlaceTable.PLACE_TABLE_NAME,
new String[] {GuideDBConstants.PlaceTable.NAME_COL},
GuideDBConstants.PlaceTable.ID_COL + "=" + uniqueId,
null, null, null, null);
if (!cursor.moveToFirst()) {
logger.warn("Got an empty cursor");
return "";
}
return cursor.getString(cursor.getColumnIndex(GuideDBConstants.PlaceTable.NAME_COL));
}
/**
* Queries db for all of the given place ids and returns an array of the
* places retrieved. <b>Use this method instead of getPlaceById if you need
* to get more than one place at a time.</b> Simply calling getPlaceById
* over and over will hammer the database with a bunch of unnecessary
* queries and result in poor performance.
*
* @param uniqueIds The ids to query the database for
* @param db The database to query
* @return An array of the places retrieved. Some places may be null if the
* they were not found.
*/
public static Place[] getPlaceArrayById(int[] uniqueIds, SQLiteDatabase db) {
if (uniqueIds == null || uniqueIds.length == 0) {
logger.warn("Got a bad unique ID array");
throw new IllegalArgumentException("You must give a non-null, non-empty array");
}
StringBuilder query = new StringBuilder("SELECT * FROM "
+ GuideDBConstants.PlaceTable.PLACE_TABLE_NAME + " WHERE "
+ GuideDBConstants.PlaceTable.ID_COL + " IN (");
for (int i : uniqueIds) {
query.append(i);
query.append(',');
}
query.deleteCharAt(query.length() - 1); // delete the trailing comma
query.append(')');
Cursor cursor = db.rawQuery(query.toString(), null);
if (!cursor.moveToFirst()) {
logger.warn("Got an empty cursor");
return null;
}
Place[] places = new Place[uniqueIds.length];
int i = 0;
while (!cursor.isAfterLast()) {
places[i] = getPlaceFromCursor(cursor);
cursor.moveToNext();
i++;
}
return places;
}
/**
* Creates a Place object from a cursor. The cursor should have come from a
* query to the places table in the sqlite database. This method will use
* the cursor at its current position.
*
* @param cursor The cursor to use to create the place
* @return The place created with the data in the cursor
*/
public static Place getPlaceFromCursor(Cursor cursor) {
Place.Builder bldr = new Place.Builder();
try {
int index = cursor.getColumnIndex(GuideDBConstants.PlaceTable.ID_COL);
if (index != -1) {
bldr.setUniqueId(cursor.getInt(index));
} else {
// This should never happen. We should always get an ID column
// back. If it does happen, something went wrong, so we want
// to abort and log an error message
logger.error("Got a cursor with no ID column!");
return null;
}
index = cursor.getColumnIndex(GuideDBConstants.PlaceTable.AUDIO_LOC_COL);
if (index != -1) {
bldr.setAudioLoc(cursor.getString(index));
}
index = cursor.getColumnIndex(GuideDBConstants.PlaceTable.CATEGORY_COL);
if (index != -1) {
bldr.addCategory(cursor.getString(index));
}
index = cursor.getColumnIndex(GuideDBConstants.PlaceTable.DESCRIPTION_COL);
if (index != -1) {
bldr.setDescription(cursor.getString(index));
}
index = cursor.getColumnIndex(GuideDBConstants.PlaceTable.HOURS_COL);
if (index != -1) {
bldr.setHours(cursor.getString(index));
}
index = cursor.getColumnIndex(GuideDBConstants.PlaceTable.IMAGE_LOC_COL);
if (index != -1) {
bldr.setImageLoc(cursor.getString(index));
}
index = cursor.getColumnIndex(GuideDBConstants.PlaceTable.LATITUDE_COL);
if (index != -1) {
bldr.setLatitude(cursor.getDouble(index));
}
index = cursor.getColumnIndex(GuideDBConstants.PlaceTable.LONGITUDE_COL);
if (index != -1) {
bldr.setLongitude(cursor.getDouble(index));
}
index = cursor.getColumnIndex(GuideDBConstants.PlaceTable.NAME_COL);
if (index != -1) {
bldr.setName(cursor.getString(index));
}
index = cursor.getColumnIndex(GuideDBConstants.PlaceTable.VIDEO_LOC_COL);
if (index != -1) {
bldr.setVideoLoc(cursor.getString(index));
}
} catch (Exception e) {
logger.error("Caught exception while trying to " + "create place from a cursor: ", e);
return null;
}
return bldr.build();
}
/**
* Creates a Tour object from a cursor containing a query to the Tour table.
* Uses the Cursor at its current position.
* <p/>
* Precondition: cursor must contain an id column
*
* @param cursor The cursor to use
* @param db The database to inflate the Places on the tour from
* @return a Tour containing the attributes in the cursor
*/
@NeedsTesting(lastModifiedDate = "12/23/12")
public static Tour getTourFromCursor(Cursor cursor, SQLiteDatabase db) {
Tour.Builder bldr = new Tour.Builder();
int index = cursor.getColumnIndex(TourTable.ID_COL);
if (index == -1) {
throw new SQLiteException("Your cursor must contain an id column");
}
int tourId = cursor.getInt(index);
bldr.setUniqueId(tourId);
index = cursor.getColumnIndex(TourTable.PLACES_ON_TOUR_COL);
if (index != -1) {
String placeIds = cursor.getString(index);
try {
bldr.setAgenda(getAgendaFromIds(placeIds, db));
} catch (NumberFormatException e) {
logger.error("A place ID stored in the cursor of tour with id: " + tourId
+ " is not formatted as an integer", e);
logger.error("String that caused error: {}", placeIds);
}
}
index = cursor.getColumnIndex(TourTable.DESCRIPTION_COL);
if (index != -1) {
String description = cursor.getString(index);
bldr.setDescription(description);
}
index = cursor.getColumnIndex(TourTable.DISTANCE_COL);
if (index != -1) {
String distance = cursor.getString(index);
bldr.setDistance(distance);
}
index = cursor.getColumnIndex(TourTable.ICON_LOC_COL);
if (index != -1) {
String iconLoc = cursor.getString(index);
bldr.setIconLoc(iconLoc);
}
index = cursor.getColumnIndex(TourTable.NAME_COL);
if (index != -1) {
String name = cursor.getString(index);
bldr.setName(name);
}
index = cursor.getColumnIndex(TourTable.TIME_REQUIRED_COL);
if (index != -1) {
String timeReq = cursor.getString(index);
bldr.setTimeReq(timeReq);
}
return bldr.build();
}
/**
* Makes an Agenda from a comma delimited String of place ids
*
* @param placeIds The comma delimited String of place ids
* @param db The database to query for the places
* @return an Agenda filled with places matching the given ids
*/
public static Agenda getAgendaFromIds(String placeIds, SQLiteDatabase db) {
if (placeIds == null || placeIds.equals("")) {
return new Agenda(); // Empty Agenda
}
String[] placeIdStrings = placeIds.split(",");
int[] placeIdInts = new int[placeIdStrings.length];
{
for (int i = 0; i < placeIdStrings.length; i++) {
placeIdInts[i] = Integer.parseInt(placeIdStrings[i]);
}
}
return getAgendaFromIds(placeIdInts, db);
}
/**
* Makes an Agenda from an integer array of place ids
*
* @param placeIds The array of place ids
* @param db The database to query for the places
* @return an Agenda filled with places matching the given ids
*/
public static Agenda getAgendaFromIds(int[] placeIds, SQLiteDatabase db) {
if (placeIds == null || placeIds.length == 0) {
return new Agenda(); // Empty Agenda
}
Place[] placeArr = getPlaceArrayById(placeIds, db);
Agenda agenda = new Agenda();
for (Place place : placeArr) {
agenda.add(place);
}
return agenda;
}
/**
* Convenience method to query the places table of the database for all
* places. Ask for only the columns needed; passing null will return all
* columns, which will most likely just waste memory.
*
* @param columns The columns to query for
* @param db The database to query
* @return A Cursor of call places in the database with the given columns
*/
public static Cursor getAllPlaces(String[] columns, SQLiteDatabase db) {
return db.query(
GuideDBConstants.PlaceTable.PLACE_TABLE_NAME,
columns,
null, null, null, null,
GuideDBConstants.PlaceTable.NAME_COL);
}
}