Browse Source

DATAMONGO-479 - Polishing.

Removed ServersideJavaScript abstraction as we still had to resort on instanceof checks and it created more ambiguities than it helped (e.g. in a script with name and code, which of the two get's executed?). We now have an ExecutableMongoScript which is code only and a NamedMongoScript, which basically is the former assigned to a name. Execution can be triggered on the former or a name.

ScriptOperations.exists(…) now returns a primitive boolean to avoid null checks. JavaDoc.

Original pull request: #254.
pull/271/merge
Oliver Gierke 11 years ago
parent
commit
39d9312005
  1. 94
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/DefaultScriptOperations.java
  2. 32
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/ScriptOperations.java
  3. 8
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/CustomConversions.java
  4. 18
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/MongoConverters.java
  5. 18
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/script/ExecutableMongoScript.java
  6. 54
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/script/NamedMongoScript.java
  7. 30
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/script/ServerSideJavaScript.java
  8. 41
      spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/DefaultScriptOperationsTests.java
  9. 32
      spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/DefaultScriptOperationsUnitTests.java
  10. 58
      spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/convert/NamedMongoScriptConvertsUnitTests.java
  11. 21
      spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/script/NamedMongoScriptUnitTests.java

94
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/DefaultScriptOperations.java

@ -1,5 +1,5 @@
/* /*
* Copyright 2014 the original author or authors. * Copyright 2014-2015 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -27,8 +27,8 @@ import java.util.Set;
import org.bson.types.ObjectId; import org.bson.types.ObjectId;
import org.springframework.dao.DataAccessException; import org.springframework.dao.DataAccessException;
import org.springframework.data.mongodb.core.script.CallableMongoScript; import org.springframework.data.mongodb.core.script.ExecutableMongoScript;
import org.springframework.data.mongodb.core.script.ServerSideJavaScript; import org.springframework.data.mongodb.core.script.NamedMongoScript;
import org.springframework.util.Assert; import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils; import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils; import org.springframework.util.ObjectUtils;
@ -41,12 +41,14 @@ import com.mongodb.MongoException;
* Default implementation of {@link ScriptOperations} capable of saving and executing {@link ServerSideJavaScript}. * Default implementation of {@link ScriptOperations} capable of saving and executing {@link ServerSideJavaScript}.
* *
* @author Christoph Strobl * @author Christoph Strobl
* @author Oliver Gierke
* @since 1.7 * @since 1.7
*/ */
public class DefaultScriptOperations implements ScriptOperations { class DefaultScriptOperations implements ScriptOperations {
private static final String SCRIPT_COLLECTION_NAME = "system.js"; private static final String SCRIPT_COLLECTION_NAME = "system.js";
private static final String SCRIPT_NAME_PREFIX = "func_"; private static final String SCRIPT_NAME_PREFIX = "func_";
private final MongoOperations mongoOperations; private final MongoOperations mongoOperations;
/** /**
@ -63,39 +65,39 @@ public class DefaultScriptOperations implements ScriptOperations {
/* /*
* (non-Javadoc) * (non-Javadoc)
* @see org.springframework.data.mongodb.core.ScriptOperations#save(org.springframework.data.mongodb.core.script.MongoScript) * @see org.springframework.data.mongodb.core.ScriptOperations#register(org.springframework.data.mongodb.core.script.ExecutableMongoScript)
*/
@Override
public NamedMongoScript register(ExecutableMongoScript script) {
return register(new NamedMongoScript(generateScriptName(), script));
}
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.core.ScriptOperations#register(org.springframework.data.mongodb.core.script.NamedMongoScript)
*/ */
@Override @Override
public CallableMongoScript register(ServerSideJavaScript script) { public NamedMongoScript register(NamedMongoScript script) {
Assert.notNull(script, "Script must not be null!"); Assert.notNull(script, "Script must not be null!");
CallableMongoScript callableScript = (script instanceof CallableMongoScript) ? (CallableMongoScript) script mongoOperations.save(script, SCRIPT_COLLECTION_NAME);
: new CallableMongoScript(generateScriptName(), script); return script;
mongoOperations.save(callableScript, SCRIPT_COLLECTION_NAME);
return callableScript;
} }
/* /*
* (non-Javadoc) * (non-Javadoc)
* @see org.springframework.data.mongodb.core.ScriptOperations#execute(org.springframework.data.mongodb.core.script.MongoScript, java.lang.Object[]) * @see org.springframework.data.mongodb.core.ScriptOperations#execute(org.springframework.data.mongodb.core.script.ExecutableMongoScript, java.lang.Object[])
*/ */
@Override @Override
public Object execute(final ServerSideJavaScript script, final Object... args) { public Object execute(final ExecutableMongoScript script, final Object... args) {
Assert.notNull(script, "Script must not be null!"); Assert.notNull(script, "Script must not be null!");
if (script instanceof CallableMongoScript) {
return call(((CallableMongoScript) script).getName(), args);
}
return mongoOperations.execute(new DbCallback<Object>() { return mongoOperations.execute(new DbCallback<Object>() {
@Override @Override
public Object doInDB(DB db) throws MongoException, DataAccessException { 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)); return db.eval(script.getCode(), convertScriptArgs(args));
} }
}); });
@ -114,9 +116,7 @@ public class DefaultScriptOperations implements ScriptOperations {
@Override @Override
public Object doInDB(DB db) throws MongoException, DataAccessException { public Object doInDB(DB db) throws MongoException, DataAccessException {
return db.eval(String.format("%s(%s)", scriptName, convertAndJoinScriptArgs(args)));
String evalString = scriptName + "(" + convertAndJoinScriptArgs(args) + ")";
return db.eval(evalString);
} }
}); });
} }
@ -126,43 +126,33 @@ public class DefaultScriptOperations implements ScriptOperations {
* @see org.springframework.data.mongodb.core.ScriptOperations#exists(java.lang.String) * @see org.springframework.data.mongodb.core.ScriptOperations#exists(java.lang.String)
*/ */
@Override @Override
public Boolean exists(String scriptName) { public boolean exists(String scriptName) {
Assert.hasText(scriptName, "ScriptName must not be null or empty!"); Assert.hasText(scriptName, "ScriptName must not be null or empty!");
return mongoOperations.exists(query(where("name").is(scriptName)), CallableMongoScript.class, return mongoOperations.exists(query(where("name").is(scriptName)), NamedMongoScript.class, SCRIPT_COLLECTION_NAME);
SCRIPT_COLLECTION_NAME);
} }
/* /*
* (non-Javadoc) * (non-Javadoc)
* @see org.springframework.data.mongodb.core.ScriptOperations#scriptNames() * @see org.springframework.data.mongodb.core.ScriptOperations#getScriptNames()
*/ */
@Override @Override
public Set<String> scriptNames() { public Set<String> getScriptNames() {
List<CallableMongoScript> scripts = (mongoOperations.findAll(CallableMongoScript.class, SCRIPT_COLLECTION_NAME)); List<NamedMongoScript> scripts = mongoOperations.findAll(NamedMongoScript.class, SCRIPT_COLLECTION_NAME);
if (CollectionUtils.isEmpty(scripts)) { if (CollectionUtils.isEmpty(scripts)) {
return Collections.emptySet(); return Collections.emptySet();
} }
Set<String> scriptNames = new HashSet<String>(); Set<String> scriptNames = new HashSet<String>();
for (CallableMongoScript script : scripts) {
for (NamedMongoScript script : scripts) {
scriptNames.add(script.getName()); scriptNames.add(script.getName());
} }
return scriptNames;
}
/** 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) { private Object[] convertScriptArgs(Object... args) {
@ -172,23 +162,27 @@ public class DefaultScriptOperations implements ScriptOperations {
} }
List<Object> convertedValues = new ArrayList<Object>(args.length); List<Object> convertedValues = new ArrayList<Object>(args.length);
for (Object arg : args) { for (Object arg : args) {
if (arg instanceof String) { convertedValues.add(arg instanceof String ? String.format("'%s'", arg) : this.mongoOperations.getConverter()
convertedValues.add("'" + arg + "'"); .convertToMongoType(arg));
} else {
convertedValues.add(this.mongoOperations.getConverter().convertToMongoType(arg));
}
} }
return convertedValues.toArray(); return convertedValues.toArray();
} }
private String convertAndJoinScriptArgs(Object... args) { private String convertAndJoinScriptArgs(Object... args) {
return ObjectUtils.isEmpty(args) ? "" : StringUtils.arrayToCommaDelimitedString(convertScriptArgs(args));
if (ObjectUtils.isEmpty(args)) {
return "";
} }
return StringUtils.arrayToCommaDelimitedString(convertScriptArgs(args)); /**
* 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 static String generateScriptName() {
return SCRIPT_NAME_PREFIX + randomUUID().toString().replaceAll("-", "");
} }
} }

32
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/ScriptOperations.java

@ -1,5 +1,5 @@
/* /*
* Copyright 2014 the original author or authors. * Copyright 2014-2015 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -17,27 +17,36 @@ package org.springframework.data.mongodb.core;
import java.util.Set; import java.util.Set;
import org.springframework.data.mongodb.core.script.CallableMongoScript; import org.springframework.data.mongodb.core.script.ExecutableMongoScript;
import org.springframework.data.mongodb.core.script.ServerSideJavaScript; import org.springframework.data.mongodb.core.script.NamedMongoScript;
import com.mongodb.DB; import com.mongodb.DB;
/** /**
* Script operations on {@link com.mongodb.DB} level. Allows interaction with server side {@literal JavaScript} * Script operations on {@link com.mongodb.DB} level. Allows interaction with server side JavaScript functions.
* functions.
* *
* @author Christoph Strobl * @author Christoph Strobl
* @author Oliver Gierke
* @since 1.7 * @since 1.7
*/ */
public interface ScriptOperations { public interface ScriptOperations {
/** /**
* Store given {@literal script} to {@link com.mongodb.DB} so it can be called via its name. * Store given {@link ExecutableMongoScript} generating a syntheitcal name so that it can be called by it
* subsequently.
* *
* @param script must not be {@literal null}. * @param script must not be {@literal null}.
* @return {@link CallableMongoScript} with name under which the {@literal JavaScript} function can be called. * @return {@link NamedMongoScript} with name under which the {@code JavaScript} function can be called.
*/ */
CallableMongoScript register(ServerSideJavaScript script); NamedMongoScript register(ExecutableMongoScript script);
/**
* Registers the given {@link NamedMongoScript} in the database.
*
* @param script the {@link NamedMongoScript} to be registered.
* @return
*/
NamedMongoScript register(NamedMongoScript script);
/** /**
* Executes the {@literal script} by either calling it via its {@literal name} or directly sending it. * Executes the {@literal script} by either calling it via its {@literal name} or directly sending it.
@ -47,7 +56,7 @@ public interface ScriptOperations {
* @return the script evaluation result. * @return the script evaluation result.
* @throws org.springframework.dao.DataAccessException * @throws org.springframework.dao.DataAccessException
*/ */
Object execute(ServerSideJavaScript script, Object... args); Object execute(ExecutableMongoScript script, Object... args);
/** /**
* Call the {@literal JavaScript} by its name. * Call the {@literal JavaScript} by its name.
@ -64,13 +73,12 @@ public interface ScriptOperations {
* @param scriptName must not be {@literal null} or empty. * @param scriptName must not be {@literal null} or empty.
* @return false if no {@link ServerSideJavaScript} with given name exists. * @return false if no {@link ServerSideJavaScript} with given name exists.
*/ */
Boolean exists(String scriptName); boolean exists(String scriptName);
/** /**
* Returns names of {@literal JavaScript} functions that can be called. * Returns names of {@literal JavaScript} functions that can be called.
* *
* @return empty {@link Set} if no scripts found. * @return empty {@link Set} if no scripts found.
*/ */
Set<String> scriptNames(); Set<String> getScriptNames();
} }

8
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/CustomConversions.java

@ -44,8 +44,8 @@ import org.springframework.data.convert.WritingConverter;
import org.springframework.data.mapping.model.SimpleTypeHolder; import org.springframework.data.mapping.model.SimpleTypeHolder;
import org.springframework.data.mongodb.core.convert.MongoConverters.BigDecimalToStringConverter; 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.BigIntegerToStringConverter;
import org.springframework.data.mongodb.core.convert.MongoConverters.CallableMongoScriptToDBObjectConverter; import org.springframework.data.mongodb.core.convert.MongoConverters.NamedMongoScriptToDBObjectConverter;
import org.springframework.data.mongodb.core.convert.MongoConverters.DBObjectToCallableMongoScriptCoverter; import org.springframework.data.mongodb.core.convert.MongoConverters.DBObjectToNamedMongoScriptCoverter;
import org.springframework.data.mongodb.core.convert.MongoConverters.DBObjectToStringConverter; 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.StringToBigDecimalConverter;
import org.springframework.data.mongodb.core.convert.MongoConverters.StringToBigIntegerConverter; import org.springframework.data.mongodb.core.convert.MongoConverters.StringToBigIntegerConverter;
@ -120,8 +120,8 @@ public class CustomConversions {
toRegister.add(StringToURLConverter.INSTANCE); toRegister.add(StringToURLConverter.INSTANCE);
toRegister.add(DBObjectToStringConverter.INSTANCE); toRegister.add(DBObjectToStringConverter.INSTANCE);
toRegister.add(TermToStringConverter.INSTANCE); toRegister.add(TermToStringConverter.INSTANCE);
toRegister.add(CallableMongoScriptToDBObjectConverter.INSTANCE); toRegister.add(NamedMongoScriptToDBObjectConverter.INSTANCE);
toRegister.add(DBObjectToCallableMongoScriptCoverter.INSTANCE); toRegister.add(DBObjectToNamedMongoScriptCoverter.INSTANCE);
toRegister.addAll(JodaTimeConverters.getConvertersToRegister()); toRegister.addAll(JodaTimeConverters.getConvertersToRegister());
toRegister.addAll(GeoConverters.getConvertersToRegister()); toRegister.addAll(GeoConverters.getConvertersToRegister());

18
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/MongoConverters.java

@ -1,5 +1,5 @@
/* /*
* Copyright 2011-2014 the original author or authors. * Copyright 2011-2015 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -28,7 +28,7 @@ import org.springframework.core.convert.converter.Converter;
import org.springframework.data.convert.ReadingConverter; import org.springframework.data.convert.ReadingConverter;
import org.springframework.data.convert.WritingConverter; import org.springframework.data.convert.WritingConverter;
import org.springframework.data.mongodb.core.query.Term; import org.springframework.data.mongodb.core.query.Term;
import org.springframework.data.mongodb.core.script.CallableMongoScript; import org.springframework.data.mongodb.core.script.NamedMongoScript;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
import com.mongodb.BasicDBObject; import com.mongodb.BasicDBObject;
@ -187,13 +187,12 @@ abstract class MongoConverters {
* @author Christoph Strobl * @author Christoph Strobl
* @since 1.7 * @since 1.7
*/ */
@ReadingConverter public static enum DBObjectToNamedMongoScriptCoverter implements Converter<DBObject, NamedMongoScript> {
public static enum DBObjectToCallableMongoScriptCoverter implements Converter<DBObject, CallableMongoScript> {
INSTANCE; INSTANCE;
@Override @Override
public CallableMongoScript convert(DBObject source) { public NamedMongoScript convert(DBObject source) {
if (source == null) { if (source == null) {
return null; return null;
@ -202,7 +201,7 @@ abstract class MongoConverters {
String id = source.get("_id").toString(); String id = source.get("_id").toString();
Object rawValue = source.get("value"); Object rawValue = source.get("value");
return new CallableMongoScript(id, ((Code) rawValue).getCode()); return new NamedMongoScript(id, ((Code) rawValue).getCode());
} }
} }
@ -210,13 +209,12 @@ abstract class MongoConverters {
* @author Christoph Strobl * @author Christoph Strobl
* @since 1.7 * @since 1.7
*/ */
@WritingConverter public static enum NamedMongoScriptToDBObjectConverter implements Converter<NamedMongoScript, DBObject> {
public static enum CallableMongoScriptToDBObjectConverter implements Converter<CallableMongoScript, DBObject> {
INSTANCE; INSTANCE;
@Override @Override
public DBObject convert(CallableMongoScript source) { public DBObject convert(NamedMongoScript source) {
if (source == null) { if (source == null) {
return new BasicDBObject(); return new BasicDBObject();
@ -225,9 +223,7 @@ abstract class MongoConverters {
BasicDBObjectBuilder builder = new BasicDBObjectBuilder(); BasicDBObjectBuilder builder = new BasicDBObjectBuilder();
builder.append("_id", source.getName()); builder.append("_id", source.getName());
if (source.getCode() != null) {
builder.append("value", new Code(source.getCode())); builder.append("value", new Code(source.getCode()));
}
return builder.get(); return builder.get();
} }

18
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/script/ExecutableMongoScript.java

@ -1,5 +1,5 @@
/* /*
* Copyright 2014 the original author or authors. * Copyright 2014-2015 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -18,19 +18,20 @@ package org.springframework.data.mongodb.core.script;
import org.springframework.util.Assert; import org.springframework.util.Assert;
/** /**
* {@link ServerSideJavaScript} implementation that can be saved or directly executed. * Value object for MongoDB JavaScript functions implementation that can be saved or directly executed.
* *
* @author Christoph Strobl * @author Christoph Strobl
* @author Oliver Gierke
* @since 1.7 * @since 1.7
*/ */
public class ExecutableMongoScript implements ServerSideJavaScript { public class ExecutableMongoScript {
private final String code; private final String code;
/** /**
* Creates new {@link ExecutableMongoScript}. * Creates new {@link ExecutableMongoScript}.
* *
* @param code must not be {@literal null} or {@literal empty}. * @param code must not be {@literal null} or empty.
*/ */
public ExecutableMongoScript(String code) { public ExecutableMongoScript(String code) {
@ -38,13 +39,12 @@ public class ExecutableMongoScript implements ServerSideJavaScript {
this.code = code; this.code = code;
} }
/* /**
* (non-Javadoc) * Returns the actual script code.
* @see org.springframework.data.mongodb.core.script.MongoScript#getCode() *
* @return will never be {@literal null} or empty.
*/ */
@Override
public String getCode() { public String getCode() {
return this.code; return this.code;
} }
} }

54
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/script/CallableMongoScript.java → spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/script/NamedMongoScript.java

@ -1,5 +1,5 @@
/* /*
* Copyright 2014 the original author or authors. * Copyright 2014-2015 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -19,62 +19,68 @@ import org.springframework.data.annotation.Id;
import org.springframework.util.Assert; import org.springframework.util.Assert;
/** /**
* A {@link ServerSideJavaScript} implementation that allows calling the function by its {@literal name} once it has * An {@link ExecutableMongoScript} assigned to a name that allows calling the function by its {@literal name} once it
* been saved to the {@link com.mongodb.DB} instance. * has been saved to the {@link com.mongodb.DB} instance.
* *
* @author Christoph Strobl * @author Christoph Strobl
* @author Oliver Gierke
* @since 1.7 * @since 1.7
*/ */
public class CallableMongoScript implements ServerSideJavaScript { public class NamedMongoScript {
private final @Id String name; private final @Id String name;
private final ServerSideJavaScript script; private final ExecutableMongoScript script;
/** /**
* Creates new {@link CallableMongoScript} that can be saved to the {@link com.mongodb.DB} instance. * Creates new {@link NamedMongoScript} that can be saved to the {@link com.mongodb.DB} instance.
* *
* @param name must not be {@literal null} or {@literal empty}. * @param name must not be {@literal null} or empty.
* @param rawScript the {@link String} representation of the {@literal JavaScript} function. Must not be * @param rawScript the {@link String} representation of the {@literal JavaScript} function. Must not be
* {@literal null} or {@literal empty}. * {@literal null} or empty.
*/ */
public CallableMongoScript(String name, String rawScript) { public NamedMongoScript(String name, String rawScript) {
this(name, new ExecutableMongoScript(rawScript)); this(name, new ExecutableMongoScript(rawScript));
} }
/** /**
* Creates new {@link CallableMongoScript}. * Creates new {@link NamedMongoScript}.
* *
* @param name must not be {@literal null} or {@literal empty}. * @param name must not be {@literal null} or empty.
* @param script can be {@literal null}. * @param script must not be {@literal null}.
*/ */
public CallableMongoScript(String name, ServerSideJavaScript script) { public NamedMongoScript(String name, ExecutableMongoScript script) {
Assert.hasText(name, "Name must not be null or empty!"); Assert.hasText(name, "Name must not be null or empty!");
Assert.notNull(script, "ExecutableMongoScript must not be null!");
this.name = name; this.name = name;
this.script = script; this.script = script;
} }
/* /**
* (non-Javadoc) * Returns the actual script code.
* @see org.springframework.data.mongodb.core.script.MongoScript#getCode() *
* @return will never be {@literal null}.
*/ */
@Override
public String getCode() { public String getCode() {
return script.getCode();
if (script == null) {
return null;
} }
return script.getCode(); /**
* Returns the underlying {@link ExecutableMongoScript}.
*
* @return will never be {@literal null}.
*/
public ExecutableMongoScript getScript() {
return script;
} }
/** /**
* Get the name of the {@link CallableMongoScript} script. * Returns the name of the script.
* *
* @return * @return will never be {@literal null} or empty.
*/ */
public String getName() { public String getName() {
return name; return name;
} }
} }

30
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/script/ServerSideJavaScript.java

@ -1,30 +0,0 @@
/*
* 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();
}

41
spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/DefaultScriptOperationsTests.java

@ -1,5 +1,5 @@
/* /*
* Copyright 2014 the original author or authors. * Copyright 2014-2015 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -15,26 +15,22 @@
*/ */
package org.springframework.data.mongodb.core; package org.springframework.data.mongodb.core;
import static org.hamcrest.collection.IsEmptyCollection.*; import static org.hamcrest.Matchers.*;
import static org.hamcrest.core.Is.*;
import static org.hamcrest.core.IsCollectionContaining.*;
import static org.junit.Assert.*; import static org.junit.Assert.*;
import static org.junit.Assume.*; import static org.junit.Assume.*;
import static org.springframework.data.mongodb.core.query.Criteria.*; import static org.springframework.data.mongodb.core.query.Criteria.*;
import static org.springframework.data.mongodb.core.query.Query.*; import static org.springframework.data.mongodb.core.query.Query.*;
import org.hamcrest.core.Is;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.UncategorizedDataAccessException; import org.springframework.dao.UncategorizedDataAccessException;
import org.springframework.data.mongodb.core.query.Query; 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.data.mongodb.core.script.ExecutableMongoScript;
import org.springframework.data.mongodb.core.script.NamedMongoScript;
import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@ -43,7 +39,11 @@ import com.mongodb.Mongo;
import com.mongodb.MongoClient; import com.mongodb.MongoClient;
/** /**
* Integration tests for {@link DefaultScriptOperations}.
*
* @author Christoph Strobl * @author Christoph Strobl
* @author Oliver Gierke
* @since 1.7
*/ */
@RunWith(SpringJUnit4ClassRunner.class) @RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration @ContextConfiguration
@ -70,7 +70,7 @@ public class DefaultScriptOperationsTests {
static final String SCRIPT_NAME = "echo"; static final String SCRIPT_NAME = "echo";
static final String JS_FUNCTION = "function(x) { return x; }"; static final String JS_FUNCTION = "function(x) { return x; }";
static final ExecutableMongoScript EXECUTABLE_SCRIPT = new ExecutableMongoScript(JS_FUNCTION); static final ExecutableMongoScript EXECUTABLE_SCRIPT = new ExecutableMongoScript(JS_FUNCTION);
static final CallableMongoScript CALLABLE_SCRIPT = new CallableMongoScript(SCRIPT_NAME, JS_FUNCTION); static final NamedMongoScript CALLABLE_SCRIPT = new NamedMongoScript(SCRIPT_NAME, JS_FUNCTION);
@Autowired MongoTemplate template; @Autowired MongoTemplate template;
DefaultScriptOperations scriptOps; DefaultScriptOperations scriptOps;
@ -87,18 +87,7 @@ public class DefaultScriptOperationsTests {
*/ */
@Test @Test
public void executeShouldDirectlyRunExecutableMongoScript() { public void executeShouldDirectlyRunExecutableMongoScript() {
assertThat(scriptOps.execute(EXECUTABLE_SCRIPT, 10), is((Object) 10D));
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);
} }
/** /**
@ -121,7 +110,7 @@ public class DefaultScriptOperationsTests {
@Test @Test
public void saveShouldStoreExecutableScriptCorrectly() { public void saveShouldStoreExecutableScriptCorrectly() {
CallableMongoScript script = scriptOps.register(EXECUTABLE_SCRIPT); NamedMongoScript script = scriptOps.register(EXECUTABLE_SCRIPT);
Query query = query(where("_id").is(script.getName())); Query query = query(where("_id").is(script.getName()));
assumeThat(template.exists(query, JAVASCRIPT_COLLECTION_NAME), is(true)); assumeThat(template.exists(query, JAVASCRIPT_COLLECTION_NAME), is(true));
@ -138,9 +127,9 @@ public class DefaultScriptOperationsTests {
Query query = query(where("_id").is(SCRIPT_NAME)); Query query = query(where("_id").is(SCRIPT_NAME));
assumeThat(template.exists(query, JAVASCRIPT_COLLECTION_NAME), is(true)); assumeThat(template.exists(query, JAVASCRIPT_COLLECTION_NAME), is(true));
Object result = scriptOps.execute(CALLABLE_SCRIPT, 10); Object result = scriptOps.call(CALLABLE_SCRIPT.getName(), 10);
assertThat(result, Is.<Object> is(10D)); assertThat(result, is((Object) 10D));
} }
/** /**
@ -172,7 +161,7 @@ public class DefaultScriptOperationsTests {
Object result = scriptOps.call(SCRIPT_NAME, 10); Object result = scriptOps.call(SCRIPT_NAME, 10);
assertThat(result, Is.<Object> is(10D)); assertThat(result, is((Object) 10D));
} }
/** /**
@ -191,7 +180,7 @@ public class DefaultScriptOperationsTests {
scriptOps.register(CALLABLE_SCRIPT); scriptOps.register(CALLABLE_SCRIPT);
assertThat(scriptOps.scriptNames(), hasItems("echo")); assertThat(scriptOps.getScriptNames(), hasItems("echo"));
} }
/** /**
@ -199,6 +188,6 @@ public class DefaultScriptOperationsTests {
*/ */
@Test @Test
public void scriptNamesShouldReturnEmptySetWhenNoScriptRegistered() { public void scriptNamesShouldReturnEmptySetWhenNoScriptRegistered() {
assertThat(scriptOps.scriptNames(), empty()); assertThat(scriptOps.getScriptNames(), is(empty()));
} }
} }

32
spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/DefaultScriptOperationsUnitTests.java

@ -1,5 +1,5 @@
/* /*
* Copyright 2014 the original author or authors. * Copyright 2014-2015 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -26,30 +26,41 @@ import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor; import org.mockito.ArgumentCaptor;
import org.mockito.Mock; import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner; import org.mockito.runners.MockitoJUnitRunner;
import org.springframework.data.mongodb.core.script.CallableMongoScript;
import org.springframework.data.mongodb.core.script.ExecutableMongoScript; import org.springframework.data.mongodb.core.script.ExecutableMongoScript;
import org.springframework.data.mongodb.core.script.NamedMongoScript;
/** /**
* Unit tests for {@link DefaultScriptOperations}.
*
* @author Christoph Strobl * @author Christoph Strobl
* @author Oliver Gierke
* @since 1.7 * @since 1.7
*/ */
@RunWith(MockitoJUnitRunner.class) @RunWith(MockitoJUnitRunner.class)
public class DefaultScriptOperationsUnitTests { public class DefaultScriptOperationsUnitTests {
DefaultScriptOperations scriptOps; DefaultScriptOperations scriptOps;
@Mock MongoOperations mongoOperationsMock; @Mock MongoOperations mongoOperations;
@Before @Before
public void setUp() { public void setUp() {
this.scriptOps = new DefaultScriptOperations(mongoOperationsMock); this.scriptOps = new DefaultScriptOperations(mongoOperations);
}
/**
* @see DATAMONGO-479
*/
@Test(expected = IllegalArgumentException.class)
public void rejectsNullExecutableMongoScript() {
scriptOps.register((ExecutableMongoScript) null);
} }
/** /**
* @see DATAMONGO-479 * @see DATAMONGO-479
*/ */
@Test(expected = IllegalArgumentException.class) @Test(expected = IllegalArgumentException.class)
public void saveShouldThrowExceptionWhenCalledWithNullValue() { public void rejectsNullNamedMongoScript() {
scriptOps.register(null); scriptOps.register((NamedMongoScript) null);
} }
/** /**
@ -58,9 +69,9 @@ public class DefaultScriptOperationsUnitTests {
@Test @Test
public void saveShouldUseCorrectCollectionName() { public void saveShouldUseCorrectCollectionName() {
scriptOps.register(new CallableMongoScript("foo", "function...")); scriptOps.register(new NamedMongoScript("foo", "function..."));
verify(mongoOperationsMock, times(1)).save(any(CallableMongoScript.class), eq("system.js")); verify(mongoOperations, times(1)).save(any(NamedMongoScript.class), eq("system.js"));
} }
/** /**
@ -71,9 +82,9 @@ public class DefaultScriptOperationsUnitTests {
scriptOps.register(new ExecutableMongoScript("function...")); scriptOps.register(new ExecutableMongoScript("function..."));
ArgumentCaptor<CallableMongoScript> captor = ArgumentCaptor.forClass(CallableMongoScript.class); ArgumentCaptor<NamedMongoScript> captor = ArgumentCaptor.forClass(NamedMongoScript.class);
verify(mongoOperationsMock, times(1)).save(captor.capture(), eq("system.js")); verify(mongoOperations, times(1)).save(captor.capture(), eq("system.js"));
Assert.assertThat(captor.getValue().getName(), notNullValue()); Assert.assertThat(captor.getValue().getName(), notNullValue());
} }
@ -116,5 +127,4 @@ public class DefaultScriptOperationsUnitTests {
public void callShouldThrowExceptionWhenScriptNameIsEmpty() { public void callShouldThrowExceptionWhenScriptNameIsEmpty() {
scriptOps.call(""); scriptOps.call("");
} }
} }

58
spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/convert/CallableMongoScriptConvertsUnitTests.java → spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/convert/NamedMongoScriptConvertsUnitTests.java

@ -1,5 +1,5 @@
/* /*
* Copyright 2014 the original author or authors. * Copyright 2014-2015 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -15,53 +15,55 @@
*/ */
package org.springframework.data.mongodb.core.convert; package org.springframework.data.mongodb.core.convert;
import static org.hamcrest.core.IsEqual.*; import static org.hamcrest.Matchers.*;
import static org.hamcrest.core.IsInstanceOf.*;
import static org.hamcrest.core.IsNull.*;
import static org.junit.Assert.*; import static org.junit.Assert.*;
import org.bson.types.Code; import org.bson.types.Code;
import org.hamcrest.core.IsEqual;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.junit.runners.Suite; import org.junit.runners.Suite;
import org.junit.runners.Suite.SuiteClasses; import org.junit.runners.Suite.SuiteClasses;
import org.springframework.data.mongodb.core.convert.CallableMongoScriptConvertsUnitTests.CallableMongoScriptToDboConverterUnitTests; import org.springframework.core.convert.converter.Converter;
import org.springframework.data.mongodb.core.convert.CallableMongoScriptConvertsUnitTests.DboToCallableMongoScriptConverterUnitTests; import org.springframework.data.mongodb.core.convert.MongoConverters.DBObjectToNamedMongoScriptCoverter;
import org.springframework.data.mongodb.core.convert.MongoConverters.CallableMongoScriptToDBObjectConverter; import org.springframework.data.mongodb.core.convert.MongoConverters.NamedMongoScriptToDBObjectConverter;
import org.springframework.data.mongodb.core.convert.MongoConverters.DBObjectToCallableMongoScriptCoverter; import org.springframework.data.mongodb.core.convert.NamedMongoScriptConvertsUnitTests.DboToNamedMongoScriptConverterUnitTests;
import org.springframework.data.mongodb.core.script.CallableMongoScript; import org.springframework.data.mongodb.core.convert.NamedMongoScriptConvertsUnitTests.NamedMongoScriptToDboConverterUnitTests;
import org.springframework.data.mongodb.core.script.NamedMongoScript;
import com.mongodb.BasicDBObject; import com.mongodb.BasicDBObject;
import com.mongodb.BasicDBObjectBuilder; import com.mongodb.BasicDBObjectBuilder;
import com.mongodb.DBObject; import com.mongodb.DBObject;
/** /**
* Unit tests for {@link Converter} implementations for {@link NamedMongoScript}.
*
* @author Christoph Strobl * @author Christoph Strobl
* @author Oliver Gierke
* @since 1.7
*/ */
@RunWith(Suite.class) @RunWith(Suite.class)
@SuiteClasses({ CallableMongoScriptToDboConverterUnitTests.class, DboToCallableMongoScriptConverterUnitTests.class }) @SuiteClasses({ NamedMongoScriptToDboConverterUnitTests.class, DboToNamedMongoScriptConverterUnitTests.class })
public class CallableMongoScriptConvertsUnitTests { public class NamedMongoScriptConvertsUnitTests {
static final String FUNCTION_NAME = "echo"; static final String FUNCTION_NAME = "echo";
static final String JS_FUNCTION = "function(x) { return x; }"; static final String JS_FUNCTION = "function(x) { return x; }";
static final CallableMongoScript ECHO_SCRIPT = new CallableMongoScript(FUNCTION_NAME, JS_FUNCTION); static final NamedMongoScript ECHO_SCRIPT = new NamedMongoScript(FUNCTION_NAME, JS_FUNCTION);
static final DBObject FUNCTION = new BasicDBObjectBuilder().add("_id", FUNCTION_NAME) static final DBObject FUNCTION = new BasicDBObjectBuilder().add("_id", FUNCTION_NAME)
.add("value", new Code(JS_FUNCTION)).get(); .add("value", new Code(JS_FUNCTION)).get();
/** /**
* @author Christoph Strobl * @author Christoph Strobl
*/ */
public static class CallableMongoScriptToDboConverterUnitTests { public static class NamedMongoScriptToDboConverterUnitTests {
CallableMongoScriptToDBObjectConverter converter = CallableMongoScriptToDBObjectConverter.INSTANCE; NamedMongoScriptToDBObjectConverter converter = NamedMongoScriptToDBObjectConverter.INSTANCE;
/** /**
* @see DATAMONGO-479 * @see DATAMONGO-479
*/ */
@Test @Test
public void convertShouldReturnEmptyDboWhenScriptIsNull() { public void convertShouldReturnEmptyDboWhenScriptIsNull() {
assertThat(converter.convert(null), IsEqual.<DBObject> equalTo(new BasicDBObject())); assertThat(converter.convert(null), is((DBObject) new BasicDBObject()));
} }
/** /**
@ -73,8 +75,8 @@ public class CallableMongoScriptConvertsUnitTests {
DBObject dbo = converter.convert(ECHO_SCRIPT); DBObject dbo = converter.convert(ECHO_SCRIPT);
Object id = dbo.get("_id"); Object id = dbo.get("_id");
assertThat(id, instanceOf(String.class)); assertThat(id, is(instanceOf(String.class)));
assertThat(id, IsEqual.<Object> equalTo(FUNCTION_NAME)); assertThat(id, is((Object) FUNCTION_NAME));
} }
/** /**
@ -86,24 +88,24 @@ public class CallableMongoScriptConvertsUnitTests {
DBObject dbo = converter.convert(ECHO_SCRIPT); DBObject dbo = converter.convert(ECHO_SCRIPT);
Object code = dbo.get("value"); Object code = dbo.get("value");
assertThat(code, instanceOf(Code.class)); assertThat(code, is(instanceOf(Code.class)));
assertThat(code, equalTo((Object) new Code(JS_FUNCTION))); assertThat(code, is((Object) new Code(JS_FUNCTION)));
} }
} }
/** /**
* @author Christoph Strobl * @author Christoph Strobl
*/ */
public static class DboToCallableMongoScriptConverterUnitTests { public static class DboToNamedMongoScriptConverterUnitTests {
DBObjectToCallableMongoScriptCoverter converter = DBObjectToCallableMongoScriptCoverter.INSTANCE; DBObjectToNamedMongoScriptCoverter converter = DBObjectToNamedMongoScriptCoverter.INSTANCE;
/** /**
* @see DATAMONGO-479 * @see DATAMONGO-479
*/ */
@Test @Test
public void convertShouldReturnNullIfSourceIsNull() { public void convertShouldReturnNullIfSourceIsNull() {
assertThat(converter.convert(null), nullValue()); assertThat(converter.convert(null), is(nullValue()));
} }
/** /**
@ -112,9 +114,9 @@ public class CallableMongoScriptConvertsUnitTests {
@Test @Test
public void convertShouldConvertIdCorreclty() { public void convertShouldConvertIdCorreclty() {
CallableMongoScript script = converter.convert(FUNCTION); NamedMongoScript script = converter.convert(FUNCTION);
assertThat(script.getName(), equalTo(FUNCTION_NAME)); assertThat(script.getName(), is(FUNCTION_NAME));
} }
/** /**
@ -123,10 +125,10 @@ public class CallableMongoScriptConvertsUnitTests {
@Test @Test
public void convertShouldConvertScriptValueCorreclty() { public void convertShouldConvertScriptValueCorreclty() {
CallableMongoScript script = converter.convert(FUNCTION); NamedMongoScript script = converter.convert(FUNCTION);
assertThat(script.getCode(), notNullValue()); assertThat(script.getCode(), is(notNullValue()));
assertThat(script.getCode(), equalTo(JS_FUNCTION)); assertThat(script.getCode(), is(JS_FUNCTION));
} }
} }

21
spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/script/CallableMongoScriptUnitTests.java → spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/script/NamedMongoScriptUnitTests.java

@ -1,5 +1,5 @@
/* /*
* Copyright 2014 the original author or authors. * Copyright 2014-2015 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -15,22 +15,26 @@
*/ */
package org.springframework.data.mongodb.core.script; package org.springframework.data.mongodb.core.script;
import static org.hamcrest.core.IsEqual.*; import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.*; import static org.junit.Assert.*;
import org.junit.Test; import org.junit.Test;
/** /**
* Unit tests for {@link NamedMongoScript}.
*
* @author Christoph Strobl * @author Christoph Strobl
* @author Oliver Gierke
* @since 1.7
*/ */
public class CallableMongoScriptUnitTests { public class NamedMongoScriptUnitTests {
/** /**
* @see DATAMONGO-479 * @see DATAMONGO-479
*/ */
@Test(expected = IllegalArgumentException.class) @Test(expected = IllegalArgumentException.class)
public void shouldThrowExceptionWhenScriptNameIsNull() { public void shouldThrowExceptionWhenScriptNameIsNull() {
new CallableMongoScript(null, "return 1;"); new NamedMongoScript(null, "return 1;");
} }
/** /**
@ -38,7 +42,7 @@ public class CallableMongoScriptUnitTests {
*/ */
@Test(expected = IllegalArgumentException.class) @Test(expected = IllegalArgumentException.class)
public void shouldThrowExceptionWhenScriptNameIsEmptyString() { public void shouldThrowExceptionWhenScriptNameIsEmptyString() {
new CallableMongoScript("", "return 1"); new NamedMongoScript("", "return 1");
} }
/** /**
@ -46,7 +50,7 @@ public class CallableMongoScriptUnitTests {
*/ */
@Test(expected = IllegalArgumentException.class) @Test(expected = IllegalArgumentException.class)
public void shouldThrowExceptionWhenRawScriptIsEmptyString() { public void shouldThrowExceptionWhenRawScriptIsEmptyString() {
new CallableMongoScript("foo", ""); new NamedMongoScript("foo", "");
} }
/** /**
@ -57,9 +61,6 @@ public class CallableMongoScriptUnitTests {
String jsFunction = "function(x) { return x; }"; String jsFunction = "function(x) { return x; }";
CallableMongoScript script = new CallableMongoScript("echo", jsFunction); assertThat(new NamedMongoScript("echo", jsFunction).getCode(), is(jsFunction));
assertThat(script.getCode(), equalTo(jsFunction));
} }
} }
Loading…
Cancel
Save