aboutsummaryrefslogtreecommitdiff
path: root/WordPress/src/main/java/org/wordpress/android/datasets/CommentTable.java
diff options
context:
space:
mode:
authorChris Warrington <cmw@google.com>2016-10-18 12:29:21 +0100
committerChris Warrington <cmw@google.com>2016-10-18 12:34:18 +0100
commite3780081075c01aa1dff6d1f373cb43192b33e68 (patch)
treefb734615933a39f3d009210dc0d1457160479b35 /WordPress/src/main/java/org/wordpress/android/datasets/CommentTable.java
parent7e05eb7e57827eddc885570bc00aed8a50320dbf (diff)
parent025b8b226c8d8edba2b309ca878572f40512eca7 (diff)
downloadgradle-perf-android-medium-e3780081075c01aa1dff6d1f373cb43192b33e68.tar.gz
Change-Id: I63f5e16d09297c48432192761b840310935eb903
Diffstat (limited to 'WordPress/src/main/java/org/wordpress/android/datasets/CommentTable.java')
-rw-r--r--WordPress/src/main/java/org/wordpress/android/datasets/CommentTable.java419
1 files changed, 419 insertions, 0 deletions
diff --git a/WordPress/src/main/java/org/wordpress/android/datasets/CommentTable.java b/WordPress/src/main/java/org/wordpress/android/datasets/CommentTable.java
new file mode 100644
index 000000000..9545ec10f
--- /dev/null
+++ b/WordPress/src/main/java/org/wordpress/android/datasets/CommentTable.java
@@ -0,0 +1,419 @@
+package org.wordpress.android.datasets;
+
+import android.content.ContentValues;
+import android.database.Cursor;
+import android.database.sqlite.SQLiteDatabase;
+import android.database.sqlite.SQLiteException;
+import android.database.sqlite.SQLiteStatement;
+
+import org.wordpress.android.WordPress;
+import org.wordpress.android.WordPressDB;
+import org.wordpress.android.models.Comment;
+import org.wordpress.android.models.CommentList;
+import org.wordpress.android.models.CommentStatus;
+import org.wordpress.android.util.AppLog;
+import org.wordpress.android.util.SqlUtils;
+import org.wordpress.android.util.StringUtils;
+
+/**
+ * replaces the comments table used in versions prior to 2.6.1, which didn't use a primary key
+ * and missed a few important fields
+ */
+public class CommentTable {
+ public static final String COMMENTS_TABLE = "comments";
+
+ public static void createTables(SQLiteDatabase db) {
+ db.execSQL("CREATE TABLE IF NOT EXISTS " + COMMENTS_TABLE + " ("
+ + " blog_id INTEGER DEFAULT 0,"
+ + " post_id INTEGER DEFAULT 0,"
+ + " comment_id INTEGER DEFAULT 0,"
+ + " comment TEXT,"
+ + " published TEXT,"
+ + " status TEXT,"
+ + " author_name TEXT,"
+ + " author_url TEXT,"
+ + " author_email TEXT,"
+ + " post_title TEXT,"
+ + " profile_image_url TEXT,"
+ + " PRIMARY KEY (blog_id, post_id, comment_id)"
+ + " );");
+ }
+
+ private static void dropTables(SQLiteDatabase db) {
+ db.execSQL("DROP TABLE IF EXISTS " + COMMENTS_TABLE);
+ }
+
+ public static void reset(SQLiteDatabase db) {
+ AppLog.i(AppLog.T.COMMENTS, "resetting comment table");
+ dropTables(db);
+ createTables(db);
+ }
+
+ private static SQLiteDatabase getReadableDb() {
+ return WordPress.wpDB.getDatabase();
+ }
+ private static SQLiteDatabase getWritableDb() {
+ return WordPress.wpDB.getDatabase();
+ }
+
+ /*
+ * purge comments attached to blogs that no longer exist, and remove older comments
+ * TODO: call after hiding or deleting blogs
+ */
+ private static final int MAX_COMMENTS = 1000;
+ public static int purge(SQLiteDatabase db) {
+ int numDeleted = 0;
+
+ // get rid of comments on blogs that don't exist or are hidden
+ String sql = " blog_id NOT IN (SELECT DISTINCT id FROM " + WordPressDB.BLOGS_TABLE
+ + " WHERE isHidden = 0)";
+ numDeleted += db.delete(COMMENTS_TABLE, sql, null);
+
+ // get rid of older comments if we've reached the max
+ int numExisting = (int)SqlUtils.getRowCount(db, COMMENTS_TABLE);
+ if (numExisting > MAX_COMMENTS) {
+ int numToPurge = numExisting - MAX_COMMENTS;
+ sql = " comment_id IN (SELECT DISTINCT comment_id FROM " + COMMENTS_TABLE
+ + " ORDER BY published LIMIT " + Integer.toString(numToPurge) + ")";
+ numDeleted += db.delete(COMMENTS_TABLE, sql, null);
+ }
+
+ return numDeleted;
+ }
+
+ /**
+ * add a single comment - will update existing comment with same IDs
+ * @param localBlogId - unique id in account table for the blog the comment is from
+ * @param comment - comment object to store
+ */
+ public static void addComment(int localBlogId, final Comment comment) {
+ if (comment == null)
+ return;
+
+ ContentValues values = new ContentValues();
+ values.put("blog_id", localBlogId);
+ values.put("post_id", comment.postID);
+ values.put("comment_id", comment.commentID);
+ values.put("author_name", comment.getAuthorName());
+ values.put("author_url", comment.getAuthorUrl());
+ values.put("comment", SqlUtils.maxSQLiteText(comment.getCommentText()));
+ values.put("status", comment.getStatus());
+ values.put("author_email", comment.getAuthorEmail());
+ values.put("post_title", comment.getPostTitle());
+ values.put("published", comment.getPublished());
+ values.put("profile_image_url", comment.getProfileImageUrl());
+
+ getWritableDb().insertWithOnConflict(COMMENTS_TABLE, null, values, SQLiteDatabase.CONFLICT_REPLACE);
+ }
+
+ /**
+ * retrieve a single comment
+ * @param localBlogId - unique id in account table for the blog the comment is from
+ * @param commentId - commentId of the actual comment
+ * @return Comment if found, null otherwise
+ */
+ public static Comment getComment(int localBlogId, long commentId) {
+ String[] args = {Integer.toString(localBlogId), Long.toString(commentId)};
+ Cursor c = getReadableDb().rawQuery("SELECT * FROM " + COMMENTS_TABLE + " WHERE blog_id=? AND comment_id=?", args);
+ try {
+ if (!c.moveToFirst()) {
+ return null;
+ }
+ return getCommentFromCursor(c);
+ } finally {
+ SqlUtils.closeCursor(c);
+ }
+ }
+
+ /**
+ * get all comments for a blog
+ * @param localBlogId - unique id in account table for this blog
+ * @return list of comments for this blog
+ */
+ public static CommentList getCommentsForBlog(int localBlogId) {
+ CommentList comments = new CommentList();
+
+ String[] args = {Integer.toString(localBlogId)};
+ Cursor c = getReadableDb().rawQuery(
+ "SELECT * FROM " + COMMENTS_TABLE + " WHERE blog_id=? ORDER BY published DESC", args);
+
+ try {
+ while (c.moveToNext()) {
+ Comment comment = getCommentFromCursor(c);
+ comments.add(comment);
+ }
+
+ return comments;
+ } finally {
+ SqlUtils.closeCursor(c);
+ }
+ }
+
+ /**
+ * get comments for a blog that have a specific status
+ * @param localBlogId - unique id in account table for this blog
+ * @param filter - status to filter comments by
+ * @return list of comments for this blog
+ */
+ public static CommentList getCommentsForBlogWithFilter(int localBlogId, CommentStatus filter) {
+ CommentList comments = new CommentList();
+ Cursor c;
+
+ //aggregating 'all' to include approved and unapproved comments
+ if (CommentStatus.UNKNOWN.equals(filter)){
+ //we need to get the filter values for both XMLrpc and REST api as in the case of a migration where existing
+ // data is present on a device, we still need to be able to filter both values
+ String[] args = {Integer.toString(localBlogId),
+ CommentStatus.toString(CommentStatus.APPROVED),
+ CommentStatus.toString(CommentStatus.UNAPPROVED),
+ CommentStatus.toRESTString(CommentStatus.APPROVED),
+ CommentStatus.toRESTString(CommentStatus.UNAPPROVED)};
+ c = getReadableDb().rawQuery(
+ "SELECT * FROM " + COMMENTS_TABLE + " WHERE blog_id=? AND (status=? OR status=? OR status=? OR status=?) ORDER BY published DESC", args);
+
+ } else {
+ //we need to get the filter values for both XMLrpc and REST api as in the case of a migration where existing
+ // data is present on a device, we still need to be able to filter both values
+ String[] args = {Integer.toString(localBlogId), CommentStatus.toString(filter), CommentStatus.toRESTString(filter)};
+ c = getReadableDb().rawQuery(
+ "SELECT * FROM " + COMMENTS_TABLE + " WHERE blog_id=? AND (status=? OR status=?) ORDER BY published DESC", args);
+ }
+
+ try {
+ while (c.moveToNext()) {
+ Comment comment = getCommentFromCursor(c);
+ comments.add(comment);
+ }
+
+ return comments;
+ } finally {
+ SqlUtils.closeCursor(c);
+ }
+ }
+
+ /**
+ * delete all comments for a blog
+ * @param localBlogId - unique id in account table for this blog
+ * @return number of comments deleted
+ */
+ public static int deleteCommentsForBlog(int localBlogId) {
+ return getWritableDb().delete(COMMENTS_TABLE, "blog_id=?", new String[]{Integer.toString(localBlogId)});
+ }
+
+ /**
+ * delete comments for a blog that match a specific status
+ * @param localBlogId - unique id in account table for this blog
+ * @param filter - status to use to filter the query
+ * @return number of comments deleted
+ */
+ public static int deleteCommentsForBlogWithFilter(int localBlogId, CommentStatus filter) {
+ if (CommentStatus.UNKNOWN.equals(filter)){
+ //we need to get the filter values for both XMLrpc and REST api as in the case of a migration where existing
+ // data is present on a device, we still need to be able to filter both values
+ String[] args = {Integer.toString(localBlogId),
+ CommentStatus.toString(CommentStatus.APPROVED),
+ CommentStatus.toString(CommentStatus.UNAPPROVED),
+ CommentStatus.toRESTString(CommentStatus.APPROVED),
+ CommentStatus.toRESTString(CommentStatus.UNAPPROVED)};
+ return getWritableDb().delete(COMMENTS_TABLE, "blog_id=? AND (status=? OR status=? OR status=? OR status=?)", args);
+
+ } else {
+ //we need to get the filter values for both XMLrpc and REST api as in the case of a migration where existing
+ // data is present on a device, we still need to be able to filter both values
+ String[] args = {Integer.toString(localBlogId), CommentStatus.toString(filter), CommentStatus.toRESTString(filter)};
+ return getWritableDb().delete(COMMENTS_TABLE, "blog_id=? AND (status=? OR status=?)", args);
+ }
+ }
+
+ /**
+ * saves comments for passed blog to local db, overwriting existing ones if necessary
+ * @param localBlogId - unique id in account table for this blog
+ * @param comments - list of comments to save
+ * @return true if saved, false on failure
+ */
+ public static boolean saveComments(int localBlogId, final CommentList comments) {
+ if (comments == null || comments.size() == 0)
+ return false;
+
+ final String sql = " INSERT OR REPLACE INTO " + COMMENTS_TABLE + "("
+ + " blog_id," // 1
+ + " post_id," // 2
+ + " comment_id," // 3
+ + " comment," // 4
+ + " published," // 5
+ + " status," // 6
+ + " author_name," // 7
+ + " author_url," // 8
+ + " author_email," // 9
+ + " post_title," // 10
+ + " profile_image_url" // 11
+ + " ) VALUES (?1,?2,?3,?4,?5,?6,?7,?8,?9,?10,?11)";
+
+ SQLiteDatabase db = getWritableDb();
+ SQLiteStatement stmt = db.compileStatement(sql);
+ db.beginTransaction();
+ try {
+ try {
+ for (Comment comment: comments) {
+ stmt.bindLong ( 1, localBlogId);
+ stmt.bindLong ( 2, comment.postID);
+ stmt.bindLong ( 3, comment.commentID);
+ stmt.bindString( 4, SqlUtils.maxSQLiteText(comment.getCommentText()));
+ stmt.bindString( 5, comment.getPublished());
+ stmt.bindString( 6, comment.getStatus());
+ stmt.bindString( 7, comment.getAuthorName());
+ stmt.bindString( 8, comment.getAuthorUrl());
+ stmt.bindString( 9, comment.getAuthorEmail());
+ stmt.bindString(10, comment.getPostTitle());
+ stmt.bindString(11, comment.getProfileImageUrl());
+ stmt.execute();
+ }
+
+ db.setTransactionSuccessful();
+ return true;
+ } catch (SQLiteException e) {
+ AppLog.e(AppLog.T.COMMENTS, e);
+ return false;
+ }
+ } finally {
+ db.endTransaction();
+ SqlUtils.closeStatement(stmt);
+ }
+ }
+
+ /**
+ * updates the passed comment
+ * @param localBlogId - unique id in account table for this blog
+ * @param comment - comment to update
+ */
+ public static void updateComment(int localBlogId, final Comment comment) {
+ // this will replace the existing comment
+ addComment(localBlogId, comment);
+ }
+
+ /**
+ * updates the status for the passed comment
+ * @param localBlogId - unique id in account table for this blog
+ * @param commentId - id of comment (returned by api)
+ * @param newStatus - status to change to
+ */
+ public static void updateCommentStatus(int localBlogId, long commentId, String newStatus) {
+ ContentValues values = new ContentValues();
+ values.put("status", newStatus);
+ String[] args = {Integer.toString(localBlogId),
+ Long.toString(commentId)};
+ getWritableDb().update(COMMENTS_TABLE, values, "blog_id=? AND comment_id=?", args);
+ }
+
+ /**
+ * updates the status for the passed list of comments
+ * @param localBlogId - unique id in account table for this blog
+ * @param comments - list of comments to update
+ * @param newStatus - status to change to
+ */
+ public static void updateCommentsStatus(int localBlogId, final CommentList comments, String newStatus) {
+ if (comments == null || comments.size() == 0)
+ return;
+ getWritableDb().beginTransaction();
+ try {
+ for (Comment comment: comments) {
+ updateCommentStatus(localBlogId, comment.commentID, newStatus);
+ }
+ getWritableDb().setTransactionSuccessful();
+ } finally {
+ getWritableDb().endTransaction();
+ }
+ }
+
+ /**
+ * updates the post title for the passed comment
+ * @param localBlogId - unique id in account table for this blog
+ * @param postTitle - title to update to
+ * @return true if title updated
+ */
+ public static boolean updateCommentPostTitle(int localBlogId, long commentId, String postTitle) {
+ ContentValues values = new ContentValues();
+ values.put("post_title", StringUtils.notNullStr(postTitle));
+ String[] args = {Integer.toString(localBlogId),
+ Long.toString(commentId)};
+ int count = getWritableDb().update(COMMENTS_TABLE, values, "blog_id=? AND comment_id=?", args);
+ return (count > 0);
+ }
+
+ /**
+ * delete a single comment
+ * @param localBlogId - unique id in account table for this blog
+ * @param commentId - commentId of the actual comment
+ * @return true if comment deleted, false otherwise
+ */
+ public static boolean deleteComment(int localBlogId, long commentId) {
+ String[] args = {Integer.toString(localBlogId),
+ Long.toString(commentId)};
+ int count = getWritableDb().delete(COMMENTS_TABLE, "blog_id=? AND comment_id=?", args);
+ return (count > 0);
+ }
+
+ /**
+ * delete a list of comments
+ * @param localBlogId - unique id in account table for this blog
+ * @param comments - list of comments to delete
+ */
+ public static void deleteComments(int localBlogId, final CommentList comments) {
+ if (comments == null || comments.size() == 0)
+ return;
+ getWritableDb().beginTransaction();
+ try {
+ for (Comment comment: comments) {
+ deleteComment(localBlogId, comment.commentID);
+ }
+ getWritableDb().setTransactionSuccessful();
+ } finally {
+ getWritableDb().endTransaction();
+ }
+ }
+
+ /**
+ * returns the number of unmoderated comments for a specific blog
+ * @param localBlogId - unique id in account table for this blog
+ */
+ public static int getUnmoderatedCommentCount(int localBlogId) {
+ String sql = "SELECT COUNT(*) FROM " + COMMENTS_TABLE + " WHERE blog_id=? AND status=?";
+ String[] args = {Integer.toString(localBlogId), "hold"};
+ return SqlUtils.intForQuery(getReadableDb(), sql, args);
+ }
+
+ private static Comment getCommentFromCursor(Cursor c) {
+ final String authorName = c.getString(c.getColumnIndex("author_name"));
+ final String content = c.getString(c.getColumnIndex("comment"));
+ final String published = c.getString(c.getColumnIndex("published"));
+ final String status = c.getString(c.getColumnIndex("status"));
+ final String authorUrl = c.getString(c.getColumnIndex("author_url"));
+ final String authorEmail = c.getString(c.getColumnIndex("author_email"));
+ final String postTitle = c.getString(c.getColumnIndex("post_title"));
+ final String profileImageUrl = c.getString(c.getColumnIndex("profile_image_url"));
+
+ int postId = c.getInt(c.getColumnIndex("post_id"));
+ int commentId = c.getInt(c.getColumnIndex("comment_id"));
+
+ return new Comment(
+ postId,
+ commentId,
+ authorName,
+ published,
+ content,
+ status,
+ postTitle,
+ authorUrl,
+ authorEmail,
+ profileImageUrl);
+ }
+
+
+ /**
+ * Delete big comments (Maximum 512 * 1024 = 524288) (fix #2855)
+ * @return number of deleted comments
+ */
+ public static int deleteBigComments(SQLiteDatabase db) {
+ return db.delete(COMMENTS_TABLE, "LENGTH(comment) >= 524288", null);
+ }
+}