package fr.ydelouis.selfoss.model; import android.content.Context; import android.content.Intent; import android.util.Log; import com.j256.ormlite.dao.BaseDaoImpl; import com.j256.ormlite.stmt.DeleteBuilder; import com.j256.ormlite.stmt.QueryBuilder; import com.j256.ormlite.stmt.SelectArg; import com.j256.ormlite.stmt.Where; import com.j256.ormlite.support.ConnectionSource; import java.sql.SQLException; import java.util.List; import fr.ydelouis.selfoss.entity.Article; import fr.ydelouis.selfoss.entity.ArticleType; import fr.ydelouis.selfoss.entity.Filter; import fr.ydelouis.selfoss.entity.Source; import fr.ydelouis.selfoss.entity.Tag; public class ArticleDao extends BaseDaoImpl<Article, Integer> { public static final String COLUMN_ID = "id"; public static final String COLUMN_DATETIME = "dateTime"; public static final String COLUMN_UNREAD = "unread"; public static final String COLUMN_STARRED = "starred"; public static final String COLUMN_TAGS = "tags"; public static final String COLUMN_SOURCE_ID = "sourceId"; public static final String COLUMN_UPDATE_TIME = "updateTime"; public static final String ACTION_CREATION = "fr.ydelouis.selfoss.article.ACTION_CREATION"; public static final String ACTION_UPDATE = "fr.ydelouis.selfoss.article.ACTION_UPDATE"; public static final String EXTRA_ARTICLE = "article"; private Context context; public ArticleDao(ConnectionSource connectionSource) throws SQLException { super(connectionSource, Article.class); } public void setContext(Context context) { this.context = context.getApplicationContext(); } @Override public CreateOrUpdateStatus createOrUpdate(Article article) { try { CreateOrUpdateStatus status = super.createOrUpdate(article); if (status.isCreated()) { notifyCreation(article); } else if (status.isUpdated()) { notifyUpdate(article); } return status; } catch (SQLException e) { throw new RuntimeException(e); } } @Override public int update(Article article) { try { int updated = super.update(article); if (updated > 0) { notifyUpdate(article); } return updated; } catch (SQLException e) { throw new RuntimeException(e); } } public void updateAlsoCached(Article article) { int updated = update(article); if (updated != 0) { notifyUpdate(article); article.setCached(!article.isCached()); createOrUpdate(article); article.setCached(!article.isCached()); } } public List<Article> queryForUnread(Filter filter) { try { QueryBuilder<Article, Integer> queryBuilder = queryBuilder(); Where<Article, Integer> where = queryBuilder.where(); whereFilter(where, filter); where.and().eq(COLUMN_UNREAD, true); queryBuilder.orderBy(COLUMN_DATETIME, false); return queryBuilder.query(); } catch (SQLException e) { throw new RuntimeException(e); } } public List<Article> queryForPrevious(Filter filter, Article firstArticle) { try { QueryBuilder<Article, Integer> queryBuilder = queryBuilder(); Where<Article, Integer> where = queryBuilder.where(); whereFilter(where, filter); if (firstArticle != null) { where.and().gt(COLUMN_DATETIME, firstArticle.getDateTime()); } queryBuilder.orderBy(COLUMN_DATETIME, false); return queryBuilder.query(); } catch (SQLException e) { throw new RuntimeException(e); } } public List<Article> queryForNext(Filter filter, Article article, long pageSize) { try { QueryBuilder<Article, Integer> queryBuilder = queryBuilder(); Where<Article, Integer> where = queryBuilder.where(); whereFilter(where, filter); if (article != null) { where.and().lt(COLUMN_DATETIME, article.getDateTime()); } queryBuilder.orderBy(COLUMN_DATETIME, false); queryBuilder.offset(0l).limit(pageSize); return queryBuilder.query(); } catch (SQLException e) { throw new RuntimeException(e); } } public int queryForCount() { try { return (int) queryBuilder().countOf(); } catch (SQLException e) { throw new RuntimeException(e); } } public int queryForCount(ArticleType type) { return queryForCount(type, Tag.ALL); } public int queryForCount(ArticleType type, Tag tag) { try { QueryBuilder<Article, Integer> queryBuilder = queryBuilder(); Where<Article, Integer> where = queryBuilder.where(); whereTypeAndTag(where, type, tag); where.and().gt(COLUMN_ID, 0); return (int) queryBuilder.countOf(); } catch (SQLException e) { throw new RuntimeException(e); } } public int queryForCount(ArticleType type, Source source) { try { QueryBuilder<Article, Integer> queryBuilder = queryBuilder(); Where<Article, Integer> where = queryBuilder.where(); whereTypeAndSource(where, type, source); where.and().gt(COLUMN_ID, 0); return (int) queryBuilder.countOf(); } catch (SQLException e) { throw new RuntimeException(e); } } private void whereFilter(Where<Article, Integer> where, Filter filter) throws SQLException { if (filter.getTag() != null) { whereTypeAndTag(where, filter.getType(), filter.getTag()); } else { whereTypeAndSource(where, filter.getType(), filter.getSource()); } } private void whereType(Where<Article, Integer> where, ArticleType type) throws SQLException { if (type == ArticleType.Unread) { where.eq(COLUMN_UNREAD, true); } else if (type == ArticleType.Starred) { where.eq(COLUMN_STARRED, true); } else { where.lt(COLUMN_ID, 0); } } private void whereTypeAndTag(Where<Article, Integer> where, ArticleType type, Tag tag) throws SQLException { whereType(where, type); if (!Tag.ALL.equals(tag)) { where.and().like(COLUMN_TAGS, new SelectArg("%" + tag.getName(null) + "%")); } } private void whereTypeAndSource(Where<Article, Integer> where, ArticleType type, Source source) throws SQLException { whereType(where, type); where.and().like(COLUMN_SOURCE_ID, source.getId()); } public String queryForLatestUpdateTime() { try { QueryBuilder<Article, Integer> queryBuilder = queryBuilder(); queryBuilder.where().isNotNull(COLUMN_UPDATE_TIME); queryBuilder.orderBy(COLUMN_UPDATE_TIME, false); queryBuilder.limit(1l); Article latestUpdated = queryBuilder.queryForFirst(); if (latestUpdated != null) { return latestUpdated.getUpdateTime(); } else { return null; } } catch (SQLException e) { throw new RuntimeException(e); } } public void deleteCachedOlderThan(long dateTime) { try { DeleteBuilder<Article, Integer> deleteBuilder = deleteBuilder(); deleteBuilder.where().lt(COLUMN_ID, 0).and().lt(COLUMN_DATETIME, dateTime); deleteBuilder.delete(); } catch (SQLException e) { throw new RuntimeException(e); } } public void deleteUnread() { try { DeleteBuilder<Article, Integer> deleteBuilder = deleteBuilder(); deleteBuilder.where().eq(COLUMN_UNREAD, true).and().gt(COLUMN_ID, 0); deleteBuilder.delete(); } catch (SQLException e) { throw new RuntimeException(e); } } public void deleteFavorite() { try { DeleteBuilder<Article, Integer> deleteBuilder = deleteBuilder(); deleteBuilder.where().eq(COLUMN_STARRED, true).and().gt(COLUMN_ID, 0); deleteBuilder.delete(); } catch (SQLException e) { throw new RuntimeException(e); } } public void deleteReadNotFavoriteAndNotCached() { try { DeleteBuilder<Article, Integer> deleteBuilder = deleteBuilder(); deleteBuilder.where() .eq(COLUMN_UNREAD, false) .and().eq(COLUMN_STARRED, false) .and().gt(COLUMN_ID, 0); deleteBuilder.delete(); } catch (SQLException e) { throw new RuntimeException(e); } } public void deleteNotFavoriteOlderThan(long dateTime) { try { DeleteBuilder<Article, Integer> deleteBuilder = deleteBuilder(); deleteBuilder.where() .eq(COLUMN_STARRED, false) .and().lt(COLUMN_DATETIME, dateTime); deleteBuilder.delete(); } catch (SQLException e) { throw new RuntimeException(e); } } private void notifyCreation(Article article) { broadcast(ACTION_CREATION, article); } private void notifyUpdate(Article article) { broadcast(ACTION_UPDATE, article); } private void broadcast(String action, Article article) { if (context != null) { Intent intent = new Intent(action); intent.putExtra(EXTRA_ARTICLE, article); context.sendBroadcast(intent); } else { Log.w(ArticleDao.class.getSimpleName(), "Context not set, so changes are not broadcast"); } } }