Skip to content

Commit

Permalink
Merge pull request #20 from dizzzz/update
Browse files Browse the repository at this point in the history
Update
  • Loading branch information
dizzzz committed Feb 2, 2015
2 parents 11ae6b5 + 3280fdf commit a73c4a2
Show file tree
Hide file tree
Showing 5 changed files with 291 additions and 2 deletions.
3 changes: 3 additions & 0 deletions java/src/org/exist/mongodb/xquery/MongodbModule.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import org.exist.mongodb.xquery.mongodb.collection.Insert;
import org.exist.mongodb.xquery.mongodb.collection.MapReduce;
import org.exist.mongodb.xquery.mongodb.collection.Save;
import org.exist.mongodb.xquery.mongodb.collection.Update;
import org.exist.mongodb.xquery.mongodb.db.EvalCommand;
import org.exist.mongodb.xquery.mongodb.db.ListCollections;
import org.exist.xquery.AbstractInternalModule;
Expand Down Expand Up @@ -64,6 +65,8 @@ public class MongodbModule extends AbstractInternalModule {
new FunctionDef(MapReduce.signatures[0], MapReduce.class),
new FunctionDef(Remove.signatures[0], Remove.class),
new FunctionDef(Save.signatures[0], Save.class),
new FunctionDef(Update.signatures[0], Update.class),
new FunctionDef(Update.signatures[1], Update.class),
};

