#58 - Add sample for usage of server-side JavaScript.
Use a server-side script to simulate putIfAbsent(…) as contracted by the Map interface. The operation will be atomic since MongoDB will put a lock on database until the script is finished.
This commit is contained in:
committed by
Oliver Gierke
parent
8d77a9a37e
commit
50cb4b9bba
@@ -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");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -17,7 +17,6 @@ package example.springdata.mongodb.customer;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import org.bson.types.ObjectId;
|
||||
import org.springframework.data.mongodb.core.mapping.Document;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
@@ -30,9 +29,7 @@ import org.springframework.util.Assert;
|
||||
@Document
|
||||
public class Customer {
|
||||
|
||||
private ObjectId id;
|
||||
private String firstname, lastname;
|
||||
|
||||
private String id, firstname, lastname;
|
||||
private Address address;
|
||||
|
||||
/**
|
||||
|
||||
@@ -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");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -17,7 +17,6 @@ package example.springdata.mongodb.customer;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.bson.types.ObjectId;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.data.geo.Distance;
|
||||
import org.springframework.data.geo.GeoResults;
|
||||
@@ -29,7 +28,7 @@ import org.springframework.data.repository.CrudRepository;
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public interface CustomerRepository extends CrudRepository<Customer, ObjectId> {
|
||||
public interface CustomerRepository extends CrudRepository<Customer, String> {
|
||||
|
||||
/**
|
||||
* Derived query using dynamic sort information.
|
||||
@@ -41,7 +40,7 @@ public interface CustomerRepository extends CrudRepository<Customer, ObjectId> {
|
||||
List<Customer> findByLastname(String lastname, Sort sort);
|
||||
|
||||
/**
|
||||
* Showcase for a repository query using geo-spatial functionality.
|
||||
* Show case for a repository query using geo-spatial functionality.
|
||||
*
|
||||
* @param point
|
||||
* @param distance
|
||||
|
||||
@@ -0,0 +1,116 @@
|
||||
/*
|
||||
* Copyright 2015 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 example.springdata.mongodb.advanced;
|
||||
|
||||
import static org.hamcrest.core.Is.*;
|
||||
import static org.hamcrest.core.IsNull.*;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import example.springdata.mongodb.customer.Customer;
|
||||
import example.springdata.mongodb.util.RequiresMongoDB;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.ClassRule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.SpringApplicationConfiguration;
|
||||
import org.springframework.data.mongodb.core.MongoOperations;
|
||||
import org.springframework.data.mongodb.core.script.ExecutableMongoScript;
|
||||
import org.springframework.data.mongodb.core.script.NamedMongoScript;
|
||||
import org.springframework.data.util.Version;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
|
||||
import com.mongodb.BasicDBObject;
|
||||
import com.mongodb.DBObject;
|
||||
|
||||
/**
|
||||
* @author Christoph Strobl
|
||||
*/
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@SpringApplicationConfiguration(classes = ApplicationConfiguration.class)
|
||||
public class ServersideScriptTests {
|
||||
|
||||
@ClassRule public static RequiresMongoDB mongodbAvailable = RequiresMongoDB.atLeast(new Version(2, 6));
|
||||
|
||||
@Autowired AdvancedRepository repository;
|
||||
@Autowired MongoOperations operations;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
|
||||
if (!operations.collectionExists(Customer.class)) {
|
||||
operations.createCollection(Customer.class);
|
||||
}
|
||||
|
||||
// just make sure we remove everything properly
|
||||
operations.getCollection("system.js").remove(new BasicDBObject());
|
||||
repository.deleteAll();
|
||||
}
|
||||
|
||||
/**
|
||||
* Store and call an arbitrary JavaScript function (in this case a simple echo script) via its name.
|
||||
*/
|
||||
@Test
|
||||
public void saveAndCallScriptViaName() {
|
||||
|
||||
operations.scriptOps()
|
||||
.register(new NamedMongoScript("echoScript", new ExecutableMongoScript("function(x) { return x; }")));
|
||||
|
||||
Object o = operations.scriptOps().call("echoScript", "Hello echo...!");
|
||||
assertThat(o, is((Object) "Hello echo...!"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Use a script execution to create an atomic put-if-absent operation that fulfills the contract of
|
||||
* {@link Map#putIfAbsent(Object, Object)}
|
||||
*/
|
||||
@Test
|
||||
public void complexScriptExecutionSimulatingPutIfAbsent() {
|
||||
|
||||
Customer ned = new Customer("Ned", "Stark");
|
||||
ned.setId("ned-stark");
|
||||
|
||||
// #1: on first insert null has to be returned
|
||||
assertThat(operations.scriptOps().execute(createExecutablePutIfAbsentScript(ned)), nullValue());
|
||||
|
||||
// #2: change the firstname and put the object again, we expect a return value.
|
||||
ned.setFirstname("Eddard");
|
||||
assertThat(operations.scriptOps().execute(createExecutablePutIfAbsentScript(ned)), notNullValue());
|
||||
|
||||
// #3: make sure the entity has not been altered by #2
|
||||
assertThat(repository.findOne(ned.getId()).getFirstname(), is("Ned"));
|
||||
assertThat(repository.count(), is(1L));
|
||||
}
|
||||
|
||||
private ExecutableMongoScript createExecutablePutIfAbsentScript(Customer customer) {
|
||||
|
||||
String collectionName = operations.getCollectionName(Customer.class);
|
||||
Object id = operations.getConverter().getMappingContext().getPersistentEntity(Customer.class)
|
||||
.getIdentifierAccessor(customer).getIdentifier();
|
||||
|
||||
DBObject dbo = new BasicDBObject();
|
||||
operations.getConverter().write(customer, dbo);
|
||||
|
||||
String scriptString = String.format(
|
||||
"object = db.%1$s.findOne('{\"_id\": \"%2$s\"}'); if (object == null) { db.%1s.insert(%3$s); return null; } else { return object; }",
|
||||
collectionName, id, dbo);
|
||||
|
||||
return new ExecutableMongoScript(scriptString);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user