Browse Source

DATAJDBC-335 - Address review comments.

Original pull request: #121.
pull/122/head
Jens Schauder 7 years ago
parent
commit
8eb80ba5cc
  1. 51
      spring-data-relational/src/main/java/org/springframework/data/relational/core/sql/AbstractImportValidator.java
  2. 2
      spring-data-relational/src/main/java/org/springframework/data/relational/core/sql/AssignValue.java
  3. 4
      spring-data-relational/src/main/java/org/springframework/data/relational/core/sql/DefaultUpdate.java
  4. 28
      spring-data-relational/src/main/java/org/springframework/data/relational/core/sql/DefaultUpdateBuilder.java
  5. 10
      spring-data-relational/src/main/java/org/springframework/data/relational/core/sql/DeleteValidator.java
  6. 37
      spring-data-relational/src/main/java/org/springframework/data/relational/core/sql/SelectValidator.java
  7. 19
      spring-data-relational/src/main/java/org/springframework/data/relational/core/sql/UpdateBuilder.java
  8. 16
      spring-data-relational/src/test/java/org/springframework/data/relational/core/sql/DeleteValidatorUnitTests.java
  9. 18
      spring-data-relational/src/test/java/org/springframework/data/relational/core/sql/SelectValidatorUnitTests.java
  10. 2
      spring-data-relational/src/test/java/org/springframework/data/relational/core/sql/UpdateBuilderUnitTests.java
  11. 3
      spring-data-relational/src/test/java/org/springframework/data/relational/core/sql/render/UpdateRendererUnitTests.java

51
spring-data-relational/src/main/java/org/springframework/data/relational/core/sql/AbstractImportValidator.java

@ -18,6 +18,8 @@ package org.springframework.data.relational.core.sql; @@ -18,6 +18,8 @@ package org.springframework.data.relational.core.sql;
import java.util.HashSet;
import java.util.Set;
import org.springframework.lang.Nullable;
/**
* Validator for statements to import columns.
*
@ -42,13 +44,7 @@ abstract class AbstractImportValidator implements Visitor { @@ -42,13 +44,7 @@ abstract class AbstractImportValidator implements Visitor {
}
if (segment instanceof Where) {
segment.visit(item -> {
if (item instanceof Table) {
requiredByWhere.add((Table) item);
}
});
segment.visit(new SubselectFilteringWhereVisitor());
}
if (segment instanceof Join || segment instanceof OrderByField || segment instanceof From
@ -63,4 +59,45 @@ abstract class AbstractImportValidator implements Visitor { @@ -63,4 +59,45 @@ abstract class AbstractImportValidator implements Visitor {
*/
@Override
public void leave(Visitable segment) {}
/**
* {@link Visitor} that skips sub-{@link Select} and collects columns within a {@link Where} clause.
*/
class SubselectFilteringWhereVisitor implements Visitor {
private @Nullable Select selectFilter;
/*
* (non-Javadoc)
* @see org.springframework.data.relational.core.sql.Visitor#enter(org.springframework.data.relational.core.sql.Visitable)
*/
@Override
public void enter(Visitable segment) {
if (selectFilter != null) {
return;
}
if (segment instanceof Select) {
this.selectFilter = (Select) segment;
return;
}
if (segment instanceof Table) {
requiredByWhere.add((Table) segment);
}
}
/*
* (non-Javadoc)
* @see org.springframework.data.relational.core.sql.Visitor#leave(org.springframework.data.relational.core.sql.Visitable)
*/
@Override
public void leave(Visitable segment) {
if (this.selectFilter == segment) {
this.selectFilter = null;
}
}
}
}

2
spring-data-relational/src/main/java/org/springframework/data/relational/core/sql/AssignValue.java