public final static ErrorCode MONG0001 = new MongodbErrorCode("MONG0001", "Forbidden");
Expand Down
166 changes: 166 additions & 0 deletions java/src/org/exist/mongodb/xquery/mongodb/collection/Update.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
/*
* eXist Open Source Native XML Database
* Copyright (C) 2014 The eXist Project
* http://exist-db.org
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
package org.exist.mongodb.xquery.mongodb.collection;

import com.mongodb.BasicDBObject;
import com.mongodb.DB;
import com.mongodb.DBCollection;
import com.mongodb.MongoClient;
import com.mongodb.MongoCommandException;
import com.mongodb.MongoException;
import com.mongodb.WriteResult;
import com.mongodb.util.JSON;
import com.mongodb.util.JSONParseException;
import org.exist.dom.QName;
import static org.exist.mongodb.shared.FunctionDefinitions.PARAMETER_COLLECTION;
import static org.exist.mongodb.shared.FunctionDefinitions.PARAMETER_DATABASE;
import static org.exist.mongodb.shared.FunctionDefinitions.PARAMETER_MONGODB_CLIENT;
import org.exist.mongodb.shared.MongodbClientStore;
import org.exist.mongodb.xquery.MongodbModule;
import org.exist.xquery.BasicFunction;
import org.exist.xquery.Cardinality;
import org.exist.xquery.FunctionSignature;
import org.exist.xquery.XPathException;
import org.exist.xquery.XQueryContext;
import org.exist.xquery.value.FunctionParameterSequenceType;
import org.exist.xquery.value.FunctionReturnSequenceType;
import org.exist.xquery.value.Sequence;
import org.exist.xquery.value.SequenceType;
import org.exist.xquery.value.StringValue;
import org.exist.xquery.value.Type;

/**
* Functions to save a document in mongodb
*
* @author Dannes Wessels
*/
public class Update extends BasicFunction {

private static final String UPDATE = "update";

public static final String PARAM_CRITERIA = "criteria";
public static final String DESCR_CRITERIA = "The selection criteria for the update";

public static final FunctionParameterSequenceType PARAMETER_CRITERIA
= new FunctionParameterSequenceType(PARAM_CRITERIA, Type.STRING, Cardinality.ONE, DESCR_CRITERIA);

public static final String PARAM_MODIFICATION = "modification";
public static final String DESCR_MODIFICATION = "The modifications to apply";

public static final FunctionParameterSequenceType PARAMETER_MODIFICATION
= new FunctionParameterSequenceType(PARAM_MODIFICATION, Type.STRING, Cardinality.ONE, DESCR_MODIFICATION);

public static final String PARAM_UPSERT = "upsert";
public static final String DESCR_UPSERT = "When true, inserts a document if no document matches the update query criteria";

public static final FunctionParameterSequenceType PARAMETER_UPSERT
= new FunctionParameterSequenceType(PARAM_UPSERT, Type.BOOLEAN, Cardinality.ONE, DESCR_UPSERT);

public static final String PARAM_MULTI = "multi";
public static final String DESCR_MULTI = "When true, updates all documents in the collection that match the update query criteria, otherwise only updates one";

public static final FunctionParameterSequenceType PARAMETER_MULTI
= new FunctionParameterSequenceType(PARAM_MULTI, Type.BOOLEAN, Cardinality.ONE, DESCR_MULTI);


public final static FunctionSignature signatures[] = {
new FunctionSignature(
new QName(UPDATE, MongodbModule.NAMESPACE_URI, MongodbModule.PREFIX), "Modify an existing document or documents in collection. By default the method updates a single document.",
new SequenceType[]{
PARAMETER_MONGODB_CLIENT, PARAMETER_DATABASE, PARAMETER_COLLECTION, PARAMETER_CRITERIA, PARAMETER_MODIFICATION},
new FunctionReturnSequenceType(Type.STRING, Cardinality.ONE, "The write result, JSON formatted")
),

new FunctionSignature(
new QName(UPDATE, MongodbModule.NAMESPACE_URI, MongodbModule.PREFIX), "Modify an existing document or documents in collection.",
new SequenceType[]{
PARAMETER_MONGODB_CLIENT, PARAMETER_DATABASE, PARAMETER_COLLECTION, PARAMETER_CRITERIA, PARAMETER_MODIFICATION, PARAMETER_UPSERT, PARAMETER_MULTI},
new FunctionReturnSequenceType(Type.STRING, Cardinality.ONE, "The write result, JSON formatted")
),

};

public Update(XQueryContext context, FunctionSignature signature) {
super(context, signature);
}

@Override
public Sequence eval(Sequence[] args, Sequence contextSequence) throws XPathException {

try {
String mongodbClientId = args[0].itemAt(0).getStringValue();
String dbname = args[1].itemAt(0).getStringValue();
String collection = args[2].itemAt(0).getStringValue();

// Check id
MongodbClientStore.getInstance().validate(mongodbClientId);

// Get Mongodb client
MongoClient client = MongodbClientStore.getInstance().get(mongodbClientId);

// Get database
DB db = client.getDB(dbname);
DBCollection dbcol = db.getCollection(collection);

// Get data
BasicDBObject criterium = (BasicDBObject) JSON.parse(args[3].itemAt(0).getStringValue());
BasicDBObject modification = (BasicDBObject) JSON.parse(args[4].itemAt(0).getStringValue());

Boolean upsert = (args.length >= 6)
? args[5].itemAt(0).toJavaObject(Boolean.class)
: null;

Boolean multi = (args.length >= 7)
? args[6].itemAt(0).toJavaObject(Boolean.class)
: null;

// Execute update
WriteResult update = (upsert == null)
? dbcol.update(criterium, modification)
: dbcol.update(criterium, modification, upsert, multi);

return new StringValue(update.toString());

} catch (MongoCommandException ex){
// TODO return as value?
LOG.error(ex.getMessage(), ex);
throw new XPathException(this, MongodbModule.MONG0005, ex.getMessage());

} catch (JSONParseException ex) {
String msg = "Invalid JSON data: " + ex.getMessage();
LOG.error(msg);
throw new XPathException(this, MongodbModule.MONG0004, msg);

} catch (XPathException ex) {
LOG.error(ex.getMessage(), ex);
throw new XPathException(this, ex.getMessage(), ex);

} catch (MongoException ex) {
LOG.error(ex.getMessage(), ex);
throw new XPathException(this, MongodbModule.MONG0002, ex.getMessage());

} catch (Throwable t) {
LOG.error(t.getMessage(), t);
throw new XPathException(this, MongodbModule.MONG0003, t.getMessage());
}

}

}
2 changes: 1 addition & 1 deletion java/test/src/org/exist/mongodb/test/map-reduce.xql
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ function mapreduce:mapreduce_write_collection() {
: collection#map-reduce() test command failure exception
:)
declare
%test:assertError("Command Failure")
%test:assertError("mongodb:MONG0005")
function mapreduce:mapreduce_command_failure() {
let $mongodbClientId := support:getToken()

Expand Down
3 changes: 2 additions & 1 deletion java/test/src/org/exist/mongodb/test/suite.xql
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,6 @@ test:suite((
inspect:module-functions(xs:anyURI("insert.xql")),
inspect:module-functions(xs:anyURI("map-reduce.xql")),
inspect:module-functions(xs:anyURI("mongo.xql")),
inspect:module-functions(xs:anyURI("save.xql"))
inspect:module-functions(xs:anyURI("save.xql")),
inspect:module-functions(xs:anyURI("update.xql"))
))
119 changes: 119 additions & 0 deletions java/test/src/org/exist/mongodb/test/update.xql
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
xquery version "3.0";

module namespace mongoMain="http://exist-db.org/mongodb/test/update";

import module namespace xqjson = "http://xqilla.sourceforge.net/lib/xqjson";

import module namespace test="http://exist-db.org/xquery/xqsuite"
at "resource:org/exist/xquery/lib/xqsuite/xqsuite.xql";

import module namespace mongodb = "http://exist-db.org/xquery/mongodb"
at "java:org.exist.mongodb.xquery.MongodbModule";

import module namespace support = "http://exist-db.org/ext/mongodb/test/support"
at "./support.xqm";


(: Connect to mongodb, store token :)
declare %test:setUp function mongoMain:setup()
{
support:setup()
};

(: Disconnect from mongodb, cleanup token :)
declare %test:tearDown function mongoMain:cleanup()
{
support:cleanup()
};

(:
: Actual tests below this line
:)

(: collection#update() add contents :)
declare
%test:assertEquals(1,1)
function mongoMain:update_overwrite() {
let $mongodbClientId := support:getToken()
let $insert := mongodb:insert($mongodbClientId, $support:database, $support:mongoCollection,
"{ x : 1 , y : 2 , z : 3 }")

let $update := mongodb:update($mongodbClientId, $support:database, $support:mongoCollection,
"{ x : 1 }", "{'$set' : { q : 4 }}")

return
(
mongodb:count($mongodbClientId, $support:database, $support:mongoCollection, "{ x : 1 }"),
mongodb:count($mongodbClientId, $support:database, $support:mongoCollection, "{ q : 4 }")
)
};


(: collection#update() noupsert contents :)
declare
%test:assertEquals(0)
function mongoMain:update_noupsert() {
let $mongodbClientId := support:getToken()

let $update := mongodb:update($mongodbClientId, $support:database, $support:mongoCollection,
"{ x : 2 }", "{ qa : 4 }", false(), false())

return
mongodb:count($mongodbClientId, $support:database, $support:mongoCollection, "{ qa : 4 }")
};

(: collection#update() upsert contents :)
declare
%test:assertEquals(1)
function mongoMain:update_upsert() {
let $mongodbClientId := support:getToken()

let $update := mongodb:update($mongodbClientId, $support:database, $support:mongoCollection,
"{ x : 3 }", "{ qb : 4 }", true(), false())

return
mongodb:count($mongodbClientId, $support:database, $support:mongoCollection, "{ qb : 4 }")
};


(: collection#update() multi, 2 documents :)
declare
%test:assertEquals(2,2)
function mongoMain:update_multi() {
let $mongodbClientId := support:getToken()
let $insert1 := mongodb:insert($mongodbClientId, $support:database, $support:mongoCollection,
"{ x : 10 , y : 1 , z : 3 }")
let $insert2 := mongodb:insert($mongodbClientId, $support:database, $support:mongoCollection,
"{ x : 10 , y : 2 , z : 3 }")

let $update := mongodb:update($mongodbClientId, $support:database, $support:mongoCollection,
"{ x : 10 }", "{'$set' : { qc : 4 }}", false(), true())

return
(
mongodb:count($mongodbClientId, $support:database, $support:mongoCollection, "{ x : 10 }"),
mongodb:count($mongodbClientId, $support:database, $support:mongoCollection, "{ qc : 4 }")
)
};

(: collection#update() nomulti, 2 documents :)
declare
%test:assertEquals(2,1)
function mongoMain:update_nomulti() {
let $mongodbClientId := support:getToken()
let $insert1 := mongodb:insert($mongodbClientId, $support:database, $support:mongoCollection,
"{ x : 20 , y : 1 , z : 3 }")
let $insert2 := mongodb:insert($mongodbClientId, $support:database, $support:mongoCollection,
"{ x : 20 , y : 2 , z : 3 }")

let $update := mongodb:update($mongodbClientId, $support:database, $support:mongoCollection,
"{ x : 20 }", "{'$set' : { qd : 4 }}", false(), false())

return
(
mongodb:count($mongodbClientId, $support:database, $support:mongoCollection, "{ x : 20 }"),
mongodb:count($mongodbClientId, $support:database, $support:mongoCollection, "{ qd : 4 }")
)
};


0 comments on commit a73c4a2

Please sign in to comment.