SQLite.java revision e33dc87ec6782df9a3711d06c687521ff2a97d86
1package com.xtremelabs.robolectric.util; 2 3import android.content.ContentValues; 4import android.database.sqlite.SQLiteException; 5 6import java.util.ArrayList; 7import java.util.Iterator; 8import java.util.List; 9import java.util.Map.Entry; 10 11/** 12 * SQL utility methods to support the database-related shadows, such as 13 * {@code ShadowSQLiteDatabase} and {@code ShadowSQLiteCursor}. 14 */ 15public class SQLite { 16 17 /** 18 * Create a SQL INSERT string. Returned values are then bound via 19 * JDBC to facilitate various data types. 20 * 21 * @param table table name 22 * @param values column name/value pairs 23 * @return insert string 24 */ 25 public static SQLStringAndBindings buildInsertString(String table, ContentValues values) { 26 StringBuilder sb = new StringBuilder(); 27 28 sb.append("INSERT INTO "); 29 sb.append(table); 30 sb.append(" "); 31 32 SQLStringAndBindings columnsValueClause = buildColumnValuesClause(values); 33 sb.append(columnsValueClause.sql); 34 sb.append(";"); 35 36 return new SQLStringAndBindings(sb.toString(), columnsValueClause.columnValues); 37 } 38 39 /** 40 * Create a SQL UPDATE string. Returned values are then bound via 41 * JDBC to facilitate various data types. 42 * 43 * @param table table name 44 * @param values column name/value pairs 45 * @param whereClause SQL where clause fragment 46 * @param whereArgs Array of substitutions for args in whereClause 47 * @return update string 48 */ 49 public static SQLStringAndBindings buildUpdateString(String table, ContentValues values, String whereClause, String[] whereArgs) { 50 StringBuilder sb = new StringBuilder(); 51 52 sb.append("UPDATE "); 53 sb.append(table); 54 sb.append(" SET "); 55 56 SQLStringAndBindings columnAssignmentsClause = buildColumnAssignmentsClause(values); 57 sb.append(columnAssignmentsClause.sql); 58 59 if (whereClause != null) { 60 String where = whereClause; 61 if (whereArgs != null) { 62 where = buildWhereClause(whereClause, whereArgs); 63 } 64 sb.append(" WHERE "); 65 sb.append(where); 66 } 67 sb.append(";"); 68 69 return new SQLStringAndBindings(sb.toString(), columnAssignmentsClause.columnValues); 70 } 71 72 /** 73 * Create a SQL DELETE string. 74 * 75 * @param table table name 76 * @param whereClause SQL where clause fragment 77 * @param whereArgs Array of substitutions for args in whereClause 78 * @return delete string 79 */ 80 public static String buildDeleteString(String table, String whereClause, String[] whereArgs) { 81 StringBuilder sb = new StringBuilder(); 82 83 sb.append("DELETE FROM "); 84 sb.append(table); 85 86 if (whereClause != null) { 87 String where = whereClause; 88 if (whereArgs != null) { 89 where = buildWhereClause(whereClause, whereArgs); 90 } 91 sb.append(" WHERE "); 92 sb.append(where); 93 } 94 sb.append(";"); 95 96 return sb.toString(); 97 } 98 99 /** 100 * Build a WHERE clause used in SELECT, UPDATE and DELETE statements. 101 * 102 * @param selection SQL where clause fragment 103 * @param selectionArgs Array of substitutions for args in selection 104 * @return where clause 105 */ 106 public static String buildWhereClause(String selection, String[] selectionArgs) throws SQLiteException { 107 String whereClause = selection; 108 int argsNeeded = 0; 109 int args = 0; 110 111 for (String selectionArg : selectionArgs) { 112 if (selectionArg!=null)args++; 113 whereClause = whereClause.replaceFirst("\\?", "'" + selectionArg + "'"); 114 } 115 116 for (char c : selection.toCharArray()) { 117 if (c=='?') argsNeeded++; 118 } 119 120 if (argsNeeded<args) throw new SQLiteException("bind or column index out of range: too many selectionArgs for the given sql statement!"); 121 122 123 return whereClause; 124 } 125 126 /** 127 * Build the '(columns...) VALUES (values...)' clause used in INSERT 128 * statements. 129 * 130 * @param values column name/value pairs 131 * @return SQLStringAndBindings 132 */ 133 public static SQLStringAndBindings buildColumnValuesClause(ContentValues values) { 134 StringBuilder clause = new StringBuilder("("); 135 List<Object> columnValues = new ArrayList<Object>(values.size()); 136 137 Iterator<Entry<String, Object>> itemEntries = values.valueSet().iterator(); 138 while (itemEntries.hasNext()) { 139 Entry<String, Object> entry = itemEntries.next(); 140 clause.append(entry.getKey()); 141 if (itemEntries.hasNext()) { 142 clause.append(", "); 143 } 144 columnValues.add(entry.getValue()); 145 } 146 147 clause.append(") VALUES ("); 148 for (int i = 0; i < values.size() - 1; i++) { 149 clause.append("?, "); 150 } 151 clause.append("?)"); 152 153 return new SQLStringAndBindings(clause.toString(), columnValues); 154 } 155 156 /** 157 * Build the '(col1=?, col2=? ... )' clause used in UPDATE statements. 158 * 159 * @param values column name/value pairs 160 * @return SQLStringAndBindings 161 */ 162 public static SQLStringAndBindings buildColumnAssignmentsClause(ContentValues values) { 163 StringBuilder clause = new StringBuilder(); 164 List<Object> columnValues = new ArrayList<Object>(values.size()); 165 166 Iterator<Entry<String, Object>> itemsEntries = values.valueSet().iterator(); 167 while (itemsEntries.hasNext()) { 168 Entry<String, Object> entry = itemsEntries.next(); 169 clause.append(entry.getKey()); 170 clause.append("=?"); 171 if (itemsEntries.hasNext()) { 172 clause.append(", "); 173 } 174 columnValues.add(entry.getValue()); 175 } 176 177 return new SQLStringAndBindings(clause.toString(), columnValues); 178 } 179 180 /** 181 * Container for a SQL fragment and the objects which are to be 182 * bound to the arguments in the fragment. 183 */ 184 public static class SQLStringAndBindings { 185 public String sql; 186 public List<Object> columnValues; 187 188 public SQLStringAndBindings(String sql, List<Object> columnValues) { 189 this.sql = sql; 190 this.columnValues = columnValues; 191 } 192 } 193 194} 195