e06405067d8bb4d144c9ebf1e41e498758468823
[Sunshine.git] / app / src / main / java / uk / me / njae / sunshine / data / WeatherProvider.java
1 package uk.me.njae.sunshine.data;
2
3 import android.content.ContentProvider;
4 import android.content.ContentUris;
5 import android.content.ContentValues;
6 import android.content.UriMatcher;
7 import android.database.Cursor;
8 import android.database.sqlite.SQLiteDatabase;
9 import android.database.sqlite.SQLiteQueryBuilder;
10 import android.net.Uri;
11
12 /**
13 * Created by neil on 09/11/14.
14 */
15 public class WeatherProvider extends ContentProvider {
16
17 // The URI Matcher used by this content provider.
18 private static final UriMatcher sUriMatcher = buildUriMatcher();
19
20 private static final int WEATHER = 100;
21 private static final int WEATHER_WITH_LOCATION = 101;
22 private static final int WEATHER_WITH_LOCATION_AND_DATE = 102;
23 private static final int LOCATION = 300;
24 private static final int LOCATION_ID = 301;
25
26 private WeatherDbHelper mOpenHelper;
27
28 private static UriMatcher buildUriMatcher() {
29 // I know what you're thinking. Why create a UriMatcher when you can use regular
30 // expressions instead? Because you're not crazy, that's why.
31
32 // All paths added to the UriMatcher have a corresponding code to return when a match is
33 // found. The code passed into the constructor represents the code to return for the root
34 // URI. It's common to use NO_MATCH as the code for this case.
35 final UriMatcher matcher = new UriMatcher(UriMatcher.NO_MATCH);
36 final String authority = WeatherContract.CONTENT_AUTHORITY;
37
38 // For each type of URI you want to add, create a corresponding code.
39 matcher.addURI(authority, WeatherContract.PATH_WEATHER, WEATHER);
40 matcher.addURI(authority, WeatherContract.PATH_WEATHER + "/*", WEATHER_WITH_LOCATION);
41 matcher.addURI(authority, WeatherContract.PATH_WEATHER + "/*/*", WEATHER_WITH_LOCATION_AND_DATE);
42
43 matcher.addURI(authority, WeatherContract.PATH_LOCATION, LOCATION);
44 matcher.addURI(authority, WeatherContract.PATH_LOCATION + "/#", LOCATION_ID);
45
46 return matcher;
47 }
48
49
50 private static final SQLiteQueryBuilder sWeatherByLocationSettingQueryBuilder;
51
52 static {
53 sWeatherByLocationSettingQueryBuilder = new SQLiteQueryBuilder();
54 sWeatherByLocationSettingQueryBuilder.setTables(
55 WeatherContract.WeatherEntry.TABLE_NAME + " INNER JOIN " +
56 WeatherContract.LocationEntry.TABLE_NAME +
57 " ON " + WeatherContract.WeatherEntry.TABLE_NAME +
58 "." + WeatherContract.WeatherEntry.COLUMN_LOC_KEY +
59 " = " + WeatherContract.LocationEntry.TABLE_NAME +
60 "." + WeatherContract.LocationEntry._ID);
61 }
62
63 private static final String sLocationSettingSelection =
64 WeatherContract.LocationEntry.TABLE_NAME+
65 "." + WeatherContract.LocationEntry.COLUMN_LOCATION_SETTING + " = ? ";
66 private static final String sLocationSettingWithStartDateSelection =
67 WeatherContract.LocationEntry.TABLE_NAME+
68 "." + WeatherContract.LocationEntry.COLUMN_LOCATION_SETTING + " = ? AND " +
69 WeatherContract.WeatherEntry.COLUMN_DATETEXT + " >= ? ";
70 private static final String sLocationSettingAndDaySelection =
71 WeatherContract.LocationEntry.TABLE_NAME +
72 "." + WeatherContract.LocationEntry.COLUMN_LOCATION_SETTING + " = ? AND " +
73 WeatherContract.WeatherEntry.COLUMN_DATETEXT + " = ? ";
74
75 private Cursor getWeatherByLocationSetting(Uri uri, String[] projection, String sortOrder) {
76 String locationSetting = WeatherContract.WeatherEntry.getLocationSettingFromUri(uri);
77 String startDate = WeatherContract.WeatherEntry.getStartDateFromUri(uri);
78
79 String[] selectionArgs;
80 String selection;
81
82 if (startDate == null) {
83 selection = sLocationSettingSelection;
84 selectionArgs = new String[]{locationSetting};
85 } else {
86 selectionArgs = new String[]{locationSetting, startDate};
87 selection = sLocationSettingWithStartDateSelection;
88 }
89
90 return sWeatherByLocationSettingQueryBuilder.query(mOpenHelper.getReadableDatabase(),
91 projection,
92 selection,
93 selectionArgs,
94 null,
95 null,
96 sortOrder
97 );
98 }
99
100 private Cursor getWeatherByLocationSettingAndDate(
101 Uri uri, String[] projection, String sortOrder) {
102 String locationSetting = WeatherContract.WeatherEntry.getLocationSettingFromUri(uri);
103 String date = WeatherContract.WeatherEntry.getDateFromUri(uri);
104
105 return sWeatherByLocationSettingQueryBuilder.query(mOpenHelper.getReadableDatabase(),
106 projection,
107 sLocationSettingAndDaySelection,
108 new String[]{locationSetting, date},
109 null,
110 null,
111 sortOrder
112 );
113 }
114
115 @Override
116 public boolean onCreate() {
117 mOpenHelper = new WeatherDbHelper(getContext());
118 return true;
119 }
120
121 @Override
122 public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
123 String sortOrder) {
124 // Here's the switch statement that, given a URI, will determine what kind of request it is,
125 // and query the database accordingly.
126 Cursor retCursor;
127 switch (sUriMatcher.match(uri)) {
128 // "weather/*/*"
129 case WEATHER_WITH_LOCATION_AND_DATE:
130 {
131 retCursor = getWeatherByLocationSettingAndDate(uri, projection, sortOrder);
132 break;
133 }
134 // "weather/*"
135 case WEATHER_WITH_LOCATION: {
136 retCursor = getWeatherByLocationSetting(uri, projection, sortOrder);
137 break;
138 }
139 // "weather"
140 case WEATHER: {
141 retCursor = mOpenHelper.getReadableDatabase().query(
142 WeatherContract.WeatherEntry.TABLE_NAME,
143 projection,
144 selection,
145 selectionArgs,
146 null,
147 null,
148 sortOrder
149 );
150 break;
151 }
152 // "location/*"
153 case LOCATION_ID: {
154 retCursor = mOpenHelper.getReadableDatabase().query(
155 WeatherContract.LocationEntry.TABLE_NAME,
156 projection,
157 WeatherContract.LocationEntry._ID + " = '" + ContentUris.parseId(uri) + "'",
158 null,
159 null,
160 null,
161 sortOrder
162 );
163 break;
164 }
165 // "location"
166 case LOCATION: {
167 retCursor = mOpenHelper.getReadableDatabase().query(
168 WeatherContract.LocationEntry.TABLE_NAME,
169 projection,
170 selection,
171 selectionArgs,
172 null,
173 null,
174 sortOrder);
175 break;
176 }
177
178 default:
179 throw new UnsupportedOperationException("Unknown uri: " + uri);
180 }
181 retCursor.setNotificationUri(getContext().getContentResolver(), uri);
182 return retCursor;
183 }
184
185 @Override
186 public String getType(Uri uri) {
187 // Use the Uri Matcher to determine what kind of URI this is.
188 final int match = sUriMatcher.match(uri);
189
190 switch (match) {
191 case WEATHER_WITH_LOCATION_AND_DATE:
192 return WeatherContract.WeatherEntry.CONTENT_ITEM_TYPE;
193 case WEATHER_WITH_LOCATION:
194 return WeatherContract.WeatherEntry.CONTENT_TYPE;
195 case WEATHER:
196 return WeatherContract.WeatherEntry.CONTENT_TYPE;
197 case LOCATION:
198 return WeatherContract.LocationEntry.CONTENT_TYPE;
199 case LOCATION_ID:
200 return WeatherContract.LocationEntry.CONTENT_ITEM_TYPE;
201 default:
202 throw new UnsupportedOperationException("Unknown uri: " + uri);
203 }
204 }
205
206 @Override
207 public Uri insert(Uri uri, ContentValues contentValues) {
208 final SQLiteDatabase db = mOpenHelper.getWritableDatabase();
209 final int match = sUriMatcher.match(uri);
210 Uri returnUri;
211
212 switch (match) {
213 case WEATHER: {
214 long _id = db.insert(WeatherContract.WeatherEntry.TABLE_NAME, null, contentValues);
215 if ( _id > 0 )
216 returnUri = WeatherContract.WeatherEntry.buildWeatherUri(_id);
217 else
218 throw new android.database.SQLException("Failed to insert row into " + uri);
219 break;
220 }
221 case LOCATION: {
222 long _id = db.insert(WeatherContract.LocationEntry.TABLE_NAME, null, contentValues);
223 if ( _id > 0 )
224 returnUri = WeatherContract.LocationEntry.buildLocationUri(_id);
225 else
226 throw new android.database.SQLException("Failed to insert row into " + uri);
227 break;
228 }
229 default:
230 throw new UnsupportedOperationException("Unknown uri: " + uri);
231 }
232 getContext().getContentResolver().notifyChange(returnUri, null);
233 return returnUri;
234 }
235
236 @Override
237 public int delete(Uri uri, String selection, String[] selectionArgs) {
238 final SQLiteDatabase db = mOpenHelper.getWritableDatabase();
239 final int match = sUriMatcher.match(uri);
240 int rowsDeleted = 0;
241
242 switch (match) {
243 case WEATHER: {
244 rowsDeleted = db.delete(WeatherContract.WeatherEntry.TABLE_NAME, selection, selectionArgs);
245 break;
246 }
247 case LOCATION: {
248 rowsDeleted = db.delete(WeatherContract.LocationEntry.TABLE_NAME, selection, selectionArgs);
249 break;
250 }
251 default:
252 throw new UnsupportedOperationException("Unknown uri: " + uri);
253 }
254 if (selection == null || rowsDeleted != 0) {
255 getContext().getContentResolver().notifyChange(uri, null);
256 }
257 return rowsDeleted;
258 }
259
260 @Override
261 public int update(Uri uri, ContentValues contentValues, String selection, String[] selectionArgs) {
262 final SQLiteDatabase db = mOpenHelper.getWritableDatabase();
263 final int match = sUriMatcher.match(uri);
264 int rowsUpdated;
265
266 switch (match) {
267 case WEATHER:
268 rowsUpdated = db.update(WeatherContract.WeatherEntry.TABLE_NAME, contentValues, selection,
269 selectionArgs);
270 break;
271 case LOCATION:
272 rowsUpdated = db.update(WeatherContract.LocationEntry.TABLE_NAME, contentValues, selection,
273 selectionArgs);
274 break;
275 default:
276 throw new UnsupportedOperationException("Unknown uri: " + uri);
277 }
278 if (rowsUpdated != 0) {
279 getContext().getContentResolver().notifyChange(uri, null);
280 }
281 return rowsUpdated;
282 }
283
284 @Override
285 public int bulkInsert(Uri uri, ContentValues[] values) {
286 final SQLiteDatabase db = mOpenHelper.getWritableDatabase();
287 final int match = sUriMatcher.match(uri);
288 switch (match) {
289 case WEATHER:
290 db.beginTransaction();
291 int returnCount = 0;
292 try {
293 for (ContentValues value : values) {
294 long _id = db.insert(WeatherContract.WeatherEntry.TABLE_NAME, null, value);
295 if (_id != -1) {
296 returnCount++;
297 }
298 }
299 db.setTransactionSuccessful();
300 } finally {
301 db.endTransaction();
302 }
303 getContext().getContentResolver().notifyChange(uri, null);
304 return returnCount;
305 default:
306 return super.bulkInsert(uri, values);
307 }
308 }
309 }