diff --git a/pom.xml b/pom.xml
index fe60487ec8..43db4e7280 100644
--- a/pom.xml
+++ b/pom.xml
@@ -5,7 +5,7 @@
org.springframework.dataspring-data-relational-parent
- 1.1.0.BUILD-SNAPSHOT
+ 2.2.0.DATAJDBC-335-SNAPSHOTpomSpring Data Relational Parent
diff --git a/spring-data-jdbc-distribution/pom.xml b/spring-data-jdbc-distribution/pom.xml
index 1753776a73..6817da4185 100644
--- a/spring-data-jdbc-distribution/pom.xml
+++ b/spring-data-jdbc-distribution/pom.xml
@@ -14,7 +14,7 @@
org.springframework.dataspring-data-relational-parent
- 1.1.0.BUILD-SNAPSHOT
+ 2.2.0.DATAJDBC-335-SNAPSHOT../pom.xml
diff --git a/spring-data-jdbc/pom.xml b/spring-data-jdbc/pom.xml
index 9458230173..f9155913f8 100644
--- a/spring-data-jdbc/pom.xml
+++ b/spring-data-jdbc/pom.xml
@@ -5,7 +5,7 @@
4.0.0spring-data-jdbc
- 1.1.0.BUILD-SNAPSHOT
+ 2.2.0.DATAJDBC-335-SNAPSHOTSpring Data JDBCSpring Data module for JDBC repositories.
@@ -14,7 +14,7 @@
org.springframework.dataspring-data-relational-parent
- 1.1.0.BUILD-SNAPSHOT
+ 2.2.0.DATAJDBC-335-SNAPSHOT
diff --git a/spring-data-relational/pom.xml b/spring-data-relational/pom.xml
index 11e7db737c..6c93650ac5 100644
--- a/spring-data-relational/pom.xml
+++ b/spring-data-relational/pom.xml
@@ -5,7 +5,7 @@
4.0.0spring-data-relational
- 1.1.0.BUILD-SNAPSHOT
+ 2.2.0.DATAJDBC-335-SNAPSHOTSpring Data RelationalSpring Data Relational support
@@ -13,7 +13,7 @@
org.springframework.dataspring-data-relational-parent
- 1.1.0.BUILD-SNAPSHOT
+ 2.2.0.DATAJDBC-335-SNAPSHOT
diff --git a/spring-data-relational/src/main/java/org/springframework/data/relational/core/sql/AbstractImportValidator.java b/spring-data-relational/src/main/java/org/springframework/data/relational/core/sql/AbstractImportValidator.java
new file mode 100644
index 0000000000..12c41a7d88
--- /dev/null
+++ b/spring-data-relational/src/main/java/org/springframework/data/relational/core/sql/AbstractImportValidator.java
@@ -0,0 +1,103 @@
+/*
+ * Copyright 2019 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.relational.core.sql;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import org.springframework.lang.Nullable;
+
+/**
+ * Validator for statements to import columns.
+ *
+ * @author Mark Paluch
+ * @since 1.1
+ */
+abstract class AbstractImportValidator implements Visitor {
+
+ Set
requiredByWhere = new HashSet<>();
+ Set
from = new HashSet<>();
+ Visitable parent;
+
+ /*
+ * (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 (segment instanceof Table && parent instanceof From) {
+ from.add((Table) segment);
+ }
+
+ if (segment instanceof Where) {
+ segment.visit(new SubselectFilteringWhereVisitor());
+ }
+
+ if (segment instanceof Join || segment instanceof OrderByField || segment instanceof From
+ || segment instanceof Select || segment instanceof Where || segment instanceof SimpleFunction) {
+ parent = 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) {}
+
+ /**
+ * {@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;
+ }
+ }
+ }
+}
diff --git a/spring-data-relational/src/main/java/org/springframework/data/relational/core/sql/AssignValue.java b/spring-data-relational/src/main/java/org/springframework/data/relational/core/sql/AssignValue.java
new file mode 100644
index 0000000000..8304bf56ad
--- /dev/null
+++ b/spring-data-relational/src/main/java/org/springframework/data/relational/core/sql/AssignValue.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright 2019 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.relational.core.sql;
+
+import org.springframework.util.Assert;
+
+/**
+ * Assign a {@link Expression} to a {@link Column}.
+ *
+ * Results in a rendered assignment: {@code = } (e.g. {@code col = 'foo'}.
+ *
+ * @author Mark Paluch
+ * @since 1.1
+ */
+public class AssignValue extends AbstractSegment implements Assignment {
+
+ private final Column column;
+ private final Expression value;
+
+ private AssignValue(Column column, Expression value) {
+ super(column, value);
+ this.column = column;
+ this.value = value;
+ }
+
+ /**
+ * Creates a {@link AssignValue value} assignment to a {@link Column} given an {@link Expression}.
+ *
+ * @param target target column, must not be {@literal null}.
+ * @param value assignment value, must not be {@literal null}.
+ * @return the {@link AssignValue}.
+ */
+ public static AssignValue create(Column target, Expression value) {
+
+ Assert.notNull(target, "Target column must not be null!");
+ Assert.notNull(value, "Value must not be null!");
+
+ return new AssignValue(target, value);
+ }
+
+ /**
+ * @return the target {@link Column}.
+ */
+ public Column getColumn() {
+ return column;
+ }
+
+ /**
+ * @return the value to assign.
+ */
+ public Expression getValue() {
+ return value;
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see java.lang.Object#toString()
+ */
+ @Override
+ public String toString() {
+
+ StringBuilder builder = new StringBuilder();
+ return builder.append(this.column).append(" = ").append(this.value).toString();
+ }
+}
diff --git a/spring-data-relational/src/main/java/org/springframework/data/relational/core/sql/Assignment.java b/spring-data-relational/src/main/java/org/springframework/data/relational/core/sql/Assignment.java
new file mode 100644
index 0000000000..2a932bcf32
--- /dev/null
+++ b/spring-data-relational/src/main/java/org/springframework/data/relational/core/sql/Assignment.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright 2019 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.relational.core.sql;
+
+/**
+ * Update assignment to a {@link Column}.
+ *
+ * @author Mark Paluch
+ */
+public interface Assignment extends Segment {}
diff --git a/spring-data-relational/src/main/java/org/springframework/data/relational/core/sql/Assignments.java b/spring-data-relational/src/main/java/org/springframework/data/relational/core/sql/Assignments.java
new file mode 100644
index 0000000000..968f25af61
--- /dev/null
+++ b/spring-data-relational/src/main/java/org/springframework/data/relational/core/sql/Assignments.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2019 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.relational.core.sql;
+
+/**
+ * Factory for common {@link Assignment}s.
+ *
+ * @author Mark Paluch
+ * @since 1.1
+ * @see SQL
+ * @see Expressions
+ * @see Functions
+ */
+public abstract class Assignments {
+
+ /**
+ * Creates a {@link AssignValue value} assignment to a {@link Column} given an {@link Expression}.
+ *
+ * @param target target column, must not be {@literal null}.
+ * @param value assignment value, must not be {@literal null}.
+ * @return the {@link AssignValue}.
+ */
+ public static AssignValue value(Column target, Expression value) {
+ return AssignValue.create(target, value);
+ }
+
+ // Utility constructor.
+ private Assignments() {}
+}
diff --git a/spring-data-relational/src/main/java/org/springframework/data/relational/core/sql/Column.java b/spring-data-relational/src/main/java/org/springframework/data/relational/core/sql/Column.java
index 356a8e83b4..72f354a16e 100644
--- a/spring-data-relational/src/main/java/org/springframework/data/relational/core/sql/Column.java
+++ b/spring-data-relational/src/main/java/org/springframework/data/relational/core/sql/Column.java
@@ -200,6 +200,20 @@ public Condition isNotNull() {
return isNull().not();
}
+ // -------------------------------------------------------------------------
+ // Methods for Assignment creation.
+ // -------------------------------------------------------------------------
+
+ /**
+ * Creates a value {@link AssignValue assignment}.
+ *
+ * @param value the value to assign.
+ * @return the {@link AssignValue} assignment.
+ */
+ public AssignValue set(Expression value) {
+ return Assignments.value(this, value);
+ }
+
/*
* (non-Javadoc)
* @see org.springframework.data.relational.core.sql.Named#getName()
diff --git a/spring-data-relational/src/main/java/org/springframework/data/relational/core/sql/DefaultDelete.java b/spring-data-relational/src/main/java/org/springframework/data/relational/core/sql/DefaultDelete.java
new file mode 100644
index 0000000000..6d84c45402
--- /dev/null
+++ b/spring-data-relational/src/main/java/org/springframework/data/relational/core/sql/DefaultDelete.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2019 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.relational.core.sql;
+
+import org.springframework.lang.Nullable;
+import org.springframework.util.Assert;
+
+/**
+ * Default {@link Delete} implementation.
+ *
+ * @author Mark Paluch
+ * @since 1.1
+ */
+class DefaultDelete implements Delete {
+
+ private final From from;
+ private final @Nullable Where where;
+
+ DefaultDelete(Table table, @Nullable Condition where) {
+
+ this.from = new From(table);
+ this.where = where != null ? new Where(where) : null;
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.springframework.data.relational.core.sql.Visitable#visit(org.springframework.data.relational.core.sql.Visitor)
+ */
+ @Override
+ public void visit(Visitor visitor) {
+
+ Assert.notNull(visitor, "Visitor must not be null!");
+
+ visitor.enter(this);
+
+ from.visit(visitor);
+
+ if (where != null) {
+ where.visit(visitor);
+ }
+
+ visitor.leave(this);
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see java.lang.Object#toString()
+ */
+ @Override
+ public String toString() {
+
+ StringBuilder builder = new StringBuilder();
+
+ builder.append("DELETE ").append(this.from);
+
+ if (this.where != null) {
+ builder.append(' ').append(this.where);
+ }
+
+ return builder.toString();
+ }
+}
diff --git a/spring-data-relational/src/main/java/org/springframework/data/relational/core/sql/DefaultDeleteBuilder.java b/spring-data-relational/src/main/java/org/springframework/data/relational/core/sql/DefaultDeleteBuilder.java
new file mode 100644
index 0000000000..8d350ccc07
--- /dev/null
+++ b/spring-data-relational/src/main/java/org/springframework/data/relational/core/sql/DefaultDeleteBuilder.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright 2019 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.relational.core.sql;
+
+import org.springframework.lang.Nullable;
+import org.springframework.util.Assert;
+
+/**
+ * Default {@link SelectBuilder} implementation.
+ *
+ * @author Mark Paluch
+ * @since 1.1
+ */
+class DefaultDeleteBuilder implements DeleteBuilder, DeleteBuilder.DeleteWhereAndOr, DeleteBuilder.DeleteWhere {
+
+ private Table from;
+ private @Nullable Condition where;
+
+ /*
+ * (non-Javadoc)
+ * @see org.springframework.data.relational.core.sql.DeleteBuilder#from(org.springframework.data.relational.core.sql.Table)
+ */
+ @Override
+ public DeleteWhere from(Table table) {
+
+ Assert.notNull(table, "Table must not be null!");
+
+ this.from = table;
+ return this;
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.springframework.data.relational.core.sql.DeleteBuilder.DeleteWhere#where(org.springframework.data.relational.core.sql.Condition)
+ */
+ @Override
+ public DeleteWhereAndOr where(Condition condition) {
+
+ Assert.notNull(condition, "Where Condition must not be null!");
+ this.where = condition;
+ return this;
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.springframework.data.relational.core.sql.DeleteBuilder.DeleteWhereAndOr#and(org.springframework.data.relational.core.sql.Condition)
+ */
+ @Override
+ public DeleteWhereAndOr and(Condition condition) {
+
+ Assert.notNull(condition, "Condition must not be null!");
+ this.where = this.where.and(condition);
+ return this;
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.springframework.data.relational.core.sql.DeleteBuilder.DeleteWhereAndOr#or(org.springframework.data.relational.core.sql.Condition)
+ */
+ @Override
+ public DeleteWhereAndOr or(Condition condition) {
+
+ Assert.notNull(condition, "Condition must not be null!");
+ this.where = this.where.or(condition);
+ return this;
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.springframework.data.relational.core.sql.DeleteBuilder.BuildDelete#build()
+ */
+ @Override
+ public Delete build() {
+
+ DefaultDelete delete = new DefaultDelete(this.from, this.where);
+
+ DeleteValidator.validate(delete);
+
+ return delete;
+ }
+}
diff --git a/spring-data-relational/src/main/java/org/springframework/data/relational/core/sql/DefaultInsert.java b/spring-data-relational/src/main/java/org/springframework/data/relational/core/sql/DefaultInsert.java
new file mode 100644
index 0000000000..0f0715e7b1
--- /dev/null
+++ b/spring-data-relational/src/main/java/org/springframework/data/relational/core/sql/DefaultInsert.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright 2019 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.relational.core.sql;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.springframework.lang.Nullable;
+import org.springframework.util.Assert;
+import org.springframework.util.StringUtils;
+
+/**
+ * Default {@link Insert} implementation.
+ *
+ * @author Mark Paluch
+ * @since 1.1
+ */
+class DefaultInsert implements Insert {
+
+ private final Into into;
+ private final List columns;
+ private final Values values;
+
+ DefaultInsert(@Nullable Table into, List columns, List values) {
+ this.into = new Into(into);
+ this.columns = new ArrayList<>(columns);
+ this.values = new Values(new ArrayList<>(values));
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.springframework.data.relational.core.sql.Visitable#visit(org.springframework.data.relational.core.sql.Visitor)
+ */
+ @Override
+ public void visit(Visitor visitor) {
+
+ Assert.notNull(visitor, "Visitor must not be null!");
+
+ visitor.enter(this);
+
+ into.visit(visitor);
+ columns.forEach(it -> it.visit(visitor));
+ values.visit(visitor);
+
+ visitor.leave(this);
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see java.lang.Object#toString()
+ */
+ @Override
+ public String toString() {
+
+ StringBuilder builder = new StringBuilder();
+
+ builder.append("INSERT ").append(this.into);
+
+ if (!this.columns.isEmpty()) {
+ builder.append(" (").append(StringUtils.collectionToDelimitedString(this.columns, ", ")).append(")");
+ }
+
+ builder.append(" ").append(this.values);
+
+ return builder.toString();
+ }
+}
diff --git a/spring-data-relational/src/main/java/org/springframework/data/relational/core/sql/DefaultInsertBuilder.java b/spring-data-relational/src/main/java/org/springframework/data/relational/core/sql/DefaultInsertBuilder.java
new file mode 100644
index 0000000000..af7f96dc2e
--- /dev/null
+++ b/spring-data-relational/src/main/java/org/springframework/data/relational/core/sql/DefaultInsertBuilder.java
@@ -0,0 +1,139 @@
+/*
+ * Copyright 2019 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.relational.core.sql;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+
+import org.springframework.util.Assert;
+
+/**
+ * Default {@link InsertBuilder} implementation.
+ *
+ * @author Mark Paluch
+ * @since 1.1
+ */
+class DefaultInsertBuilder
+ implements InsertBuilder, InsertBuilder.InsertIntoColumnsAndValuesWithBuild, InsertBuilder.InsertValuesWithBuild {
+
+ private Table into;
+ private List columns = new ArrayList<>();
+ private List values = new ArrayList<>();
+
+ /*
+ * (non-Javadoc)
+ * @see org.springframework.data.relational.core.sql.InsertBuilder#into(org.springframework.data.relational.core.sql.Table)
+ */
+ @Override
+ public InsertIntoColumnsAndValues into(Table table) {
+
+ Assert.notNull(table, "Insert Into Table must not be null!");
+
+ this.into = table;
+ return this;
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.springframework.data.relational.core.sql.InsertBuilder.InsertIntoColumnsAndValues#column(org.springframework.data.relational.core.sql.Column)
+ */
+ @Override
+ public InsertIntoColumnsAndValuesWithBuild column(Column column) {
+
+ Assert.notNull(column, "Column must not be null!");
+
+ this.columns.add(column);
+
+ return this;
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.springframework.data.relational.core.sql.InsertBuilder.InsertIntoColumnsAndValues#columns(org.springframework.data.relational.core.sql.Column[])
+ */
+ @Override
+ public InsertIntoColumnsAndValuesWithBuild columns(Column... columns) {
+
+ Assert.notNull(columns, "Columns must not be null!");
+
+ return columns(Arrays.asList(columns));
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.springframework.data.relational.core.sql.InsertBuilder.InsertIntoColumnsAndValues#columns(java.util.Collection)
+ */
+ @Override
+ public InsertIntoColumnsAndValuesWithBuild columns(Collection columns) {
+
+ Assert.notNull(columns, "Columns must not be null!");
+
+ this.columns.addAll(columns);
+
+ return this;
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.springframework.data.relational.core.sql.InsertBuilder.InsertIntoColumnsAndValuesWithBuild#value(org.springframework.data.relational.core.sql.Expression)
+ */
+ @Override
+ public InsertValuesWithBuild value(Expression value) {
+
+ Assert.notNull(value, "Value must not be null!");
+
+ this.values.add(value);
+
+ return this;
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.springframework.data.relational.core.sql.InsertBuilder.InsertIntoColumnsAndValuesWithBuild#values(org.springframework.data.relational.core.sql.Expression[])
+ */
+ @Override
+ public InsertValuesWithBuild values(Expression... values) {
+
+ Assert.notNull(values, "Values must not be null!");
+
+ return values(Arrays.asList(values));
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.springframework.data.relational.core.sql.InsertBuilder.InsertIntoColumnsAndValuesWithBuild#values(java.util.Collection)
+ */
+ @Override
+ public InsertValuesWithBuild values(Collection extends Expression> values) {
+
+ Assert.notNull(values, "Values must not be null!");
+
+ this.values.addAll(values);
+
+ return this;
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.springframework.data.relational.core.sql.InsertBuilder.BuildInsert#build()
+ */
+ @Override
+ public Insert build() {
+ return new DefaultInsert(this.into, this.columns, this.values);
+ }
+}
diff --git a/spring-data-relational/src/main/java/org/springframework/data/relational/core/sql/DefaultSelect.java b/spring-data-relational/src/main/java/org/springframework/data/relational/core/sql/DefaultSelect.java
index 6bd8f8d5af..5b5816257e 100644
--- a/spring-data-relational/src/main/java/org/springframework/data/relational/core/sql/DefaultSelect.java
+++ b/spring-data-relational/src/main/java/org/springframework/data/relational/core/sql/DefaultSelect.java
@@ -44,7 +44,7 @@ class DefaultSelect implements Select {
this.distinct = distinct;
this.selectList = new SelectList(new ArrayList<>(selectList));
- this.from = new From(from);
+ this.from = new From(new ArrayList<>(from));
this.limit = limit;
this.offset = offset;
this.joins = new ArrayList<>(joins);
diff --git a/spring-data-relational/src/main/java/org/springframework/data/relational/core/sql/DefaultUpdate.java b/spring-data-relational/src/main/java/org/springframework/data/relational/core/sql/DefaultUpdate.java
new file mode 100644
index 0000000000..135fdffded
--- /dev/null
+++ b/spring-data-relational/src/main/java/org/springframework/data/relational/core/sql/DefaultUpdate.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright 2019 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.relational.core.sql;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.springframework.lang.Nullable;
+import org.springframework.util.Assert;
+import org.springframework.util.StringUtils;
+
+/**
+ * Default {@link Update} implementation.
+ *
+ * @author Mark Paluch
+ * @since 1.1
+ */
+class DefaultUpdate implements Update {
+
+ private final Table table;
+ private final List assignments;
+ private final @Nullable Where where;
+
+ DefaultUpdate(Table table, List assignments, @Nullable Condition where) {
+ this.table = table;
+ this.assignments = new ArrayList<>(assignments);
+ this.where = where != null ? new Where(where) : null;
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.springframework.data.relational.core.sql.Visitable#visit(org.springframework.data.relational.core.sql.Visitor)
+ */
+ @Override
+ public void visit(Visitor visitor) {
+
+ Assert.notNull(visitor, "Visitor must not be null!");
+
+ visitor.enter(this);
+
+ this.table.visit(visitor);
+ this.assignments.forEach(it -> it.visit(visitor));
+
+ if (this.where != null) {
+ this.where.visit(visitor);
+ }
+
+ visitor.leave(this);
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see java.lang.Object#toString()
+ */
+ @Override
+ public String toString() {
+
+ StringBuilder builder = new StringBuilder();
+ builder.append("UPDATE ").append(table);
+
+ if (!assignments.isEmpty()) {
+ builder.append(" SET ").append(StringUtils.collectionToDelimitedString(this.assignments, ", "));
+ }
+
+ if (this.where != null) {
+ builder.append(" ").append(this.where);
+ }
+
+ return builder.toString();
+ }
+}
diff --git a/spring-data-relational/src/main/java/org/springframework/data/relational/core/sql/DefaultUpdateBuilder.java b/spring-data-relational/src/main/java/org/springframework/data/relational/core/sql/DefaultUpdateBuilder.java
new file mode 100644
index 0000000000..8fcbb3c333
--- /dev/null
+++ b/spring-data-relational/src/main/java/org/springframework/data/relational/core/sql/DefaultUpdateBuilder.java
@@ -0,0 +1,145 @@
+/*
+ * Copyright 2019 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.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.UpdateWhere;
+import org.springframework.data.relational.core.sql.UpdateBuilder.UpdateWhereAndOr;
+import org.springframework.lang.Nullable;
+import org.springframework.util.Assert;
+
+/**
+ * Default {@link UpdateBuilder} implementation.
+ *
+ * @author Mark Paluch
+ * @since 1.1
+ */
+class DefaultUpdateBuilder implements UpdateBuilder, UpdateWhere, UpdateWhereAndOr, UpdateAssign {
+
+ private Table table;
+ private List assignments = new ArrayList<>();
+ private @Nullable Condition where;
+
+ /*
+ * (non-Javadoc)
+ * @see org.springframework.data.relational.core.sql.UpdateBuilder#table(org.springframework.data.relational.core.sql.Table)
+ */
+ @Override
+ public UpdateAssign table(Table table) {
+
+ Assert.notNull(table, "Table must not be null!");
+
+ this.table = table;
+
+ return this;
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.springframework.data.relational.core.sql.UpdateBuilder.UpdateAssign#set(org.springframework.data.relational.core.sql.Assignment)
+ */
+ @Override
+ public DefaultUpdateBuilder set(Assignment assignment) {
+
+ Assert.notNull(assignment, "Assignment must not be null!");
+
+ this.assignments.add(assignment);
+
+ return this;
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.springframework.data.relational.core.sql.UpdateBuilder.UpdateAssign#set(org.springframework.data.relational.core.sql.Assignment...)
+ */
+ @Override
+ 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;
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.springframework.data.relational.core.sql.UpdateBuilder.UpdateWhere#where(org.springframework.data.relational.core.sql.Condition)
+ */
+ @Override
+ public UpdateWhereAndOr where(Condition condition) {
+
+ Assert.notNull(condition, "Condition must not be null!");
+
+ this.where = condition;
+
+ return this;
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.springframework.data.relational.core.sql.UpdateBuilder.UpdateWhereAndOr#and(org.springframework.data.relational.core.sql.Condition)
+ */
+ @Override
+ public UpdateWhereAndOr and(Condition condition) {
+
+ Assert.notNull(condition, "Condition must not be null!");
+
+ this.where = this.where.and(condition);
+
+ return this;
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.springframework.data.relational.core.sql.UpdateBuilder.UpdateWhereAndOr#or(org.springframework.data.relational.core.sql.Condition)
+ */
+ @Override
+ public UpdateWhereAndOr or(Condition condition) {
+
+ Assert.notNull(condition, "Condition must not be null!");
+
+ this.where = this.where.and(condition);
+
+ return this;
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.springframework.data.relational.core.sql.UpdateBuilder.BuildUpdate#build()
+ */
+ @Override
+ public Update build() {
+ return new DefaultUpdate(this.table, this.assignments, this.where);
+ }
+}
diff --git a/spring-data-relational/src/main/java/org/springframework/data/relational/core/sql/Delete.java b/spring-data-relational/src/main/java/org/springframework/data/relational/core/sql/Delete.java
new file mode 100644
index 0000000000..da85aa2b4d
--- /dev/null
+++ b/spring-data-relational/src/main/java/org/springframework/data/relational/core/sql/Delete.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2019 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.relational.core.sql;
+
+/**
+ * AST for a {@code DELETE} statement. Visiting order:
+ *
+ *
Self
+ *
{@link Table FROM tables} clause
+ *
{@link Where WHERE} condition
+ *
+ *
+ * @author Mark Paluch
+ * @since 1.1
+ * @see StatementBuilder
+ * @see DeleteBuilder
+ * @see SQL
+ */
+public interface Delete extends Segment, Visitable {
+
+ /**
+ * Creates a new {@link DeleteBuilder}.
+ *
+ * @return a new {@link DeleteBuilder}.
+ */
+ static DeleteBuilder builder() {
+ return new DefaultDeleteBuilder();
+ }
+}
diff --git a/spring-data-relational/src/main/java/org/springframework/data/relational/core/sql/DeleteBuilder.java b/spring-data-relational/src/main/java/org/springframework/data/relational/core/sql/DeleteBuilder.java
new file mode 100644
index 0000000000..d98576fc3e
--- /dev/null
+++ b/spring-data-relational/src/main/java/org/springframework/data/relational/core/sql/DeleteBuilder.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright 2019 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.relational.core.sql;
+
+/**
+ * Entry point to construct a {@link Delete} statement.
+ *
+ * @author Mark Paluch
+ * @since 1.1
+ * @see StatementBuilder
+ */
+public interface DeleteBuilder {
+
+ /**
+ * Declare a {@link Table} for {@code DELETE FROM}.
+ *
+ * @param table the table to {@code DELETE FROM} must not be {@literal null}.
+ * @return {@code this} builder.
+ * @see From
+ * @see SQL#table(String)
+ */
+ DeleteWhere from(Table table);
+
+ /**
+ * Interface exposing {@code WHERE} methods.
+ */
+ interface DeleteWhere extends BuildDelete {
+
+ /**
+ * Apply a {@code WHERE} clause.
+ *
+ * @param condition the {@code WHERE} condition.
+ * @return {@code this} builder.
+ * @see Where
+ * @see Condition
+ */
+ DeleteWhereAndOr where(Condition condition);
+ }
+
+ /**
+ * Interface exposing {@code AND}/{@code OR} combinator methods for {@code WHERE} {@link Condition}s.
+ */
+ interface DeleteWhereAndOr extends BuildDelete {
+
+ /**
+ * Combine the previous {@code WHERE} {@link Condition} using {@code AND}.
+ *
+ * @param condition the condition, must not be {@literal null}.
+ * @return {@code this} builder.
+ * @see Condition#and(Condition)
+ */
+ DeleteWhereAndOr and(Condition condition);
+
+ /**
+ * Combine the previous {@code WHERE} {@link Condition} using {@code OR}.
+ *
+ * @param condition the condition, must not be {@literal null}.
+ * @return {@code this} builder.
+ * @see Condition#or(Condition)
+ */
+ DeleteWhereAndOr or(Condition condition);
+ }
+
+ /**
+ * Interface exposing the {@link Delete} build method.
+ */
+ interface BuildDelete {
+
+ /**
+ * Build the {@link Delete} statement and verify basic relationship constraints such as all referenced columns have
+ * a {@code FROM} table import.
+ *
+ * @return the build and immutable {@link Delete} statement.
+ */
+ Delete build();
+ }
+}
diff --git a/spring-data-relational/src/main/java/org/springframework/data/relational/core/sql/DeleteValidator.java b/spring-data-relational/src/main/java/org/springframework/data/relational/core/sql/DeleteValidator.java
new file mode 100644
index 0000000000..51e327727c
--- /dev/null
+++ b/spring-data-relational/src/main/java/org/springframework/data/relational/core/sql/DeleteValidator.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2019 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.relational.core.sql;
+
+/**
+ * Validator for {@link Delete} statements.
+ *
+ * Validates that all {@link Column}s using a table qualifier have a table import from the {@code FROM} clause.
+ *
+ * @author Mark Paluch
+ * @since 1.1
+ */
+class DeleteValidator extends AbstractImportValidator {
+
+ /**
+ * 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) {
+
+ select.visit(this);
+
+ for (Table table : requiredByWhere) {
+ if (!from.contains(table)) {
+ throw new IllegalStateException(
+ String.format("Required table [%s] by a WHERE predicate not imported by FROM %s", table, from));
+ }
+ }
+ }
+}
diff --git a/spring-data-relational/src/main/java/org/springframework/data/relational/core/sql/Insert.java b/spring-data-relational/src/main/java/org/springframework/data/relational/core/sql/Insert.java
new file mode 100644
index 0000000000..cf3e1c7d21
--- /dev/null
+++ b/spring-data-relational/src/main/java/org/springframework/data/relational/core/sql/Insert.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2019 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.relational.core.sql;
+
+/**
+ * AST for a {@code INSERT} statement. Visiting order:
+ *
+ *
Self
+ *
{@link Into INTO table} clause
+ *
{@link Column columns}
+ *
{@link Values VALUEs}
+ *
+ *
+ * @author Mark Paluch
+ * @since 1.1
+ * @see StatementBuilder
+ * @see InsertBuilder
+ * @see SQL
+ */
+public interface Insert extends Segment, Visitable {
+
+ /**
+ * Creates a new {@link InsertBuilder}.
+ *
+ * @return a new {@link InsertBuilder}.
+ */
+ static InsertBuilder builder() {
+ return new DefaultInsertBuilder();
+ }
+}
diff --git a/spring-data-relational/src/main/java/org/springframework/data/relational/core/sql/InsertBuilder.java b/spring-data-relational/src/main/java/org/springframework/data/relational/core/sql/InsertBuilder.java
new file mode 100644
index 0000000000..f20c8e62df
--- /dev/null
+++ b/spring-data-relational/src/main/java/org/springframework/data/relational/core/sql/InsertBuilder.java
@@ -0,0 +1,201 @@
+/*
+ * Copyright 2019 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.relational.core.sql;
+
+import java.util.Collection;
+
+/**
+ * Entry point to construct an {@link Insert} statement.
+ *
+ * @author Mark Paluch
+ * @since 1.1
+ * @see StatementBuilder
+ */
+public interface InsertBuilder {
+
+ /**
+ * Declare a {@link Table} to {@code INSERT INTO}.
+ *
+ * @param table the table to {@code INSERT INTO} must not be {@literal null}.
+ * @return {@code this} builder.
+ * @see Into
+ * @see SQL#table(String)
+ */
+ InsertIntoColumnsAndValues into(Table table);
+
+ /**
+ * Interface exposing {@code WHERE} methods.
+ */
+ interface InsertIntoColumnsAndValues extends InsertValues {
+
+ /**
+ * Add a {@link Column} to the {@code INTO} column list. Calling this method multiple times will add the
+ * {@link Column} multiple times.
+ *
+ * @param column the column.
+ * @return {@code this} builder.
+ * @see Column
+ */
+ InsertIntoColumnsAndValuesWithBuild column(Column column);
+
+ /**
+ * Add a one or more {@link Column} to the {@code INTO} column list. Calling this method multiple times will add the
+ * {@link Column} multiple times.
+ *
+ * @param columns the columns.
+ * @return {@code this} builder.
+ * @see Column
+ */
+ InsertIntoColumnsAndValuesWithBuild columns(Column... columns);
+
+ /**
+ * Add a one or more {@link Column} to the {@code INTO} column list. Calling this method multiple times will add the
+ * {@link Column} multiple times.
+ *
+ * @param columns the columns.
+ * @return {@code this} builder.
+ * @see Column
+ */
+ InsertIntoColumnsAndValuesWithBuild columns(Collection columns);
+ }
+
+ /**
+ * Interface exposing {@code value} methods to add values to the {@code INSERT} statement and the build method.
+ */
+ interface InsertIntoColumnsAndValuesWithBuild extends InsertIntoColumnsAndValues, InsertValues, BuildInsert {
+
+ /**
+ * Add a {@link Expression value} to the {@code VALUES} list. Calling this method multiple times will add a
+ * {@link Expression value} multiple times.
+ *
+ * @param value the value to use.
+ * @return {@code this} builder.
+ * @see Column
+ */
+ @Override
+ InsertValuesWithBuild value(Expression value);
+
+ /**
+ * Add one or more {@link Expression values} to the {@code VALUES} list. Calling this method multiple times will add
+ * a {@link Expression values} multiple times.
+ *
+ * @param values the values.
+ * @return {@code this} builder.
+ * @see Column
+ */
+ @Override
+ InsertValuesWithBuild values(Expression... values);
+
+ /**
+ * Add one or more {@link Expression values} to the {@code VALUES} list. Calling this method multiple times will add
+ * a {@link Expression values} multiple times.
+ *
+ * @param values the values.
+ * @return {@code this} builder.
+ * @see Column
+ */
+ @Override
+ InsertValuesWithBuild values(Collection extends Expression> values);
+ }
+
+ /**
+ * Interface exposing {@code value} methods to add values to the {@code INSERT} statement and the build method.
+ */
+ interface InsertValuesWithBuild extends InsertValues, BuildInsert {
+
+ /**
+ * Add a {@link Expression value} to the {@code VALUES} list. Calling this method multiple times will add a
+ * {@link Expression value} multiple times.
+ *
+ * @param value the value to use.
+ * @return {@code this} builder.
+ * @see Column
+ */
+ @Override
+ InsertValuesWithBuild value(Expression value);
+
+ /**
+ * Add one or more {@link Expression values} to the {@code VALUES} list. Calling this method multiple times will add
+ * a {@link Expression values} multiple times.
+ *
+ * @param values the values.
+ * @return {@code this} builder.
+ * @see Column
+ */
+ @Override
+ InsertValuesWithBuild values(Expression... values);
+
+ /**
+ * Add one or more {@link Expression values} to the {@code VALUES} list. Calling this method multiple times will add
+ * a {@link Expression values} multiple times.
+ *
+ * @param values the values.
+ * @return {@code this} builder.
+ * @see Column
+ */
+ @Override
+ InsertValuesWithBuild values(Collection extends Expression> values);
+ }
+
+ /**
+ * Interface exposing {@code value} methods to add values to the {@code INSERT} statement.
+ */
+ interface InsertValues {
+
+ /**
+ * Add a {@link Expression value} to the {@code VALUES} list. Calling this method multiple times will add a
+ * {@link Expression value} multiple times.
+ *
+ * @param value the value to use.
+ * @return {@code this} builder.
+ * @see Column
+ */
+ InsertValuesWithBuild value(Expression value);
+
+ /**
+ * Add one or more {@link Expression values} to the {@code VALUES} list. Calling this method multiple times will add
+ * a {@link Expression values} multiple times.
+ *
+ * @param values the values.
+ * @return {@code this} builder.
+ * @see Column
+ */
+ InsertValuesWithBuild values(Expression... values);
+
+ /**
+ * Add one or more {@link Expression values} to the {@code VALUES} list. Calling this method multiple times will add
+ * a {@link Expression values} multiple times.
+ *
+ * @param values the values.
+ * @return {@code this} builder.
+ * @see Column
+ */
+ InsertValuesWithBuild values(Collection extends Expression> values);
+ }
+
+ /**
+ * Interface exposing the {@link Insert} build method.
+ */
+ interface BuildInsert {
+
+ /**
+ * Build the {@link Insert} statement.
+ *
+ * @return the build and immutable {@link Insert} statement.
+ */
+ Insert build();
+ }
+}
diff --git a/spring-data-relational/src/main/java/org/springframework/data/relational/core/sql/Into.java b/spring-data-relational/src/main/java/org/springframework/data/relational/core/sql/Into.java
new file mode 100644
index 0000000000..9758a91e82
--- /dev/null
+++ b/spring-data-relational/src/main/java/org/springframework/data/relational/core/sql/Into.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2019 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.relational.core.sql;
+
+import java.util.Arrays;
+import java.util.List;
+
+import org.springframework.util.StringUtils;
+
+/**
+ * {@code INTO} clause.
+ *
+ * @author Mark Paluch
+ * @since 1.1
+ */
+public class Into extends AbstractSegment {
+
+ private final List
tables) {
+
+ super(tables.toArray(new Table[] {}));
+
+ this.tables = tables;
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see java.lang.Object#toString()
+ */
+ @Override
+ public String toString() {
+ return "INTO " + StringUtils.collectionToDelimitedString(tables, ", ");
+ }
+}
diff --git a/spring-data-relational/src/main/java/org/springframework/data/relational/core/sql/Literal.java b/spring-data-relational/src/main/java/org/springframework/data/relational/core/sql/Literal.java
new file mode 100644
index 0000000000..f874dc9fb8
--- /dev/null
+++ b/spring-data-relational/src/main/java/org/springframework/data/relational/core/sql/Literal.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2019 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.relational.core.sql;
+
+import org.springframework.lang.Nullable;
+
+/**
+ * Represents a literal.
+ *
+ * @author Mark Paluch
+ * @since 1.1
+ */
+public class Literal extends AbstractSegment implements Expression {
+
+ private @Nullable T content;
+
+ Literal(@Nullable T content) {
+ this.content = content;
+ }
+
+ /**
+ * @return the content of the literal.
+ */
+ @Nullable
+ public T getContent() {
+ return content;
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see java.lang.Object#toString()
+ */
+ @Override
+ public String toString() {
+
+ if (this.content == null) {
+ return "NULL";
+ }
+
+ return content.toString();
+ }
+}
diff --git a/spring-data-relational/src/main/java/org/springframework/data/relational/core/sql/NumericLiteral.java b/spring-data-relational/src/main/java/org/springframework/data/relational/core/sql/NumericLiteral.java
new file mode 100644
index 0000000000..d09d93d66a
--- /dev/null
+++ b/spring-data-relational/src/main/java/org/springframework/data/relational/core/sql/NumericLiteral.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2019 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.relational.core.sql;
+
+import org.springframework.lang.Nullable;
+
+/**
+ * Represents a {@link Number} literal.
+ *
+ * @author Mark Paluch
+ * @since 1.1
+ */
+public class NumericLiteral extends Literal {
+
+ NumericLiteral(@Nullable Number content) {
+ super(content);
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.springframework.data.relational.core.sql.Literal#getContent()
+ */
+ @Override
+ @Nullable
+ public Number getContent() {
+ return super.getContent();
+ }
+}
diff --git a/spring-data-relational/src/main/java/org/springframework/data/relational/core/sql/SQL.java b/spring-data-relational/src/main/java/org/springframework/data/relational/core/sql/SQL.java
index 0f45a8637e..c01954f5a5 100644
--- a/spring-data-relational/src/main/java/org/springframework/data/relational/core/sql/SQL.java
+++ b/spring-data-relational/src/main/java/org/springframework/data/relational/core/sql/SQL.java
@@ -16,6 +16,7 @@
package org.springframework.data.relational.core.sql;
import org.springframework.data.relational.core.sql.BindMarker.NamedBindMarker;
+import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
/**
@@ -77,6 +78,45 @@ public static BindMarker bindMarker(String name) {
return new NamedBindMarker(name);
}
+ /**
+ * Creates a new {@link StringLiteral} from the {@code content}.
+ *
+ * @param content the literal content.
+ * @return a new {@link StringLiteral}.
+ */
+ public static StringLiteral literalOf(@Nullable CharSequence content) {
+ return new StringLiteral(content);
+ }
+
+ /**
+ * Creates a new {@link NumericLiteral} from the {@code content}.
+ *
+ * @param content the literal content.
+ * @return a new {@link NumericLiteral}.
+ */
+ public static NumericLiteral literalOf(@Nullable Number content) {
+ return new NumericLiteral(content);
+ }
+
+ /**
+ * Creates a new {@link Literal} from the {@code content}.
+ *
+ * @param content the literal content.
+ * @return a new {@link Literal}.
+ */
+ public static Literal literalOf(@Nullable T content) {
+ return new Literal<>(content);
+ }
+
+ /**
+ * Creates a new {@code NULL} {@link Literal}.
+ *
+ * @return a new {@link Literal}.
+ */
+ public static Literal nullLiteral() {
+ return new Literal<>(null);
+ }
+
// Utility constructor.
private SQL() {}
}
diff --git a/spring-data-relational/src/main/java/org/springframework/data/relational/core/sql/SelectBuilder.java b/spring-data-relational/src/main/java/org/springframework/data/relational/core/sql/SelectBuilder.java
index b1ea5ceb94..f4ef3c8e61 100644
--- a/spring-data-relational/src/main/java/org/springframework/data/relational/core/sql/SelectBuilder.java
+++ b/spring-data-relational/src/main/java/org/springframework/data/relational/core/sql/SelectBuilder.java
@@ -22,6 +22,7 @@
*
* @author Mark Paluch
* @since 1.1
+ * @see StatementBuilder
*/
public interface SelectBuilder {
diff --git a/spring-data-relational/src/main/java/org/springframework/data/relational/core/sql/SelectValidator.java b/spring-data-relational/src/main/java/org/springframework/data/relational/core/sql/SelectValidator.java
index e1f9257818..5a199bf32b 100644
--- a/spring-data-relational/src/main/java/org/springframework/data/relational/core/sql/SelectValidator.java
+++ b/spring-data-relational/src/main/java/org/springframework/data/relational/core/sql/SelectValidator.java
@@ -17,6 +17,7 @@
import java.util.HashSet;
import java.util.Set;
+import java.util.Stack;
/**
* Validator for {@link Select} statements.
@@ -27,18 +28,22 @@
* @author Mark Paluch
* @since 1.1
*/
-class SelectValidator implements Visitor {
+class SelectValidator extends AbstractImportValidator {
+
+ private final Stack