From 85b897c7d778ae70d837ae0c2a9e7b4252ea8945 Mon Sep 17 00:00:00 2001 From: Sebastian Zeller Date: Tue, 20 Oct 2020 13:27:27 +0200 Subject: Filter the All Episodes tab via SQL Query Fixes #4414 --- .../antennapod/core/feed/FeedItemFilter.java | 52 ++++++++++++++++++++++ .../danoeh/antennapod/core/storage/DBReader.java | 25 +++++++++++ .../antennapod/core/storage/PodDBAdapter.java | 26 +++++++---- 3 files changed, 95 insertions(+), 8 deletions(-) (limited to 'core/src/main/java/de') diff --git a/core/src/main/java/de/danoeh/antennapod/core/feed/FeedItemFilter.java b/core/src/main/java/de/danoeh/antennapod/core/feed/FeedItemFilter.java index e8e478a86..b9d79715a 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/feed/FeedItemFilter.java +++ b/core/src/main/java/de/danoeh/antennapod/core/feed/FeedItemFilter.java @@ -8,6 +8,7 @@ import java.util.Arrays; import java.util.List; import de.danoeh.antennapod.core.storage.DBReader; +import de.danoeh.antennapod.core.storage.PodDBAdapter; import de.danoeh.antennapod.core.util.LongList; import static de.danoeh.antennapod.core.feed.FeedItem.TAG_FAVORITE; @@ -15,6 +16,7 @@ import static de.danoeh.antennapod.core.feed.FeedItem.TAG_FAVORITE; public class FeedItemFilter { private final String[] mProperties; + private final String mQuery; private boolean showPlayed = false; private boolean showUnplayed = false; @@ -78,6 +80,45 @@ public class FeedItemFilter { break; } } + + mQuery = makeQuery(); + } + + private String makeQuery() { + // The keys used within this method, but explicitly combined with their table + String keyRead = PodDBAdapter.TABLE_NAME_FEED_ITEMS + "." + PodDBAdapter.KEY_READ; + String keyPosition = PodDBAdapter.TABLE_NAME_FEED_MEDIA + "." + PodDBAdapter.KEY_POSITION; + String keyDownloaded = PodDBAdapter.TABLE_NAME_FEED_MEDIA + "." + PodDBAdapter.KEY_DOWNLOADED; + String keyMediaId = PodDBAdapter.TABLE_NAME_FEED_MEDIA + "." + PodDBAdapter.KEY_ID; + String keyItemId = PodDBAdapter.TABLE_NAME_FEED_ITEMS + "." + PodDBAdapter.KEY_ID; + String keyFeedItem = PodDBAdapter.KEY_FEEDITEM; + String tableQueue = PodDBAdapter.TABLE_NAME_QUEUE; + String tableFavorites = PodDBAdapter.TABLE_NAME_FAVORITES; + + List statements = new ArrayList<>(); + if (showPlayed) statements.add(keyRead + " = 1 "); + if (showUnplayed) statements.add(" NOT " + keyRead + " = 1 "); // Match "New" items (read = -1) as well + if (showPaused) statements.add(" (" + keyPosition + " NOT NULL AND " + keyPosition + " > 0 " + ") "); + if (showNotPaused) statements.add(" (" + keyPosition + " IS NULL OR " + keyPosition + " = 0 " + ") "); + if (showQueued) statements.add(keyItemId + " IN (SELECT " + keyFeedItem + " FROM " + tableQueue + ") "); + if (showNotQueued) statements.add(keyItemId + " NOT IN (SELECT " + keyFeedItem + " FROM " + tableQueue + ") "); + if (showDownloaded) statements.add(keyDownloaded + " = 1 "); + if (showNotDownloaded) statements.add(keyDownloaded + " = 0 "); + if (showHasMedia) statements.add(keyMediaId + " NOT NULL "); + if (showNoMedia) statements.add(keyMediaId + " IS NULL "); + if (showIsFavorite) statements.add(keyItemId + " IN (SELECT " + keyFeedItem + " FROM " + tableFavorites + ") "); + if (showNotFavorite) statements.add(keyItemId + " NOT IN (SELECT " + keyFeedItem + " FROM " + tableFavorites + ") "); + + if (statements.isEmpty()) { + return ""; + } + StringBuilder query = new StringBuilder(" (" + statements.get(0)); + for (String r : statements.subList(1, statements.size())) { + query.append(" AND "); + query.append(r); + } + query.append(") "); + return query.toString(); } /** @@ -125,6 +166,17 @@ public class FeedItemFilter { return result; } + /** + * Express this filter using an SQL boolean statement that can be inserted into an SQL WHERE clause + * to yield output filtered according to the rules of this filter. + * + * @return An SQL boolean statement that matches the desired items, + * empty string if there is nothing to filter + */ + public String getQuery() { + return mQuery; + } + public String[] getValues() { return mProperties.clone(); } diff --git a/core/src/main/java/de/danoeh/antennapod/core/storage/DBReader.java b/core/src/main/java/de/danoeh/antennapod/core/storage/DBReader.java index b218a73f9..2ba817b94 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/storage/DBReader.java +++ b/core/src/main/java/de/danoeh/antennapod/core/storage/DBReader.java @@ -17,6 +17,7 @@ import java.util.Map; import de.danoeh.antennapod.core.feed.Chapter; import de.danoeh.antennapod.core.feed.Feed; import de.danoeh.antennapod.core.feed.FeedItem; +import de.danoeh.antennapod.core.feed.FeedItemFilter; import de.danoeh.antennapod.core.feed.FeedMedia; import de.danoeh.antennapod.core.feed.FeedPreferences; import de.danoeh.antennapod.core.feed.SubscriptionsFilter; @@ -386,6 +387,30 @@ public final class DBReader { } } + /** + * Loads a filtered list of FeedItems sorted by pubDate in descending order. + * + * @param offset The first episode that should be loaded. + * @param limit The maximum number of episodes that should be loaded. + * @param filter The filter describing which episodes to filter out. + */ + @NonNull + public static List getRecentlyPublishedEpisodesFiltered(int offset, int limit, + FeedItemFilter filter) { + Log.d(TAG, "getRecentlyPublishedEpisodesFiltered() called with: " + + "offset = [" + offset + "]" + " limit = [" + limit + "]" + " filter = [" + filter.getQuery() + "]"); + + PodDBAdapter adapter = PodDBAdapter.getInstance(); + adapter.open(); + try (Cursor cursor = adapter.getRecentlyPublishedItemsCursorFiltered(offset, limit, filter)) { + List items = extractItemlistFromCursor(adapter, cursor); + loadAdditionalFeedItemListData(items); + return items; + } finally { + adapter.close(); + } + } + /** * Loads the playback history from the database. A FeedItem is in the playback history if playback of the correpsonding episode * has been completed at least once. diff --git a/core/src/main/java/de/danoeh/antennapod/core/storage/PodDBAdapter.java b/core/src/main/java/de/danoeh/antennapod/core/storage/PodDBAdapter.java index 539bedd9f..a02cce504 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/storage/PodDBAdapter.java +++ b/core/src/main/java/de/danoeh/antennapod/core/storage/PodDBAdapter.java @@ -31,6 +31,7 @@ import java.util.Set; import de.danoeh.antennapod.core.feed.Chapter; import de.danoeh.antennapod.core.feed.Feed; import de.danoeh.antennapod.core.feed.FeedItem; +import de.danoeh.antennapod.core.feed.FeedItemFilter; import de.danoeh.antennapod.core.feed.FeedMedia; import de.danoeh.antennapod.core.feed.FeedPreferences; import de.danoeh.antennapod.core.preferences.UserPreferences; @@ -116,14 +117,14 @@ public class PodDBAdapter { public static final String KEY_FEED_SKIP_ENDING = "feed_skip_ending"; // Table names - static final String TABLE_NAME_FEEDS = "Feeds"; - static final String TABLE_NAME_FEED_ITEMS = "FeedItems"; - static final String TABLE_NAME_FEED_IMAGES = "FeedImages"; - static final String TABLE_NAME_FEED_MEDIA = "FeedMedia"; - static final String TABLE_NAME_DOWNLOAD_LOG = "DownloadLog"; - static final String TABLE_NAME_QUEUE = "Queue"; - static final String TABLE_NAME_SIMPLECHAPTERS = "SimpleChapters"; - static final String TABLE_NAME_FAVORITES = "Favorites"; + public static final String TABLE_NAME_FEEDS = "Feeds"; + public static final String TABLE_NAME_FEED_ITEMS = "FeedItems"; + public static final String TABLE_NAME_FEED_IMAGES = "FeedImages"; + public static final String TABLE_NAME_FEED_MEDIA = "FeedMedia"; + public static final String TABLE_NAME_DOWNLOAD_LOG = "DownloadLog"; + public static final String TABLE_NAME_QUEUE = "Queue"; + public static final String TABLE_NAME_SIMPLECHAPTERS = "SimpleChapters"; + public static final String TABLE_NAME_FAVORITES = "Favorites"; // SQL Statements for creating new tables private static final String TABLE_PRIMARY_KEY = KEY_ID @@ -1053,6 +1054,15 @@ public class PodDBAdapter { return db.rawQuery(query, null); } + public final Cursor getRecentlyPublishedItemsCursorFiltered(int offset, int limit, + FeedItemFilter filter) { + String filterQuery = filter.getQuery(); + String whereClause = "".equals(filterQuery) ? "" : " WHERE " + filter.getQuery(); + final String query = SELECT_FEED_ITEMS_AND_MEDIA + whereClause + + " ORDER BY " + KEY_PUBDATE + " DESC LIMIT " + offset + ", " + limit; + return db.rawQuery(query, null); + } + public Cursor getDownloadedItemsCursor() { final String query = SELECT_FEED_ITEMS_AND_MEDIA + "WHERE " + TABLE_NAME_FEED_MEDIA + "." + KEY_DOWNLOADED + " > 0"; -- cgit v1.2.3 From f610ceffc2a257d5e43e5b1d728284fc2800c42c Mon Sep 17 00:00:00 2001 From: ByteHamster Date: Fri, 22 Jan 2021 11:27:51 +0100 Subject: Split up filter model and database handling --- .../antennapod/core/feed/FeedItemFilter.java | 151 ++++++--------------- .../danoeh/antennapod/core/storage/DBReader.java | 29 +--- .../antennapod/core/storage/PodDBAdapter.java | 14 +- .../core/storage/mapper/FeedItemFilterQuery.java | 76 +++++++++++ 4 files changed, 123 insertions(+), 147 deletions(-) create mode 100644 core/src/main/java/de/danoeh/antennapod/core/storage/mapper/FeedItemFilterQuery.java (limited to 'core/src/main/java/de') diff --git a/core/src/main/java/de/danoeh/antennapod/core/feed/FeedItemFilter.java b/core/src/main/java/de/danoeh/antennapod/core/feed/FeedItemFilter.java index 16ab5a171..bd30a3953 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/feed/FeedItemFilter.java +++ b/core/src/main/java/de/danoeh/antennapod/core/feed/FeedItemFilter.java @@ -3,127 +3,68 @@ package de.danoeh.antennapod.core.feed; import android.text.TextUtils; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import de.danoeh.antennapod.core.storage.DBReader; -import de.danoeh.antennapod.core.storage.PodDBAdapter; import de.danoeh.antennapod.core.util.LongList; import static de.danoeh.antennapod.core.feed.FeedItem.TAG_FAVORITE; public class FeedItemFilter { - private final String[] mProperties; - private final String mQuery; - - private boolean showPlayed = false; - private boolean showUnplayed = false; - private boolean showPaused = false; - private boolean showNotPaused = false; - private boolean showQueued = false; - private boolean showNotQueued = false; - private boolean showDownloaded = false; - private boolean showNotDownloaded = false; - private boolean showHasMedia = false; - private boolean showNoMedia = false; - private boolean showIsFavorite = false; - private boolean showNotFavorite = false; + private final String[] properties; + + public final boolean showPlayed; + public final boolean showUnplayed; + public final boolean showPaused; + public final boolean showNotPaused; + public final boolean showQueued; + public final boolean showNotQueued; + public final boolean showDownloaded; + public final boolean showNotDownloaded; + public final boolean showHasMedia; + public final boolean showNoMedia; + public final boolean showIsFavorite; + public final boolean showNotFavorite; + + public static FeedItemFilter unfiltered() { + return new FeedItemFilter(""); + } public FeedItemFilter(String properties) { this(TextUtils.split(properties, ",")); } public FeedItemFilter(String[] properties) { - this.mProperties = properties; - for (String property : properties) { - // see R.arrays.feed_filter_values - switch (property) { - case "unplayed": - showUnplayed = true; - break; - case "paused": - showPaused = true; - break; - case "not_paused": - showNotPaused = true; - break; - case "played": - showPlayed = true; - break; - case "queued": - showQueued = true; - break; - case "not_queued": - showNotQueued = true; - break; - case "downloaded": - showDownloaded = true; - break; - case "not_downloaded": - showNotDownloaded = true; - break; - case "has_media": - showHasMedia = true; - break; - case "no_media": - showNoMedia = true; - break; - case "is_favorite": - showIsFavorite = true; - break; - case "not_favorite": - showNotFavorite = true; - break; - default: - break; - } - } - - mQuery = makeQuery(); + this.properties = properties; + + // see R.arrays.feed_filter_values + showUnplayed = hasProperty("unplayed"); + showPaused = hasProperty("paused"); + showNotPaused = hasProperty("not_paused"); + showPlayed = hasProperty("played"); + showQueued = hasProperty("queued"); + showNotQueued = hasProperty("not_queued"); + showDownloaded = hasProperty("downloaded"); + showNotDownloaded = hasProperty("not_downloaded"); + showHasMedia = hasProperty("has_media"); + showNoMedia = hasProperty("no_media"); + showIsFavorite = hasProperty("is_favorite"); + showNotFavorite = hasProperty("not_favorite"); } - private String makeQuery() { - // The keys used within this method, but explicitly combined with their table - String keyRead = PodDBAdapter.TABLE_NAME_FEED_ITEMS + "." + PodDBAdapter.KEY_READ; - String keyPosition = PodDBAdapter.TABLE_NAME_FEED_MEDIA + "." + PodDBAdapter.KEY_POSITION; - String keyDownloaded = PodDBAdapter.TABLE_NAME_FEED_MEDIA + "." + PodDBAdapter.KEY_DOWNLOADED; - String keyMediaId = PodDBAdapter.TABLE_NAME_FEED_MEDIA + "." + PodDBAdapter.KEY_ID; - String keyItemId = PodDBAdapter.TABLE_NAME_FEED_ITEMS + "." + PodDBAdapter.KEY_ID; - String keyFeedItem = PodDBAdapter.KEY_FEEDITEM; - String tableQueue = PodDBAdapter.TABLE_NAME_QUEUE; - String tableFavorites = PodDBAdapter.TABLE_NAME_FAVORITES; - - List statements = new ArrayList<>(); - if (showPlayed) statements.add(keyRead + " = 1 "); - if (showUnplayed) statements.add(" NOT " + keyRead + " = 1 "); // Match "New" items (read = -1) as well - if (showPaused) statements.add(" (" + keyPosition + " NOT NULL AND " + keyPosition + " > 0 " + ") "); - if (showNotPaused) statements.add(" (" + keyPosition + " IS NULL OR " + keyPosition + " = 0 " + ") "); - if (showQueued) statements.add(keyItemId + " IN (SELECT " + keyFeedItem + " FROM " + tableQueue + ") "); - if (showNotQueued) statements.add(keyItemId + " NOT IN (SELECT " + keyFeedItem + " FROM " + tableQueue + ") "); - if (showDownloaded) statements.add(keyDownloaded + " = 1 "); - if (showNotDownloaded) statements.add(keyDownloaded + " = 0 "); - if (showHasMedia) statements.add(keyMediaId + " NOT NULL "); - if (showNoMedia) statements.add(keyMediaId + " IS NULL "); - if (showIsFavorite) statements.add(keyItemId + " IN (SELECT " + keyFeedItem + " FROM " + tableFavorites + ") "); - if (showNotFavorite) statements.add(keyItemId + " NOT IN (SELECT " + keyFeedItem + " FROM " + tableFavorites + ") "); - - if (statements.isEmpty()) { - return ""; - } - StringBuilder query = new StringBuilder(" (" + statements.get(0)); - for (String r : statements.subList(1, statements.size())) { - query.append(" AND "); - query.append(r); - } - query.append(") "); - return query.toString(); + private boolean hasProperty(String property) { + return Arrays.asList(properties).contains(property); } /** * Run a list of feed items through the filter. */ public List filter(List items) { - if(mProperties.length == 0) return items; + if (properties.length == 0) { + return items; + } List result = new ArrayList<>(); @@ -164,23 +105,11 @@ public class FeedItemFilter { return result; } - /** - * Express this filter using an SQL boolean statement that can be inserted into an SQL WHERE clause - * to yield output filtered according to the rules of this filter. - * - * @return An SQL boolean statement that matches the desired items, - * empty string if there is nothing to filter - */ - public String getQuery() { - return mQuery; - } - public String[] getValues() { - return mProperties.clone(); + return properties.clone(); } public boolean isShowDownloaded() { return showDownloaded; } - } diff --git a/core/src/main/java/de/danoeh/antennapod/core/storage/DBReader.java b/core/src/main/java/de/danoeh/antennapod/core/storage/DBReader.java index 58f838a75..ee46f4e62 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/storage/DBReader.java +++ b/core/src/main/java/de/danoeh/antennapod/core/storage/DBReader.java @@ -366,27 +366,6 @@ public final class DBReader { } } - /** - * Loads a list of FeedItems sorted by pubDate in descending order. - * - * @param offset The first episode that should be loaded. - * @param limit The maximum number of episodes that should be loaded. - */ - @NonNull - public static List getRecentlyPublishedEpisodes(int offset, int limit) { - Log.d(TAG, "getRecentlyPublishedEpisodes() called with: " + "offset = [" + offset + "]" + " limit = [" + limit + "]" ); - - PodDBAdapter adapter = PodDBAdapter.getInstance(); - adapter.open(); - try (Cursor cursor = adapter.getRecentlyPublishedItemsCursor(offset, limit)) { - List items = extractItemlistFromCursor(adapter, cursor); - loadAdditionalFeedItemListData(items); - return items; - } finally { - adapter.close(); - } - } - /** * Loads a filtered list of FeedItems sorted by pubDate in descending order. * @@ -395,14 +374,12 @@ public final class DBReader { * @param filter The filter describing which episodes to filter out. */ @NonNull - public static List getRecentlyPublishedEpisodesFiltered(int offset, int limit, - FeedItemFilter filter) { - Log.d(TAG, "getRecentlyPublishedEpisodesFiltered() called with: " - + "offset = [" + offset + "]" + " limit = [" + limit + "]" + " filter = [" + filter.getQuery() + "]"); + public static List getRecentlyPublishedEpisodes(int offset, int limit, FeedItemFilter filter) { + Log.d(TAG, "getRecentlyPublishedEpisodes() called with: offset=" + offset + ", limit=" + limit); PodDBAdapter adapter = PodDBAdapter.getInstance(); adapter.open(); - try (Cursor cursor = adapter.getRecentlyPublishedItemsCursorFiltered(offset, limit, filter)) { + try (Cursor cursor = adapter.getRecentlyPublishedItemsCursor(offset, limit, filter)) { List items = extractItemlistFromCursor(adapter, cursor); loadAdditionalFeedItemListData(items); return items; diff --git a/core/src/main/java/de/danoeh/antennapod/core/storage/PodDBAdapter.java b/core/src/main/java/de/danoeh/antennapod/core/storage/PodDBAdapter.java index 7eae8b9f0..4a06829ce 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/storage/PodDBAdapter.java +++ b/core/src/main/java/de/danoeh/antennapod/core/storage/PodDBAdapter.java @@ -16,6 +16,7 @@ import android.util.Log; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import de.danoeh.antennapod.core.storage.mapper.FeedItemFilterQuery; import org.apache.commons.io.FileUtils; import java.io.File; @@ -1045,16 +1046,9 @@ public class PodDBAdapter { return db.rawQuery(query, null); } - public final Cursor getRecentlyPublishedItemsCursor(int offset, int limit) { - final String query = SELECT_FEED_ITEMS_AND_MEDIA - + "ORDER BY " + KEY_PUBDATE + " DESC LIMIT " + offset + ", " + limit; - return db.rawQuery(query, null); - } - - public final Cursor getRecentlyPublishedItemsCursorFiltered(int offset, int limit, - FeedItemFilter filter) { - String filterQuery = filter.getQuery(); - String whereClause = "".equals(filterQuery) ? "" : " WHERE " + filter.getQuery(); + public final Cursor getRecentlyPublishedItemsCursor(int offset, int limit, FeedItemFilter filter) { + String filterQuery = FeedItemFilterQuery.generateFrom(filter); + String whereClause = "".equals(filterQuery) ? "" : " WHERE " + filterQuery; final String query = SELECT_FEED_ITEMS_AND_MEDIA + whereClause + " ORDER BY " + KEY_PUBDATE + " DESC LIMIT " + offset + ", " + limit; return db.rawQuery(query, null); diff --git a/core/src/main/java/de/danoeh/antennapod/core/storage/mapper/FeedItemFilterQuery.java b/core/src/main/java/de/danoeh/antennapod/core/storage/mapper/FeedItemFilterQuery.java new file mode 100644 index 000000000..f6963b5ac --- /dev/null +++ b/core/src/main/java/de/danoeh/antennapod/core/storage/mapper/FeedItemFilterQuery.java @@ -0,0 +1,76 @@ +package de.danoeh.antennapod.core.storage.mapper; + +import de.danoeh.antennapod.core.feed.FeedItemFilter; +import de.danoeh.antennapod.core.storage.PodDBAdapter; + +import java.util.ArrayList; +import java.util.List; + +public class FeedItemFilterQuery { + private FeedItemFilterQuery() { + // Must not be instantiated + } + + /** + * Express the filter using an SQL boolean statement that can be inserted into an SQL WHERE clause + * to yield output filtered according to the rules of this filter. + * + * @return An SQL boolean statement that matches the desired items, + * empty string if there is nothing to filter + */ + public static String generateFrom(FeedItemFilter filter) { + // The keys used within this method, but explicitly combined with their table + String keyRead = PodDBAdapter.TABLE_NAME_FEED_ITEMS + "." + PodDBAdapter.KEY_READ; + String keyPosition = PodDBAdapter.TABLE_NAME_FEED_MEDIA + "." + PodDBAdapter.KEY_POSITION; + String keyDownloaded = PodDBAdapter.TABLE_NAME_FEED_MEDIA + "." + PodDBAdapter.KEY_DOWNLOADED; + String keyMediaId = PodDBAdapter.TABLE_NAME_FEED_MEDIA + "." + PodDBAdapter.KEY_ID; + String keyItemId = PodDBAdapter.TABLE_NAME_FEED_ITEMS + "." + PodDBAdapter.KEY_ID; + String keyFeedItem = PodDBAdapter.KEY_FEEDITEM; + String tableQueue = PodDBAdapter.TABLE_NAME_QUEUE; + String tableFavorites = PodDBAdapter.TABLE_NAME_FAVORITES; + + List statements = new ArrayList<>(); + if (filter.showPlayed) { + statements.add(keyRead + " = 1 "); + } else if (filter.showUnplayed) { + statements.add(" NOT " + keyRead + " = 1 "); // Match "New" items (read = -1) as well + } + if (filter.showPaused) { + statements.add(" (" + keyPosition + " NOT NULL AND " + keyPosition + " > 0 " + ") "); + } else if (filter.showNotPaused) { + statements.add(" (" + keyPosition + " IS NULL OR " + keyPosition + " = 0 " + ") "); + } + if (filter.showQueued) { + statements.add(keyItemId + " IN (SELECT " + keyFeedItem + " FROM " + tableQueue + ") "); + } else if (filter.showNotQueued) { + statements.add(keyItemId + " NOT IN (SELECT " + keyFeedItem + " FROM " + tableQueue + ") "); + } + if (filter.showDownloaded) { + statements.add(keyDownloaded + " = 1 "); + } else if (filter.showNotDownloaded) { + statements.add(keyDownloaded + " = 0 "); + } + if (filter.showHasMedia) { + statements.add(keyMediaId + " NOT NULL "); + } else if (filter.showNoMedia) { + statements.add(keyMediaId + " IS NULL "); + } + if (filter.showIsFavorite) { + statements.add(keyItemId + " IN (SELECT " + keyFeedItem + " FROM " + tableFavorites + ") "); + } else if (filter.showNotFavorite) { + statements.add(keyItemId + " NOT IN (SELECT " + keyFeedItem + " FROM " + tableFavorites + ") "); + } + + if (statements.isEmpty()) { + return ""; + } + + StringBuilder query = new StringBuilder(" (" + statements.get(0)); + for (String r : statements.subList(1, statements.size())) { + query.append(" AND "); + query.append(r); + } + query.append(") "); + return query.toString(); + } +} -- cgit v1.2.3