DATAMONGO-479 - Add support for calling functions.
We added ScriptOperations to MongoTemplate. Those allow storage and execution of java script function directly on the MongoDB server instance. Having ScriptOperations in place builds the foundation for annotation driver support in repository layer. Original pull request: #254.
This commit is contained in:
committed by
Oliver Gierke
parent
7a3aff12a5
commit
a0e42f5dfe
@@ -0,0 +1,194 @@
|
||||
/*
|
||||
* Copyright 2014 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.data.mongodb.core;
|
||||
|
||||
import static java.util.UUID.*;
|
||||
import static org.springframework.data.mongodb.core.query.Criteria.*;
|
||||
import static org.springframework.data.mongodb.core.query.Query.*;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.bson.types.ObjectId;
|
||||
import org.springframework.dao.DataAccessException;
|
||||
import org.springframework.data.mongodb.core.script.CallableMongoScript;
|
||||
import org.springframework.data.mongodb.core.script.ServerSideJavaScript;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import com.mongodb.DB;
|
||||
import com.mongodb.MongoException;
|
||||
|
||||
/**
|
||||
* Default implementation of {@link ScriptOperations} capable of saving and executing {@link ServerSideJavaScript}.
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
* @since 1.7
|
||||
*/
|
||||
public class DefaultScriptOperations implements ScriptOperations {
|
||||
|
||||
private static final String SCRIPT_COLLECTION_NAME = "system.js";
|
||||
private static final String SCRIPT_NAME_PREFIX = "func_";
|
||||
private final MongoOperations mongoOperations;
|
||||
|
||||
/**
|
||||
* Creates new {@link DefaultScriptOperations} using given {@link MongoOperations}.
|
||||
*
|
||||
* @param mongoOperations must not be {@literal null}.
|
||||
*/
|
||||
public DefaultScriptOperations(MongoOperations mongoOperations) {
|
||||
|
||||
Assert.notNull(mongoOperations, "MongoOperations must not be null!");
|
||||
|
||||
this.mongoOperations = mongoOperations;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.ScriptOperations#save(org.springframework.data.mongodb.core.script.MongoScript)
|
||||
*/
|
||||
@Override
|
||||
public CallableMongoScript register(ServerSideJavaScript script) {
|
||||
|
||||
Assert.notNull(script, "Script must not be null!");
|
||||
|
||||
CallableMongoScript callableScript = (script instanceof CallableMongoScript) ? (CallableMongoScript) script
|
||||
: new CallableMongoScript(generateScriptName(), script);
|
||||
mongoOperations.save(callableScript, SCRIPT_COLLECTION_NAME);
|
||||
return callableScript;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.ScriptOperations#execute(org.springframework.data.mongodb.core.script.MongoScript, java.lang.Object[])
|
||||
*/
|
||||
@Override
|
||||
public Object execute(final ServerSideJavaScript script, final Object... args) {
|
||||
|
||||
Assert.notNull(script, "Script must not be null!");
|
||||
|
||||
if (script instanceof CallableMongoScript) {
|
||||
return call(((CallableMongoScript) script).getName(), args);
|
||||
}
|
||||
|
||||
return mongoOperations.execute(new DbCallback<Object>() {
|
||||
|
||||
@Override
|
||||
public Object doInDB(DB db) throws MongoException, DataAccessException {
|
||||
|
||||
Assert.notNull(script.getCode(), "Script.code must not be null!");
|
||||
|
||||
return db.eval(script.getCode(), convertScriptArgs(args));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.ScriptOperations#call(java.lang.String, java.lang.Object[])
|
||||
*/
|
||||
@Override
|
||||
public Object call(final String scriptName, final Object... args) {
|
||||
|
||||
Assert.hasText(scriptName, "ScriptName must not be null or empty!");
|
||||
|
||||
return mongoOperations.execute(new DbCallback<Object>() {
|
||||
|
||||
@Override
|
||||
public Object doInDB(DB db) throws MongoException, DataAccessException {
|
||||
|
||||
String evalString = scriptName + "(" + convertAndJoinScriptArgs(args) + ")";
|
||||
return db.eval(evalString);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.ScriptOperations#exists(java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public Boolean exists(String scriptName) {
|
||||
|
||||
Assert.hasText(scriptName, "ScriptName must not be null or empty!");
|
||||
|
||||
return mongoOperations.exists(query(where("name").is(scriptName)), CallableMongoScript.class,
|
||||
SCRIPT_COLLECTION_NAME);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.ScriptOperations#scriptNames()
|
||||
*/
|
||||
@Override
|
||||
public Set<String> scriptNames() {
|
||||
|
||||
List<CallableMongoScript> scripts = (mongoOperations.findAll(CallableMongoScript.class, SCRIPT_COLLECTION_NAME));
|
||||
|
||||
if (CollectionUtils.isEmpty(scripts)) {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
|
||||
Set<String> scriptNames = new HashSet<String>();
|
||||
for (CallableMongoScript script : scripts) {
|
||||
scriptNames.add(script.getName());
|
||||
}
|
||||
return scriptNames;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a valid name for the {@literal JavaScript}. MongoDB requires an id of type String for scripts. Calling
|
||||
* scripts having {@link ObjectId} as id fails. Therefore we create a random UUID without {@code -} (as this won't
|
||||
* work) an prefix the result with {@link #SCRIPT_NAME_PREFIX}.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
private String generateScriptName() {
|
||||
return SCRIPT_NAME_PREFIX + randomUUID().toString().replaceAll("-", "");
|
||||
}
|
||||
|
||||
private Object[] convertScriptArgs(Object... args) {
|
||||
|
||||
if (ObjectUtils.isEmpty(args)) {
|
||||
return args;
|
||||
}
|
||||
|
||||
List<Object> convertedValues = new ArrayList<Object>(args.length);
|
||||
for (Object arg : args) {
|
||||
if (arg instanceof String) {
|
||||
convertedValues.add("'" + arg + "'");
|
||||
} else {
|
||||
convertedValues.add(this.mongoOperations.getConverter().convertToMongoType(arg));
|
||||
}
|
||||
}
|
||||
return convertedValues.toArray();
|
||||
}
|
||||
|
||||
private String convertAndJoinScriptArgs(Object... args) {
|
||||
|
||||
if (ObjectUtils.isEmpty(args)) {
|
||||
return "";
|
||||
}
|
||||
|
||||
return StringUtils.arrayToCommaDelimitedString(convertScriptArgs(args));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -284,6 +284,14 @@ public interface MongoOperations {
|
||||
*/
|
||||
IndexOperations indexOps(Class<?> entityClass);
|
||||
|
||||
/**
|
||||
* Returns the {@link ScriptOperations} that can be performed on {@link com.mongodb.DB} level.
|
||||
*
|
||||
* @return
|
||||
* @since 1.7
|
||||
*/
|
||||
ScriptOperations scriptOps();
|
||||
|
||||
/**
|
||||
* Query for a list of objects of type T from the collection used by the entity class.
|
||||
* <p/>
|
||||
@@ -994,4 +1002,5 @@ public interface MongoOperations {
|
||||
* @return
|
||||
*/
|
||||
MongoConverter getConverter();
|
||||
|
||||
}
|
||||
|
||||
@@ -540,6 +540,15 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
||||
return new DefaultIndexOperations(this, determineCollectionName(entityClass));
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.MongoOperations#scriptOps()
|
||||
*/
|
||||
@Override
|
||||
public ScriptOperations scriptOps() {
|
||||
return new DefaultScriptOperations(this);
|
||||
}
|
||||
|
||||
// Find methods that take a Query to express the query and that return a single object.
|
||||
|
||||
public <T> T findOne(Query query, Class<T> entityClass) {
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* Copyright 2014 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.data.mongodb.core;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.data.mongodb.core.script.CallableMongoScript;
|
||||
import org.springframework.data.mongodb.core.script.ServerSideJavaScript;
|
||||
|
||||
import com.mongodb.DB;
|
||||
|
||||
/**
|
||||
* Script operations on {@link com.mongodb.DB} level. Allows interaction with server side {@literal JavaScript}
|
||||
* functions.
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
* @since 1.7
|
||||
*/
|
||||
public interface ScriptOperations {
|
||||
|
||||
/**
|
||||
* Store given {@literal script} to {@link com.mongodb.DB} so it can be called via its name.
|
||||
*
|
||||
* @param script must not be {@literal null}.
|
||||
* @return {@link CallableMongoScript} with name under which the {@literal JavaScript} function can be called.
|
||||
*/
|
||||
CallableMongoScript register(ServerSideJavaScript script);
|
||||
|
||||
/**
|
||||
* Executes the {@literal script} by either calling it via its {@literal name} or directly sending it.
|
||||
*
|
||||
* @param script must not be {@literal null}.
|
||||
* @param args arguments to pass on for script execution.
|
||||
* @return the script evaluation result.
|
||||
* @throws org.springframework.dao.DataAccessException
|
||||
*/
|
||||
Object execute(ServerSideJavaScript script, Object... args);
|
||||
|
||||
/**
|
||||
* Call the {@literal JavaScript} by its name.
|
||||
*
|
||||
* @param scriptName must not be {@literal null} or empty.
|
||||
* @param args
|
||||
* @return
|
||||
*/
|
||||
Object call(String scriptName, Object... args);
|
||||
|
||||
/**
|
||||
* Checks {@link DB} for existence of {@link ServerSideJavaScript} with given name.
|
||||
*
|
||||
* @param scriptName must not be {@literal null} or empty.
|
||||
* @return false if no {@link ServerSideJavaScript} with given name exists.
|
||||
*/
|
||||
Boolean exists(String scriptName);
|
||||
|
||||
/**
|
||||
* Returns names of {@literal JavaScript} functions that can be called.
|
||||
*
|
||||
* @return empty {@link Set} if no scripts found.
|
||||
*/
|
||||
Set<String> scriptNames();
|
||||
|
||||
}
|
||||
@@ -44,6 +44,8 @@ import org.springframework.data.convert.WritingConverter;
|
||||
import org.springframework.data.mapping.model.SimpleTypeHolder;
|
||||
import org.springframework.data.mongodb.core.convert.MongoConverters.BigDecimalToStringConverter;
|
||||
import org.springframework.data.mongodb.core.convert.MongoConverters.BigIntegerToStringConverter;
|
||||
import org.springframework.data.mongodb.core.convert.MongoConverters.CallableMongoScriptToDBObjectConverter;
|
||||
import org.springframework.data.mongodb.core.convert.MongoConverters.DBObjectToCallableMongoScriptCoverter;
|
||||
import org.springframework.data.mongodb.core.convert.MongoConverters.DBObjectToStringConverter;
|
||||
import org.springframework.data.mongodb.core.convert.MongoConverters.StringToBigDecimalConverter;
|
||||
import org.springframework.data.mongodb.core.convert.MongoConverters.StringToBigIntegerConverter;
|
||||
@@ -118,6 +120,8 @@ public class CustomConversions {
|
||||
toRegister.add(StringToURLConverter.INSTANCE);
|
||||
toRegister.add(DBObjectToStringConverter.INSTANCE);
|
||||
toRegister.add(TermToStringConverter.INSTANCE);
|
||||
toRegister.add(CallableMongoScriptToDBObjectConverter.INSTANCE);
|
||||
toRegister.add(DBObjectToCallableMongoScriptCoverter.INSTANCE);
|
||||
|
||||
toRegister.addAll(JodaTimeConverters.getConvertersToRegister());
|
||||
toRegister.addAll(GeoConverters.getConvertersToRegister());
|
||||
|
||||
@@ -20,6 +20,7 @@ import java.math.BigInteger;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
|
||||
import org.bson.types.Code;
|
||||
import org.bson.types.ObjectId;
|
||||
import org.springframework.core.convert.ConversionFailedException;
|
||||
import org.springframework.core.convert.TypeDescriptor;
|
||||
@@ -27,8 +28,11 @@ import org.springframework.core.convert.converter.Converter;
|
||||
import org.springframework.data.convert.ReadingConverter;
|
||||
import org.springframework.data.convert.WritingConverter;
|
||||
import org.springframework.data.mongodb.core.query.Term;
|
||||
import org.springframework.data.mongodb.core.script.CallableMongoScript;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import com.mongodb.BasicDBObject;
|
||||
import com.mongodb.BasicDBObjectBuilder;
|
||||
import com.mongodb.DBObject;
|
||||
|
||||
/**
|
||||
@@ -178,4 +182,54 @@ abstract class MongoConverters {
|
||||
return source == null ? null : source.getFormatted();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @author Christoph Strobl
|
||||
* @since 1.7
|
||||
*/
|
||||
@ReadingConverter
|
||||
public static enum DBObjectToCallableMongoScriptCoverter implements Converter<DBObject, CallableMongoScript> {
|
||||
|
||||
INSTANCE;
|
||||
|
||||
@Override
|
||||
public CallableMongoScript convert(DBObject source) {
|
||||
|
||||
if (source == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
String id = source.get("_id").toString();
|
||||
Object rawValue = source.get("value");
|
||||
|
||||
return new CallableMongoScript(id, ((Code) rawValue).getCode());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @author Christoph Strobl
|
||||
* @since 1.7
|
||||
*/
|
||||
@WritingConverter
|
||||
public static enum CallableMongoScriptToDBObjectConverter implements Converter<CallableMongoScript, DBObject> {
|
||||
|
||||
INSTANCE;
|
||||
|
||||
@Override
|
||||
public DBObject convert(CallableMongoScript source) {
|
||||
|
||||
if (source == null) {
|
||||
return new BasicDBObject();
|
||||
}
|
||||
|
||||
BasicDBObjectBuilder builder = new BasicDBObjectBuilder();
|
||||
|
||||
builder.append("_id", source.getName());
|
||||
if (source.getCode() != null) {
|
||||
builder.append("value", new Code(source.getCode()));
|
||||
}
|
||||
|
||||
return builder.get();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* Copyright 2014 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.data.mongodb.core.script;
|
||||
|
||||
import org.springframework.data.annotation.Id;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* A {@link ServerSideJavaScript} implementation that allows calling the function by its {@literal name} once it has
|
||||
* been saved to the {@link com.mongodb.DB} instance.
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
* @since 1.7
|
||||
*/
|
||||
public class CallableMongoScript implements ServerSideJavaScript {
|
||||
|
||||
private final @Id String name;
|
||||
private final ServerSideJavaScript script;
|
||||
|
||||
/**
|
||||
* Creates new {@link CallableMongoScript} that can be saved to the {@link com.mongodb.DB} instance.
|
||||
*
|
||||
* @param name must not be {@literal null} or {@literal empty}.
|
||||
* @param rawScript the {@link String} representation of the {@literal JavaScript} function. Must not be
|
||||
* {@literal null} or {@literal empty}.
|
||||
*/
|
||||
public CallableMongoScript(String name, String rawScript) {
|
||||
this(name, new ExecutableMongoScript(rawScript));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link CallableMongoScript}.
|
||||
*
|
||||
* @param name must not be {@literal null} or {@literal empty}.
|
||||
* @param script can be {@literal null}.
|
||||
*/
|
||||
public CallableMongoScript(String name, ServerSideJavaScript script) {
|
||||
|
||||
Assert.hasText(name, "Name must not be null or empty!");
|
||||
this.name = name;
|
||||
this.script = script;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.script.MongoScript#getCode()
|
||||
*/
|
||||
@Override
|
||||
public String getCode() {
|
||||
|
||||
if (script == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return script.getCode();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the name of the {@link CallableMongoScript} script.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright 2014 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.data.mongodb.core.script;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* {@link ServerSideJavaScript} implementation that can be saved or directly executed.
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
* @since 1.7
|
||||
*/
|
||||
public class ExecutableMongoScript implements ServerSideJavaScript {
|
||||
|
||||
private final String code;
|
||||
|
||||
/**
|
||||
* Creates new {@link ExecutableMongoScript}.
|
||||
*
|
||||
* @param code must not be {@literal null} or {@literal empty}.
|
||||
*/
|
||||
public ExecutableMongoScript(String code) {
|
||||
|
||||
Assert.hasText(code, "Code must not be null or empty!");
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.script.MongoScript#getCode()
|
||||
*/
|
||||
@Override
|
||||
public String getCode() {
|
||||
return this.code;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright 2014 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.data.mongodb.core.script;
|
||||
|
||||
/**
|
||||
* @author Christoph Strobl
|
||||
* @since 1.7
|
||||
*/
|
||||
public interface ServerSideJavaScript {
|
||||
|
||||
/**
|
||||
* Get the {@link String} representation of the JavaScript code.
|
||||
*
|
||||
* @return {@literal null} when no code available.
|
||||
*/
|
||||
String getCode();
|
||||
}
|
||||
@@ -0,0 +1,204 @@
|
||||
/*
|
||||
* Copyright 2014 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.data.mongodb.core;
|
||||
|
||||
import static org.hamcrest.collection.IsEmptyCollection.*;
|
||||
import static org.hamcrest.core.Is.*;
|
||||
import static org.hamcrest.core.IsCollectionContaining.*;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.junit.Assume.*;
|
||||
import static org.springframework.data.mongodb.core.query.Criteria.*;
|
||||
import static org.springframework.data.mongodb.core.query.Query.*;
|
||||
|
||||
import org.hamcrest.core.Is;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.dao.DataAccessException;
|
||||
import org.springframework.dao.UncategorizedDataAccessException;
|
||||
import org.springframework.data.mongodb.core.query.Query;
|
||||
import org.springframework.data.mongodb.core.script.CallableMongoScript;
|
||||
import org.springframework.data.mongodb.core.script.ExecutableMongoScript;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
|
||||
import com.mongodb.BasicDBObject;
|
||||
import com.mongodb.Mongo;
|
||||
import com.mongodb.MongoClient;
|
||||
|
||||
/**
|
||||
* @author Christoph Strobl
|
||||
*/
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@ContextConfiguration
|
||||
public class DefaultScriptOperationsTests {
|
||||
|
||||
@Configuration
|
||||
static class Config {
|
||||
|
||||
private static final String DB_NAME = "script-tests";
|
||||
|
||||
@Bean
|
||||
public Mongo mongo() throws Exception {
|
||||
return new MongoClient();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public MongoTemplate template() throws Exception {
|
||||
return new MongoTemplate(mongo(), DB_NAME);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static final String JAVASCRIPT_COLLECTION_NAME = "system.js";
|
||||
static final String SCRIPT_NAME = "echo";
|
||||
static final String JS_FUNCTION = "function(x) { return x; }";
|
||||
static final ExecutableMongoScript EXECUTABLE_SCRIPT = new ExecutableMongoScript(JS_FUNCTION);
|
||||
static final CallableMongoScript CALLABLE_SCRIPT = new CallableMongoScript(SCRIPT_NAME, JS_FUNCTION);
|
||||
|
||||
@Autowired MongoTemplate template;
|
||||
DefaultScriptOperations scriptOps;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
|
||||
template.getCollection(JAVASCRIPT_COLLECTION_NAME).remove(new BasicDBObject());
|
||||
this.scriptOps = new DefaultScriptOperations(template);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-479
|
||||
*/
|
||||
@Test
|
||||
public void executeShouldDirectlyRunExecutableMongoScript() {
|
||||
|
||||
Object result = scriptOps.execute(EXECUTABLE_SCRIPT, 10);
|
||||
|
||||
assertThat(result, Is.<Object> is(10D));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-479
|
||||
*/
|
||||
@Test(expected = DataAccessException.class)
|
||||
public void executeThowsDataAccessExceptionWhenRunningCallableScriptThatHasNotBeenSavedBefore() {
|
||||
scriptOps.execute(CALLABLE_SCRIPT, 10);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-479
|
||||
*/
|
||||
@Test
|
||||
public void saveShouldStoreCallableScriptCorrectly() {
|
||||
|
||||
Query query = query(where("_id").is(SCRIPT_NAME));
|
||||
assumeThat(template.exists(query, JAVASCRIPT_COLLECTION_NAME), is(false));
|
||||
|
||||
scriptOps.register(CALLABLE_SCRIPT);
|
||||
|
||||
assumeThat(template.exists(query, JAVASCRIPT_COLLECTION_NAME), is(true));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-479
|
||||
*/
|
||||
@Test
|
||||
public void saveShouldStoreExecutableScriptCorrectly() {
|
||||
|
||||
CallableMongoScript script = scriptOps.register(EXECUTABLE_SCRIPT);
|
||||
|
||||
Query query = query(where("_id").is(script.getName()));
|
||||
assumeThat(template.exists(query, JAVASCRIPT_COLLECTION_NAME), is(true));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-479
|
||||
*/
|
||||
@Test
|
||||
public void executeShouldRunCallableScriptThatHasBeenSavedBefore() {
|
||||
|
||||
scriptOps.register(CALLABLE_SCRIPT);
|
||||
|
||||
Query query = query(where("_id").is(SCRIPT_NAME));
|
||||
assumeThat(template.exists(query, JAVASCRIPT_COLLECTION_NAME), is(true));
|
||||
|
||||
Object result = scriptOps.execute(CALLABLE_SCRIPT, 10);
|
||||
|
||||
assertThat(result, Is.<Object> is(10D));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-479
|
||||
*/
|
||||
@Test
|
||||
public void existsShouldReturnTrueIfScriptAvailableOnServer() {
|
||||
|
||||
scriptOps.register(CALLABLE_SCRIPT);
|
||||
|
||||
assertThat(scriptOps.exists(SCRIPT_NAME), is(true));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-479
|
||||
*/
|
||||
@Test
|
||||
public void existsShouldReturnFalseIfScriptNotAvailableOnServer() {
|
||||
assertThat(scriptOps.exists(SCRIPT_NAME), is(false));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-479
|
||||
*/
|
||||
@Test
|
||||
public void callShouldExecuteExistingScript() {
|
||||
|
||||
scriptOps.register(CALLABLE_SCRIPT);
|
||||
|
||||
Object result = scriptOps.call(SCRIPT_NAME, 10);
|
||||
|
||||
assertThat(result, Is.<Object> is(10D));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-479
|
||||
*/
|
||||
@Test(expected = UncategorizedDataAccessException.class)
|
||||
public void callShouldThrowExceptionWhenCallingScriptThatDoesNotExist() {
|
||||
scriptOps.call(SCRIPT_NAME, 10);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-479
|
||||
*/
|
||||
@Test
|
||||
public void scriptNamesShouldContainNameOfRegisteredScript() {
|
||||
|
||||
scriptOps.register(CALLABLE_SCRIPT);
|
||||
|
||||
assertThat(scriptOps.scriptNames(), hasItems("echo"));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-479
|
||||
*/
|
||||
@Test
|
||||
public void scriptNamesShouldReturnEmptySetWhenNoScriptRegistered() {
|
||||
assertThat(scriptOps.scriptNames(), empty());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,120 @@
|
||||
/*
|
||||
* Copyright 2014 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.data.mongodb.core;
|
||||
|
||||
import static org.hamcrest.core.IsNull.*;
|
||||
import static org.mockito.Matchers.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.runners.MockitoJUnitRunner;
|
||||
import org.springframework.data.mongodb.core.script.CallableMongoScript;
|
||||
import org.springframework.data.mongodb.core.script.ExecutableMongoScript;
|
||||
|
||||
/**
|
||||
* @author Christoph Strobl
|
||||
* @since 1.7
|
||||
*/
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class DefaultScriptOperationsUnitTests {
|
||||
|
||||
DefaultScriptOperations scriptOps;
|
||||
@Mock MongoOperations mongoOperationsMock;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
this.scriptOps = new DefaultScriptOperations(mongoOperationsMock);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-479
|
||||
*/
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void saveShouldThrowExceptionWhenCalledWithNullValue() {
|
||||
scriptOps.register(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-479
|
||||
*/
|
||||
@Test
|
||||
public void saveShouldUseCorrectCollectionName() {
|
||||
|
||||
scriptOps.register(new CallableMongoScript("foo", "function..."));
|
||||
|
||||
verify(mongoOperationsMock, times(1)).save(any(CallableMongoScript.class), eq("system.js"));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-479
|
||||
*/
|
||||
@Test
|
||||
public void saveShouldGenerateScriptNameForExecutableMongoScripts() {
|
||||
|
||||
scriptOps.register(new ExecutableMongoScript("function..."));
|
||||
|
||||
ArgumentCaptor<CallableMongoScript> captor = ArgumentCaptor.forClass(CallableMongoScript.class);
|
||||
|
||||
verify(mongoOperationsMock, times(1)).save(captor.capture(), eq("system.js"));
|
||||
Assert.assertThat(captor.getValue().getName(), notNullValue());
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-479
|
||||
*/
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void executeShouldThrowExceptionWhenScriptIsNull() {
|
||||
scriptOps.execute(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-479
|
||||
*/
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void existsShouldThrowExceptionWhenScriptNameIsNull() {
|
||||
scriptOps.exists(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-479
|
||||
*/
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void existsShouldThrowExceptionWhenScriptNameIsEmpty() {
|
||||
scriptOps.exists("");
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-479
|
||||
*/
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void callShouldThrowExceptionWhenScriptNameIsNull() {
|
||||
scriptOps.call(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-479
|
||||
*/
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void callShouldThrowExceptionWhenScriptNameIsEmpty() {
|
||||
scriptOps.call("");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,133 @@
|
||||
/*
|
||||
* Copyright 2014 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.data.mongodb.core.convert;
|
||||
|
||||
import static org.hamcrest.core.IsEqual.*;
|
||||
import static org.hamcrest.core.IsInstanceOf.*;
|
||||
import static org.hamcrest.core.IsNull.*;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import org.bson.types.Code;
|
||||
import org.hamcrest.core.IsEqual;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.Suite;
|
||||
import org.junit.runners.Suite.SuiteClasses;
|
||||
import org.springframework.data.mongodb.core.convert.CallableMongoScriptConvertsUnitTests.CallableMongoScriptToDboConverterUnitTests;
|
||||
import org.springframework.data.mongodb.core.convert.CallableMongoScriptConvertsUnitTests.DboToCallableMongoScriptConverterUnitTests;
|
||||
import org.springframework.data.mongodb.core.convert.MongoConverters.CallableMongoScriptToDBObjectConverter;
|
||||
import org.springframework.data.mongodb.core.convert.MongoConverters.DBObjectToCallableMongoScriptCoverter;
|
||||
import org.springframework.data.mongodb.core.script.CallableMongoScript;
|
||||
|
||||
import com.mongodb.BasicDBObject;
|
||||
import com.mongodb.BasicDBObjectBuilder;
|
||||
import com.mongodb.DBObject;
|
||||
|
||||
/**
|
||||
* @author Christoph Strobl
|
||||
*/
|
||||
@RunWith(Suite.class)
|
||||
@SuiteClasses({ CallableMongoScriptToDboConverterUnitTests.class, DboToCallableMongoScriptConverterUnitTests.class })
|
||||
public class CallableMongoScriptConvertsUnitTests {
|
||||
|
||||
static final String FUNCTION_NAME = "echo";
|
||||
static final String JS_FUNCTION = "function(x) { return x; }";
|
||||
static final CallableMongoScript ECHO_SCRIPT = new CallableMongoScript(FUNCTION_NAME, JS_FUNCTION);
|
||||
static final DBObject FUNCTION = new BasicDBObjectBuilder().add("_id", FUNCTION_NAME)
|
||||
.add("value", new Code(JS_FUNCTION)).get();
|
||||
|
||||
/**
|
||||
* @author Christoph Strobl
|
||||
*/
|
||||
public static class CallableMongoScriptToDboConverterUnitTests {
|
||||
|
||||
CallableMongoScriptToDBObjectConverter converter = CallableMongoScriptToDBObjectConverter.INSTANCE;
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-479
|
||||
*/
|
||||
@Test
|
||||
public void convertShouldReturnEmptyDboWhenScriptIsNull() {
|
||||
assertThat(converter.convert(null), IsEqual.<DBObject> equalTo(new BasicDBObject()));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-479
|
||||
*/
|
||||
@Test
|
||||
public void convertShouldConvertScriptNameCorreclty() {
|
||||
|
||||
DBObject dbo = converter.convert(ECHO_SCRIPT);
|
||||
|
||||
Object id = dbo.get("_id");
|
||||
assertThat(id, instanceOf(String.class));
|
||||
assertThat(id, IsEqual.<Object> equalTo(FUNCTION_NAME));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-479
|
||||
*/
|
||||
@Test
|
||||
public void convertShouldConvertScriptCodeCorreclty() {
|
||||
|
||||
DBObject dbo = converter.convert(ECHO_SCRIPT);
|
||||
|
||||
Object code = dbo.get("value");
|
||||
assertThat(code, instanceOf(Code.class));
|
||||
assertThat(code, equalTo((Object) new Code(JS_FUNCTION)));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @author Christoph Strobl
|
||||
*/
|
||||
public static class DboToCallableMongoScriptConverterUnitTests {
|
||||
|
||||
DBObjectToCallableMongoScriptCoverter converter = DBObjectToCallableMongoScriptCoverter.INSTANCE;
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-479
|
||||
*/
|
||||
@Test
|
||||
public void convertShouldReturnNullIfSourceIsNull() {
|
||||
assertThat(converter.convert(null), nullValue());
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-479
|
||||
*/
|
||||
@Test
|
||||
public void convertShouldConvertIdCorreclty() {
|
||||
|
||||
CallableMongoScript script = converter.convert(FUNCTION);
|
||||
|
||||
assertThat(script.getName(), equalTo(FUNCTION_NAME));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-479
|
||||
*/
|
||||
@Test
|
||||
public void convertShouldConvertScriptValueCorreclty() {
|
||||
|
||||
CallableMongoScript script = converter.convert(FUNCTION);
|
||||
|
||||
assertThat(script.getCode(), notNullValue());
|
||||
assertThat(script.getCode(), equalTo(JS_FUNCTION));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Copyright 2014 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.data.mongodb.core.script;
|
||||
|
||||
import static org.hamcrest.core.IsEqual.*;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* @author Christoph Strobl
|
||||
*/
|
||||
public class CallableMongoScriptUnitTests {
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-479
|
||||
*/
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void shouldThrowExceptionWhenScriptNameIsNull() {
|
||||
new CallableMongoScript(null, "return 1;");
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-479
|
||||
*/
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void shouldThrowExceptionWhenScriptNameIsEmptyString() {
|
||||
new CallableMongoScript("", "return 1");
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-479
|
||||
*/
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void shouldThrowExceptionWhenRawScriptIsEmptyString() {
|
||||
new CallableMongoScript("foo", "");
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-479
|
||||
*/
|
||||
@Test
|
||||
public void getCodeShouldReturnCodeRepresentationOfRawScript() {
|
||||
|
||||
String jsFunction = "function(x) { return x; }";
|
||||
|
||||
CallableMongoScript script = new CallableMongoScript("echo", jsFunction);
|
||||
|
||||
assertThat(script.getCode(), equalTo(jsFunction));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
* Copyright 2014 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.data.mongodb.core.script;
|
||||
|
||||
import static org.hamcrest.core.IsEqual.*;
|
||||
import static org.hamcrest.core.IsNull.*;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.ExpectedException;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
/**
|
||||
* @author Christoph Strobl
|
||||
*/
|
||||
public class ExecutableMongoScriptUnitTests {
|
||||
|
||||
public @Rule ExpectedException expectedException = ExpectedException.none();
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-479
|
||||
*/
|
||||
@Test
|
||||
public void constructorShouldThrowExceptionWhenRawScriptIsNull() {
|
||||
|
||||
expectException(IllegalArgumentException.class, "must not be", "null");
|
||||
|
||||
new ExecutableMongoScript(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-479
|
||||
*/
|
||||
@Test
|
||||
public void constructorShouldThrowExceptionWhenRawScriptIsEmpty() {
|
||||
|
||||
expectException(IllegalArgumentException.class, "must not be", "empty");
|
||||
|
||||
new ExecutableMongoScript("");
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-479
|
||||
*/
|
||||
@Test
|
||||
public void getCodeShouldReturnCodeRepresentationOfRawScript() {
|
||||
|
||||
String jsFunction = "function(x) { return x; }";
|
||||
|
||||
ExecutableMongoScript script = new ExecutableMongoScript(jsFunction);
|
||||
|
||||
assertThat(script.getCode(), notNullValue());
|
||||
assertThat(script.getCode().toString(), equalTo(jsFunction));
|
||||
}
|
||||
|
||||
private void expectException(Class<?> type, String... messageFragments) {
|
||||
|
||||
expectedException.expect(IllegalArgumentException.class);
|
||||
|
||||
if (!ObjectUtils.isEmpty(messageFragments)) {
|
||||
for (String fragment : messageFragments) {
|
||||
expectedException.expectMessage(fragment);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1325,6 +1325,25 @@ MapReduceResults<ValueObject> results = mongoOperations.mapReduce(query, "jmr1",
|
||||
|
||||
Note that you can specify additional limit and sort values as well on the query but not skip values.
|
||||
|
||||
[[mongo.server-side-scripts]]
|
||||
== Script Operations
|
||||
|
||||
MongoDB allows to execute JavaScript functions on the server by either directly sending the script or calling a stored one. `ScriptOperations` can be accessed via `MongoTemplate` and provides basic abstraction for `JavaScript` usage.
|
||||
|
||||
=== Example Usage
|
||||
|
||||
[source,java]
|
||||
----
|
||||
ScriptOperations scriptOps = template.scriptOps();
|
||||
|
||||
ServerSideJavaScript echoScript = new ExecutableMongoScript("function(x) { return x; }");
|
||||
scriptOps.execute(echoScript, "directly execute script");
|
||||
|
||||
scriptOps.register(new CallableMongoScript("echo", echoScript));
|
||||
scriptOps.call("echo", "execute script via name");
|
||||
----
|
||||
|
||||
|
||||
[[mongo.group]]
|
||||
== Group Operations
|
||||
|
||||
|
||||
Reference in New Issue
Block a user