@ -72,7 +72,7 @@ public class AssignValue extends AbstractSegment implements Assignment { @@ -72,7 +72,7 @@ public class AssignValue extends AbstractSegment implements Assignment {
@Override
public String toString() {
StringBuilder builder = new StringBuilder(32);
StringBuilder builder = new StringBuilder();
return builder.append(this.column).append(" = ").append(this.value).toString();
}
}

4
spring-data-relational/src/main/java/org/springframework/data/relational/core/sql/DefaultUpdate.java

@ -68,7 +68,7 @@ class DefaultUpdate implements Update { @@ -68,7 +68,7 @@ class DefaultUpdate implements Update {
@Override
public String toString() {
StringBuilder builder = new StringBuilder(32);
StringBuilder builder = new StringBuilder();
builder.append("UPDATE ").append(table);
if (!assignments.isEmpty()) {
@ -76,7 +76,7 @@ class DefaultUpdate implements Update { @@ -76,7 +76,7 @@ class DefaultUpdate implements Update {
}
if (this.where != null) {
builder.append(" WHERE ").append(this.where);
builder.append(" ").append(this.where);
}
return builder.toString();

28
spring-data-relational/src/main/java/org/springframework/data/relational/core/sql/DefaultUpdateBuilder.java

@ -16,10 +16,11 @@ @@ -16,10 +16,11 @@
package org.springframework.data.relational.core.sql;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import org.springframework.data.relational.core.sql.UpdateBuilder.UpdateAssign;
import org.springframework.data.relational.core.sql.UpdateBuilder.UpdateAssignAnd;
import org.springframework.data.relational.core.sql.UpdateBuilder.UpdateWhere;
import org.springframework.data.relational.core.sql.UpdateBuilder.UpdateWhereAndOr;
import org.springframework.lang.Nullable;
@ -31,7 +32,7 @@ import org.springframework.util.Assert; @@ -31,7 +32,7 @@ import org.springframework.util.Assert;
* @author Mark Paluch
* @since 1.1
*/
class DefaultUpdateBuilder implements UpdateBuilder, UpdateWhere, UpdateWhereAndOr, UpdateAssign, UpdateAssignAnd {
class DefaultUpdateBuilder implements UpdateBuilder, UpdateWhere, UpdateWhereAndOr, UpdateAssign {
private Table table;
private List<Assignment> assignments = new ArrayList<>();
@ -67,11 +68,28 @@ class DefaultUpdateBuilder implements UpdateBuilder, UpdateWhere, UpdateWhereAnd @@ -67,11 +68,28 @@ class DefaultUpdateBuilder implements UpdateBuilder, UpdateWhere, UpdateWhereAnd
/*
* (non-Javadoc)
* @see org.springframework.data.relational.core.sql.UpdateBuilder.UpdateAssignAnd#and(org.springframework.data.relational.core.sql.Assignment)
* @see org.springframework.data.relational.core.sql.UpdateBuilder.UpdateAssign#set(org.springframework.data.relational.core.sql.Assignment...)
*/
@Override
public DefaultUpdateBuilder and(Assignment assignment) {
return set(assignment);
public UpdateWhere set(Assignment... assignments) {
Assert.notNull(assignments, "Assignment must not be null!");
return set(Arrays.asList(assignments));
}
/*
* (non-Javadoc)
* @see org.springframework.data.relational.core.sql.UpdateBuilder.UpdateAssign#set(java.util.Collection)
*/
@Override
public UpdateWhere set(Collection<? extends Assignment> assignments) {
Assert.notNull(assignments, "Assignment must not be null!");
this.assignments.addAll(assignments);
return this;
}
/*

10
spring-data-relational/src/main/java/org/springframework/data/relational/core/sql/DeleteValidator.java

@ -25,8 +25,14 @@ package org.springframework.data.relational.core.sql; @@ -25,8 +25,14 @@ package org.springframework.data.relational.core.sql;
*/
class DeleteValidator extends AbstractImportValidator {
public static void validate(Delete select) {
new DeleteValidator().doValidate(select);
/**
* Validates a {@link Delete} statement.
*
* @param delete the {@link Delete} statement.
* @throws IllegalStateException if the statement is not valid.
*/
public static void validate(Delete delete) {
new DeleteValidator().doValidate(delete);
}
private void doValidate(Delete select) {

37
spring-data-relational/src/main/java/org/springframework/data/relational/core/sql/SelectValidator.java

@ -17,6 +17,7 @@ package org.springframework.data.relational.core.sql; @@ -17,6 +17,7 @@ package org.springframework.data.relational.core.sql;
import java.util.HashSet;
import java.util.Set;
import java.util.Stack;
/**
* Validator for {@link Select} statements.
@ -29,12 +30,20 @@ import java.util.Set; @@ -29,12 +30,20 @@ import java.util.Set;
*/
class SelectValidator extends AbstractImportValidator {
private final Stack<Select> selects = new Stack<>();
private int selectFieldCount;
private Set<Table> requiredBySelect = new HashSet<>();
private Set<Table> requiredByOrderBy = new HashSet<>();
private Set<Table> join = new HashSet<>();
/**
* Validates a {@link Select} statement.
*
* @param select the {@link Select} statement.
* @throws IllegalStateException if the statement is not valid.
*/
public static void validate(Select select) {
new SelectValidator().doValidate(select);
}
@ -76,6 +85,14 @@ class SelectValidator extends AbstractImportValidator { @@ -76,6 +85,14 @@ class SelectValidator extends AbstractImportValidator {
@Override
public void enter(Visitable segment) {
if (segment instanceof Select) {
selects.push((Select) segment);
}
if (selects.size() > 1) {
return;
}
super.enter(segment);
if (segment instanceof AsteriskFromTable && parent instanceof Select) {
@ -107,15 +124,23 @@ class SelectValidator extends AbstractImportValidator { @@ -107,15 +124,23 @@ class SelectValidator extends AbstractImportValidator {
if (segment instanceof Table && parent instanceof Join) {
join.add((Table) segment);
}
}
if (segment instanceof Where) {
segment.visit(item -> {
/*
* (non-Javadoc)
* @see org.springframework.data.relational.core.sql.AbstractImportValidator#leave(org.springframework.data.relational.core.sql.Visitable)
*/
@Override
public void leave(Visitable segment) {
if (item instanceof Table) {
requiredByWhere.add((Table) item);
if (segment instanceof Select) {
selects.remove(segment);
}
});
if (selects.size() > 1) {
return;
}
super.leave(segment);
}
}

19
spring-data-relational/src/main/java/org/springframework/data/relational/core/sql/UpdateBuilder.java

@ -15,6 +15,8 @@ @@ -15,6 +15,8 @@
*/
package org.springframework.data.relational.core.sql;
import java.util.Collection;
/**
* Entry point to construct an {@link Update} statement.
*
@ -44,22 +46,25 @@ public interface UpdateBuilder { @@ -44,22 +46,25 @@ public interface UpdateBuilder {
* @return {@code this} builder.
* @see Assignment
*/
UpdateAssignAnd set(Assignment assignment);
}
UpdateWhere set(Assignment assignment);
/**
* Interface exposing {@code SET} methods.
* Apply one or more {@link Assignment SET assignments}.
*
* @param assignments the {@link Assignment column assignments}.
* @return {@code this} builder.
* @see Assignment
*/
interface UpdateAssignAnd extends UpdateWhere {
UpdateWhere set(Assignment... assignments);
/**
* Apply a {@link Assignment SET assignment}.
* Apply one or more {@link Assignment SET assignments}.
*
* @param assignment a single {@link Assignment column assignment}.
* @param assignments the {@link Assignment column assignments}.
* @return {@code this} builder.
* @see Assignment
*/
UpdateAssignAnd and(Assignment assignment);
UpdateWhere set(Collection<? extends Assignment> assignments);
}
/**

16
spring-data-relational/src/test/java/org/springframework/data/relational/core/sql/DeleteValidatorUnitTests.java

@ -20,7 +20,7 @@ import static org.assertj.core.api.Assertions.*; @@ -20,7 +20,7 @@ import static org.assertj.core.api.Assertions.*;
import org.junit.Test;
/**
* Unit tests for {@link SelectValidator}.
* Unit tests for {@link DeleteValidator}.
*
* @author Mark Paluch
*/
@ -40,4 +40,18 @@ public class DeleteValidatorUnitTests { @@ -40,4 +40,18 @@ public class DeleteValidatorUnitTests {
}).isInstanceOf(IllegalStateException.class)
.hasMessageContaining("Required table [table] by a WHERE predicate not imported by FROM [bar]");
}
@Test // DATAJDBC-335
public void shouldIgnoreImportsFromSubselectsInWhereClause() {
Table foo = SQL.table("foo");
Column bar = foo.column("bar");
Table floo = SQL.table("floo");
Column bah = floo.column("bah");
Select subselect = Select.builder().select(bah).from(floo).build();
assertThat(Delete.builder().from(foo).where(Conditions.in(bar, subselect)).build()).isNotNull();
}
}

18
spring-data-relational/src/test/java/org/springframework/data/relational/core/sql/SelectValidatorUnitTests.java

@ -88,4 +88,22 @@ public class SelectValidatorUnitTests { @@ -88,4 +88,22 @@ public class SelectValidatorUnitTests {
}).isInstanceOf(IllegalStateException.class)
.hasMessageContaining("Required table [table] by a WHERE predicate not imported by FROM [bar] or JOIN []");
}
@Test // DATAJDBC-309
public void shouldIgnoreImportsFromSubselectsInWhereClause() {
Table foo = SQL.table("foo");
Column bar = foo.column("bar");
Table floo = SQL.table("floo");
Column bah = floo.column("bah");
Select subselect = Select.builder().select(bah).from(floo).build();
assertThatThrownBy(() -> {
Select.builder().select(bah).from(foo).where(Conditions.in(bar, subselect)).build();
}).isInstanceOf(IllegalStateException.class)
.hasMessageContaining("Required table [floo] by a SELECT column not imported by FROM [foo] or JOIN []");
}
}

2
spring-data-relational/src/test/java/org/springframework/data/relational/core/sql/UpdateBuilderUnitTests.java

@ -55,7 +55,7 @@ public class UpdateBuilderUnitTests { @@ -55,7 +55,7 @@ public class UpdateBuilderUnitTests {
update.visit(visitor);
assertThat(visitor.enter).containsSequence(update, table, Assignments.value(column, SQL.bindMarker()), column,
table, SQL.bindMarker(), column.isNull());
table, SQL.bindMarker(), new Where(column.isNull()));
assertThat(update.toString()).isEqualTo("UPDATE mytable SET mytable.foo = ? WHERE mytable.foo IS NULL");
}

3
spring-data-relational/src/test/java/org/springframework/data/relational/core/sql/render/UpdateRendererUnitTests.java

@ -51,8 +51,7 @@ public class UpdateRendererUnitTests { @@ -51,8 +51,7 @@ public class UpdateRendererUnitTests {
Column bar = table.column("bar");
Update update = StatementBuilder.update(table) //
.set(foo.set(SQL.bindMarker())) //
.and(bar.set(SQL.bindMarker())) //
.set(foo.set(SQL.bindMarker()), bar.set(SQL.bindMarker())) //
.build();
assertThat(SqlRenderer.toString(update)).isEqualTo("UPDATE mytable SET mytable.foo = ?, mytable.bar = ?");

Loading…
Cancel
Save