Permalink
Browse files

fixed bug where lists in documents were not properly wrapped for rhino

  • Loading branch information...
1 parent 01f13ea commit 70d89ec8e4d4f4b170a627ac4b9180b42e1b8701 @mschoch mschoch committed Jun 30, 2012
@@ -1,7 +1,9 @@
package com.couchbase.touchdb.javascript;
+import java.util.List;
import java.util.Map;
+import org.elasticsearch.script.javascript.support.NativeList;
import org.elasticsearch.script.javascript.support.NativeMap;
import org.mozilla.javascript.Context;
import org.mozilla.javascript.Function;
@@ -113,6 +115,9 @@ public Scriptable wrapAsJavaObject(Context cx, Scriptable scope, Object javaObje
if (javaObject instanceof Map) {
return new NativeMap(scope, (Map) javaObject);
}
+ else if(javaObject instanceof List) {
+ return new NativeList(scope, (List<Object>)javaObject);
+ }
return super.wrapAsJavaObject(cx, scope, javaObject, staticType);
}
@@ -0,0 +1,207 @@
+/*
+ * Licensed to ElasticSearch and Shay Banon under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. ElasticSearch licenses this
+ * file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.elasticsearch.script.javascript.support;
+
+import java.util.List;
+
+import org.mozilla.javascript.Scriptable;
+import org.mozilla.javascript.Undefined;
+import org.mozilla.javascript.Wrapper;
+
+/**
+ *
+ */
+public class NativeList implements Scriptable, Wrapper {
+ private static final long serialVersionUID = 3664761893203964569L;
+
+ private List<Object> list;
+ private Scriptable parentScope;
+ private Scriptable prototype;
+
+
+ public static NativeList wrap(Scriptable scope, List<Object> list) {
+ return new NativeList(scope, list);
+ }
+
+ public NativeList(Scriptable scope, List<Object> list) {
+ this.parentScope = scope;
+ this.list = list;
+ }
+
+ /* (non-Javadoc)
+ * @see org.mozilla.javascript.Wrapper#unwrap()
+ */
+
+ public Object unwrap() {
+ return list;
+ }
+
+ /* (non-Javadoc)
+ * @see org.mozilla.javascript.Scriptable#getClassName()
+ */
+
+ public String getClassName() {
+ return "NativeList";
+ }
+
+ /* (non-Javadoc)
+ * @see org.mozilla.javascript.Scriptable#get(java.lang.String, org.mozilla.javascript.Scriptable)
+ */
+
+ public Object get(String name, Scriptable start) {
+ if ("length".equals(name)) {
+ return list.size();
+ } else {
+ return Undefined.instance;
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see org.mozilla.javascript.Scriptable#get(int, org.mozilla.javascript.Scriptable)
+ */
+
+ public Object get(int index, Scriptable start) {
+ if (index < 0 || index >= list.size()) {
+ return Undefined.instance;
+ }
+ return list.get(index);
+ }
+
+ /* (non-Javadoc)
+ * @see org.mozilla.javascript.Scriptable#has(java.lang.String, org.mozilla.javascript.Scriptable)
+ */
+
+ public boolean has(String name, Scriptable start) {
+ if ("length".equals(name)) {
+ return true;
+ }
+ return false;
+ }
+
+ /* (non-Javadoc)
+ * @see org.mozilla.javascript.Scriptable#has(int, org.mozilla.javascript.Scriptable)
+ */
+
+ public boolean has(int index, Scriptable start) {
+ return index >= 0 && index < list.size();
+ }
+
+ /* (non-Javadoc)
+ * @see org.mozilla.javascript.Scriptable#put(java.lang.String, org.mozilla.javascript.Scriptable, java.lang.Object)
+ */
+
+ @SuppressWarnings("unchecked")
+ public void put(String name, Scriptable start, Object value) {
+ // do nothing here...
+ }
+
+ /* (non-Javadoc)
+ * @see org.mozilla.javascript.Scriptable#put(int, org.mozilla.javascript.Scriptable, java.lang.Object)
+ */
+
+ public void put(int index, Scriptable start, Object value) {
+ if (index == list.size()) {
+ list.add(value);
+ } else {
+ list.set(index, value);
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see org.mozilla.javascript.Scriptable#delete(java.lang.String)
+ */
+
+ public void delete(String name) {
+ // nothing here
+ }
+
+ /* (non-Javadoc)
+ * @see org.mozilla.javascript.Scriptable#delete(int)
+ */
+
+ public void delete(int index) {
+ list.remove(index);
+ }
+
+ /* (non-Javadoc)
+ * @see org.mozilla.javascript.Scriptable#getPrototype()
+ */
+
+ public Scriptable getPrototype() {
+ return this.prototype;
+ }
+
+ /* (non-Javadoc)
+ * @see org.mozilla.javascript.Scriptable#setPrototype(org.mozilla.javascript.Scriptable)
+ */
+
+ public void setPrototype(Scriptable prototype) {
+ this.prototype = prototype;
+ }
+
+ /* (non-Javadoc)
+ * @see org.mozilla.javascript.Scriptable#getParentScope()
+ */
+
+ public Scriptable getParentScope() {
+ return this.parentScope;
+ }
+
+ /* (non-Javadoc)
+ * @see org.mozilla.javascript.Scriptable#setParentScope(org.mozilla.javascript.Scriptable)
+ */
+
+ public void setParentScope(Scriptable parent) {
+ this.parentScope = parent;
+ }
+
+ /* (non-Javadoc)
+ * @see org.mozilla.javascript.Scriptable#getIds()
+ */
+
+ public Object[] getIds() {
+ int size = list.size();
+ Object[] ids = new Object[size];
+ for (int i = 0; i < size; ++i) {
+ ids[i] = i;
+ }
+ return ids;
+ }
+
+ /* (non-Javadoc)
+ * @see org.mozilla.javascript.Scriptable#getDefaultValue(java.lang.Class)
+ */
+
+ public Object getDefaultValue(Class hint) {
+ return null;
+ }
+
+ /* (non-Javadoc)
+ * @see org.mozilla.javascript.Scriptable#hasInstance(org.mozilla.javascript.Scriptable)
+ */
+
+ public boolean hasInstance(Scriptable value) {
+ if (!(value instanceof Wrapper))
+ return false;
+ Object instance = ((Wrapper) value).unwrap();
+ return List.class.isInstance(instance);
+ }
+
+}
@@ -83,4 +83,103 @@ public void testJavaScriptDesignDocument() {
server.close();
}
+ public void testRealJavaScriptDesignDocument() {
+
+ TDServer server = null;
+ try {
+ server = new TDServer(getServerPath());
+ } catch (IOException e) {
+ fail("Creating server caused IOException");
+ }
+
+ //register the javascript view compilter
+ TDView.setCompiler(new TDJavaScriptViewCompiler());
+
+ send(server, "PUT", "/rhinodb", TDStatus.CREATED, null);
+
+ // PUT:
+ Map<String,Object> doc1 = new HashMap<String,Object>();
+ List<String> cat1 = new ArrayList();
+ cat1.add("apple");
+ cat1.add("bannana");
+ doc1.put("categories", cat1);
+ Map<String,Object> result = (Map<String,Object>)sendBody(server, "PUT", "/rhinodb/doc1", doc1, TDStatus.CREATED, null);
+
+ Map<String,Object> doc2 = new HashMap<String,Object>();
+ List<String> cat2 = new ArrayList();
+ cat2.add("clock");
+ cat2.add("dill");
+ doc2.put("categories", cat2);
+ Map<String,Object> result2 = (Map<String,Object>)sendBody(server, "PUT", "/rhinodb/doc2", doc2, TDStatus.CREATED, null);
+
+ Map<String,Object> doc3 = new HashMap<String,Object>();
+ List<String> cat3 = new ArrayList();
+ cat3.add("elephant");
+ cat3.add("fun");
+ doc3.put("categories", cat3);
+ Map<String,Object> result3 = (Map<String,Object>)sendBody(server, "PUT", "/rhinodb/doc3", doc3, TDStatus.CREATED, null);
+
+
+ Map<String,Object> ddocViewTest = new HashMap<String,Object>();
+ ddocViewTest.put("map", "function(doc) { if (doc.categories) { for (i in doc.categories) { emit(doc.categories[i], 1); } } }");
+
+ Map<String,Object> ddocViews = new HashMap<String,Object>();
+ ddocViews.put("test", ddocViewTest);
+
+ Map<String,Object> ddoc = new HashMap<String,Object>();
+ ddoc.put("views", ddocViews);
+ Map<String,Object> ddocresult = (Map<String,Object>)sendBody(server, "PUT", "/rhinodb/_design/doc", ddoc, TDStatus.CREATED, null);
+
+ // Build up our expected result
+
+ Map<String,Object> row1 = new HashMap<String,Object>();
+ row1.put("id", "doc1");
+ row1.put("key", "apple");
+ row1.put("value", 1.0);
+
+ Map<String,Object> row2 = new HashMap<String,Object>();
+ row2.put("id", "doc1");
+ row2.put("key", "bannana");
+ row2.put("value", 1.0);
+
+ Map<String,Object> row3 = new HashMap<String,Object>();
+ row3.put("id", "doc2");
+ row3.put("key", "clock");
+ row3.put("value", 1.0);
+
+ Map<String,Object> row4 = new HashMap<String,Object>();
+ row4.put("id", "doc2");
+ row4.put("key", "dill");
+ row4.put("value", 1.0);
+
+ Map<String,Object> row5 = new HashMap<String,Object>();
+ row5.put("id", "doc3");
+ row5.put("key", "elephant");
+ row5.put("value", 1.0);
+
+ Map<String,Object> row6 = new HashMap<String,Object>();
+ row6.put("id", "doc3");
+ row6.put("key", "fun");
+ row6.put("value", 1.0);
+
+ List<Map<String,Object>> expectedRows = new ArrayList<Map<String,Object>>();
+
+ expectedRows.add(row1);
+ expectedRows.add(row2);
+ expectedRows.add(row3);
+ expectedRows.add(row4);
+ expectedRows.add(row5);
+ expectedRows.add(row6);
+
+ Map<String,Object> expectedResult = new HashMap<String,Object>();
+ expectedResult.put("offset", 0);
+ expectedResult.put("total_rows", 6);
+ expectedResult.put("rows", expectedRows);
+
+ // Query the view and check the result:
+ Object res = send(server, "GET", "/rhinodb/_design/doc/_view/test", TDStatus.OK, expectedResult);
+
+ server.close();
+ }
+
}

0 comments on commit 70d89ec

Please sign in to comment.