diff --git a/TouchDB-Android-Ektorp/.classpath b/TouchDB-Android-Ektorp/.classpath
index 1b0421b..ce767aa 100644
--- a/TouchDB-Android-Ektorp/.classpath
+++ b/TouchDB-Android-Ektorp/.classpath
@@ -1,12 +1,11 @@
-
-
-
-
-
-
-
+
+
+
+
+
+
diff --git a/TouchDB-Android-Ektorp/libs/org.ektorp-1.2.2.jar b/TouchDB-Android-Ektorp/libs/org.ektorp-1.2.2.jar
deleted file mode 100644
index a3909ee..0000000
Binary files a/TouchDB-Android-Ektorp/libs/org.ektorp-1.2.2.jar and /dev/null differ
diff --git a/TouchDB-Android-Ektorp/libs/org.ektorp.android-1.2.2.jar b/TouchDB-Android-Ektorp/libs/org.ektorp.android-1.2.2.jar
deleted file mode 100644
index 1ae7e48..0000000
Binary files a/TouchDB-Android-Ektorp/libs/org.ektorp.android-1.2.2.jar and /dev/null differ
diff --git a/TouchDB-Android-Ektorp/lint.xml b/TouchDB-Android-Ektorp/lint.xml
new file mode 100644
index 0000000..ee0eead
--- /dev/null
+++ b/TouchDB-Android-Ektorp/lint.xml
@@ -0,0 +1,3 @@
+
+
+
\ No newline at end of file
diff --git a/TouchDB-Android-Ektorp/project.properties b/TouchDB-Android-Ektorp/project.properties
index 63f16dd..eda01e1 100644
--- a/TouchDB-Android-Ektorp/project.properties
+++ b/TouchDB-Android-Ektorp/project.properties
@@ -8,6 +8,6 @@
# project structure.
# Project target.
-target=android-17
+target=Google Inc.:Google APIs:15
android.library=true
android.library.reference.1=../TouchDB-Android
diff --git a/TouchDB-Android-Listener/.classpath b/TouchDB-Android-Listener/.classpath
index cecf57d..dd64e62 100644
--- a/TouchDB-Android-Listener/.classpath
+++ b/TouchDB-Android-Listener/.classpath
@@ -6,5 +6,6 @@
+
diff --git a/TouchDB-Android/.classpath b/TouchDB-Android/.classpath
index 462ef5c..374d658 100644
--- a/TouchDB-Android/.classpath
+++ b/TouchDB-Android/.classpath
@@ -1,10 +1,13 @@
-
-
-
-
+
+
+
+
+
+
+
diff --git a/TouchDB-Android/.settings/org.hibernate.eclipse.console.prefs b/TouchDB-Android/.settings/org.hibernate.eclipse.console.prefs
new file mode 100644
index 0000000..1f6dcec
--- /dev/null
+++ b/TouchDB-Android/.settings/org.hibernate.eclipse.console.prefs
@@ -0,0 +1,4 @@
+#Sat Mar 30 13:04:34 GMT+05:30 2013
+default.configuration=
+eclipse.preferences.version=1
+hibernate3.enabled=false
diff --git a/TouchDB-Android/project.properties b/TouchDB-Android/project.properties
index e61077f..4c10f5c 100644
--- a/TouchDB-Android/project.properties
+++ b/TouchDB-Android/project.properties
@@ -8,5 +8,5 @@
# project structure.
# Project target.
-target=android-17
+target=Google Inc.:Google APIs:15
android.library=true
diff --git a/TouchDB-Android/src/com/couchbase/touchdb/TDDatabase.java b/TouchDB-Android/src/com/couchbase/touchdb/TDDatabase.java
index 7fe8555..aefa66b 100644
--- a/TouchDB-Android/src/com/couchbase/touchdb/TDDatabase.java
+++ b/TouchDB-Android/src/com/couchbase/touchdb/TDDatabase.java
@@ -23,6 +23,7 @@
import java.io.InputStream;
import java.net.URL;
import java.util.ArrayList;
+import java.util.Date;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.HashSet;
@@ -35,6 +36,7 @@
import android.content.ContentValues;
import android.database.Cursor;
import android.database.SQLException;
+import android.database.sqlite.SQLiteConstraintException;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteException;
import android.util.Log;
@@ -52,2462 +54,2793 @@
*/
public class TDDatabase extends Observable {
- private String path;
- private String name;
- private SQLiteDatabase database;
- private boolean open = false;
- private int transactionLevel = 0;
- public static final String TAG = "TDDatabase";
-
- private Map views;
- private Map filters;
- private Map validations;
- private List activeReplicators;
- private TDBlobStore attachments;
-
- /**
- * Options for what metadata to include in document bodies
- */
- public enum TDContentOptions {
- TDIncludeAttachments, TDIncludeConflicts, TDIncludeRevs, TDIncludeRevsInfo, TDIncludeLocalSeq, TDNoBody
- }
-
- private static final Set KNOWN_SPECIAL_KEYS;
-
- static {
- KNOWN_SPECIAL_KEYS = new HashSet();
- KNOWN_SPECIAL_KEYS.add("_id");
- KNOWN_SPECIAL_KEYS.add("_rev");
- KNOWN_SPECIAL_KEYS.add("_attachments");
- KNOWN_SPECIAL_KEYS.add("_deleted");
- KNOWN_SPECIAL_KEYS.add("_revisions");
- KNOWN_SPECIAL_KEYS.add("_revs_info");
- KNOWN_SPECIAL_KEYS.add("_conflicts");
- KNOWN_SPECIAL_KEYS.add("_deleted_conflicts");
- }
-
- public static final String SCHEMA = "" +
- "CREATE TABLE docs ( " +
- " doc_id INTEGER PRIMARY KEY, " +
- " docid TEXT UNIQUE NOT NULL); " +
- " CREATE INDEX docs_docid ON docs(docid); " +
- " CREATE TABLE revs ( " +
- " sequence INTEGER PRIMARY KEY AUTOINCREMENT, " +
- " doc_id INTEGER NOT NULL REFERENCES docs(doc_id) ON DELETE CASCADE, " +
- " revid TEXT NOT NULL, " +
- " parent INTEGER REFERENCES revs(sequence) ON DELETE SET NULL, " +
- " current BOOLEAN, " +
- " deleted BOOLEAN DEFAULT 0, " +
- " json BLOB); " +
- " CREATE INDEX revs_by_id ON revs(revid, doc_id); " +
- " CREATE INDEX revs_current ON revs(doc_id, current); " +
- " CREATE INDEX revs_parent ON revs(parent); " +
- " CREATE TABLE localdocs ( " +
- " docid TEXT UNIQUE NOT NULL, " +
- " revid TEXT NOT NULL, " +
- " json BLOB); " +
- " CREATE INDEX localdocs_by_docid ON localdocs(docid); " +
- " CREATE TABLE views ( " +
- " view_id INTEGER PRIMARY KEY, " +
- " name TEXT UNIQUE NOT NULL," +
- " version TEXT, " +
- " lastsequence INTEGER DEFAULT 0); " +
- " CREATE INDEX views_by_name ON views(name); " +
- " CREATE TABLE maps ( " +
- " view_id INTEGER NOT NULL REFERENCES views(view_id) ON DELETE CASCADE, " +
- " sequence INTEGER NOT NULL REFERENCES revs(sequence) ON DELETE CASCADE, " +
- " key TEXT NOT NULL COLLATE JSON, " +
- " value TEXT); " +
- " CREATE INDEX maps_keys on maps(view_id, key COLLATE JSON); " +
- " CREATE TABLE attachments ( " +
- " sequence INTEGER NOT NULL REFERENCES revs(sequence) ON DELETE CASCADE, " +
- " filename TEXT NOT NULL, " +
- " key BLOB NOT NULL, " +
- " type TEXT, " +
- " length INTEGER NOT NULL, " +
- " revpos INTEGER DEFAULT 0); " +
- " CREATE INDEX attachments_by_sequence on attachments(sequence, filename); " +
- " CREATE TABLE replicators ( " +
- " remote TEXT NOT NULL, " +
- " push BOOLEAN, " +
- " last_sequence TEXT, " +
- " UNIQUE (remote, push)); " +
- " PRAGMA user_version = 3"; // at the end, update user_version
-
- /*************************************************************************************************/
- /*** TDDatabase ***/
- /*************************************************************************************************/
-
- public String getAttachmentStorePath() {
- String attachmentStorePath = path;
- int lastDotPosition = attachmentStorePath.lastIndexOf('.');
- if( lastDotPosition > 0 ) {
- attachmentStorePath = attachmentStorePath.substring(0, lastDotPosition);
- }
- attachmentStorePath = attachmentStorePath + File.separator + "attachments";
- return attachmentStorePath;
- }
-
- public static TDDatabase createEmptyDBAtPath(String path) {
- if(!FileDirUtils.removeItemIfExists(path)) {
- return null;
- }
- TDDatabase result = new TDDatabase(path);
- File af = new File(result.getAttachmentStorePath());
- //recursively delete attachments path
- if(!FileDirUtils.deleteRecursive(af)) {
- return null;
- }
- if(!result.open()) {
- return null;
- }
- return result;
- }
-
- public TDDatabase(String path) {
- assert(path.startsWith("/")); //path must be absolute
- this.path = path;
- this.name = FileDirUtils.getDatabaseNameFromPath(path);
- }
-
- public String toString() {
- return this.getClass().getName() + "[" + path + "]";
- }
-
- public boolean exists() {
- return new File(path).exists();
- }
-
- /**
- * Replaces the database with a copy of another database.
- *
- * This is primarily used to install a canned database on first launch of an app, in which case you should first check .exists to avoid replacing the database if it exists already. The canned database would have been copied into your app bundle at build time.
- *
- * @param databasePath Path of the database file that should replace this one.
- * @param attachmentsPath Path of the associated attachments directory, or nil if there are no attachments.
- * @return true if the database was copied, IOException if an error occurs
- **/
- public boolean replaceWithDatabase(String databasePath, String attachmentsPath) throws IOException {
- String dstAttachmentsPath = this.getAttachmentStorePath();
- File sourceFile = new File(databasePath);
- File destFile = new File(path);
- FileDirUtils.copyFile(sourceFile, destFile);
- File attachmentsFile = new File(dstAttachmentsPath);
- FileDirUtils.deleteRecursive(attachmentsFile);
- attachmentsFile.mkdirs();
- if(attachmentsPath != null) {
- FileDirUtils.copyFolder(new File(attachmentsPath), attachmentsFile);
- }
- return true;
- }
-
- public boolean initialize(String statements) {
- try {
- for (String statement : statements.split(";")) {
- database.execSQL(statement);
- }
- } catch (SQLException e) {
- close();
- return false;
- }
- return true;
- }
-
- public boolean open() {
- if(open) {
- return true;
- }
-
- try {
- database = SQLiteDatabase.openDatabase(path, null, SQLiteDatabase.CREATE_IF_NECESSARY);
- TDCollateJSON.registerCustomCollators(database);
- }
- catch(SQLiteException e) {
- Log.e(TDDatabase.TAG, "Error opening", e);
- return false;
- }
-
- // Stuff we need to initialize every time the database opens:
- if(!initialize("PRAGMA foreign_keys = ON;")) {
- Log.e(TDDatabase.TAG, "Error turning on foreign keys");
- return false;
- }
-
- // Check the user_version number we last stored in the database:
- int dbVersion = database.getVersion();
-
- // Incompatible version changes increment the hundreds' place:
- if(dbVersion >= 100) {
- Log.w(TDDatabase.TAG, "TDDatabase: Database version (" + dbVersion + ") is newer than I know how to work with");
- database.close();
- return false;
- }
-
- if(dbVersion < 1) {
- // First-time initialization:
- // (Note: Declaring revs.sequence as AUTOINCREMENT means the values will always be
- // monotonically increasing, never reused. See )
- if(!initialize(SCHEMA)) {
- database.close();
- return false;
- }
- dbVersion = 3;
- }
-
- if (dbVersion < 2) {
- // Version 2: added attachments.revpos
- String upgradeSql = "ALTER TABLE attachments ADD COLUMN revpos INTEGER DEFAULT 0; " +
- "PRAGMA user_version = 2";
- if(!initialize(upgradeSql)) {
- database.close();
- return false;
- }
- dbVersion = 2;
- }
-
- if (dbVersion < 3) {
- String upgradeSql = "CREATE TABLE localdocs ( " +
- "docid TEXT UNIQUE NOT NULL, " +
- "revid TEXT NOT NULL, " +
- "json BLOB); " +
- "CREATE INDEX localdocs_by_docid ON localdocs(docid); " +
- "PRAGMA user_version = 3";
- if(!initialize(upgradeSql)) {
- database.close();
- return false;
- }
- dbVersion = 3;
- }
-
- if (dbVersion < 4) {
- String upgradeSql = "CREATE TABLE info ( " +
- "key TEXT PRIMARY KEY, " +
- "value TEXT); " +
- "INSERT INTO INFO (key, value) VALUES ('privateUUID', '" + TDMisc.TDCreateUUID() + "'); " +
- "INSERT INTO INFO (key, value) VALUES ('publicUUID', '" + TDMisc.TDCreateUUID() + "'); " +
- "PRAGMA user_version = 4";
- if(!initialize(upgradeSql)) {
- database.close();
- return false;
- }
- }
-
- try {
- attachments = new TDBlobStore(getAttachmentStorePath());
- } catch (IllegalArgumentException e) {
- Log.e(TDDatabase.TAG, "Could not initialize attachment store", e);
- database.close();
- return false;
- }
-
- open = true;
- return true;
- }
-
- public boolean close() {
- if(!open) {
- return false;
- }
-
- if(views != null) {
- for (TDView view : views.values()) {
- view.databaseClosing();
- }
- }
- views = null;
-
- if(activeReplicators != null) {
- for(TDReplicator replicator : activeReplicators) {
- replicator.databaseClosing();
- }
- activeReplicators = null;
- }
-
- if(database != null && database.isOpen()) {
- database.close();
- }
- open = false;
- transactionLevel = 0;
- return true;
- }
-
- public boolean deleteDatabase() {
- if(open) {
- if(!close()) {
- return false;
- }
- }
- else if(!exists()) {
- return true;
- }
- File file = new File(path);
- File attachmentsFile = new File(getAttachmentStorePath());
-
- boolean deleteStatus = file.delete();
- //recursively delete attachments path
- boolean deleteAttachmentStatus = FileDirUtils.deleteRecursive(attachmentsFile);
- return deleteStatus && deleteAttachmentStatus;
- }
-
- public String getPath() {
- return path;
- }
-
- public String getName() {
- return name;
- }
-
- public void setName(String name) {
- this.name = name;
- }
-
- // Leave this package protected, so it can only be used
- // TDView uses this accessor
- SQLiteDatabase getDatabase() {
- return database;
- }
-
- public TDBlobStore getAttachments() {
- return attachments;
- }
-
- public long totalDataSize() {
- File f = new File(path);
- long size = f.length() + attachments.totalDataSize();
- return size;
- }
-
- /**
- * Begins a database transaction. Transactions can nest.
- * Every beginTransaction() must be balanced by a later endTransaction()
- */
- public boolean beginTransaction() {
- try {
- database.beginTransaction();
- ++transactionLevel;
- //Log.v(TAG, "Begin transaction (level " + Integer.toString(transactionLevel) + ")...");
- } catch (SQLException e) {
- return false;
- }
- return true;
- }
-
- /**
- * Commits or aborts (rolls back) a transaction.
- *
- * @param commit If true, commits; if false, aborts and rolls back, undoing all changes made since the matching -beginTransaction call, *including* any committed nested transactions.
- */
- public boolean endTransaction(boolean commit) {
- assert(transactionLevel > 0);
-
- if(commit) {
- //Log.v(TAG, "Committing transaction (level " + Integer.toString(transactionLevel) + ")...");
- database.setTransactionSuccessful();
- database.endTransaction();
- }
- else {
- Log.v(TAG, "CANCEL transaction (level " + Integer.toString(transactionLevel) + ")...");
- try {
- database.endTransaction();
- } catch (SQLException e) {
- return false;
- }
- }
-
- --transactionLevel;
- return true;
- }
-
- /**
- * Compacts the database storage by removing the bodies and attachments of obsolete revisions.
- */
- public TDStatus compact() {
- // Can't delete any rows because that would lose revision tree history.
- // But we can remove the JSON of non-current revisions, which is most of the space.
- try {
- Log.v(TDDatabase.TAG, "Deleting JSON of old revisions...");
- ContentValues args = new ContentValues();
- args.put("json", (String)null);
- database.update("revs", args, "current=0", null);
- } catch (SQLException e) {
- Log.e(TDDatabase.TAG, "Error compacting", e);
- return new TDStatus(TDStatus.INTERNAL_SERVER_ERROR);
- }
-
- Log.v(TDDatabase.TAG, "Deleting old attachments...");
- TDStatus result = garbageCollectAttachments();
-
- Log.v(TDDatabase.TAG, "Vacuuming SQLite database...");
- try {
- database.execSQL("VACUUM");
- } catch (SQLException e) {
- Log.e(TDDatabase.TAG, "Error vacuuming database", e);
- return new TDStatus(TDStatus.INTERNAL_SERVER_ERROR);
- }
-
- return result;
- }
-
- public String privateUUID() {
- String result = null;
- Cursor cursor = null;
- try {
- cursor = database.rawQuery("SELECT value FROM info WHERE key='privateUUID'", null);
- if(cursor.moveToFirst()) {
- result = cursor.getString(0);
- }
- } catch(SQLException e) {
- Log.e(TAG, "Error querying privateUUID", e);
- } finally {
- if(cursor != null) {
- cursor.close();
- }
- }
- return result;
- }
-
- public String publicUUID() {
- String result = null;
- Cursor cursor = null;
- try {
- cursor = database.rawQuery("SELECT value FROM info WHERE key='publicUUID'", null);
- if(cursor.moveToFirst()) {
- result = cursor.getString(0);
- }
- } catch(SQLException e) {
- Log.e(TAG, "Error querying privateUUID", e);
- } finally {
- if(cursor != null) {
- cursor.close();
- }
- }
- return result;
- }
-
- /** GETTING DOCUMENTS: **/
-
- public int getDocumentCount() {
- String sql = "SELECT COUNT(DISTINCT doc_id) FROM revs WHERE current=1 AND deleted=0";
- Cursor cursor = null;
- int result = 0;
- try {
- cursor = database.rawQuery(sql, null);
- if(cursor.moveToFirst()) {
- result = cursor.getInt(0);
- }
- } catch(SQLException e) {
- Log.e(TDDatabase.TAG, "Error getting document count", e);
- } finally {
- if(cursor != null) {
- cursor.close();
- }
- }
-
- return result;
- }
-
- public long getLastSequence() {
- String sql = "SELECT MAX(sequence) FROM revs";
- Cursor cursor = null;
- long result = 0;
- try {
- cursor = database.rawQuery(sql, null);
- if(cursor.moveToFirst()) {
- result = cursor.getLong(0);
- }
- } catch (SQLException e) {
- Log.e(TDDatabase.TAG, "Error getting last sequence", e);
- } finally {
- if(cursor != null) {
- cursor.close();
- }
- }
- return result;
- }
-
- /** Splices the contents of an NSDictionary into JSON data (that already represents a dict), without parsing the JSON. */
- public byte[] appendDictToJSON(byte[] json, Map dict) {
- if(dict.size() == 0) {
- return json;
- }
-
- byte[] extraJSON = null;
- try {
- extraJSON = TDServer.getObjectMapper().writeValueAsBytes(dict);
- } catch (Exception e) {
- Log.e(TDDatabase.TAG, "Error convert extra JSON to bytes", e);
- return null;
- }
-
- int jsonLength = json.length;
- int extraLength = extraJSON.length;
- if(jsonLength == 2) { // Original JSON was empty
- return extraJSON;
- }
- byte[] newJson = new byte[jsonLength + extraLength - 1];
- System.arraycopy(json, 0, newJson, 0, jsonLength - 1); // Copy json w/o trailing '}'
- newJson[jsonLength - 1] = ','; // Add a ','
- System.arraycopy(extraJSON, 1, newJson, jsonLength, extraLength - 1);
- return newJson;
- }
-
- /** Inserts the _id, _rev and _attachments properties into the JSON data and stores it in rev.
- Rev must already have its revID and sequence properties set. */
- public Map extraPropertiesForRevision(TDRevision rev, EnumSet contentOptions) {
-
- String docId = rev.getDocId();
- String revId = rev.getRevId();
- long sequenceNumber = rev.getSequence();
- assert(revId != null);
- assert(sequenceNumber > 0);
-
- // Get attachment metadata, and optionally the contents:
- boolean withAttachments = contentOptions.contains(TDContentOptions.TDIncludeAttachments);
- Map attachmentsDict = getAttachmentsDictForSequenceWithContent(sequenceNumber, withAttachments);
-
- // Get more optional stuff to put in the properties:
- //OPT: This probably ends up making redundant SQL queries if multiple options are enabled.
- Long localSeq = null;
- if(contentOptions.contains(TDContentOptions.TDIncludeLocalSeq)) {
- localSeq = sequenceNumber;
- }
-
- Map revHistory = null;
- if(contentOptions.contains(TDContentOptions.TDIncludeRevs)) {
- revHistory = getRevisionHistoryDict(rev);
- }
-
- List