Created
September 17, 2013 11:50
-
-
Save vmx/6593306 to your computer and use it in GitHub Desktop.
This is what I hacked together in June. I don't think it works, but you perhaps get some idea.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/CouchbaseLiteProject/.idea/libraries/CBLite_aar.xml b/CouchbaseLiteProject/.idea/libraries/CBLite_aar.xml | |
index 0a46271..fad1f82 100644 | |
--- a/CouchbaseLiteProject/.idea/libraries/CBLite_aar.xml | |
+++ b/CouchbaseLiteProject/.idea/libraries/CBLite_aar.xml | |
@@ -2,6 +2,8 @@ | |
<library name="CBLite.aar"> | |
<CLASSES> | |
<root url="jar://$PROJECT_DIR$/CBLiteEktorp/build/exploded-bundles/CBLite.aar/classes.jar!/" /> | |
+ <root url="jar://$PROJECT_DIR$/CBLiteJavascript/build/exploded-bundles/CBLite.aar/classes.jar!/" /> | |
+ <root url="jar://$PROJECT_DIR$/CBLiteListener/build/exploded-bundles/CBLite.aar/classes.jar!/" /> | |
</CLASSES> | |
<JAVADOC /> | |
<SOURCES /> | |
diff --git a/CouchbaseLiteProject/.idea/libraries/commons_io_2_0_1.xml b/CouchbaseLiteProject/.idea/libraries/commons_io_2_0_1.xml | |
index 2facd2d..0a01985 100644 | |
--- a/CouchbaseLiteProject/.idea/libraries/commons_io_2_0_1.xml | |
+++ b/CouchbaseLiteProject/.idea/libraries/commons_io_2_0_1.xml | |
@@ -3,6 +3,8 @@ | |
<CLASSES> | |
<root url="jar://$USER_HOME$/.gradle/caches/artifacts-24/filestore/commons-io/commons-io/2.0.1/jar/7ffdb02f95af1c1a208544e076cea5b8e66e731a/commons-io-2.0.1.jar!/" /> | |
<root url="jar://$MAVEN_REPOSITORY$/commons-io/commons-io/2.0.1/commons-io-2.0.1.jar!/" /> | |
+ <root url="jar://$PROJECT_DIR$/CBLiteEktorp/libs/commons-io-2.0.1.jar!/" /> | |
+ <root url="jar://$PROJECT_DIR$/CBLiteJavascript/build/exploded-bundles/CBLiteEktorp.aar/libs/commons-io-2.0.1.jar!/" /> | |
</CLASSES> | |
<JAVADOC /> | |
<SOURCES /> | |
diff --git a/CouchbaseLiteProject/.idea/libraries/jackson_core_asl_1_9_2.xml b/CouchbaseLiteProject/.idea/libraries/jackson_core_asl_1_9_2.xml | |
index 8980760..8377f4a 100644 | |
--- a/CouchbaseLiteProject/.idea/libraries/jackson_core_asl_1_9_2.xml | |
+++ b/CouchbaseLiteProject/.idea/libraries/jackson_core_asl_1_9_2.xml | |
@@ -4,6 +4,9 @@ | |
<root url="jar://$USER_HOME$/.gradle/caches/artifacts-24/filestore/org.codehaus.jackson/jackson-core-asl/1.9.2/jar/8493982bba1727106d767034bd0d8e77bc1931a9/jackson-core-asl-1.9.2.jar!/" /> | |
<root url="jar://$PROJECT_DIR$/CBLite/libs/jackson-core-asl-1.9.2.jar!/" /> | |
<root url="jar://$PROJECT_DIR$/CBLiteJavascript/libs/jackson-core-asl-1.9.2.jar!/" /> | |
+ <root url="jar://$PROJECT_DIR$/CBLiteEktorp/build/exploded-bundles/CBLite.aar/libs/jackson-core-asl-1.9.2.jar!/" /> | |
+ <root url="jar://$PROJECT_DIR$/CBLiteJavascript/build/exploded-bundles/CBLite.aar/libs/jackson-core-asl-1.9.2.jar!/" /> | |
+ <root url="jar://$PROJECT_DIR$/CBLiteListener/build/exploded-bundles/CBLite.aar/libs/jackson-core-asl-1.9.2.jar!/" /> | |
</CLASSES> | |
<JAVADOC /> | |
<SOURCES /> | |
diff --git a/CouchbaseLiteProject/.idea/libraries/jackson_mapper_asl_1_9_2.xml b/CouchbaseLiteProject/.idea/libraries/jackson_mapper_asl_1_9_2.xml | |
index bccae79..3589729 100644 | |
--- a/CouchbaseLiteProject/.idea/libraries/jackson_mapper_asl_1_9_2.xml | |
+++ b/CouchbaseLiteProject/.idea/libraries/jackson_mapper_asl_1_9_2.xml | |
@@ -4,6 +4,9 @@ | |
<root url="jar://$USER_HOME$/.gradle/caches/artifacts-24/filestore/org.codehaus.jackson/jackson-mapper-asl/1.9.2/jar/95400a7922ce75383866eb72f6ef4a7897923945/jackson-mapper-asl-1.9.2.jar!/" /> | |
<root url="jar://$PROJECT_DIR$/CBLite/libs/jackson-mapper-asl-1.9.2.jar!/" /> | |
<root url="jar://$PROJECT_DIR$/CBLiteJavascript/libs/jackson-mapper-asl-1.9.2.jar!/" /> | |
+ <root url="jar://$PROJECT_DIR$/CBLiteEktorp/build/exploded-bundles/CBLite.aar/libs/jackson-mapper-asl-1.9.2.jar!/" /> | |
+ <root url="jar://$PROJECT_DIR$/CBLiteJavascript/build/exploded-bundles/CBLite.aar/libs/jackson-mapper-asl-1.9.2.jar!/" /> | |
+ <root url="jar://$PROJECT_DIR$/CBLiteListener/build/exploded-bundles/CBLite.aar/libs/jackson-mapper-asl-1.9.2.jar!/" /> | |
</CLASSES> | |
<JAVADOC /> | |
<SOURCES /> | |
diff --git a/CouchbaseLiteProject/.idea/libraries/org_ektorp_1_2_2.xml b/CouchbaseLiteProject/.idea/libraries/org_ektorp_1_2_2.xml | |
index b77c025..7f20d36 100644 | |
--- a/CouchbaseLiteProject/.idea/libraries/org_ektorp_1_2_2.xml | |
+++ b/CouchbaseLiteProject/.idea/libraries/org_ektorp_1_2_2.xml | |
@@ -2,6 +2,8 @@ | |
<library name="org.ektorp-1.2.2"> | |
<CLASSES> | |
<root url="jar://$USER_HOME$/.gradle/caches/artifacts-24/filestore/org.ektorp/org.ektorp/1.2.2/jar/3b35f20715a8f3686adec854b57bd10dad353045/org.ektorp-1.2.2.jar!/" /> | |
+ <root url="jar://$PROJECT_DIR$/CBLiteEktorp/libs/org.ektorp-1.2.2.jar!/" /> | |
+ <root url="jar://$PROJECT_DIR$/CBLiteJavascript/build/exploded-bundles/CBLiteEktorp.aar/libs/org.ektorp-1.2.2.jar!/" /> | |
</CLASSES> | |
<JAVADOC /> | |
<SOURCES /> | |
diff --git a/CouchbaseLiteProject/.idea/libraries/org_ektorp_android_1_2_2.xml b/CouchbaseLiteProject/.idea/libraries/org_ektorp_android_1_2_2.xml | |
index 0b895c0..99c1c8d 100644 | |
--- a/CouchbaseLiteProject/.idea/libraries/org_ektorp_android_1_2_2.xml | |
+++ b/CouchbaseLiteProject/.idea/libraries/org_ektorp_android_1_2_2.xml | |
@@ -2,6 +2,8 @@ | |
<library name="org.ektorp.android-1.2.2"> | |
<CLASSES> | |
<root url="jar://$USER_HOME$/.gradle/caches/artifacts-24/filestore/org.ektorp/org.ektorp.android/1.2.2/jar/63c5dcdb3c383eb035001aa216b28b38e4ddd9a4/org.ektorp.android-1.2.2.jar!/" /> | |
+ <root url="jar://$PROJECT_DIR$/CBLiteEktorp/libs/org.ektorp.android-1.2.2.jar!/" /> | |
+ <root url="jar://$PROJECT_DIR$/CBLiteJavascript/build/exploded-bundles/CBLiteEktorp.aar/libs/org.ektorp.android-1.2.2.jar!/" /> | |
</CLASSES> | |
<JAVADOC /> | |
<SOURCES /> | |
diff --git a/CouchbaseLiteProject/.idea/libraries/slf4j_api_1_6_1.xml b/CouchbaseLiteProject/.idea/libraries/slf4j_api_1_6_1.xml | |
index 44dd477..7a0e281 100644 | |
--- a/CouchbaseLiteProject/.idea/libraries/slf4j_api_1_6_1.xml | |
+++ b/CouchbaseLiteProject/.idea/libraries/slf4j_api_1_6_1.xml | |
@@ -2,6 +2,8 @@ | |
<library name="slf4j-api-1.6.1"> | |
<CLASSES> | |
<root url="jar://$USER_HOME$/.gradle/caches/artifacts-24/filestore/org.slf4j/slf4j-api/1.6.1/jar/6f3b8a24bf970f17289b234284c94f43eb42f0e4/slf4j-api-1.6.1.jar!/" /> | |
+ <root url="jar://$PROJECT_DIR$/CBLiteEktorp/libs/slf4j-api-1.6.1.jar!/" /> | |
+ <root url="jar://$PROJECT_DIR$/CBLiteJavascript/build/exploded-bundles/CBLiteEktorp.aar/libs/slf4j-api-1.6.1.jar!/" /> | |
</CLASSES> | |
<JAVADOC /> | |
<SOURCES /> | |
diff --git a/CouchbaseLiteProject/.idea/libraries/slf4j_jdk14_1_6_1.xml b/CouchbaseLiteProject/.idea/libraries/slf4j_jdk14_1_6_1.xml | |
index 6c130a4..ca58477 100644 | |
--- a/CouchbaseLiteProject/.idea/libraries/slf4j_jdk14_1_6_1.xml | |
+++ b/CouchbaseLiteProject/.idea/libraries/slf4j_jdk14_1_6_1.xml | |
@@ -2,6 +2,8 @@ | |
<library name="slf4j-jdk14-1.6.1"> | |
<CLASSES> | |
<root url="jar://$USER_HOME$/.gradle/caches/artifacts-24/filestore/org.slf4j/slf4j-jdk14/1.6.1/jar/251899d8c17e29ed4c53d98c88e54241a14d9591/slf4j-jdk14-1.6.1.jar!/" /> | |
+ <root url="jar://$PROJECT_DIR$/CBLiteEktorp/libs/slf4j-jdk14-1.6.1.jar!/" /> | |
+ <root url="jar://$PROJECT_DIR$/CBLiteJavascript/build/exploded-bundles/CBLiteEktorp.aar/libs/slf4j-jdk14-1.6.1.jar!/" /> | |
</CLASSES> | |
<JAVADOC /> | |
<SOURCES /> | |
diff --git a/CouchbaseLiteProject/.idea/misc.xml b/CouchbaseLiteProject/.idea/misc.xml | |
index 8f7672f..d38a61c 100644 | |
--- a/CouchbaseLiteProject/.idea/misc.xml | |
+++ b/CouchbaseLiteProject/.idea/misc.xml | |
@@ -4,7 +4,7 @@ | |
<entry_points version="2.0" /> | |
</component> | |
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_6" assert-keyword="true" jdk-15="true" project-jdk-name="Android 4.2.2" project-jdk-type="Android SDK"> | |
- <output url="file://$PROJECT_DIR$/build/classes" /> | |
+ <output url="file://$PROJECT_DIR$/classes" /> | |
</component> | |
</project> | |
diff --git a/CouchbaseLiteProject/.idea/modules.xml b/CouchbaseLiteProject/.idea/modules.xml | |
index 91f6afa..073b3a4 100644 | |
--- a/CouchbaseLiteProject/.idea/modules.xml | |
+++ b/CouchbaseLiteProject/.idea/modules.xml | |
@@ -2,12 +2,12 @@ | |
<project version="4"> | |
<component name="ProjectModuleManager"> | |
<modules> | |
- <module fileurl="file://$PROJECT_DIR$/CBLite.iml" filepath="$PROJECT_DIR$/CBLite.iml" /> | |
+ <module fileurl="file://$PROJECT_DIR$/CBLite/CBLite.iml" filepath="$PROJECT_DIR$/CBLite/CBLite.iml" /> | |
<module fileurl="file://$PROJECT_DIR$/CBLiteEktorp/CBLiteEktorp.iml" filepath="$PROJECT_DIR$/CBLiteEktorp/CBLiteEktorp.iml" /> | |
<module fileurl="file://$PROJECT_DIR$/CBLiteJavascript/CBLiteJavascript.iml" filepath="$PROJECT_DIR$/CBLiteJavascript/CBLiteJavascript.iml" /> | |
<module fileurl="file://$PROJECT_DIR$/CBLiteListener/CBLiteListener.iml" filepath="$PROJECT_DIR$/CBLiteListener/CBLiteListener.iml" /> | |
<module fileurl="file://$PROJECT_DIR$/CouchbaseLiteProject.iml" filepath="$PROJECT_DIR$/CouchbaseLiteProject.iml" /> | |
- <module fileurl="file://$PROJECT_DIR$/CouchbaseLiteProject-CouchbaseLiteProject.iml" filepath="$PROJECT_DIR$/CouchbaseLiteProject-CouchbaseLiteProject.iml" /> | |
+ <module fileurl="file://$PROJECT_DIR$/CouchbaseLiteProject/CouchbaseLiteProject-CouchbaseLiteProject.iml" filepath="$PROJECT_DIR$/CouchbaseLiteProject/CouchbaseLiteProject-CouchbaseLiteProject.iml" /> | |
</modules> | |
</component> | |
</project> | |
diff --git a/CouchbaseLiteProject/CBLite/src/instrumentTest/java/com/couchbase/cblite/testapp/tests/Collation.java b/CouchbaseLiteProject/CBLite/src/instrumentTest/java/com/couchbase/cblite/testapp/tests/Collation.java | |
index 1ca4901..214d429 100644 | |
--- a/CouchbaseLiteProject/CBLite/src/instrumentTest/java/com/couchbase/cblite/testapp/tests/Collation.java | |
+++ b/CouchbaseLiteProject/CBLite/src/instrumentTest/java/com/couchbase/cblite/testapp/tests/Collation.java | |
@@ -30,7 +30,7 @@ public class Collation extends AndroidTestCase { | |
return null; | |
} | |
} | |
- | |
+/* | |
public void testCollateScalars() { | |
int mode = kTDCollateJSON_Unicode; | |
@@ -101,8 +101,8 @@ public class Collation extends AndroidTestCase { | |
public void testCollateUnicodeStrings() { | |
int mode = kTDCollateJSON_Unicode; | |
- Assert.assertEquals(0, TDCollateJSON.testCollateJSON(mode, 0, encode("fr仕"), 0, encode("fr仕"))); | |
- Assert.assertEquals(1, TDCollateJSON.testCollateJSON(mode, 0, encode("ソmソ"), 0, encode("omo"))); | |
+ Assert.assertEquals(0, TDCollateJSON.testCollateJSON(mode, 0, encode("frスd"), 0, encode("frスd"))); | |
+ Assert.assertEquals(1, TDCollateJSON.testCollateJSON(mode, 0, encode("スmス"), 0, encode("omo"))); | |
Assert.assertEquals(-1, TDCollateJSON.testCollateJSON(mode, 0, encode("\t"), 0, encode(" "))); | |
Assert.assertEquals(-1, TDCollateJSON.testCollateJSON(mode, 0, encode("\001"), 0, encode(" "))); | |
@@ -122,5 +122,5 @@ public class Collation extends AndroidTestCase { | |
Assert.assertEquals(0xc, TDCollateJSON.testDigitToInt('c')); | |
Assert.assertEquals(0xc, TDCollateJSON.testDigitToInt('C')); | |
} | |
- | |
+*/ | |
} | |
diff --git a/CouchbaseLiteProject/CBLite/src/instrumentTest/java/com/couchbase/cblite/testapp/tests/Router.java b/CouchbaseLiteProject/CBLite/src/instrumentTest/java/com/couchbase/cblite/testapp/tests/Router.java | |
index 8e4d2be..1bfd8bd 100644 | |
--- a/CouchbaseLiteProject/CBLite/src/instrumentTest/java/com/couchbase/cblite/testapp/tests/Router.java | |
+++ b/CouchbaseLiteProject/CBLite/src/instrumentTest/java/com/couchbase/cblite/testapp/tests/Router.java | |
@@ -9,8 +9,8 @@ import junit.framework.Assert; | |
import android.util.Log; | |
import com.couchbase.cblite.CBLDatabase; | |
+import com.couchbase.cblite.CBLMapReduce; | |
import com.couchbase.cblite.CBLStatus; | |
-import com.couchbase.cblite.CBLView; | |
import com.couchbase.cblite.CBLViewMapBlock; | |
import com.couchbase.cblite.CBLViewMapEmitBlock; | |
import com.couchbase.cblite.router.CBLRouter; | |
@@ -306,7 +306,7 @@ public class Router extends CBLiteTestCase { | |
String revID2 = (String)result.get("rev"); | |
CBLDatabase db = server.getDatabaseNamed("db"); | |
- CBLView view = db.getViewNamed("design/view"); | |
+ CBLMapReduce view = db.getViewNamed("design/view"); | |
view.setMapReduceBlocks(new CBLViewMapBlock() { | |
@Override | |
@@ -397,7 +397,8 @@ public class Router extends CBLiteTestCase { | |
Map<String,Object> result; | |
CBLDatabase db = server.getDatabaseNamed("db"); | |
- CBLView view = db.getViewNamed("design/view"); | |
+ CBLMapReduce view = db.getViewNamed("design/view"); | |
+ | |
view.setMapReduceBlocks(new CBLViewMapBlock() { | |
@Override | |
@@ -423,8 +424,10 @@ public class Router extends CBLiteTestCase { | |
keys.add("12345"); | |
Map<String,Object> bodyObj = new HashMap<String,Object>(); | |
bodyObj.put("keys", keys); | |
+ | |
CBLURLConnection conn = sendRequest(server, "POST", "/db/_design/design/_view/view", null, bodyObj); | |
result = (Map<String, Object>) parseJSONResponse(conn); | |
+ System.out.println("result:" + result); | |
Assert.assertEquals(1, result.get("total_rows")); | |
} | |
diff --git a/CouchbaseLiteProject/CBLite/src/instrumentTest/java/com/couchbase/cblite/testapp/tests/Spatial.java b/CouchbaseLiteProject/CBLite/src/instrumentTest/java/com/couchbase/cblite/testapp/tests/Spatial.java | |
index 6d5fc61..a58c7a8 100644 | |
--- a/CouchbaseLiteProject/CBLite/src/instrumentTest/java/com/couchbase/cblite/testapp/tests/Spatial.java | |
+++ b/CouchbaseLiteProject/CBLite/src/instrumentTest/java/com/couchbase/cblite/testapp/tests/Spatial.java | |
@@ -17,73 +17,75 @@ | |
package com.couchbase.cblite.testapp.tests; | |
-import java.util.ArrayList; | |
-import java.util.HashMap; | |
-import java.util.List; | |
-import java.util.Map; | |
- | |
-import junit.framework.Assert; | |
import android.util.Log; | |
import com.couchbase.cblite.CBLDatabase; | |
import com.couchbase.cblite.CBLMapReduce; | |
-import com.couchbase.cblite.CBLView; | |
import com.couchbase.cblite.CBLQueryOptions; | |
import com.couchbase.cblite.CBLRevision; | |
+import com.couchbase.cblite.CBLSpatial; | |
import com.couchbase.cblite.CBLStatus; | |
+import com.couchbase.cblite.CBLView; | |
import com.couchbase.cblite.CBLView.TDViewCollation; | |
import com.couchbase.cblite.CBLViewMapBlock; | |
import com.couchbase.cblite.CBLViewMapEmitBlock; | |
import com.couchbase.cblite.CBLViewReduceBlock; | |
+import junit.framework.Assert; | |
+ | |
+import java.util.ArrayList; | |
+import java.util.HashMap; | |
+import java.util.List; | |
+import java.util.Map; | |
+ | |
public class Spatial extends CBLiteTestCase { | |
- public static final String TAG = "Views"; | |
+ public static final String TAG = "Spatial"; | |
public void testViewCreation() { | |
- Assert.assertNull(database.getExistingViewNamed("aview")); | |
+ Assert.assertNull(database.getExistingSpatialViewNamed("aview")); | |
- CBLMapReduce view = database.getViewNamed("aview"); | |
+ CBLSpatial view = database.getSpatialViewNamed("aview"); | |
Assert.assertNotNull(view); | |
Assert.assertEquals(database, view.getDb()); | |
Assert.assertEquals("aview", view.getName()); | |
Assert.assertNull(view.getMapBlock()); | |
- Assert.assertEquals(view, database.getExistingViewNamed("aview")); | |
+ Assert.assertEquals(view, database.getExistingSpatialViewNamed("aview")); | |
- boolean changed = view.setMapReduceBlocks(new CBLViewMapBlock() { | |
+ boolean changed = view.setSpatialBlock(new CBLViewMapBlock() { | |
@Override | |
public void map(Map<String, Object> document, CBLViewMapEmitBlock emitter) { | |
//no-op | |
} | |
- }, null, "1"); | |
+ }, "1"); | |
Assert.assertTrue(changed); | |
- Assert.assertEquals(1, database.getAllViews().size()); | |
- Assert.assertEquals(view, database.getAllViews().get(0)); | |
+ Assert.assertEquals(1, database.getAllSpatialViews().size()); | |
+ Assert.assertEquals(view, database.getAllSpatialViews().get(0)); | |
- changed = view.setMapReduceBlocks(new CBLViewMapBlock() { | |
+ changed = view.setSpatialBlock(new CBLViewMapBlock() { | |
@Override | |
public void map(Map<String, Object> document, CBLViewMapEmitBlock emitter) { | |
//no-op | |
} | |
- }, null, "1"); | |
+ }, "1"); | |
Assert.assertFalse(changed); | |
- changed = view.setMapReduceBlocks(new CBLViewMapBlock() { | |
+ changed = view.setSpatialBlock(new CBLViewMapBlock() { | |
@Override | |
public void map(Map<String, Object> document, CBLViewMapEmitBlock emitter) { | |
//no-op | |
} | |
- }, null, "2"); | |
+ }, "2"); | |
Assert.assertTrue(changed); | |
} | |
- | |
+/* | |
private CBLRevision putDoc(CBLDatabase db, Map<String,Object> props) { | |
CBLRevision rev = new CBLRevision(props); | |
CBLStatus status = new CBLStatus(); | |
@@ -995,7 +997,7 @@ public class Spatial extends CBLiteTestCase { | |
Assert.assertEquals(5, rows.size()); | |
Object[][] expected = new Object[][] { | |
- /* id, key0, key1, value._id, doc._id */ | |
+ // id, key0, key1, value._id, doc._id | |
new Object[] { "22222", "hello", 0, null, "22222" }, | |
new Object[] { "22222", "hello", 1, "11111", "11111" }, | |
new Object[] { "33333", "world", 0, null, "33333" }, | |
@@ -1021,5 +1023,5 @@ public class Spatial extends CBLiteTestCase { | |
Assert.assertEquals(expected[i][4], doc.get("_id")); | |
} | |
} | |
- | |
+*/ | |
} | |
diff --git a/CouchbaseLiteProject/CBLite/src/instrumentTest/java/com/couchbase/cblite/testapp/tests/Views.java b/CouchbaseLiteProject/CBLite/src/instrumentTest/java/com/couchbase/cblite/testapp/tests/Views.java | |
index 7009313..374d9bd 100644 | |
--- a/CouchbaseLiteProject/CBLite/src/instrumentTest/java/com/couchbase/cblite/testapp/tests/Views.java | |
+++ b/CouchbaseLiteProject/CBLite/src/instrumentTest/java/com/couchbase/cblite/testapp/tests/Views.java | |
@@ -26,10 +26,11 @@ import junit.framework.Assert; | |
import android.util.Log; | |
import com.couchbase.cblite.CBLDatabase; | |
+import com.couchbase.cblite.CBLMapReduce; | |
+import com.couchbase.cblite.CBLView; | |
import com.couchbase.cblite.CBLQueryOptions; | |
import com.couchbase.cblite.CBLRevision; | |
import com.couchbase.cblite.CBLStatus; | |
-import com.couchbase.cblite.CBLView; | |
import com.couchbase.cblite.CBLView.TDViewCollation; | |
import com.couchbase.cblite.CBLViewMapBlock; | |
import com.couchbase.cblite.CBLViewMapEmitBlock; | |
@@ -43,7 +44,7 @@ public class Views extends CBLiteTestCase { | |
Assert.assertNull(database.getExistingViewNamed("aview")); | |
- CBLView view = database.getViewNamed("aview"); | |
+ CBLMapReduce view = database.getViewNamed("aview"); | |
Assert.assertNotNull(view); | |
Assert.assertEquals(database, view.getDb()); | |
Assert.assertEquals("aview", view.getName()); | |
@@ -160,8 +161,8 @@ public class Views extends CBLiteTestCase { | |
} | |
} | |
- public static CBLView createView(CBLDatabase db) { | |
- CBLView view = db.getViewNamed("aview"); | |
+ public static CBLMapReduce createView(CBLDatabase db) { | |
+ CBLMapReduce view = db.getViewNamed("aview"); | |
view.setMapReduceBlocks(new CBLViewMapBlock() { | |
@Override | |
@@ -192,7 +193,7 @@ public class Views extends CBLiteTestCase { | |
CBLRevision rev3 = putDoc(database, dict3); | |
putDoc(database, dictX); | |
- CBLView view = createView(database); | |
+ CBLMapReduce view = createView(database); | |
Assert.assertEquals(1, view.getViewId()); | |
Assert.assertTrue(view.isStale()); | |
@@ -263,7 +264,7 @@ public class Views extends CBLiteTestCase { | |
public void testViewQuery() { | |
putDocs(database); | |
- CBLView view = createView(database); | |
+ CBLMapReduce view = createView(database); | |
CBLStatus updated = view.updateIndex(); | |
Assert.assertEquals(CBLStatus.OK, updated.getCode()); | |
@@ -470,7 +471,7 @@ public class Views extends CBLiteTestCase { | |
docProperties3.put("cost", 6.50); | |
putDoc(database, docProperties3); | |
- CBLView view = database.getViewNamed("totaler"); | |
+ CBLMapReduce view = database.getViewNamed("totaler"); | |
view.setMapReduceBlocks(new CBLViewMapBlock() { | |
@Override | |
@@ -560,7 +561,7 @@ public class Views extends CBLiteTestCase { | |
docProperties5.put("time", 187); | |
putDoc(database, docProperties5); | |
- CBLView view = database.getViewNamed("grouper"); | |
+ CBLMapReduce view = database.getViewNamed("grouper"); | |
view.setMapReduceBlocks(new CBLViewMapBlock() { | |
@Override | |
@@ -734,7 +735,7 @@ public class Views extends CBLiteTestCase { | |
docProperties5.put("name", "Jed"); | |
putDoc(database, docProperties5); | |
- CBLView view = database.getViewNamed("default/names"); | |
+ CBLMapReduce view = database.getViewNamed("default/names"); | |
view.setMapReduceBlocks(new CBLViewMapBlock() { | |
@Override | |
@@ -841,7 +842,7 @@ public class Views extends CBLiteTestCase { | |
putDoc(database, docProperties); | |
} | |
- CBLView view = database.getViewNamed("default/names"); | |
+ CBLMapReduce view = database.getViewNamed("default/names"); | |
view.setMapReduceBlocks(new CBLViewMapBlock() { | |
@Override | |
@@ -921,7 +922,7 @@ public class Views extends CBLiteTestCase { | |
putDoc(database, docProperties); | |
} | |
- CBLView view = database.getViewNamed("default/names"); | |
+ CBLMapReduce view = database.getViewNamed("default/names"); | |
view.setMapReduceBlocks(new CBLViewMapBlock() { | |
@Override | |
@@ -947,7 +948,7 @@ public class Views extends CBLiteTestCase { | |
public void testLargerViewQuery() { | |
putNDocs(database, 4); | |
- CBLView view = createView(database); | |
+ CBLMapReduce view = createView(database); | |
CBLStatus updated = view.updateIndex(); | |
Assert.assertEquals(CBLStatus.OK, updated.getCode()); | |
@@ -962,7 +963,7 @@ public class Views extends CBLiteTestCase { | |
public void testViewLinkedDocs() { | |
putLinkedDocs(database); | |
- CBLView view = database.getViewNamed("linked"); | |
+ CBLMapReduce view = database.getViewNamed("linked"); | |
view.setMapReduceBlocks(new CBLViewMapBlock() { | |
@Override | |
public void map(Map<String, Object> document, CBLViewMapEmitBlock emitter) { | |
diff --git a/CouchbaseLiteProject/CBLite/src/main/java/com/couchbase/cblite/CBLDatabase.java b/CouchbaseLiteProject/CBLite/src/main/java/com/couchbase/cblite/CBLDatabase.java | |
index a6fbf9a..8eb11ec 100644 | |
--- a/CouchbaseLiteProject/CBLite/src/main/java/com/couchbase/cblite/CBLDatabase.java | |
+++ b/CouchbaseLiteProject/CBLite/src/main/java/com/couchbase/cblite/CBLDatabase.java | |
@@ -60,9 +60,10 @@ public class CBLDatabase extends Observable { | |
private int transactionLevel = 0; | |
public static final String TAG = "CBLDatabase"; | |
- private Map<String, CBLView> views; | |
+ private Map<String, CBLMapReduce> views; | |
private Map<String, CBLFilterBlock> filters; | |
private Map<String, CBLValidationBlock> validations; | |
+ private Map<String, CBLSpatial> spatialViews; | |
private List<CBLReplicator> activeReplicators; | |
private CBLBlobStore attachments; | |
@@ -114,12 +115,24 @@ public class CBLDatabase extends Observable { | |
" version TEXT, " + | |
" lastsequence INTEGER DEFAULT 0); " + | |
" CREATE INDEX views_by_name ON views(name); " + | |
+ " CREATE TABLE spatial_views ( " + | |
+ " view_id INTEGER PRIMARY KEY, " + | |
+ " name TEXT UNIQUE NOT NULL," + | |
+ " version TEXT, " + | |
+ " lastsequence INTEGER DEFAULT 0); " + | |
+ " CREATE INDEX spatial_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 spatial_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 spatial_maps_keys on spatial_maps(view_id, key COLLATE JSON); " + | |
" CREATE TABLE attachments ( " + | |
" sequence INTEGER NOT NULL REFERENCES revs(sequence) ON DELETE CASCADE, " + | |
" filename TEXT NOT NULL, " + | |
@@ -150,6 +163,7 @@ public class CBLDatabase extends Observable { | |
} | |
public static CBLDatabase createEmptyDBAtPath(String path) { | |
+ System.out.println("vmx: CBLDatabase: path to db: " + path); | |
if(!FileDirUtils.removeItemIfExists(path)) { | |
return null; | |
} | |
@@ -166,6 +180,7 @@ public class CBLDatabase extends Observable { | |
} | |
public CBLDatabase(String path) { | |
+ System.out.println("vmx: CBLDatabase: path to db2: " + path); | |
assert(path.startsWith("/")); //path must be absolute | |
this.path = path; | |
this.name = FileDirUtils.getDatabaseNameFromPath(path); | |
@@ -314,8 +329,15 @@ public class CBLDatabase extends Observable { | |
for (CBLView view : views.values()) { | |
view.databaseClosing(); | |
} | |
+ views = null; | |
+ } | |
+ | |
+ if (spatialViews != null) { | |
+ for (CBLView spatialView : spatialViews.values()) { | |
+ spatialView.databaseClosing(); | |
+ } | |
+ spatialViews = null; | |
} | |
- views = null; | |
if(activeReplicators != null) { | |
for(CBLReplicator replicator : activeReplicators) { | |
@@ -1118,37 +1140,37 @@ public class CBLDatabase extends Observable { | |
/** VIEWS: **/ | |
- public CBLView registerView(CBLView view) { | |
+ public CBLMapReduce registerView(CBLMapReduce view) { | |
if(view == null) { | |
return null; | |
} | |
if(views == null) { | |
- views = new HashMap<String,CBLView>(); | |
+ views = new HashMap<String,CBLMapReduce>(); | |
} | |
views.put(view.getName(), view); | |
return view; | |
} | |
- public CBLView getViewNamed(String name) { | |
- CBLView view = null; | |
+ public CBLMapReduce getViewNamed(String name) { | |
+ CBLMapReduce view = null; | |
if(views != null) { | |
view = views.get(name); | |
} | |
if(view != null) { | |
return view; | |
} | |
- return registerView(new CBLView(this, name)); | |
+ return registerView(new CBLMapReduce(this, name)); | |
} | |
- public CBLView getExistingViewNamed(String name) { | |
- CBLView view = null; | |
+ public CBLMapReduce getExistingViewNamed(String name) { | |
+ CBLMapReduce view = null; | |
if(views != null) { | |
view = views.get(name); | |
} | |
if(view != null) { | |
return view; | |
} | |
- view = new CBLView(this, name); | |
+ view = new CBLMapReduce(this, name); | |
if(view.getViewId() == 0) { | |
return null; | |
} | |
@@ -1196,6 +1218,88 @@ public class CBLDatabase extends Observable { | |
return result; | |
} | |
+ | |
+ /** SPATIAL VIEWS: **/ | |
+ | |
+ public CBLSpatial registerSpatialView(CBLSpatial view) { | |
+ if(view == null) { | |
+ return null; | |
+ } | |
+ if(spatialViews == null) { | |
+ spatialViews = new HashMap<String,CBLSpatial>(); | |
+ } | |
+ spatialViews.put(view.getName(), view); | |
+ return view; | |
+ } | |
+ | |
+ public CBLSpatial getSpatialViewNamed(String name) { | |
+ CBLSpatial view = null; | |
+ if(spatialViews != null) { | |
+ view = spatialViews.get(name); | |
+ } | |
+ if(view != null) { | |
+ return view; | |
+ } | |
+ return registerSpatialView(new CBLSpatial(this, name)); | |
+ } | |
+ | |
+ public CBLSpatial getExistingSpatialViewNamed(String name) { | |
+ CBLSpatial view = null; | |
+ if(spatialViews != null) { | |
+ view = spatialViews.get(name); | |
+ } | |
+ if(view != null) { | |
+ return view; | |
+ } | |
+ view = new CBLSpatial(this, name); | |
+ if(view.getViewId() == 0) { | |
+ return null; | |
+ } | |
+ | |
+ return registerSpatialView(view); | |
+ } | |
+ | |
+ public List<CBLView> getAllSpatialViews() { | |
+ Cursor cursor = null; | |
+ List<CBLView> result = null; | |
+ | |
+ try { | |
+ cursor = database.rawQuery("SELECT name FROM spatial_views", null); | |
+ cursor.moveToFirst(); | |
+ result = new ArrayList<CBLView>(); | |
+ while(!cursor.isAfterLast()) { | |
+ result.add(getSpatialViewNamed(cursor.getString(0))); | |
+ cursor.moveToNext(); | |
+ } | |
+ } catch (Exception e) { | |
+ Log.e(CBLDatabase.TAG, "Error getting all spatial views", e); | |
+ } finally { | |
+ if(cursor != null) { | |
+ cursor.close(); | |
+ } | |
+ } | |
+ | |
+ return result; | |
+ } | |
+ | |
+ public CBLStatus deleteSpatialViewNamed(String name) { | |
+ CBLStatus result = new CBLStatus(CBLStatus.INTERNAL_SERVER_ERROR); | |
+ try { | |
+ String[] whereArgs = { name }; | |
+ int rowsAffected = database.delete("spatial_views", "name=?", whereArgs); | |
+ if(rowsAffected > 0) { | |
+ result.setCode(CBLStatus.OK); | |
+ } | |
+ else { | |
+ result.setCode(CBLStatus.NOT_FOUND); | |
+ } | |
+ } catch (SQLException e) { | |
+ Log.e(CBLDatabase.TAG, "Error deleting view", e); | |
+ } | |
+ return result; | |
+ } | |
+ | |
+ | |
//FIX: This has a lot of code in common with -[CBLView queryWithOptions:status:]. Unify the two! | |
public Map<String,Object> getDocsWithIDs(List<String> docIDs, CBLQueryOptions options) { | |
if(options == null) { | |
diff --git a/CouchbaseLiteProject/CBLite/src/main/java/com/couchbase/cblite/CBLMapReduce.java b/CouchbaseLiteProject/CBLite/src/main/java/com/couchbase/cblite/CBLMapReduce.java | |
index 5d6d053..d3c07ed 100644 | |
--- a/CouchbaseLiteProject/CBLite/src/main/java/com/couchbase/cblite/CBLMapReduce.java | |
+++ b/CouchbaseLiteProject/CBLite/src/main/java/com/couchbase/cblite/CBLMapReduce.java | |
@@ -1,7 +1,350 @@ | |
package com.couchbase.cblite; | |
-/** | |
- * Created by vmx on 6/5/13. | |
- */ | |
-public class CBLMapReduce { | |
+import android.content.ContentValues; | |
+import android.database.Cursor; | |
+import android.database.SQLException; | |
+import android.util.Log; | |
+ | |
+import java.util.ArrayList; | |
+import java.util.EnumSet; | |
+import java.util.HashMap; | |
+import java.util.List; | |
+import java.util.Map; | |
+ | |
+public class CBLMapReduce extends CBLView { | |
+ | |
+ public CBLMapReduce(CBLDatabase db, String name) { | |
+ this.db = db; | |
+ this.name = name; | |
+ this.viewId = -1; // means 'unknown' | |
+ this.collation = TDViewCollation.TDViewCollationUnicode; | |
+ this.type = ViewType.MAPREDUCE; | |
+ }; | |
+ | |
+ private CBLViewReduceBlock reduceBlock; | |
+ private static final String viewTableName = "views"; | |
+ private static final String mapsTableName = "maps"; | |
+ | |
+ // Are key1 and key2 grouped together at this groupLevel? | |
+ public static boolean groupTogether(Object key1, Object key2, int groupLevel) { | |
+ if(groupLevel == 0 || !(key1 instanceof List) || !(key2 instanceof List)) { | |
+ return key1.equals(key2); | |
+ } | |
+ @SuppressWarnings("unchecked") | |
+ List<Object> key1List = (List<Object>)key1; | |
+ @SuppressWarnings("unchecked") | |
+ List<Object> key2List = (List<Object>)key2; | |
+ int end = Math.min(groupLevel, Math.min(key1List.size(), key2List.size())); | |
+ for(int i = 0; i < end; ++i) { | |
+ if(!key1List.get(i).equals(key2List.get(i))) { | |
+ return false; | |
+ } | |
+ } | |
+ return true; | |
+ } | |
+ | |
+ // Returns the prefix of the key to use in the result row, at this groupLevel | |
+ @SuppressWarnings("unchecked") | |
+ public static Object groupKey(Object key, int groupLevel) { | |
+ if(groupLevel > 0 && (key instanceof List) && (((List<Object>)key).size() > groupLevel)) { | |
+ return ((List<Object>)key).subList(0, groupLevel); | |
+ } | |
+ else { | |
+ return key; | |
+ } | |
+ } | |
+ | |
+ public AbstractTouchMapEmitBlock getEmitBlock() { | |
+ return new AbstractTouchMapEmitBlock() { | |
+ @Override | |
+ public void emit(Object key, Object value) { | |
+ try { | |
+ String keyJson = CBLServer.getObjectMapper().writeValueAsString(key); | |
+ String valueJson = CBLServer.getObjectMapper().writeValueAsString(value); | |
+ Log.v(CBLDatabase.TAG, " emit(" + keyJson + ", " | |
+ + valueJson + ")"); | |
+ | |
+ ContentValues insertValues = new ContentValues(); | |
+ insertValues.put("view_id", getViewId()); | |
+ insertValues.put("sequence", sequence); | |
+ insertValues.put("key", keyJson); | |
+ insertValues.put("value", valueJson); | |
+ db.getDatabase().insert("maps", null, insertValues); | |
+ } catch (Exception e) { | |
+ Log.e(CBLDatabase.TAG, "Error emitting", e); | |
+ // find a better way to propogate this back | |
+ } | |
+ } | |
+ }; | |
+ } | |
+ | |
+ public String getViewTableName() { | |
+ return this.viewTableName; | |
+ } | |
+ | |
+ public String getMapsTableName() { | |
+ return this.mapsTableName; | |
+ } | |
+ | |
+ public CBLViewMapBlock getMapBlock() { | |
+ return mapBlock; | |
+ } | |
+ | |
+ public CBLViewReduceBlock getReduceBlock() { | |
+ return reduceBlock; | |
+ } | |
+ | |
+ public boolean setMapReduceBlocks(CBLViewMapBlock mapBlock, | |
+ CBLViewReduceBlock reduceBlock, String version) { | |
+ assert (mapBlock != null); | |
+ assert (version != null); | |
+ this.mapBlock = mapBlock; | |
+ this.reduceBlock = reduceBlock; | |
+ | |
+ return updateViewInDatabase(version); | |
+ } | |
+ | |
+ /** | |
+ * Queries the view. Does NOT first update the index. | |
+ * | |
+ * @param options The options to use. | |
+ * @param status An array of result rows -- each is a dictionary with "key" and "value" keys, and possibly "id" and "doc". | |
+ */ | |
+ @SuppressWarnings("unchecked") | |
+ public List<Map<String, Object>> queryWithOptions(CBLQueryOptions options, CBLStatus status) { | |
+ if (options == null) { | |
+ options = new CBLQueryOptions(); | |
+ } | |
+ | |
+ Cursor cursor = null; | |
+ List<Map<String, Object>> rows = new ArrayList<Map<String,Object>>(); | |
+ try { | |
+ cursor = resultSetWithOptions(options, status); | |
+ int groupLevel = options.getGroupLevel(); | |
+ boolean group = options.isGroup() || (groupLevel > 0); | |
+ boolean reduce = options.isReduce() || group; | |
+ | |
+ if(reduce && (reduceBlock == null) && !group) { | |
+ Log.w(CBLDatabase.TAG, "Cannot use reduce option in view " + name + " which has no reduce block defined"); | |
+ status.setCode(CBLStatus.BAD_REQUEST); | |
+ return null; | |
+ } | |
+ | |
+ List<Object> keysToReduce = null; | |
+ List<Object> valuesToReduce = null; | |
+ Object lastKey = null; | |
+ if(reduce) { | |
+ keysToReduce = new ArrayList<Object>(REDUCE_BATCH_SIZE); | |
+ valuesToReduce = new ArrayList<Object>(REDUCE_BATCH_SIZE); | |
+ } | |
+ | |
+ cursor.moveToFirst(); | |
+ while (!cursor.isAfterLast()) { | |
+ Object key = fromJSON(cursor.getBlob(0)); | |
+ Object value = fromJSON(cursor.getBlob(1)); | |
+ assert(key != null); | |
+ if(reduce) { | |
+ // Reduced or grouped query: | |
+ if(group && !groupTogether(key, lastKey, groupLevel) && (lastKey != null)) { | |
+ // This pair starts a new group, so reduce & record the last one: | |
+ Object reduced = (reduceBlock != null) ? reduceBlock.reduce(keysToReduce, valuesToReduce, false) : null; | |
+ Map<String,Object> row = new HashMap<String,Object>(); | |
+ row.put("key", groupKey(lastKey, groupLevel)); | |
+ if(reduced != null) { | |
+ row.put("value", reduced); | |
+ } | |
+ rows.add(row); | |
+ keysToReduce.clear(); | |
+ valuesToReduce.clear(); | |
+ } | |
+ keysToReduce.add(key); | |
+ valuesToReduce.add(value); | |
+ lastKey = key; | |
+ } else { | |
+ // Regular query: | |
+ Map<String,Object> row = new HashMap<String,Object>(); | |
+ String docId = cursor.getString(2); | |
+ Map<String,Object> docContents = null; | |
+ if(options.isIncludeDocs()) { | |
+ // http://wiki.apache.org/couchdb/Introduction_to_CouchDB_views#Linked_documents | |
+ if (value instanceof Map && ((Map) value).containsKey("_id")) { | |
+ String linkedDocId = (String) ((Map) value).get("_id"); | |
+ CBLRevision linkedDoc = db.getDocumentWithIDAndRev(linkedDocId, null, EnumSet.noneOf(CBLDatabase.TDContentOptions.class)); | |
+ docContents = linkedDoc.getProperties(); | |
+ } | |
+ else { | |
+ docContents = db.documentPropertiesFromJSON(cursor.getBlob(4), docId, cursor.getString(3), cursor.getLong(5), options.getContentOptions()); | |
+ } | |
+ } | |
+ | |
+ | |
+ if(docContents != null) { | |
+ row.put("doc", docContents); | |
+ } | |
+ if(value != null) { | |
+ row.put("value", value); | |
+ } | |
+ row.put("id", docId); | |
+ row.put("key", key); | |
+ | |
+ rows.add(row); | |
+ } | |
+ | |
+ | |
+ cursor.moveToNext(); | |
+ } | |
+ | |
+ if(reduce) { | |
+ if(keysToReduce.size() > 0) { | |
+ // Finish the last group (or the entire list, if no grouping): | |
+ Object key = group ? groupKey(lastKey, groupLevel) : null; | |
+ Object reduced = (reduceBlock != null) ? reduceBlock.reduce(keysToReduce, valuesToReduce, false) : null; | |
+ Map<String,Object> row = new HashMap<String,Object>(); | |
+ row.put("key", key); | |
+ if(reduced != null) { | |
+ row.put("value", reduced); | |
+ } | |
+ rows.add(row); | |
+ } | |
+ keysToReduce.clear(); | |
+ valuesToReduce.clear(); | |
+ } | |
+ | |
+ status.setCode(CBLStatus.OK); | |
+ | |
+ } catch (SQLException e) { | |
+ Log.e(CBLDatabase.TAG, "Error querying view", e); | |
+ return null; | |
+ } finally { | |
+ if (cursor != null) { | |
+ cursor.close(); | |
+ } | |
+ } | |
+ | |
+ return rows; | |
+ } | |
+ | |
+ public Cursor resultSetWithOptions(CBLQueryOptions options, CBLStatus status) { | |
+ if (options == null) { | |
+ options = new CBLQueryOptions(); | |
+ } | |
+ | |
+ // OPT: It would be faster to use separate tables for raw-or ascii-collated views so that | |
+ // they could be indexed with the right collation, instead of having to specify it here. | |
+ String collationStr = ""; | |
+ if(collation == TDViewCollation.TDViewCollationASCII) { | |
+ collationStr += " COLLATE JSON_ASCII"; | |
+ } | |
+ else if(collation == TDViewCollation.TDViewCollationRaw) { | |
+ collationStr += " COLLATE JSON_RAW"; | |
+ } | |
+ | |
+ String sql = "SELECT key, value, docid"; | |
+ if (options.isIncludeDocs()) { | |
+ sql = sql + ", revid, json, revs.sequence"; | |
+ } | |
+ sql = sql + " FROM maps, revs, docs WHERE maps.view_id=?"; | |
+ | |
+ List<String> argsList = new ArrayList<String>(); | |
+ argsList.add(Integer.toString(getViewId())); | |
+ | |
+ if(options.getKeys() != null) { | |
+ sql += " AND key in ("; | |
+ String item = "?"; | |
+ for (Object key : options.getKeys()) { | |
+ sql += item; | |
+ item = ", ?"; | |
+ argsList.add(toJSONString(key)); | |
+ } | |
+ sql += ")"; | |
+ } | |
+ | |
+ Object minKey = options.getStartKey(); | |
+ Object maxKey = options.getEndKey(); | |
+ boolean inclusiveMin = true; | |
+ boolean inclusiveMax = options.isInclusiveEnd(); | |
+ if (options.isDescending()) { | |
+ minKey = maxKey; | |
+ maxKey = options.getStartKey(); | |
+ inclusiveMin = inclusiveMax; | |
+ inclusiveMax = true; | |
+ } | |
+ | |
+ if (minKey != null) { | |
+ assert (minKey instanceof String); | |
+ if (inclusiveMin) { | |
+ sql += " AND key >= ?"; | |
+ } else { | |
+ sql += " AND key > ?"; | |
+ } | |
+ sql += collationStr; | |
+ argsList.add(toJSONString(minKey)); | |
+ } | |
+ | |
+ if (maxKey != null) { | |
+ assert (maxKey instanceof String); | |
+ if (inclusiveMax) { | |
+ sql += " AND key <= ?"; | |
+ } else { | |
+ sql += " AND key < ?"; | |
+ } | |
+ sql += collationStr; | |
+ argsList.add(toJSONString(maxKey)); | |
+ } | |
+ | |
+ sql = sql | |
+ + " AND revs.sequence = maps.sequence AND docs.doc_id = revs.doc_id ORDER BY key"; | |
+ sql += collationStr; | |
+ if (options.isDescending()) { | |
+ sql = sql + " DESC"; | |
+ } | |
+ sql = sql + " LIMIT ? OFFSET ?"; | |
+ argsList.add(Integer.toString(options.getLimit())); | |
+ argsList.add(Integer.toString(options.getSkip())); | |
+ | |
+ Log.v(CBLDatabase.TAG, "Query " + name + ": " + sql); | |
+ | |
+ Cursor cursor = db.getDatabase().rawQuery(sql, | |
+ argsList.toArray(new String[argsList.size()])); | |
+ return cursor; | |
+ } | |
+ | |
+ /*** Querying ***/ | |
+ public List<Map<String, Object>> dump() { | |
+ if (getViewId() < 0) { | |
+ return null; | |
+ } | |
+ | |
+ String[] selectArgs = { Integer.toString(getViewId()) }; | |
+ Cursor cursor = null; | |
+ List<Map<String, Object>> result = null; | |
+ | |
+ try { | |
+ cursor = db | |
+ .getDatabase() | |
+ .rawQuery( | |
+ "SELECT sequence, key, value FROM maps WHERE view_id=? ORDER BY key", | |
+ selectArgs); | |
+ | |
+ cursor.moveToFirst(); | |
+ result = new ArrayList<Map<String, Object>>(); | |
+ while (!cursor.isAfterLast()) { | |
+ Map<String, Object> row = new HashMap<String, Object>(); | |
+ row.put("seq", cursor.getInt(0)); | |
+ row.put("key", cursor.getString(1)); | |
+ row.put("value", cursor.getString(2)); | |
+ result.add(row); | |
+ cursor.moveToNext(); | |
+ } | |
+ } catch (SQLException e) { | |
+ Log.e(CBLDatabase.TAG, "Error dumping view", e); | |
+ return null; | |
+ } finally { | |
+ if (cursor != null) { | |
+ cursor.close(); | |
+ } | |
+ } | |
+ | |
+ return result; | |
+ } | |
} | |
diff --git a/CouchbaseLiteProject/CBLite/src/main/java/com/couchbase/cblite/CBLSpatial.java b/CouchbaseLiteProject/CBLite/src/main/java/com/couchbase/cblite/CBLSpatial.java | |
index 03a4d65..11d0d35 100644 | |
--- a/CouchbaseLiteProject/CBLite/src/main/java/com/couchbase/cblite/CBLSpatial.java | |
+++ b/CouchbaseLiteProject/CBLite/src/main/java/com/couchbase/cblite/CBLSpatial.java | |
@@ -18,18 +18,17 @@ public class CBLSpatial extends CBLView { | |
this.name = name; | |
this.viewId = -1; // means 'unknown' | |
this.collation = TDViewCollation.TDViewCollationUnicode; | |
- this.type = ViewType.MAPREDUCE; | |
+ this.type = ViewType.SPATIAL; | |
}; | |
- private CBLViewReduceBlock reduceBlock; | |
- private static final String viewTableName = "views"; | |
+ private static final String viewTableName = "spatial_views"; | |
+ private static final String mapsTableName = "spatial_maps"; | |
public AbstractTouchMapEmitBlock getEmitBlock() { | |
return new AbstractTouchMapEmitBlock() { | |
@Override | |
public void emit(Object key, Object value) { | |
- | |
try { | |
String keyJson = CBLServer.getObjectMapper().writeValueAsString(key); | |
String valueJson = CBLServer.getObjectMapper().writeValueAsString(value); | |
@@ -54,21 +53,18 @@ public class CBLSpatial extends CBLView { | |
return this.viewTableName; | |
} | |
- public CBLViewMapBlock getMapBlock() { | |
- return mapBlock; | |
+ public String getMapsTableName() { | |
+ return this.mapsTableName; | |
} | |
- public CBLViewReduceBlock getReduceBlock() { | |
- return reduceBlock; | |
+ public CBLViewMapBlock getMapBlock() { | |
+ return mapBlock; | |
} | |
- public boolean setMapReduceBlocks(CBLViewMapBlock mapBlock, | |
- CBLViewReduceBlock reduceBlock, String version) { | |
+ public boolean setSpatialBlock(CBLViewMapBlock mapBlock, String version) { | |
assert (mapBlock != null); | |
assert (version != null); | |
- | |
this.mapBlock = mapBlock; | |
- this.reduceBlock = reduceBlock; | |
return updateViewInDatabase(version); | |
} | |
@@ -79,6 +75,8 @@ public class CBLSpatial extends CBLView { | |
* @param options The options to use. | |
* @param status An array of result rows -- each is a dictionary with "key" and "value" keys, and possibly "id" and "doc". | |
*/ | |
+ // This function is the same as for the MapReduce index, only the reduce specific code | |
+ // was removed | |
@SuppressWarnings("unchecked") | |
public List<Map<String, Object>> queryWithOptions(CBLQueryOptions options, CBLStatus status) { | |
if (options == null) { | |
@@ -89,98 +87,41 @@ public class CBLSpatial extends CBLView { | |
List<Map<String, Object>> rows = new ArrayList<Map<String,Object>>(); | |
try { | |
cursor = resultSetWithOptions(options, status); | |
- int groupLevel = options.getGroupLevel(); | |
- boolean group = options.isGroup() || (groupLevel > 0); | |
- boolean reduce = options.isReduce() || group; | |
- | |
- if(reduce && (reduceBlock == null) && !group) { | |
- Log.w(CBLDatabase.TAG, "Cannot use reduce option in view " + name + " which has no reduce block defined"); | |
- status.setCode(CBLStatus.BAD_REQUEST); | |
- return null; | |
- } | |
- | |
- List<Object> keysToReduce = null; | |
- List<Object> valuesToReduce = null; | |
- Object lastKey = null; | |
- if(reduce) { | |
- keysToReduce = new ArrayList<Object>(REDUCE_BATCH_SIZE); | |
- valuesToReduce = new ArrayList<Object>(REDUCE_BATCH_SIZE); | |
- } | |
cursor.moveToFirst(); | |
while (!cursor.isAfterLast()) { | |
Object key = fromJSON(cursor.getBlob(0)); | |
Object value = fromJSON(cursor.getBlob(1)); | |
assert(key != null); | |
- if(reduce) { | |
- // Reduced or grouped query: | |
- if(group && !groupTogether(key, lastKey, groupLevel) && (lastKey != null)) { | |
- // This pair starts a new group, so reduce & record the last one: | |
- Object reduced = (reduceBlock != null) ? reduceBlock.reduce(keysToReduce, valuesToReduce, false) : null; | |
- Map<String,Object> row = new HashMap<String,Object>(); | |
- row.put("key", groupKey(lastKey, groupLevel)); | |
- if(reduced != null) { | |
- row.put("value", reduced); | |
- } | |
- rows.add(row); | |
- keysToReduce.clear(); | |
- valuesToReduce.clear(); | |
- } | |
- keysToReduce.add(key); | |
- valuesToReduce.add(value); | |
- lastKey = key; | |
- } else { | |
- // Regular query: | |
- Map<String,Object> row = new HashMap<String,Object>(); | |
- String docId = cursor.getString(2); | |
- Map<String,Object> docContents = null; | |
- if(options.isIncludeDocs()) { | |
- // http://wiki.apache.org/couchdb/Introduction_to_CouchDB_views#Linked_documents | |
- if (value instanceof Map && ((Map) value).containsKey("_id")) { | |
- String linkedDocId = (String) ((Map) value).get("_id"); | |
- CBLRevision linkedDoc = db.getDocumentWithIDAndRev(linkedDocId, null, EnumSet.noneOf(CBLDatabase.TDContentOptions.class)); | |
- docContents = linkedDoc.getProperties(); | |
- } | |
- else { | |
- docContents = db.documentPropertiesFromJSON(cursor.getBlob(4), docId, cursor.getString(3), cursor.getLong(5), options.getContentOptions()); | |
- } | |
- } | |
- | |
- | |
- if(docContents != null) { | |
- row.put("doc", docContents); | |
+ // Regular query: | |
+ Map<String,Object> row = new HashMap<String,Object>(); | |
+ String docId = cursor.getString(2); | |
+ Map<String,Object> docContents = null; | |
+ if(options.isIncludeDocs()) { | |
+ // http://wiki.apache.org/couchdb/Introduction_to_CouchDB_views#Linked_documents | |
+ if (value instanceof Map && ((Map) value).containsKey("_id")) { | |
+ String linkedDocId = (String) ((Map) value).get("_id"); | |
+ CBLRevision linkedDoc = db.getDocumentWithIDAndRev(linkedDocId, null, EnumSet.noneOf(CBLDatabase.TDContentOptions.class)); | |
+ docContents = linkedDoc.getProperties(); | |
} | |
- if(value != null) { | |
- row.put("value", value); | |
+ else { | |
+ docContents = db.documentPropertiesFromJSON(cursor.getBlob(4), docId, cursor.getString(3), cursor.getLong(5), options.getContentOptions()); | |
} | |
- row.put("id", docId); | |
- row.put("key", key); | |
- | |
- rows.add(row); | |
} | |
- | |
- cursor.moveToNext(); | |
- } | |
- | |
- if(reduce) { | |
- if(keysToReduce.size() > 0) { | |
- // Finish the last group (or the entire list, if no grouping): | |
- Object key = group ? groupKey(lastKey, groupLevel) : null; | |
- Object reduced = (reduceBlock != null) ? reduceBlock.reduce(keysToReduce, valuesToReduce, false) : null; | |
- Map<String,Object> row = new HashMap<String,Object>(); | |
- row.put("key", key); | |
- if(reduced != null) { | |
- row.put("value", reduced); | |
- } | |
- rows.add(row); | |
+ if(docContents != null) { | |
+ row.put("doc", docContents); | |
} | |
- keysToReduce.clear(); | |
- valuesToReduce.clear(); | |
- } | |
+ if(value != null) { | |
+ row.put("value", value); | |
+ } | |
+ row.put("id", docId); | |
+ row.put("key", key); | |
+ rows.add(row); | |
+ } | |
+ cursor.moveToNext(); | |
status.setCode(CBLStatus.OK); | |
- | |
} catch (SQLException e) { | |
Log.e(CBLDatabase.TAG, "Error querying view", e); | |
return null; | |
@@ -192,4 +133,77 @@ public class CBLSpatial extends CBLView { | |
return rows; | |
} | |
+ | |
+ public Cursor resultSetWithOptions(CBLQueryOptions options, CBLStatus status) { | |
+ if (options == null) { | |
+ options = new CBLQueryOptions(); | |
+ } | |
+ | |
+ // XXX vmx 2013-06-06: This is the part where the actual querying is happening | |
+ String sql = "SELECT key, value, docid"; | |
+ if (options.isIncludeDocs()) { | |
+ sql = sql + ", revid, json, revs.sequence"; | |
+ } | |
+ sql = sql + " FROM maps, revs, docs WHERE maps.view_id=?"; | |
+ | |
+ List<String> argsList = new ArrayList<String>(); | |
+ argsList.add(Integer.toString(getViewId())); | |
+ | |
+ if(options.getKeys() != null) { | |
+ sql += " AND key in ("; | |
+ String item = "?"; | |
+ for (Object key : options.getKeys()) { | |
+ sql += item; | |
+ item = ", ?"; | |
+ argsList.add(toJSONString(key)); | |
+ } | |
+ sql += ")"; | |
+ } | |
+ | |
+ Object minKey = options.getStartKey(); | |
+ Object maxKey = options.getEndKey(); | |
+ boolean inclusiveMin = true; | |
+ boolean inclusiveMax = options.isInclusiveEnd(); | |
+ if (options.isDescending()) { | |
+ minKey = maxKey; | |
+ maxKey = options.getStartKey(); | |
+ inclusiveMin = inclusiveMax; | |
+ inclusiveMax = true; | |
+ } | |
+ | |
+ if (minKey != null) { | |
+ assert (minKey instanceof String); | |
+ if (inclusiveMin) { | |
+ sql += " AND key >= ?"; | |
+ } else { | |
+ sql += " AND key > ?"; | |
+ } | |
+ argsList.add(toJSONString(minKey)); | |
+ } | |
+ | |
+ if (maxKey != null) { | |
+ assert (maxKey instanceof String); | |
+ if (inclusiveMax) { | |
+ sql += " AND key <= ?"; | |
+ } else { | |
+ sql += " AND key < ?"; | |
+ } | |
+ argsList.add(toJSONString(maxKey)); | |
+ } | |
+ | |
+ sql = sql | |
+ + " AND revs.sequence = maps.sequence AND docs.doc_id = revs.doc_id ORDER BY key"; | |
+ if (options.isDescending()) { | |
+ sql = sql + " DESC"; | |
+ } | |
+ sql = sql + " LIMIT ? OFFSET ?"; | |
+ argsList.add(Integer.toString(options.getLimit())); | |
+ argsList.add(Integer.toString(options.getSkip())); | |
+ | |
+ Log.v(CBLDatabase.TAG, "Query " + name + ": " + sql); | |
+ | |
+ Cursor cursor = db.getDatabase().rawQuery(sql, | |
+ argsList.toArray(new String[argsList.size()])); | |
+ return cursor; | |
+ } | |
} | |
diff --git a/CouchbaseLiteProject/CBLite/src/main/java/com/couchbase/cblite/CBLView.java b/CouchbaseLiteProject/CBLite/src/main/java/com/couchbase/cblite/CBLView.java | |
index 0e51e6f..55ab2a3 100644 | |
--- a/CouchbaseLiteProject/CBLite/src/main/java/com/couchbase/cblite/CBLView.java | |
+++ b/CouchbaseLiteProject/CBLite/src/main/java/com/couchbase/cblite/CBLView.java | |
@@ -18,6 +18,7 @@ | |
package com.couchbase.cblite; | |
import java.util.ArrayList; | |
+import java.util.EnumSet; | |
import java.util.HashMap; | |
import java.util.List; | |
import java.util.Map; | |
@@ -25,14 +26,18 @@ import java.util.Map; | |
import android.content.ContentValues; | |
import android.database.Cursor; | |
import android.database.SQLException; | |
+import android.database.sqlite.SQLiteDatabase; | |
import android.util.Log; | |
/** | |
* Represents a view available in a database. | |
*/ | |
-public class CBLView { | |
+public abstract class CBLView { | |
public static final int REDUCE_BATCH_SIZE = 100; | |
+ // mapBlock is also used for the Spatial index function as it has the same semantics as | |
+ // the MapReduce index map function | |
+ protected CBLViewMapBlock mapBlock; | |
public enum TDViewCollation { | |
TDViewCollationUnicode, TDViewCollationRaw, TDViewCollationASCII | |
@@ -56,6 +61,18 @@ public class CBLView { | |
this.collation = TDViewCollation.TDViewCollationUnicode; | |
} | |
*/ | |
+ | |
+ // The emit block actually stores the data from the emit in the database | |
+ // hence it's different between the MapReduce and the Spatial index | |
+ public abstract AbstractTouchMapEmitBlock getEmitBlock(); | |
+ | |
+ // The name of the table the views of the index are stored in | |
+ public abstract String getViewTableName(); | |
+ | |
+ // The name of the table where the actual data of the index is stored in | |
+ public abstract String getMapsTableName(); | |
+ | |
+ | |
public CBLDatabase getDb() { | |
return db; | |
}; | |
@@ -72,6 +89,197 @@ public class CBLView { | |
this.collation = collation; | |
} | |
+ | |
+ /** | |
+ * Updates the view's index (incrementally) if necessary. | |
+ * @return 200 if updated, 304 if already up-to-date, else an error code | |
+ */ | |
+ @SuppressWarnings("unchecked") | |
+ public CBLStatus updateIndex() { | |
+ Log.v(CBLDatabase.TAG, "Re-indexing view " + name + " ..."); | |
+ assert (mapBlock != null); | |
+ | |
+ if (getViewId() < 0) { | |
+ return new CBLStatus(CBLStatus.NOT_FOUND); | |
+ } | |
+ | |
+ db.beginTransaction(); | |
+ CBLStatus result = new CBLStatus(CBLStatus.INTERNAL_SERVER_ERROR); | |
+ Cursor cursor = null; | |
+ | |
+ try { | |
+ | |
+ long lastSequence = getLastSequenceIndexed(); | |
+ long dbMaxSequence = db.getLastSequence(); | |
+ if(lastSequence == dbMaxSequence) { | |
+ result.setCode(CBLStatus.NOT_MODIFIED); | |
+ return result; | |
+ } | |
+ | |
+ // First remove obsolete emitted results from the 'maps' table: | |
+ long sequence = lastSequence; | |
+ if (lastSequence < 0) { | |
+ return result; | |
+ } | |
+ | |
+ if (lastSequence == 0) { | |
+ // If the lastSequence has been reset to 0, make sure to remove | |
+ // any leftover rows: | |
+ String[] whereArgs = { Integer.toString(getViewId()) }; | |
+ db.getDatabase().delete(getMapsTableName(), "view_id=?", whereArgs); | |
+ } else { | |
+ // Delete all obsolete map results (ones from since-replaced | |
+ // revisions): | |
+ String[] args = { Integer.toString(getViewId()), | |
+ Long.toString(lastSequence), | |
+ Long.toString(lastSequence) }; | |
+ db.getDatabase().execSQL( | |
+ "DELETE FROM " + getMapsTableName() + " WHERE view_id=? AND sequence IN (" | |
+ + "SELECT parent FROM revs WHERE sequence>? " | |
+ + "AND parent>0 AND parent<=?)", args); | |
+ } | |
+ | |
+ int deleted = 0; | |
+ cursor = db.getDatabase().rawQuery("SELECT changes()", null); | |
+ cursor.moveToFirst(); | |
+ deleted = cursor.getInt(0); | |
+ cursor.close(); | |
+ | |
+ // This is the emit() block, which gets called from within the | |
+ // user-defined map() block | |
+ // that's called down below. | |
+ AbstractTouchMapEmitBlock emitBlock = getEmitBlock(); | |
+ | |
+ // Now scan every revision added since the last time the view was | |
+ // indexed: | |
+ String[] selectArgs = { Long.toString(lastSequence) }; | |
+ | |
+ cursor = db.getDatabase().rawQuery( | |
+ "SELECT revs.doc_id, sequence, docid, revid, json FROM revs, docs " | |
+ + "WHERE sequence>? AND current!=0 AND deleted=0 " | |
+ + "AND revs.doc_id = docs.doc_id " | |
+ + "ORDER BY revs.doc_id, revid DESC", selectArgs); | |
+ | |
+ cursor.moveToFirst(); | |
+ | |
+ long lastDocID = 0; | |
+ while (!cursor.isAfterLast()) { | |
+ long docID = cursor.getLong(0); | |
+ if (docID != lastDocID) { | |
+ // Only look at the first-iterated revision of any document, | |
+ // because this is the | |
+ // one with the highest revid, hence the "winning" revision | |
+ // of a conflict. | |
+ lastDocID = docID; | |
+ | |
+ // Reconstitute the document as a dictionary: | |
+ sequence = cursor.getLong(1); | |
+ String docId = cursor.getString(2); | |
+ if(docId.startsWith("_design/")) { // design docs don't get indexed! | |
+ cursor.moveToNext(); | |
+ continue; | |
+ } | |
+ String revId = cursor.getString(3); | |
+ byte[] json = cursor.getBlob(4); | |
+ Map<String, Object> properties = db | |
+ .documentPropertiesFromJSON(json, docId, revId, | |
+ sequence, EnumSet.noneOf(CBLDatabase.TDContentOptions.class)); | |
+ | |
+ if (properties != null) { | |
+ // Call the user-defined map() to emit new key/value | |
+ // pairs from this revision: | |
+ Log.v(CBLDatabase.TAG, | |
+ " call map for sequence=" | |
+ + Long.toString(sequence)); | |
+ emitBlock.setSequence(sequence); | |
+ mapBlock.map(properties, emitBlock); | |
+ } | |
+ | |
+ } | |
+ | |
+ cursor.moveToNext(); | |
+ } | |
+ | |
+ // Finally, record the last revision sequence number that was | |
+ // indexed: | |
+ ContentValues updateValues = new ContentValues(); | |
+ updateValues.put("lastSequence", dbMaxSequence); | |
+ String[] whereArgs = { Integer.toString(getViewId()) }; | |
+ db.getDatabase().update(getViewTableName(), updateValues, "view_id=?", | |
+ whereArgs); | |
+ | |
+ // FIXME actually count number added :) | |
+ Log.v(CBLDatabase.TAG, "...Finished re-indexing view " + name | |
+ + " up to sequence " + Long.toString(dbMaxSequence) | |
+ + " (deleted " + deleted + " added " + "?" + ")"); | |
+ result.setCode(CBLStatus.OK); | |
+ | |
+ } catch (SQLException e) { | |
+ return result; | |
+ } finally { | |
+ if (cursor != null) { | |
+ cursor.close(); | |
+ } | |
+ if (!result.isSuccessful()) { | |
+ Log.w(CBLDatabase.TAG, "Failed to rebuild view " + name + ": " | |
+ + result.getCode()); | |
+ } | |
+ if(db != null) { | |
+ db.endTransaction(result.isSuccessful()); | |
+ } | |
+ } | |
+ | |
+ return result; | |
+ } | |
+ | |
+ protected boolean updateViewInDatabase(String version) { | |
+ if(!db.open()) { | |
+ return false; | |
+ } | |
+ | |
+ // Update the version column in the db. This is a little weird looking | |
+ // because we want to | |
+ // avoid modifying the db if the version didn't change, and because the | |
+ // row might not exist yet. | |
+ SQLiteDatabase database = db.getDatabase(); | |
+ | |
+ // Older Android doesnt have reliable insert or ignore, will to 2 step | |
+ // FIXME review need for change to execSQL, manual call to changes() | |
+ | |
+ String sql = "SELECT name, version FROM " + getViewTableName() + " WHERE name=?"; | |
+ String[] args = { name }; | |
+ Cursor cursor = null; | |
+ | |
+ try { | |
+ cursor = db.getDatabase().rawQuery(sql, args); | |
+ if (!cursor.moveToFirst()) { | |
+ // no such record, so insert | |
+ ContentValues insertValues = new ContentValues(); | |
+ insertValues.put("name", name); | |
+ insertValues.put("version", version); | |
+ database.insert(getViewTableName(), null, insertValues); | |
+ return true; | |
+ } | |
+ | |
+ ContentValues updateValues = new ContentValues(); | |
+ updateValues.put("version", version); | |
+ updateValues.put("lastSequence", 0); | |
+ | |
+ String[] whereArgs = { name, version }; | |
+ int rowsAffected = database.update(getViewTableName(), updateValues, | |
+ "name=? AND version!=?", whereArgs); | |
+ | |
+ return (rowsAffected > 0); | |
+ } catch (SQLException e) { | |
+ Log.e(CBLDatabase.TAG, "Error setting view lock", e); | |
+ return false; | |
+ } finally { | |
+ if (cursor != null) { | |
+ cursor.close(); | |
+ } | |
+ } | |
+ } | |
+ | |
/** | |
* Is the view's index currently out of date? | |
*/ | |
@@ -81,8 +289,8 @@ public class CBLView { | |
public int getViewId() { | |
if (viewId < 0) { | |
- String sql = "SELECT view_id FROM ? WHERE name=?"; | |
- String[] args = { getTableName(), name }; | |
+ String sql = "SELECT view_id FROM " + getViewTableName() + " WHERE name=?"; | |
+ String[] args = { name }; | |
Cursor cursor = null; | |
try { | |
cursor = db.getDatabase().rawQuery(sql, args); | |
@@ -104,8 +312,8 @@ public class CBLView { | |
} | |
public long getLastSequenceIndexed() { | |
- String sql = "SELECT lastSequence FROM ? WHERE name=?"; | |
- String[] args = { getTableName(), name }; | |
+ String sql = "SELECT lastSequence FROM " + getViewTableName() + " WHERE name=?"; | |
+ String[] args = { name }; | |
Cursor cursor = null; | |
long result = -1; | |
try { | |
@@ -133,11 +341,11 @@ public class CBLView { | |
db.beginTransaction(); | |
String[] whereArgs = { Integer.toString(getViewId()) }; | |
- db.getDatabase().delete("maps", "view_id=?", whereArgs); | |
+ db.getDatabase().delete(getMapsTableName(), "view_id=?", whereArgs); | |
ContentValues updateValues = new ContentValues(); | |
updateValues.put("lastSequence", 0); | |
- db.getDatabase().update(getTableName(), updateValues, "view_id=?", | |
+ db.getDatabase().update(getViewTableName(), updateValues, "view_id=?", | |
whereArgs); | |
success = true; | |
@@ -186,159 +394,6 @@ public class CBLView { | |
return result; | |
} | |
- public Cursor resultSetWithOptions(CBLQueryOptions options, CBLStatus status) { | |
- if (options == null) { | |
- options = new CBLQueryOptions(); | |
- } | |
- | |
- // OPT: It would be faster to use separate tables for raw-or ascii-collated views so that | |
- // they could be indexed with the right collation, instead of having to specify it here. | |
- String collationStr = ""; | |
- if(collation == TDViewCollation.TDViewCollationASCII) { | |
- collationStr += " COLLATE JSON_ASCII"; | |
- } | |
- else if(collation == TDViewCollation.TDViewCollationRaw) { | |
- collationStr += " COLLATE JSON_RAW"; | |
- } | |
- | |
- String sql = "SELECT key, value, docid"; | |
- if (options.isIncludeDocs()) { | |
- sql = sql + ", revid, json, revs.sequence"; | |
- } | |
- sql = sql + " FROM maps, revs, docs WHERE maps.view_id=?"; | |
- | |
- List<String> argsList = new ArrayList<String>(); | |
- argsList.add(Integer.toString(getViewId())); | |
- | |
- if(options.getKeys() != null) { | |
- sql += " AND key in ("; | |
- String item = "?"; | |
- for (Object key : options.getKeys()) { | |
- sql += item; | |
- item = ", ?"; | |
- argsList.add(toJSONString(key)); | |
- } | |
- sql += ")"; | |
- } | |
- | |
- Object minKey = options.getStartKey(); | |
- Object maxKey = options.getEndKey(); | |
- boolean inclusiveMin = true; | |
- boolean inclusiveMax = options.isInclusiveEnd(); | |
- if (options.isDescending()) { | |
- minKey = maxKey; | |
- maxKey = options.getStartKey(); | |
- inclusiveMin = inclusiveMax; | |
- inclusiveMax = true; | |
- } | |
- | |
- if (minKey != null) { | |
- assert (minKey instanceof String); | |
- if (inclusiveMin) { | |
- sql += " AND key >= ?"; | |
- } else { | |
- sql += " AND key > ?"; | |
- } | |
- sql += collationStr; | |
- argsList.add(toJSONString(minKey)); | |
- } | |
- | |
- if (maxKey != null) { | |
- assert (maxKey instanceof String); | |
- if (inclusiveMax) { | |
- sql += " AND key <= ?"; | |
- } else { | |
- sql += " AND key < ?"; | |
- } | |
- sql += collationStr; | |
- argsList.add(toJSONString(maxKey)); | |
- } | |
- | |
- sql = sql | |
- + " AND revs.sequence = maps.sequence AND docs.doc_id = revs.doc_id ORDER BY key"; | |
- sql += collationStr; | |
- if (options.isDescending()) { | |
- sql = sql + " DESC"; | |
- } | |
- sql = sql + " LIMIT ? OFFSET ?"; | |
- argsList.add(Integer.toString(options.getLimit())); | |
- argsList.add(Integer.toString(options.getSkip())); | |
- | |
- Log.v(CBLDatabase.TAG, "Query " + name + ": " + sql); | |
- | |
- Cursor cursor = db.getDatabase().rawQuery(sql, | |
- argsList.toArray(new String[argsList.size()])); | |
- return cursor; | |
- } | |
- | |
- // Are key1 and key2 grouped together at this groupLevel? | |
- public static boolean groupTogether(Object key1, Object key2, int groupLevel) { | |
- if(groupLevel == 0 || !(key1 instanceof List) || !(key2 instanceof List)) { | |
- return key1.equals(key2); | |
- } | |
- @SuppressWarnings("unchecked") | |
- List<Object> key1List = (List<Object>)key1; | |
- @SuppressWarnings("unchecked") | |
- List<Object> key2List = (List<Object>)key2; | |
- int end = Math.min(groupLevel, Math.min(key1List.size(), key2List.size())); | |
- for(int i = 0; i < end; ++i) { | |
- if(!key1List.get(i).equals(key2List.get(i))) { | |
- return false; | |
- } | |
- } | |
- return true; | |
- } | |
- | |
- // Returns the prefix of the key to use in the result row, at this groupLevel | |
- @SuppressWarnings("unchecked") | |
- public static Object groupKey(Object key, int groupLevel) { | |
- if(groupLevel > 0 && (key instanceof List) && (((List<Object>)key).size() > groupLevel)) { | |
- return ((List<Object>)key).subList(0, groupLevel); | |
- } | |
- else { | |
- return key; | |
- } | |
- } | |
- | |
- /*** Querying ***/ | |
- public List<Map<String, Object>> dump() { | |
- if (getViewId() < 0) { | |
- return null; | |
- } | |
- | |
- String[] selectArgs = { Integer.toString(getViewId()) }; | |
- Cursor cursor = null; | |
- List<Map<String, Object>> result = null; | |
- | |
- try { | |
- cursor = db | |
- .getDatabase() | |
- .rawQuery( | |
- "SELECT sequence, key, value FROM maps WHERE view_id=? ORDER BY key", | |
- selectArgs); | |
- | |
- cursor.moveToFirst(); | |
- result = new ArrayList<Map<String, Object>>(); | |
- while (!cursor.isAfterLast()) { | |
- Map<String, Object> row = new HashMap<String, Object>(); | |
- row.put("seq", cursor.getInt(0)); | |
- row.put("key", cursor.getString(1)); | |
- row.put("value", cursor.getString(2)); | |
- result.add(row); | |
- cursor.moveToNext(); | |
- } | |
- } catch (SQLException e) { | |
- Log.e(CBLDatabase.TAG, "Error dumping view", e); | |
- return null; | |
- } finally { | |
- if (cursor != null) { | |
- cursor.close(); | |
- } | |
- } | |
- | |
- return result; | |
- } | |
- | |
/** | |
* Utility function to use in reduce blocks. Totals an array of Numbers. | |
*/ | |
@@ -362,17 +417,6 @@ public class CBLView { | |
public static void setCompiler(CBLViewCompiler compiler) { | |
CBLView.compiler = compiler; | |
} | |
- | |
- private String getTableName() { | |
- switch (type) { | |
- case MAPREDUCE: | |
- return "views"; | |
- case SPATIAL: | |
- return "spatial_views"; | |
- default: | |
- return null; | |
- } | |
- } | |
} | |
abstract class AbstractTouchMapEmitBlock implements CBLViewMapEmitBlock { | |
diff --git a/CouchbaseLiteProject/CBLite/src/main/java/com/couchbase/cblite/router/CBLRouter.java b/CouchbaseLiteProject/CBLite/src/main/java/com/couchbase/cblite/router/CBLRouter.java | |
index 3dbacee..3565195 100644 | |
--- a/CouchbaseLiteProject/CBLite/src/main/java/com/couchbase/cblite/router/CBLRouter.java | |
+++ b/CouchbaseLiteProject/CBLite/src/main/java/com/couchbase/cblite/router/CBLRouter.java | |
@@ -26,6 +26,7 @@ import com.couchbase.cblite.CBLBody; | |
import com.couchbase.cblite.CBLChangesOptions; | |
import com.couchbase.cblite.CBLDatabase; | |
import com.couchbase.cblite.CBLFilterBlock; | |
+import com.couchbase.cblite.CBLMapReduce; | |
import com.couchbase.cblite.CBLMisc; | |
import com.couchbase.cblite.CBLQueryOptions; | |
import com.couchbase.cblite.CBLRevision; | |
@@ -1315,7 +1316,7 @@ public class CBLRouter implements Observer { | |
/** VIEW QUERIES: **/ | |
- public CBLView compileView(String viewName, Map<String,Object> viewProps) { | |
+ public CBLMapReduce compileView(String viewName, Map<String, Object> viewProps) { | |
String language = (String)viewProps.get("language"); | |
if(language == null) { | |
language = "javascript"; | |
@@ -1339,7 +1340,7 @@ public class CBLRouter implements Observer { | |
} | |
} | |
- CBLView view = db.getViewNamed(viewName); | |
+ CBLMapReduce view = db.getViewNamed(viewName); | |
view.setMapReduceBlocks(mapBlock, reduceBlock, "1"); | |
String collation = (String)viewProps.get("collation"); | |
if("raw".equals(collation)) { | |
@@ -1350,7 +1351,7 @@ public class CBLRouter implements Observer { | |
public CBLStatus queryDesignDoc(String designDoc, String viewName, List<Object> keys) { | |
String tdViewName = String.format("%s/%s", designDoc, viewName); | |
- CBLView view = db.getExistingViewNamed(tdViewName); | |
+ CBLMapReduce view = db.getExistingViewNamed(tdViewName); | |
if(view == null || view.getMapBlock() == null) { | |
// No TouchDB view is defined, or it hasn't had a map block assigned; | |
// see if there's a CouchDB view definition we can compile: | |
diff --git a/CouchbaseLiteProject/CBLiteEktorp/CBLiteEktorp.iml b/CouchbaseLiteProject/CBLiteEktorp/CBLiteEktorp.iml | |
index 50b0d3b..4832b23 100644 | |
--- a/CouchbaseLiteProject/CBLiteEktorp/CBLiteEktorp.iml | |
+++ b/CouchbaseLiteProject/CBLiteEktorp/CBLiteEktorp.iml | |
@@ -68,19 +68,15 @@ | |
</content> | |
<orderEntry type="jdk" jdkName="Android 4.2.2" jdkType="Android SDK" /> | |
<orderEntry type="sourceFolder" forTests="false" /> | |
- <orderEntry type="library" name="android-support-v4-0.1" level="project" /> | |
- <orderEntry type="library" name="jackson-core-asl-1.9.2" level="project" /> | |
- <orderEntry type="library" name="jackson-mapper-asl-1.9.2" level="project" /> | |
- <orderEntry type="library" name="httpclient-cache-4.1.1" level="project" /> | |
- <orderEntry type="library" name="commons-io-2.0.1" level="project" /> | |
- <orderEntry type="library" name="slf4j-api-1.6.1" level="project" /> | |
+ <orderEntry type="library" name="support-v4-13.0.0" level="project" /> | |
<orderEntry type="library" name="org.ektorp-1.2.2" level="project" /> | |
<orderEntry type="library" name="org.ektorp.android-1.2.2" level="project" /> | |
- <orderEntry type="library" name="CBLite.aar" level="project" /> | |
- <orderEntry type="library" name="CBLite-1.0.aar" level="project" /> | |
- <orderEntry type="library" name="CBLite-0.7.aar" level="project" /> | |
- <orderEntry type="library" name="support-v4-13.0.0" level="project" /> | |
+ <orderEntry type="library" name="slf4j-api-1.6.1" level="project" /> | |
<orderEntry type="library" name="slf4j-jdk14-1.6.1" level="project" /> | |
+ <orderEntry type="library" name="commons-io-2.0.1" level="project" /> | |
+ <orderEntry type="library" name="CBLite.aar" level="project" /> | |
+ <orderEntry type="library" name="jackson-core-asl-1.9.2" level="project" /> | |
+ <orderEntry type="library" name="jackson-mapper-asl-1.9.2" level="project" /> | |
</component> | |
</module> | |
diff --git a/CouchbaseLiteProject/CBLiteJavascript/CBLiteJavascript.iml b/CouchbaseLiteProject/CBLiteJavascript/CBLiteJavascript.iml | |
index a10969d..0f43a0e 100644 | |
--- a/CouchbaseLiteProject/CBLiteJavascript/CBLiteJavascript.iml | |
+++ b/CouchbaseLiteProject/CBLiteJavascript/CBLiteJavascript.iml | |
@@ -68,23 +68,17 @@ | |
</content> | |
<orderEntry type="jdk" jdkName="Android 4.2.2" jdkType="Android SDK" /> | |
<orderEntry type="sourceFolder" forTests="false" /> | |
- <orderEntry type="library" name="android-support-v4-0.1" level="project" /> | |
+ <orderEntry type="library" name="support-v4-13.0.0" level="project" /> | |
+ <orderEntry type="library" name="rhino-1.7R3" level="project" /> | |
+ <orderEntry type="library" name="CBLite.aar" level="project" /> | |
+ <orderEntry type="library" name="CBLiteEktorp.aar" level="project" /> | |
<orderEntry type="library" name="jackson-core-asl-1.9.2" level="project" /> | |
<orderEntry type="library" name="jackson-mapper-asl-1.9.2" level="project" /> | |
- <orderEntry type="library" name="httpclient-cache-4.1.1" level="project" /> | |
+ <orderEntry type="library" name="slf4j-jdk14-1.6.1" level="project" /> | |
<orderEntry type="library" name="commons-io-2.0.1" level="project" /> | |
<orderEntry type="library" name="slf4j-api-1.6.1" level="project" /> | |
<orderEntry type="library" name="org.ektorp-1.2.2" level="project" /> | |
<orderEntry type="library" name="org.ektorp.android-1.2.2" level="project" /> | |
- <orderEntry type="library" name="rhino-1.7R3" level="project" /> | |
- <orderEntry type="library" name="CBLite.aar" level="project" /> | |
- <orderEntry type="library" name="CBLiteEktorp.aar" level="project" /> | |
- <orderEntry type="library" name="CBLite-1.0.aar" level="project" /> | |
- <orderEntry type="library" name="CBLiteEktorp-1.0.aar" level="project" /> | |
- <orderEntry type="library" name="CBLite-0.7.aar" level="project" /> | |
- <orderEntry type="library" name="CBLiteEktorp-0.7.aar" level="project" /> | |
- <orderEntry type="library" name="support-v4-13.0.0" level="project" /> | |
- <orderEntry type="library" name="slf4j-jdk14-1.6.1" level="project" /> | |
</component> | |
</module> | |
diff --git a/CouchbaseLiteProject/CBLiteListener/CBLiteListener.iml b/CouchbaseLiteProject/CBLiteListener/CBLiteListener.iml | |
index deaa738..74c329a 100644 | |
--- a/CouchbaseLiteProject/CBLiteListener/CBLiteListener.iml | |
+++ b/CouchbaseLiteProject/CBLiteListener/CBLiteListener.iml | |
@@ -68,15 +68,12 @@ | |
</content> | |
<orderEntry type="jdk" jdkName="Android 4.2.2" jdkType="Android SDK" /> | |
<orderEntry type="sourceFolder" forTests="false" /> | |
- <orderEntry type="library" name="jackson-core-asl-1.9.2" level="project" /> | |
- <orderEntry type="library" name="jackson-mapper-asl-1.9.2" level="project" /> | |
- <orderEntry type="library" name="android-support-v4-0.1" level="project" /> | |
- <orderEntry type="library" name="android-support-v4" level="project" /> | |
+ <orderEntry type="library" name="support-v4-13.0.0" level="project" /> | |
<orderEntry type="library" name="servlet-api-2.4" level="project" /> | |
<orderEntry type="library" name="webserver" level="project" /> | |
- <orderEntry type="library" name="CBLite-1.0.aar" level="project" /> | |
- <orderEntry type="library" name="support-v4-13.0.0" level="project" /> | |
<orderEntry type="library" name="CBLite.aar" level="project" /> | |
+ <orderEntry type="library" name="jackson-core-asl-1.9.2" level="project" /> | |
+ <orderEntry type="library" name="jackson-mapper-asl-1.9.2" level="project" /> | |
</component> | |
</module> | |
diff --git a/CouchbaseLiteProject/CouchbaseLiteProject.iml b/CouchbaseLiteProject/CouchbaseLiteProject.iml | |
index 5561ede..286bd25 100644 | |
--- a/CouchbaseLiteProject/CouchbaseLiteProject.iml | |
+++ b/CouchbaseLiteProject/CouchbaseLiteProject.iml | |
@@ -1,5 +1,5 @@ | |
<?xml version="1.0" encoding="UTF-8"?> | |
-<module external.system.id="GRADLE" type="JAVA_MODULE" version="4"> | |
+<module external.linked.project.path="$MODULE_DIR$/build.gradle" external.system.id="GRADLE" type="JAVA_MODULE" version="4"> | |
<component name="FacetManager"> | |
<facet type="android-gradle" name="Android-Gradle"> | |
<configuration> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment