/**
  * Build an advanced {@link SelectionBuilder} to match the requested {@link Uri}. This is usually
  * only used by {@link #query}, since it performs table joins useful for {@link Cursor} data.
  */
 private SelectionBuilder buildExpandedSelection(Uri uri, int match) {
   final SelectionBuilder builder = new SelectionBuilder();
   switch (match) {
     case BLOCKS:
       {
         return builder.table(Tables.BLOCKS);
       }
     case BLOCKS_BETWEEN:
       {
         final List<String> segments = uri.getPathSegments();
         final String startTime = segments.get(2);
         final String endTime = segments.get(3);
         return builder
             .table(Tables.BLOCKS)
             .map(Blocks.SESSIONS_COUNT, Subquery.BLOCK_SESSIONS_COUNT)
             .map(Blocks.CONTAINS_STARRED, Subquery.BLOCK_CONTAINS_STARRED)
             .where(Blocks.BLOCK_START + ">=?", startTime)
             .where(Blocks.BLOCK_START + "<=?", endTime);
       }
     case BLOCKS_ID:
       {
         final String blockId = Blocks.getBlockId(uri);
         return builder
             .table(Tables.BLOCKS)
             .map(Blocks.SESSIONS_COUNT, Subquery.BLOCK_SESSIONS_COUNT)
             .map(Blocks.CONTAINS_STARRED, Subquery.BLOCK_CONTAINS_STARRED)
             .where(Blocks.BLOCK_ID + "=?", blockId);
       }
     case BLOCKS_ID_SESSION:
       {
         final String blockId = Blocks.getBlockId(uri);
         return builder
             .table(Tables.SESSIONS_JOIN_BLOCKS_ROOMS_TRACKS)
             .map(Blocks.SESSIONS_COUNT, Subquery.BLOCK_SESSIONS_COUNT)
             .map(Blocks.CONTAINS_STARRED, Subquery.BLOCK_CONTAINS_STARRED)
             .mapToTable(Sessions._ID, Tables.SESSIONS)
             .mapToTable(Sessions.SESSION_ID, Tables.SESSIONS)
             .mapToTable(Sessions.BLOCK_ID, Tables.SESSIONS)
             .mapToTable(Sessions.ROOM_ID, Tables.SESSIONS)
             .mapToTable(Sessions.TRACK_ID, Tables.SESSIONS)
             .where(Qualified.SESSIONS_BLOCK_ID + "=?", blockId);
       }
     case BLOCKS_ID_SESSIONS:
       {
         final String blockId = Blocks.getBlockId(uri);
         return builder
             .table(Tables.SESSIONS_JOIN_BLOCKS_ROOMS_TRACKS)
             .map(Blocks.SESSIONS_COUNT, Subquery.BLOCK_SESSIONS_COUNT)
             .map(Blocks.CONTAINS_STARRED, Subquery.BLOCK_CONTAINS_STARRED)
             .mapToTable(Sessions._ID, Tables.SESSIONS)
             .mapToTable(Sessions.SESSION_ID, Tables.SESSIONS)
             .mapToTable(Sessions.BLOCK_ID, Tables.SESSIONS)
             .mapToTable(Sessions.ROOM_ID, Tables.SESSIONS)
             .where(Qualified.SESSIONS_BLOCK_ID + "=?", blockId);
       }
     case TRACKS:
       {
         return builder
             .table(Tables.TRACKS)
             .map(Tracks.SESSIONS_COUNT, Subquery.TRACK_SESSIONS_COUNT);
       }
     case TRACKS_ID:
       {
         final String trackId = Tracks.getTrackId(uri);
         return builder.table(Tables.TRACKS).where(Tracks.TRACK_ID + "=?", trackId);
       }
     case TRACKS_ID_SESSIONS:
       {
         final String trackId = Tracks.getTrackId(uri);
         return builder
             .table(Tables.SESSIONS_JOIN_BLOCKS_ROOMS_TRACKS)
             .mapToTable(Sessions._ID, Tables.SESSIONS)
             .mapToTable(Sessions.SESSION_ID, Tables.SESSIONS)
             .mapToTable(Sessions.BLOCK_ID, Tables.SESSIONS)
             .mapToTable(Sessions.ROOM_ID, Tables.SESSIONS)
             .mapToTable(Sessions.TRACK_ID, Tables.SESSIONS)
             .where(Qualified.SESSIONS_TRACK_ID + "=?", trackId);
       }
     case ROOMS:
       {
         return builder.table(Tables.ROOMS);
       }
     case ROOMS_ID:
       {
         final String roomId = Rooms.getRoomId(uri);
         return builder.table(Tables.ROOMS).where(Rooms.ROOM_ID + "=?", roomId);
       }
     case ROOMS_ID_SESSIONS:
       {
         final String roomId = Rooms.getRoomId(uri);
         return builder
             .table(Tables.SESSIONS_JOIN_BLOCKS_ROOMS)
             .mapToTable(Sessions._ID, Tables.SESSIONS)
             .mapToTable(Sessions.BLOCK_ID, Tables.SESSIONS)
             .mapToTable(Sessions.ROOM_ID, Tables.SESSIONS)
             .where(Qualified.SESSIONS_ROOM_ID + "=?", roomId);
       }
     case SESSIONS:
       {
         return builder
             .table(Tables.SESSIONS_JOIN_BLOCKS_ROOMS)
             .mapToTable(Sessions._ID, Tables.SESSIONS)
             .mapToTable(Sessions.BLOCK_ID, Tables.SESSIONS)
             .mapToTable(Sessions.ROOM_ID, Tables.SESSIONS);
       }
     case SESSIONS_BETWEEN:
       {
         final List<String> segments = uri.getPathSegments();
         final String startTime = segments.get(2);
         final String endTime = segments.get(3);
         return builder
             .table(Tables.SESSIONS_JOIN_BLOCKS_ROOMS_TRACKS)
             .mapToTable(Sessions._ID, Tables.SESSIONS)
             .mapToTable(Sessions.BLOCK_ID, Tables.SESSIONS)
             .mapToTable(Sessions.ROOM_ID, Tables.SESSIONS)
             .mapToTable(Sessions.TRACK_ID, Tables.SESSIONS)
             .where(Sessions.BLOCK_START + ">=?", startTime)
             .where(Sessions.BLOCK_END + "<=?", endTime);
       }
     case SESSIONS_STARRED:
       {
         return builder
             .table(Tables.SESSIONS_JOIN_BLOCKS_ROOMS)
             .mapToTable(Sessions._ID, Tables.SESSIONS)
             .mapToTable(Sessions.BLOCK_ID, Tables.SESSIONS)
             .mapToTable(Sessions.ROOM_ID, Tables.SESSIONS)
             .where(Sessions.SESSION_STARRED + "=1");
       }
     case SESSIONS_NEW:
       {
         return builder
             .table(Tables.SESSIONS_JOIN_BLOCKS_ROOMS)
             .mapToTable(Sessions._ID, Tables.SESSIONS)
             .mapToTable(Sessions.BLOCK_ID, Tables.SESSIONS)
             .mapToTable(Sessions.ROOM_ID, Tables.SESSIONS)
             .where(Sessions.SESSION_NEW + "=1");
       }
     case SESSIONS_SEARCH:
       {
         final String query = Sessions.getSearchQuery(uri);
         return builder
             .table(Tables.SESSIONS_SEARCH_JOIN_SESSIONS_BLOCKS_ROOMS)
             .map(Sessions.SEARCH_SNIPPET, Subquery.SESSIONS_SNIPPET)
             .mapToTable(Sessions._ID, Tables.SESSIONS)
             .mapToTable(Sessions.SESSION_ID, Tables.SESSIONS)
             .mapToTable(Sessions.BLOCK_ID, Tables.SESSIONS)
             .mapToTable(Sessions.ROOM_ID, Tables.SESSIONS)
             .where(SessionsSearchColumns.BODY + " MATCH ?", query);
       }
     case SESSIONS_PARALLEL:
       {
         final List<String> segments = uri.getPathSegments();
         final String sessionId = segments.get(2);
         return builder
             .table(Tables.SESSIONS_JOIN_BLOCKS_ROOMS)
             .mapToTable(Sessions._ID, Tables.SESSIONS)
             .mapToTable(Sessions.BLOCK_ID, Tables.SESSIONS)
             .mapToTable(Sessions.ROOM_ID, Tables.SESSIONS)
             .map(Sessions.STARRED_IN_BLOCK_COUNT, Subquery.BLOCK_STARRED_SESSIONS_COUNT)
             .mapToTable(Tracks.TRACK_COLOR, Tables.TRACKS)
             .where(WhereClause.SESSIONS_PARALLEL, sessionId, sessionId)
             .where(Sessions.SESSION_ID + "<>?", sessionId);
       }
     case SESSIONS_AT:
       {
         final List<String> segments = uri.getPathSegments();
         final String time = segments.get(2);
         return builder
             .table(Tables.SESSIONS_JOIN_BLOCKS_ROOMS)
             .mapToTable(Sessions._ID, Tables.SESSIONS)
             .mapToTable(Sessions.BLOCK_ID, Tables.SESSIONS)
             .mapToTable(Sessions.ROOM_ID, Tables.SESSIONS)
             .where(Sessions.BLOCK_START + "<=?", time)
             .where(Sessions.BLOCK_END + ">=?", time);
       }
     case SESSIONS_ID:
       {
         final String sessionId = Sessions.getSessionId(uri);
         return builder
             .table(Tables.SESSIONS_JOIN_BLOCKS_ROOMS_TRACKS)
             .mapToTable(Sessions._ID, Tables.SESSIONS)
             .mapToTable(Sessions.BLOCK_ID, Tables.SESSIONS)
             .mapToTable(Sessions.ROOM_ID, Tables.SESSIONS)
             .mapToTable(Sessions.TRACK_ID, Tables.SESSIONS)
             .where(Qualified.SESSIONS_SESSION_ID + "=?", sessionId);
       }
     case SESSIONS_ID_SPEAKERS:
       {
         final String sessionId = Sessions.getSessionId(uri);
         return builder
             .table(Tables.SESSIONS_SPEAKERS_JOIN_SPEAKERS)
             .mapToTable(Speakers._ID, Tables.SPEAKERS)
             .mapToTable(Speakers.SPEAKER_ID, Tables.SPEAKERS)
             .where(Qualified.SESSIONS_SPEAKERS_SESSION_ID + "=?", sessionId);
       }
     case SESSIONS_ID_TAGS:
       {
         final String sessionId = Sessions.getSessionId(uri);
         return builder
             .table(Tables.SESSIONS_TAGS_JOIN_TAGS)
             .mapToTable(Tags._ID, Tables.TAGS)
             .mapToTable(Tags.TAG_ID, Tables.TAGS)
             .where(Qualified.SESSIONS_TAGS_SESSION_ID + "=?", sessionId);
       }
     case SESSIONS_ID_TRACKS:
       {
         final String sessionId = Sessions.getSessionId(uri);
         return builder
             .table(Tables.SESSIONS_JOIN_TRACKS)
             .mapToTable(Tracks._ID, Tables.TRACKS)
             .mapToTable(Tracks.TRACK_ID, Tables.TRACKS)
             .where(Qualified.SESSIONS_SESSION_ID + "=?", sessionId);
       }
     case SESSIONS_ID_PARLEYS:
       {
         final String sessionId = Sessions.getSessionId(uri);
         return builder
             .table(Tables.SESSIONS_TAGS_JOIN_PARLAYS_PRESENTATIONS_TAGS_PARLEYS_PRESENTATIONS)
             .groupBy(Qualified.PARLEYS_PRESENTATIONS_PRESENTATION_ID)
             .mapToTable(ParleysPresentations._ID, Tables.PARLEYS_PRESENTATIONS)
             .mapToTable(ParleysPresentations.PRESENTATION_ID, Tables.PARLEYS_PRESENTATIONS)
             .where(
                 Qualified.PARLEYS_PRESENTATIONS_PRESENTATION_ID
                     + " IS NOT NULL AND "
                     + Qualified.SESSIONS_TAGS_SESSION_ID
                     + "=?",
                 sessionId);
       }
     case SPEAKERS:
       {
         return builder.table(Tables.SPEAKERS);
       }
     case SPEAKERS_SEARCH:
       {
         final String query = Sessions.getSearchQuery(uri);
         return builder
             .table(Tables.SPEAKERS_SEARCH_JOIN_SPEAKERS)
             .map(Speakers.SEARCH_SNIPPET, Subquery.SPEAKERS_SNIPPET)
             .mapToTable(Speakers._ID, Tables.SPEAKERS)
             .mapToTable(Speakers.SPEAKER_ID, Tables.SPEAKERS)
             .where(SpeakersSearchColumns.BODY + " MATCH ?", query);
       }
     case SPEAKERS_ID:
       {
         final String speakerId = Speakers.getSpeakerId(uri);
         return builder.table(Tables.SPEAKERS).where(Speakers.SPEAKER_ID + "=?", speakerId);
       }
     case SPEAKERS_ID_SESSIONS:
       {
         final String speakerId = Speakers.getSpeakerId(uri);
         return builder
             .table(Tables.SESSIONS_SPEAKERS_JOIN_SESSIONS_BLOCKS_ROOMS)
             .mapToTable(Sessions._ID, Tables.SESSIONS)
             .mapToTable(Sessions.SESSION_ID, Tables.SESSIONS)
             .mapToTable(Sessions.BLOCK_ID, Tables.SESSIONS)
             .mapToTable(Sessions.ROOM_ID, Tables.SESSIONS)
             .where(Qualified.SESSIONS_SPEAKERS_SPEAKER_ID + "=?", speakerId);
       }
     case TAGS:
       {
         return builder.table(Tables.TAGS);
       }
     case TAGS_ID:
       {
         final String tagId = Tags.getTagId(uri);
         return builder.table(Tables.TAGS).where(Tags.TAG_ID + "=?", tagId);
       }
     case TAGS_ID_SESSIONS:
       {
         final String tagId = Tags.getTagId(uri);
         return builder
             .table(Tables.SESSIONS_TAGS_JOIN_SESSIONS_BLOCKS_ROOMS)
             .mapToTable(Sessions._ID, Tables.SESSIONS)
             .mapToTable(Sessions.SESSION_ID, Tables.SESSIONS)
             .mapToTable(Sessions.BLOCK_ID, Tables.SESSIONS)
             .mapToTable(Sessions.ROOM_ID, Tables.SESSIONS)
             .where(Qualified.SESSIONS_TAGS_TAG_ID + "=?", tagId);
       }
     case SESSION_TYPES:
       {
         return builder.table(Tables.SESSION_TYPES);
       }
     case SESSION_TYPES_ID:
       {
         final String sessionTypeId = SessionTypes.getSessionTypeId(uri);
         return builder
             .table(Tables.SESSION_TYPES)
             .where(SessionTypes.SESSION_TYPE_ID + "=?", sessionTypeId);
       }
     case TWEETS:
       {
         return builder.table(Tables.TWEETS);
       }
     case TWEETS_ID:
       {
         final String tweetId = Tweets.getTweetId(uri);
         return builder.table(Tables.TWEETS).where(Tweets.TWEET_ID + "=?", tweetId);
       }
     case NEWS:
       {
         return builder.table(Tables.NEWS);
       }
     case NEWS_NEW:
       {
         return builder.table(Tables.NEWS).where(News.NEWS_NEW + "=1");
       }
     case NEWS_ID:
       {
         final String newsId = News.getNewsId(uri);
         return builder.table(Tables.NEWS).where(News.NEWS_ID + "=?", newsId);
       }
     case PARLEYS:
       {
         return builder.table(Tables.PARLEYS_PRESENTATIONS);
       }
     case PARLEYS_ID:
       {
         final String presentationId = ParleysPresentations.getParleysId(uri);
         return builder
             .table(Tables.PARLEYS_PRESENTATIONS)
             .where(Qualified.PARLEYS_PRESENTATIONS_PRESENTATION_ID + "=?", presentationId);
       }
     case PARLEYS_ID_TAGS:
       {
         final String presentationId = ParleysPresentations.getParleysId(uri);
         return builder
             .table(Tables.PARLEYS_PRESENTATIONS_TAGS_JOIN_TAGS)
             .mapToTable(Tags._ID, Tables.TAGS)
             .mapToTable(Tags.TAG_ID, Tables.TAGS)
             .where(Qualified.PARLEYS_PRESENTATIONS_TAGS_PRESENTATION_ID + "=?", presentationId);
       }
     default:
       {
         throw new UnsupportedOperationException("Unknown uri: " + uri);
       }
   }
 }
 /**
  * Build a simple {@link SelectionBuilder} to match the requested {@link Uri}. This is usually
  * enough to support {@link #insert}, {@link #update}, and {@link #delete} operations.
  */
 private SelectionBuilder buildSimpleSelection(Uri uri) {
   final SelectionBuilder builder = new SelectionBuilder();
   final int match = sUriMatcher.match(uri);
   switch (match) {
     case BLOCKS:
       {
         return builder.table(Tables.BLOCKS);
       }
     case BLOCKS_ID:
       {
         final String blockId = Blocks.getBlockId(uri);
         return builder.table(Tables.BLOCKS).where(Blocks.BLOCK_ID + "=?", blockId);
       }
     case TRACKS:
       {
         return builder.table(Tables.TRACKS);
       }
     case TRACKS_ID:
       {
         final String trackId = Tracks.getTrackId(uri);
         return builder.table(Tables.TRACKS).where(Tracks.TRACK_ID + "=?", trackId);
       }
     case ROOMS:
       {
         return builder.table(Tables.ROOMS);
       }
     case ROOMS_ID:
       {
         final String roomId = Rooms.getRoomId(uri);
         return builder.table(Tables.ROOMS).where(Rooms.ROOM_ID + "=?", roomId);
       }
     case SESSIONS:
       {
         return builder.table(Tables.SESSIONS);
       }
     case SESSIONS_STARRED:
       {
         return builder.table(Tables.SESSIONS).where(Sessions.SESSION_STARRED + "=1");
       }
     case SESSIONS_NEW:
       {
         return builder.table(Tables.SESSIONS).where(Sessions.SESSION_NEW + "=1");
       }
     case SESSIONS_ID:
       {
         final String sessionId = Sessions.getSessionId(uri);
         return builder.table(Tables.SESSIONS).where(Sessions.SESSION_ID + "=?", sessionId);
       }
     case SESSIONS_ID_SPEAKERS:
       {
         final String sessionId = Sessions.getSessionId(uri);
         return builder
             .table(Tables.SESSIONS_SPEAKERS)
             .where(Sessions.SESSION_ID + "=?", sessionId);
       }
     case SESSIONS_ID_TAGS:
       {
         final String sessionId = Sessions.getSessionId(uri);
         return builder.table(Tables.SESSIONS_TAGS).where(Sessions.SESSION_ID + "=?", sessionId);
       }
     case SPEAKERS:
       {
         return builder.table(Tables.SPEAKERS);
       }
     case SPEAKERS_ID:
       {
         final String speakerId = Speakers.getSpeakerId(uri);
         return builder.table(Tables.SPEAKERS).where(Speakers.SPEAKER_ID + "=?", speakerId);
       }
     case TAGS:
       {
         return builder.table(Tables.TAGS);
       }
     case TAGS_ID:
       {
         final String tagId = Tags.getTagId(uri);
         return builder.table(Tables.TAGS).where(Tags.TAG_ID + "=?", tagId);
       }
     case SESSION_TYPES:
       {
         return builder.table(Tables.SESSION_TYPES);
       }
     case SESSION_TYPES_ID:
       {
         final String sessionTypeId = SessionTypes.getSessionTypeId(uri);
         return builder
             .table(Tables.SESSION_TYPES)
             .where(SessionTypes.SESSION_TYPE_ID + "=?", sessionTypeId);
       }
     case TWEETS:
       {
         return builder.table(Tables.TWEETS);
       }
     case TWEETS_ID:
       {
         final String tweetId = Tweets.getTweetId(uri);
         return builder.table(Tables.TWEETS).where(Tweets.TWEET_ID + "=?", tweetId);
       }
     case NEWS:
       {
         return builder.table(Tables.NEWS);
       }
     case NEWS_NEW:
       {
         return builder.table(Tables.NEWS).where(News.NEWS_NEW + "=1");
       }
     case NEWS_ID:
       {
         final String newsId = News.getNewsId(uri);
         return builder.table(Tables.NEWS).where(News.NEWS_ID + "=?", newsId);
       }
     case PARLEYS:
       {
         return builder.table(Tables.PARLEYS_PRESENTATIONS);
       }
     case PARLEYS_ID:
       {
         final String presentationId = ParleysPresentations.getParleysId(uri);
         return builder
             .table(Tables.PARLEYS_PRESENTATIONS)
             .where(ParleysPresentations.PRESENTATION_ID + "=?", presentationId);
       }
     case PARLEYS_ID_TAGS:
       {
         final String presentationId = ParleysPresentations.getParleysId(uri);
         return builder
             .table(Tables.PARLEYS_PRESENTATIONS_TAGS)
             .where(ParleysPresentations.PRESENTATION_ID + "=?", presentationId);
       }
     case SEARCH_SUGGEST:
       {
         return builder.table(Tables.SEARCH_SUGGEST);
       }
     default:
       {
         throw new UnsupportedOperationException("Unknown uri: " + uri);
       }
   }
 }