Add module for Neo4j
This initial import is a copy of the code from Spring Batch v4.3.3.
This commit is contained in:
@@ -0,0 +1,224 @@
|
||||
/*
|
||||
* Copyright 2012-2021 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
|
||||
*
|
||||
* https://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.batch.extensions.neo4j;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.neo4j.ogm.session.Session;
|
||||
import org.neo4j.ogm.session.SessionFactory;
|
||||
|
||||
import org.springframework.batch.item.ItemReader;
|
||||
import org.springframework.batch.item.data.AbstractPaginatedDataItemReader;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Restartable {@link ItemReader} that reads objects from the graph database Neo4j
|
||||
* via a paging technique.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* It executes cypher queries built from the statement fragments provided to
|
||||
* retrieve the requested data. The query is executed using paged requests of
|
||||
* a size specified in {@link #setPageSize(int)}. Additional pages are requested
|
||||
* as needed when the {@link #read()} method is called. On restart, the reader
|
||||
* will begin again at the same number item it left off at.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* Performance is dependent on your Neo4J configuration (embedded or remote) as
|
||||
* well as page size. Setting a fairly large page size and using a commit
|
||||
* interval that matches the page size should provide better performance.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* This implementation is thread-safe between calls to
|
||||
* {@link #open(org.springframework.batch.item.ExecutionContext)}, however you
|
||||
* should set <code>saveState=false</code> if used in a multi-threaded
|
||||
* environment (no restart available).
|
||||
* </p>
|
||||
*
|
||||
* @author Michael Minella
|
||||
* @author Mahmoud Ben Hassine
|
||||
*/
|
||||
public class Neo4jItemReader<T> extends AbstractPaginatedDataItemReader<T> implements InitializingBean {
|
||||
|
||||
protected Log logger = LogFactory.getLog(getClass());
|
||||
|
||||
private SessionFactory sessionFactory;
|
||||
|
||||
private String startStatement;
|
||||
private String returnStatement;
|
||||
private String matchStatement;
|
||||
private String whereStatement;
|
||||
private String orderByStatement;
|
||||
|
||||
private Class<T> targetType;
|
||||
|
||||
private Map<String, Object> parameterValues;
|
||||
|
||||
/**
|
||||
* Optional parameters to be used in the cypher query.
|
||||
*
|
||||
* @param parameterValues the parameter values to be used in the cypher query
|
||||
*/
|
||||
public void setParameterValues(Map<String, Object> parameterValues) {
|
||||
this.parameterValues = parameterValues;
|
||||
}
|
||||
|
||||
protected final Map<String, Object> getParameterValues() {
|
||||
return this.parameterValues;
|
||||
}
|
||||
|
||||
/**
|
||||
* The start segment of the cypher query. START is prepended
|
||||
* to the statement provided and should <em>not</em> be
|
||||
* included.
|
||||
*
|
||||
* @param startStatement the start fragment of the cypher query.
|
||||
*/
|
||||
public void setStartStatement(String startStatement) {
|
||||
this.startStatement = startStatement;
|
||||
}
|
||||
|
||||
/**
|
||||
* The return statement of the cypher query. RETURN is prepended
|
||||
* to the statement provided and should <em>not</em> be
|
||||
* included
|
||||
*
|
||||
* @param returnStatement the return fragment of the cypher query.
|
||||
*/
|
||||
public void setReturnStatement(String returnStatement) {
|
||||
this.returnStatement = returnStatement;
|
||||
}
|
||||
|
||||
/**
|
||||
* An optional match fragment of the cypher query. MATCH is
|
||||
* prepended to the statement provided and should <em>not</em>
|
||||
* be included.
|
||||
*
|
||||
* @param matchStatement the match fragment of the cypher query
|
||||
*/
|
||||
public void setMatchStatement(String matchStatement) {
|
||||
this.matchStatement = matchStatement;
|
||||
}
|
||||
|
||||
/**
|
||||
* An optional where fragment of the cypher query. WHERE is
|
||||
* prepended to the statement provided and should <em>not</em>
|
||||
* be included.
|
||||
*
|
||||
* @param whereStatement where fragment of the cypher query
|
||||
*/
|
||||
public void setWhereStatement(String whereStatement) {
|
||||
this.whereStatement = whereStatement;
|
||||
}
|
||||
|
||||
/**
|
||||
* A list of properties to order the results by. This is
|
||||
* required so that subsequent page requests pull back the
|
||||
* segment of results correctly. ORDER BY is prepended to
|
||||
* the statement provided and should <em>not</em> be included.
|
||||
*
|
||||
* @param orderByStatement order by fragment of the cypher query.
|
||||
*/
|
||||
public void setOrderByStatement(String orderByStatement) {
|
||||
this.orderByStatement = orderByStatement;
|
||||
}
|
||||
|
||||
protected SessionFactory getSessionFactory() {
|
||||
return sessionFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Establish the session factory for the reader.
|
||||
* @param sessionFactory the factory to use for the reader.
|
||||
*/
|
||||
public void setSessionFactory(SessionFactory sessionFactory) {
|
||||
this.sessionFactory = sessionFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
* The object type to be returned from each call to {@link #read()}
|
||||
*
|
||||
* @param targetType the type of object to return.
|
||||
*/
|
||||
public void setTargetType(Class<T> targetType) {
|
||||
this.targetType = targetType;
|
||||
}
|
||||
|
||||
protected final Class<T> getTargetType() {
|
||||
return this.targetType;
|
||||
}
|
||||
|
||||
protected String generateLimitCypherQuery() {
|
||||
StringBuilder query = new StringBuilder(128);
|
||||
|
||||
query.append("START ").append(startStatement);
|
||||
query.append(matchStatement != null ? " MATCH " + matchStatement : "");
|
||||
query.append(whereStatement != null ? " WHERE " + whereStatement : "");
|
||||
query.append(" RETURN ").append(returnStatement);
|
||||
query.append(" ORDER BY ").append(orderByStatement);
|
||||
query.append(" SKIP " + (pageSize * page));
|
||||
query.append(" LIMIT " + pageSize);
|
||||
|
||||
String resultingQuery = query.toString();
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug(resultingQuery);
|
||||
}
|
||||
|
||||
return resultingQuery;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks mandatory properties
|
||||
*
|
||||
* @see InitializingBean#afterPropertiesSet()
|
||||
*/
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
Assert.state(sessionFactory != null,"A SessionFactory is required");
|
||||
Assert.state(targetType != null, "The type to be returned is required");
|
||||
Assert.state(StringUtils.hasText(startStatement), "A START statement is required");
|
||||
Assert.state(StringUtils.hasText(returnStatement), "A RETURN statement is required");
|
||||
Assert.state(StringUtils.hasText(orderByStatement), "A ORDER BY statement is required");
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
protected Iterator<T> doPageRead() {
|
||||
Session session = getSessionFactory().openSession();
|
||||
|
||||
Iterable<T> queryResults = session.query(getTargetType(),
|
||||
generateLimitCypherQuery(),
|
||||
getParameterValues());
|
||||
|
||||
if(queryResults != null) {
|
||||
return queryResults.iterator();
|
||||
}
|
||||
else {
|
||||
return new ArrayList<T>().iterator();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,127 @@
|
||||
/*
|
||||
* Copyright 2012-2021 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
|
||||
*
|
||||
* https://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.batch.extensions.neo4j;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.neo4j.ogm.session.Session;
|
||||
import org.neo4j.ogm.session.SessionFactory;
|
||||
|
||||
import org.springframework.batch.item.ItemWriter;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* A {@link ItemWriter} implementation that writes to a Neo4j database.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* This writer is thread-safe once all properties are set (normal singleton
|
||||
* behavior) so it can be used in multiple concurrent transactions.
|
||||
* </p>
|
||||
*
|
||||
* @author Michael Minella
|
||||
* @author Glenn Renfro
|
||||
* @author Mahmoud Ben Hassine
|
||||
*
|
||||
*/
|
||||
public class Neo4jItemWriter<T> implements ItemWriter<T>, InitializingBean {
|
||||
|
||||
protected static final Log logger = LogFactory
|
||||
.getLog(Neo4jItemWriter.class);
|
||||
|
||||
private boolean delete = false;
|
||||
|
||||
private SessionFactory sessionFactory;
|
||||
|
||||
/**
|
||||
* Boolean flag indicating whether the writer should save or delete the item at write
|
||||
* time.
|
||||
* @param delete true if write should delete item, false if item should be saved.
|
||||
* Default is false.
|
||||
*/
|
||||
public void setDelete(boolean delete) {
|
||||
this.delete = delete;
|
||||
}
|
||||
|
||||
/**
|
||||
* Establish the session factory that will be used to create {@link Session} instances
|
||||
* for interacting with Neo4j.
|
||||
* @param sessionFactory sessionFactory to be used.
|
||||
*/
|
||||
public void setSessionFactory(SessionFactory sessionFactory) {
|
||||
this.sessionFactory = sessionFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks mandatory properties
|
||||
*
|
||||
* @see InitializingBean#afterPropertiesSet()
|
||||
*/
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
Assert.state(this.sessionFactory != null,
|
||||
"A SessionFactory is required");
|
||||
}
|
||||
|
||||
/**
|
||||
* Write all items to the data store.
|
||||
*
|
||||
* @see org.springframework.batch.item.ItemWriter#write(java.util.List)
|
||||
*/
|
||||
@Override
|
||||
public void write(List<? extends T> items) throws Exception {
|
||||
if(!CollectionUtils.isEmpty(items)) {
|
||||
doWrite(items);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs the actual write using the template. This can be overridden by
|
||||
* a subclass if necessary.
|
||||
*
|
||||
* @param items the list of items to be persisted.
|
||||
*/
|
||||
protected void doWrite(List<? extends T> items) {
|
||||
if(delete) {
|
||||
delete(items);
|
||||
}
|
||||
else {
|
||||
save(items);
|
||||
}
|
||||
}
|
||||
|
||||
private void delete(List<? extends T> items) {
|
||||
Session session = this.sessionFactory.openSession();
|
||||
|
||||
for(T item : items) {
|
||||
session.delete(item);
|
||||
}
|
||||
}
|
||||
|
||||
private void save(List<? extends T> items) {
|
||||
Session session = this.sessionFactory.openSession();
|
||||
|
||||
for (T item : items) {
|
||||
session.save(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,273 @@
|
||||
/*
|
||||
* Copyright 2017-2021 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
|
||||
*
|
||||
* https://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.batch.extensions.neo4j.builder;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.neo4j.ogm.session.SessionFactory;
|
||||
|
||||
import org.springframework.batch.item.data.Neo4jItemReader;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* A builder for the {@link Neo4jItemReader}.
|
||||
*
|
||||
* @author Glenn Renfro
|
||||
* @see Neo4jItemReader
|
||||
*/
|
||||
public class Neo4jItemReaderBuilder<T> {
|
||||
|
||||
private SessionFactory sessionFactory;
|
||||
|
||||
private String startStatement;
|
||||
|
||||
private String returnStatement;
|
||||
|
||||
private String matchStatement;
|
||||
|
||||
private String whereStatement;
|
||||
|
||||
private String orderByStatement;
|
||||
|
||||
private Class<T> targetType;
|
||||
|
||||
private Map<String, Object> parameterValues;
|
||||
|
||||
private int pageSize = 10;
|
||||
|
||||
private boolean saveState = true;
|
||||
|
||||
private String name;
|
||||
|
||||
private int maxItemCount = Integer.MAX_VALUE;
|
||||
|
||||
private int currentItemCount;
|
||||
|
||||
/**
|
||||
* Configure if the state of the {@link org.springframework.batch.item.ItemStreamSupport}
|
||||
* should be persisted within the {@link org.springframework.batch.item.ExecutionContext}
|
||||
* for restart purposes.
|
||||
*
|
||||
* @param saveState defaults to true
|
||||
* @return The current instance of the builder.
|
||||
*/
|
||||
public Neo4jItemReaderBuilder<T> saveState(boolean saveState) {
|
||||
this.saveState = saveState;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* The name used to calculate the key within the
|
||||
* {@link org.springframework.batch.item.ExecutionContext}. Required if
|
||||
* {@link #saveState(boolean)} is set to true.
|
||||
*
|
||||
* @param name name of the reader instance
|
||||
* @return The current instance of the builder.
|
||||
* @see org.springframework.batch.item.ItemStreamSupport#setName(String)
|
||||
*/
|
||||
public Neo4jItemReaderBuilder<T> name(String name) {
|
||||
this.name = name;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure the max number of items to be read.
|
||||
*
|
||||
* @param maxItemCount the max items to be read
|
||||
* @return The current instance of the builder.
|
||||
* @see org.springframework.batch.item.support.AbstractItemCountingItemStreamItemReader#setMaxItemCount(int)
|
||||
*/
|
||||
public Neo4jItemReaderBuilder<T> maxItemCount(int maxItemCount) {
|
||||
this.maxItemCount = maxItemCount;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Index for the current item. Used on restarts to indicate where to start from.
|
||||
*
|
||||
* @param currentItemCount current index
|
||||
* @return this instance for method chaining
|
||||
* @see org.springframework.batch.item.support.AbstractItemCountingItemStreamItemReader#setCurrentItemCount(int)
|
||||
*/
|
||||
public Neo4jItemReaderBuilder<T> currentItemCount(int currentItemCount) {
|
||||
this.currentItemCount = currentItemCount;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Establish the session factory for the reader.
|
||||
* @param sessionFactory the factory to use for the reader.
|
||||
* @return this instance for method chaining
|
||||
* @see Neo4jItemReader#setSessionFactory(SessionFactory)
|
||||
*/
|
||||
public Neo4jItemReaderBuilder<T> sessionFactory(SessionFactory sessionFactory) {
|
||||
this.sessionFactory = sessionFactory;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* The number of items to be read with each page.
|
||||
*
|
||||
* @param pageSize the number of items
|
||||
* @return this instance for method chaining
|
||||
* @see Neo4jItemReader#setPageSize(int)
|
||||
*/
|
||||
public Neo4jItemReaderBuilder<T> pageSize(int pageSize) {
|
||||
this.pageSize = pageSize;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Optional parameters to be used in the cypher query.
|
||||
*
|
||||
* @param parameterValues the parameter values to be used in the cypher query
|
||||
* @return this instance for method chaining
|
||||
* @see Neo4jItemReader#setParameterValues(Map)
|
||||
*/
|
||||
public Neo4jItemReaderBuilder<T> parameterValues(Map<String, Object> parameterValues) {
|
||||
this.parameterValues = parameterValues;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* The start segment of the cypher query. START is prepended to the statement provided
|
||||
* and should <em>not</em> be included.
|
||||
*
|
||||
* @param startStatement the start fragment of the cypher query.
|
||||
* @return this instance for method chaining
|
||||
* @see Neo4jItemReader#setStartStatement(String)
|
||||
*/
|
||||
public Neo4jItemReaderBuilder<T> startStatement(String startStatement) {
|
||||
this.startStatement = startStatement;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* The return statement of the cypher query. RETURN is prepended to the statement
|
||||
* provided and should <em>not</em> be included
|
||||
*
|
||||
* @param returnStatement the return fragment of the cypher query.
|
||||
* @return this instance for method chaining
|
||||
* @see Neo4jItemReader#setReturnStatement(String)
|
||||
*/
|
||||
public Neo4jItemReaderBuilder<T> returnStatement(String returnStatement) {
|
||||
this.returnStatement = returnStatement;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* An optional match fragment of the cypher query. MATCH is prepended to the statement
|
||||
* provided and should <em>not</em> be included.
|
||||
*
|
||||
* @param matchStatement the match fragment of the cypher query
|
||||
* @return this instance for method chaining
|
||||
* @see Neo4jItemReader#setMatchStatement(String)
|
||||
*/
|
||||
public Neo4jItemReaderBuilder<T> matchStatement(String matchStatement) {
|
||||
this.matchStatement = matchStatement;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* An optional where fragment of the cypher query. WHERE is prepended to the statement
|
||||
* provided and should <em>not</em> be included.
|
||||
*
|
||||
* @param whereStatement where fragment of the cypher query
|
||||
* @return this instance for method chaining
|
||||
* @see Neo4jItemReader#setWhereStatement(String)
|
||||
*/
|
||||
public Neo4jItemReaderBuilder<T> whereStatement(String whereStatement) {
|
||||
this.whereStatement = whereStatement;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* A list of properties to order the results by. This is required so that subsequent
|
||||
* page requests pull back the segment of results correctly. ORDER BY is prepended to
|
||||
* the statement provided and should <em>not</em> be included.
|
||||
*
|
||||
* @param orderByStatement order by fragment of the cypher query.
|
||||
* @return this instance for method chaining
|
||||
* @see Neo4jItemReader#setOrderByStatement(String)
|
||||
*/
|
||||
public Neo4jItemReaderBuilder<T> orderByStatement(String orderByStatement) {
|
||||
this.orderByStatement = orderByStatement;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* The object type to be returned from each call to {@link Neo4jItemReader#read()}
|
||||
*
|
||||
* @param targetType the type of object to return.
|
||||
* @return this instance for method chaining
|
||||
* @see Neo4jItemReader#setTargetType(Class)
|
||||
*/
|
||||
public Neo4jItemReaderBuilder<T> targetType(Class<T> targetType) {
|
||||
this.targetType = targetType;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a fully constructed {@link Neo4jItemReader}.
|
||||
*
|
||||
* @return a new {@link Neo4jItemReader}
|
||||
*/
|
||||
public Neo4jItemReader<T> build() {
|
||||
if (this.saveState) {
|
||||
Assert.hasText(this.name, "A name is required when saveState is set to true");
|
||||
}
|
||||
Assert.notNull(this.sessionFactory, "sessionFactory is required.");
|
||||
Assert.notNull(this.targetType, "targetType is required.");
|
||||
Assert.hasText(this.startStatement, "startStatement is required.");
|
||||
Assert.hasText(this.returnStatement, "returnStatement is required.");
|
||||
Assert.hasText(this.orderByStatement, "orderByStatement is required.");
|
||||
Assert.isTrue(this.pageSize > 0, "pageSize must be greater than zero");
|
||||
Assert.isTrue(this.maxItemCount > 0, "maxItemCount must be greater than zero");
|
||||
Assert.isTrue(this.maxItemCount > this.currentItemCount , "maxItemCount must be greater than currentItemCount");
|
||||
|
||||
Neo4jItemReader<T> reader = new Neo4jItemReader<>();
|
||||
reader.setMatchStatement(this.matchStatement);
|
||||
reader.setOrderByStatement(this.orderByStatement);
|
||||
reader.setPageSize(this.pageSize);
|
||||
reader.setParameterValues(this.parameterValues);
|
||||
reader.setSessionFactory(this.sessionFactory);
|
||||
reader.setTargetType(this.targetType);
|
||||
reader.setStartStatement(this.startStatement);
|
||||
reader.setReturnStatement(this.returnStatement);
|
||||
reader.setWhereStatement(this.whereStatement);
|
||||
reader.setName(this.name);
|
||||
reader.setSaveState(this.saveState);
|
||||
reader.setCurrentItemCount(this.currentItemCount);
|
||||
reader.setMaxItemCount(this.maxItemCount);
|
||||
|
||||
return reader;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* Copyright 2017-2021 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
|
||||
*
|
||||
* https://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.batch.extensions.neo4j.builder;
|
||||
|
||||
import org.neo4j.ogm.session.Session;
|
||||
import org.neo4j.ogm.session.SessionFactory;
|
||||
|
||||
import org.springframework.batch.item.data.Neo4jItemWriter;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* A builder implementation for the {@link Neo4jItemWriter}
|
||||
*
|
||||
* @author Glenn Renfro
|
||||
* @see Neo4jItemWriter
|
||||
*/
|
||||
public class Neo4jItemWriterBuilder<T> {
|
||||
|
||||
private boolean delete = false;
|
||||
|
||||
private SessionFactory sessionFactory;
|
||||
|
||||
/**
|
||||
* Boolean flag indicating whether the writer should save or delete the item at write
|
||||
* time.
|
||||
* @param delete true if write should delete item, false if item should be saved.
|
||||
* Default is false.
|
||||
* @return The current instance of the builder
|
||||
* @see Neo4jItemWriter#setDelete(boolean)
|
||||
*/
|
||||
public Neo4jItemWriterBuilder<T> delete(boolean delete) {
|
||||
this.delete = delete;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Establish the session factory that will be used to create {@link Session} instances
|
||||
* for interacting with Neo4j.
|
||||
* @param sessionFactory sessionFactory to be used.
|
||||
* @return The current instance of the builder
|
||||
* @see Neo4jItemWriter#setSessionFactory(SessionFactory)
|
||||
*/
|
||||
public Neo4jItemWriterBuilder<T> sessionFactory(SessionFactory sessionFactory) {
|
||||
this.sessionFactory = sessionFactory;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates and builds a {@link org.springframework.batch.item.data.Neo4jItemWriter}.
|
||||
*
|
||||
* @return a {@link Neo4jItemWriter}
|
||||
*/
|
||||
public Neo4jItemWriter<T> build() {
|
||||
Assert.notNull(sessionFactory, "sessionFactory is required.");
|
||||
Neo4jItemWriter<T> writer = new Neo4jItemWriter<>();
|
||||
writer.setDelete(this.delete);
|
||||
writer.setSessionFactory(this.sessionFactory);
|
||||
return writer;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,202 @@
|
||||
/*
|
||||
* Copyright 2013-2021 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
|
||||
*
|
||||
* https://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.batch.extensions.neo4j;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.MockitoJUnit;
|
||||
import org.mockito.junit.MockitoRule;
|
||||
import org.neo4j.ogm.session.Session;
|
||||
import org.neo4j.ogm.session.SessionFactory;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.ArgumentMatchers.isNull;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
public class Neo4jItemReaderTests {
|
||||
|
||||
@Rule
|
||||
public MockitoRule rule = MockitoJUnit.rule().silent();
|
||||
|
||||
@Mock
|
||||
private Iterable<String> result;
|
||||
@Mock
|
||||
private SessionFactory sessionFactory;
|
||||
@Mock
|
||||
private Session session;
|
||||
|
||||
private Neo4jItemReader<String> buildSessionBasedReader() throws Exception {
|
||||
Neo4jItemReader<String> reader = new Neo4jItemReader<>();
|
||||
|
||||
reader.setSessionFactory(this.sessionFactory);
|
||||
reader.setTargetType(String.class);
|
||||
reader.setStartStatement("n=node(*)");
|
||||
reader.setReturnStatement("*");
|
||||
reader.setOrderByStatement("n.age");
|
||||
reader.setPageSize(50);
|
||||
reader.afterPropertiesSet();
|
||||
|
||||
return reader;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAfterPropertiesSet() throws Exception {
|
||||
|
||||
Neo4jItemReader<String> reader = new Neo4jItemReader<>();
|
||||
|
||||
try {
|
||||
reader.afterPropertiesSet();
|
||||
fail("SessionFactory was not set but exception was not thrown.");
|
||||
} catch (IllegalStateException iae) {
|
||||
assertEquals("A SessionFactory is required", iae.getMessage());
|
||||
} catch (Throwable t) {
|
||||
fail("Wrong exception was thrown:" + t);
|
||||
}
|
||||
|
||||
reader.setSessionFactory(this.sessionFactory);
|
||||
|
||||
try {
|
||||
reader.afterPropertiesSet();
|
||||
fail("Target Type was not set but exception was not thrown.");
|
||||
} catch (IllegalStateException iae) {
|
||||
assertEquals("The type to be returned is required", iae.getMessage());
|
||||
} catch (Throwable t) {
|
||||
fail("Wrong exception was thrown:" + t);
|
||||
}
|
||||
|
||||
reader.setTargetType(String.class);
|
||||
|
||||
try {
|
||||
reader.afterPropertiesSet();
|
||||
fail("START was not set but exception was not thrown.");
|
||||
} catch (IllegalStateException iae) {
|
||||
assertEquals("A START statement is required", iae.getMessage());
|
||||
} catch (Throwable t) {
|
||||
fail("Wrong exception was thrown:" + t);
|
||||
}
|
||||
|
||||
reader.setStartStatement("n=node(*)");
|
||||
|
||||
try {
|
||||
reader.afterPropertiesSet();
|
||||
fail("RETURN was not set but exception was not thrown.");
|
||||
} catch (IllegalStateException iae) {
|
||||
assertEquals("A RETURN statement is required", iae.getMessage());
|
||||
} catch (Throwable t) {
|
||||
fail("Wrong exception was thrown:" + t);
|
||||
}
|
||||
|
||||
reader.setReturnStatement("n.name, n.phone");
|
||||
|
||||
try {
|
||||
reader.afterPropertiesSet();
|
||||
fail("ORDER BY was not set but exception was not thrown.");
|
||||
} catch (IllegalStateException iae) {
|
||||
assertEquals("A ORDER BY statement is required", iae.getMessage());
|
||||
} catch (Throwable t) {
|
||||
fail("Wrong exception was thrown:" + t);
|
||||
}
|
||||
|
||||
reader.setOrderByStatement("n.age");
|
||||
|
||||
reader.afterPropertiesSet();
|
||||
|
||||
reader = new Neo4jItemReader<>();
|
||||
reader.setSessionFactory(this.sessionFactory);
|
||||
reader.setTargetType(String.class);
|
||||
reader.setStartStatement("n=node(*)");
|
||||
reader.setReturnStatement("n.name, n.phone");
|
||||
reader.setOrderByStatement("n.age");
|
||||
|
||||
reader.afterPropertiesSet();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Test
|
||||
public void testNullResultsWithSession() throws Exception {
|
||||
|
||||
Neo4jItemReader<String> itemReader = buildSessionBasedReader();
|
||||
|
||||
ArgumentCaptor<String> query = ArgumentCaptor.forClass(String.class);
|
||||
|
||||
when(this.sessionFactory.openSession()).thenReturn(this.session);
|
||||
when(this.session.query(eq(String.class), query.capture(), isNull())).thenReturn(null);
|
||||
|
||||
assertFalse(itemReader.doPageRead().hasNext());
|
||||
assertEquals("START n=node(*) RETURN * ORDER BY n.age SKIP 0 LIMIT 50", query.getValue());
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Test
|
||||
public void testNoResultsWithSession() throws Exception {
|
||||
Neo4jItemReader<String> itemReader = buildSessionBasedReader();
|
||||
ArgumentCaptor<String> query = ArgumentCaptor.forClass(String.class);
|
||||
|
||||
when(this.sessionFactory.openSession()).thenReturn(this.session);
|
||||
when(this.session.query(eq(String.class), query.capture(), isNull())).thenReturn(result);
|
||||
when(result.iterator()).thenReturn(Collections.emptyIterator());
|
||||
|
||||
assertFalse(itemReader.doPageRead().hasNext());
|
||||
assertEquals("START n=node(*) RETURN * ORDER BY n.age SKIP 0 LIMIT 50", query.getValue());
|
||||
}
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
@Test
|
||||
public void testResultsWithMatchAndWhereWithSession() throws Exception {
|
||||
Neo4jItemReader<String> itemReader = buildSessionBasedReader();
|
||||
itemReader.setMatchStatement("n -- m");
|
||||
itemReader.setWhereStatement("has(n.name)");
|
||||
itemReader.setReturnStatement("m");
|
||||
itemReader.afterPropertiesSet();
|
||||
|
||||
when(this.sessionFactory.openSession()).thenReturn(this.session);
|
||||
when(this.session.query(String.class, "START n=node(*) MATCH n -- m WHERE has(n.name) RETURN m ORDER BY n.age SKIP 0 LIMIT 50", null)).thenReturn(result);
|
||||
when(result.iterator()).thenReturn(Arrays.asList("foo", "bar", "baz").iterator());
|
||||
|
||||
assertTrue(itemReader.doPageRead().hasNext());
|
||||
}
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
@Test
|
||||
public void testResultsWithMatchAndWhereWithParametersWithSession() throws Exception {
|
||||
Neo4jItemReader<String> itemReader = buildSessionBasedReader();
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("foo", "bar");
|
||||
itemReader.setParameterValues(params);
|
||||
itemReader.setMatchStatement("n -- m");
|
||||
itemReader.setWhereStatement("has(n.name)");
|
||||
itemReader.setReturnStatement("m");
|
||||
itemReader.afterPropertiesSet();
|
||||
|
||||
when(this.sessionFactory.openSession()).thenReturn(this.session);
|
||||
when(this.session.query(String.class, "START n=node(*) MATCH n -- m WHERE has(n.name) RETURN m ORDER BY n.age SKIP 0 LIMIT 50", params)).thenReturn(result);
|
||||
when(result.iterator()).thenReturn(Arrays.asList("foo", "bar", "baz").iterator());
|
||||
|
||||
assertTrue(itemReader.doPageRead().hasNext());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,149 @@
|
||||
/*
|
||||
* Copyright 2013-2021 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
|
||||
*
|
||||
* https://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.batch.extensions.neo4j;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.MockitoJUnit;
|
||||
import org.mockito.junit.MockitoRule;
|
||||
import org.neo4j.ogm.session.Session;
|
||||
import org.neo4j.ogm.session.SessionFactory;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.fail;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.verifyNoInteractions;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
public class Neo4jItemWriterTests {
|
||||
|
||||
@Rule
|
||||
public MockitoRule rule = MockitoJUnit.rule().silent();
|
||||
|
||||
private Neo4jItemWriter<String> writer;
|
||||
|
||||
@Mock
|
||||
private SessionFactory sessionFactory;
|
||||
@Mock
|
||||
private Session session;
|
||||
|
||||
@Test
|
||||
public void testAfterPropertiesSet() throws Exception{
|
||||
|
||||
writer = new Neo4jItemWriter<>();
|
||||
|
||||
try {
|
||||
writer.afterPropertiesSet();
|
||||
fail("SessionFactory was not set but exception was not thrown.");
|
||||
} catch (IllegalStateException iae) {
|
||||
assertEquals("A SessionFactory is required", iae.getMessage());
|
||||
} catch (Throwable t) {
|
||||
fail("Wrong exception was thrown.");
|
||||
}
|
||||
|
||||
writer.setSessionFactory(this.sessionFactory);
|
||||
|
||||
writer.afterPropertiesSet();
|
||||
|
||||
writer = new Neo4jItemWriter<>();
|
||||
|
||||
writer.setSessionFactory(this.sessionFactory);
|
||||
|
||||
writer.afterPropertiesSet();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWriteNullSession() throws Exception {
|
||||
|
||||
writer = new Neo4jItemWriter<>();
|
||||
|
||||
writer.setSessionFactory(this.sessionFactory);
|
||||
writer.afterPropertiesSet();
|
||||
|
||||
writer.write(null);
|
||||
|
||||
verifyNoInteractions(this.session);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWriteNullWithSession() throws Exception {
|
||||
writer = new Neo4jItemWriter<>();
|
||||
|
||||
writer.setSessionFactory(this.sessionFactory);
|
||||
writer.afterPropertiesSet();
|
||||
|
||||
when(this.sessionFactory.openSession()).thenReturn(this.session);
|
||||
writer.write(null);
|
||||
|
||||
verifyNoInteractions(this.session);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWriteNoItemsWithSession() throws Exception {
|
||||
writer = new Neo4jItemWriter<>();
|
||||
|
||||
writer.setSessionFactory(this.sessionFactory);
|
||||
writer.afterPropertiesSet();
|
||||
|
||||
when(this.sessionFactory.openSession()).thenReturn(this.session);
|
||||
writer.write(new ArrayList<>());
|
||||
|
||||
verifyNoInteractions(this.session);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWriteItemsWithSession() throws Exception {
|
||||
writer = new Neo4jItemWriter<>();
|
||||
|
||||
writer.setSessionFactory(this.sessionFactory);
|
||||
writer.afterPropertiesSet();
|
||||
|
||||
List<String> items = new ArrayList<>();
|
||||
items.add("foo");
|
||||
items.add("bar");
|
||||
|
||||
when(this.sessionFactory.openSession()).thenReturn(this.session);
|
||||
writer.write(items);
|
||||
|
||||
verify(this.session).save("foo");
|
||||
verify(this.session).save("bar");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDeleteItemsWithSession() throws Exception {
|
||||
writer = new Neo4jItemWriter<>();
|
||||
|
||||
writer.setSessionFactory(this.sessionFactory);
|
||||
writer.afterPropertiesSet();
|
||||
|
||||
List<String> items = new ArrayList<>();
|
||||
items.add("foo");
|
||||
items.add("bar");
|
||||
|
||||
writer.setDelete(true);
|
||||
|
||||
when(this.sessionFactory.openSession()).thenReturn(this.session);
|
||||
writer.write(items);
|
||||
|
||||
verify(this.session).delete("foo");
|
||||
verify(this.session).delete("bar");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,290 @@
|
||||
/*
|
||||
* Copyright 2017-2021 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
|
||||
*
|
||||
* https://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.batch.extensions.neo4j.builder;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.MockitoJUnit;
|
||||
import org.mockito.junit.MockitoRule;
|
||||
import org.neo4j.ogm.session.Session;
|
||||
import org.neo4j.ogm.session.SessionFactory;
|
||||
|
||||
import org.springframework.batch.item.data.Neo4jItemReader;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.fail;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
/**
|
||||
* @author Glenn Renfro
|
||||
*/
|
||||
public class Neo4jItemReaderBuilderTests {
|
||||
|
||||
@Rule
|
||||
public MockitoRule rule = MockitoJUnit.rule().silent();
|
||||
|
||||
@Mock
|
||||
private Iterable<String> result;
|
||||
|
||||
@Mock
|
||||
private SessionFactory sessionFactory;
|
||||
|
||||
@Mock
|
||||
private Session session;
|
||||
|
||||
@Test
|
||||
public void testFullyQualifiedItemReader() throws Exception {
|
||||
Neo4jItemReader<String> itemReader = new Neo4jItemReaderBuilder<String>()
|
||||
.sessionFactory(this.sessionFactory)
|
||||
.targetType(String.class)
|
||||
.startStatement("n=node(*)")
|
||||
.orderByStatement("n.age")
|
||||
.pageSize(50).name("bar")
|
||||
.matchStatement("n -- m")
|
||||
.whereStatement("has(n.name)")
|
||||
.returnStatement("m").build();
|
||||
|
||||
when(this.sessionFactory.openSession()).thenReturn(this.session);
|
||||
when(this.session.query(String.class,
|
||||
"START n=node(*) MATCH n -- m WHERE has(n.name) RETURN m ORDER BY n.age SKIP 0 LIMIT 50", null))
|
||||
.thenReturn(result);
|
||||
when(result.iterator()).thenReturn(Arrays.asList("foo", "bar", "baz").iterator());
|
||||
|
||||
assertEquals("The expected value was not returned by reader.", "foo", itemReader.read());
|
||||
assertEquals("The expected value was not returned by reader.", "bar", itemReader.read());
|
||||
assertEquals("The expected value was not returned by reader.", "baz", itemReader.read());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCurrentSize() throws Exception {
|
||||
Neo4jItemReader<String> itemReader = new Neo4jItemReaderBuilder<String>()
|
||||
.sessionFactory(this.sessionFactory)
|
||||
.targetType(String.class)
|
||||
.startStatement("n=node(*)")
|
||||
.orderByStatement("n.age")
|
||||
.pageSize(50).name("bar")
|
||||
.returnStatement("m")
|
||||
.currentItemCount(0)
|
||||
.maxItemCount(1)
|
||||
.build();
|
||||
|
||||
when(this.sessionFactory.openSession()).thenReturn(this.session);
|
||||
when(this.session.query(String.class, "START n=node(*) RETURN m ORDER BY n.age SKIP 0 LIMIT 50", null))
|
||||
.thenReturn(result);
|
||||
when(result.iterator()).thenReturn(Arrays.asList("foo", "bar", "baz").iterator());
|
||||
|
||||
assertEquals("The expected value was not returned by reader.", "foo", itemReader.read());
|
||||
assertNull("The expected value was not should be null.", itemReader.read());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testResultsWithMatchAndWhereWithParametersWithSession() throws Exception {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("foo", "bar");
|
||||
Neo4jItemReader<String> itemReader = new Neo4jItemReaderBuilder<String>()
|
||||
.sessionFactory(this.sessionFactory)
|
||||
.targetType(String.class)
|
||||
.startStatement("n=node(*)")
|
||||
.returnStatement("*")
|
||||
.orderByStatement("n.age")
|
||||
.pageSize(50)
|
||||
.name("foo")
|
||||
.parameterValues(params)
|
||||
.matchStatement("n -- m")
|
||||
.whereStatement("has(n.name)")
|
||||
.returnStatement("m")
|
||||
.build();
|
||||
|
||||
when(this.sessionFactory.openSession()).thenReturn(this.session);
|
||||
when(this.session.query(String.class,
|
||||
"START n=node(*) MATCH n -- m WHERE has(n.name) RETURN m ORDER BY n.age SKIP 0 LIMIT 50", params))
|
||||
.thenReturn(result);
|
||||
when(result.iterator()).thenReturn(Arrays.asList("foo", "bar", "baz").iterator());
|
||||
|
||||
assertEquals("The expected value was not returned by reader.", "foo", itemReader.read());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNoSessionFactory() {
|
||||
try {
|
||||
new Neo4jItemReaderBuilder<String>()
|
||||
.targetType(String.class)
|
||||
.startStatement("n=node(*)")
|
||||
.returnStatement("*")
|
||||
.orderByStatement("n.age")
|
||||
.pageSize(50)
|
||||
.name("bar").build();
|
||||
|
||||
fail("IllegalArgumentException should have been thrown");
|
||||
}
|
||||
catch (IllegalArgumentException iae) {
|
||||
assertEquals("IllegalArgumentException message did not match the expected result.",
|
||||
"sessionFactory is required.", iae.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testZeroPageSize() {
|
||||
validateExceptionMessage(new Neo4jItemReaderBuilder<String>()
|
||||
.sessionFactory(this.sessionFactory)
|
||||
.targetType(String.class)
|
||||
.startStatement("n=node(*)")
|
||||
.returnStatement("*")
|
||||
.orderByStatement("n.age")
|
||||
.pageSize(0)
|
||||
.name("foo")
|
||||
.matchStatement("n -- m")
|
||||
.whereStatement("has(n.name)")
|
||||
.returnStatement("m"),
|
||||
"pageSize must be greater than zero");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testZeroMaxItemCount() {
|
||||
validateExceptionMessage(new Neo4jItemReaderBuilder<String>()
|
||||
.sessionFactory(this.sessionFactory)
|
||||
.targetType(String.class)
|
||||
.startStatement("n=node(*)")
|
||||
.returnStatement("*")
|
||||
.orderByStatement("n.age")
|
||||
.pageSize(5)
|
||||
.maxItemCount(0)
|
||||
.name("foo")
|
||||
.matchStatement("n -- m")
|
||||
.whereStatement("has(n.name)")
|
||||
.returnStatement("m"),
|
||||
"maxItemCount must be greater than zero");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCurrentItemCountGreaterThanMaxItemCount() {
|
||||
validateExceptionMessage(new Neo4jItemReaderBuilder<String>()
|
||||
.sessionFactory(this.sessionFactory)
|
||||
.targetType(String.class)
|
||||
.startStatement("n=node(*)")
|
||||
.returnStatement("*")
|
||||
.orderByStatement("n.age")
|
||||
.pageSize(5)
|
||||
.maxItemCount(5)
|
||||
.currentItemCount(6)
|
||||
.name("foo")
|
||||
.matchStatement("n -- m")
|
||||
.whereStatement("has(n.name)")
|
||||
.returnStatement("m"),
|
||||
"maxItemCount must be greater than currentItemCount");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNullName() {
|
||||
validateExceptionMessage(
|
||||
new Neo4jItemReaderBuilder<String>()
|
||||
.sessionFactory(this.sessionFactory)
|
||||
.targetType(String.class)
|
||||
.startStatement("n=node(*)")
|
||||
.returnStatement("*")
|
||||
.orderByStatement("n.age")
|
||||
.pageSize(50),
|
||||
"A name is required when saveState is set to true");
|
||||
|
||||
// tests that name is not required if saveState is set to false.
|
||||
new Neo4jItemReaderBuilder<String>()
|
||||
.sessionFactory(this.sessionFactory)
|
||||
.targetType(String.class)
|
||||
.startStatement("n=node(*)")
|
||||
.returnStatement("*")
|
||||
.orderByStatement("n.age")
|
||||
.saveState(false)
|
||||
.pageSize(50)
|
||||
.build();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNullTargetType() {
|
||||
validateExceptionMessage(
|
||||
new Neo4jItemReaderBuilder<String>()
|
||||
.sessionFactory(this.sessionFactory)
|
||||
.startStatement("n=node(*)")
|
||||
.returnStatement("*")
|
||||
.orderByStatement("n.age")
|
||||
.pageSize(50)
|
||||
.name("bar")
|
||||
.matchStatement("n -- m")
|
||||
.whereStatement("has(n.name)")
|
||||
.returnStatement("m"),
|
||||
"targetType is required.");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNullStartStatement() {
|
||||
validateExceptionMessage(
|
||||
new Neo4jItemReaderBuilder<String>()
|
||||
.sessionFactory(this.sessionFactory)
|
||||
.targetType(String.class)
|
||||
.returnStatement("*")
|
||||
.orderByStatement("n.age")
|
||||
.pageSize(50).name("bar")
|
||||
.matchStatement("n -- m")
|
||||
.whereStatement("has(n.name)")
|
||||
.returnStatement("m"),
|
||||
"startStatement is required.");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNullReturnStatement() {
|
||||
validateExceptionMessage(new Neo4jItemReaderBuilder<String>()
|
||||
.sessionFactory(this.sessionFactory)
|
||||
.targetType(String.class)
|
||||
.startStatement("n=node(*)")
|
||||
.orderByStatement("n.age")
|
||||
.pageSize(50).name("bar")
|
||||
.matchStatement("n -- m")
|
||||
.whereStatement("has(n.name)"), "returnStatement is required.");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNullOrderByStatement() {
|
||||
validateExceptionMessage(
|
||||
new Neo4jItemReaderBuilder<String>()
|
||||
.sessionFactory(this.sessionFactory)
|
||||
.targetType(String.class)
|
||||
.startStatement("n=node(*)")
|
||||
.returnStatement("*")
|
||||
.pageSize(50)
|
||||
.name("bar")
|
||||
.matchStatement("n -- m")
|
||||
.whereStatement("has(n.name)")
|
||||
.returnStatement("m"),
|
||||
"orderByStatement is required.");
|
||||
}
|
||||
|
||||
private void validateExceptionMessage(Neo4jItemReaderBuilder<?> builder, String message) {
|
||||
try {
|
||||
builder.build();
|
||||
fail("IllegalArgumentException should have been thrown");
|
||||
}
|
||||
catch (IllegalArgumentException iae) {
|
||||
assertEquals("IllegalArgumentException message did not match the expected result.", message,
|
||||
iae.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
* Copyright 2017-2021 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
|
||||
*
|
||||
* https://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.batch.extensions.neo4j.builder;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.MockitoJUnit;
|
||||
import org.mockito.junit.MockitoRule;
|
||||
import org.neo4j.ogm.session.Session;
|
||||
import org.neo4j.ogm.session.SessionFactory;
|
||||
|
||||
import org.springframework.batch.item.data.Neo4jItemWriter;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.fail;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
/**
|
||||
* @author Glenn Renfro
|
||||
*/
|
||||
public class Neo4jItemWriterBuilderTests {
|
||||
|
||||
@Rule
|
||||
public MockitoRule rule = MockitoJUnit.rule().silent();
|
||||
|
||||
@Mock
|
||||
private SessionFactory sessionFactory;
|
||||
@Mock
|
||||
private Session session;
|
||||
|
||||
@Test
|
||||
public void testBasicWriter() throws Exception{
|
||||
Neo4jItemWriter<String> writer = new Neo4jItemWriterBuilder<String>()
|
||||
.sessionFactory(this.sessionFactory)
|
||||
.build();
|
||||
List<String> items = new ArrayList<>();
|
||||
items.add("foo");
|
||||
items.add("bar");
|
||||
|
||||
when(this.sessionFactory.openSession()).thenReturn(this.session);
|
||||
writer.write(items);
|
||||
|
||||
verify(this.session).save("foo");
|
||||
verify(this.session).save("bar");
|
||||
verify(this.session, never()).delete("foo");
|
||||
verify(this.session, never()).delete("bar");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBasicDelete() throws Exception{
|
||||
Neo4jItemWriter<String> writer = new Neo4jItemWriterBuilder<String>().delete(true).sessionFactory(this.sessionFactory).build();
|
||||
List<String> items = new ArrayList<>();
|
||||
items.add("foo");
|
||||
items.add("bar");
|
||||
|
||||
when(this.sessionFactory.openSession()).thenReturn(this.session);
|
||||
writer.write(items);
|
||||
|
||||
verify(this.session).delete("foo");
|
||||
verify(this.session).delete("bar");
|
||||
verify(this.session, never()).save("foo");
|
||||
verify(this.session, never()).save("bar");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNoSessionFactory() {
|
||||
try {
|
||||
new Neo4jItemWriterBuilder<String>().build();
|
||||
fail("SessionFactory was not set but exception was not thrown.");
|
||||
} catch (IllegalArgumentException iae) {
|
||||
assertEquals("sessionFactory is required.", iae.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user