Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

<groupId>com.github.EzFramework</groupId>
<artifactId>java-query-builder</artifactId>
<version>1.0.7</version>
<version>1.1.0</version>
<packaging>jar</packaging>

<name>JavaQueryBuilder</name>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,9 @@ public class Query {
/** Suffix appended to values for LIKE and NOT LIKE conditions. */
private String likeSuffix = "%";

/** The columns to include in a {@code RETURNING} clause; empty means no RETURNING. */
private List<String> returningColumns = new ArrayList<>();

/**
* Gets the source table for the query.
*
Expand Down Expand Up @@ -378,4 +381,24 @@ public String getLikeSuffix() {
public void setLikeSuffix(final String likeSuffix) {
this.likeSuffix = likeSuffix;
}

/**
* Returns the columns to include in a {@code RETURNING} clause.
*
* <p>An empty list means no {@code RETURNING} clause will be rendered.
*
* @return the list of returning column names; never {@code null}
*/
public List<String> getReturningColumns() {
return returningColumns;
}

/**
* Sets the columns to include in a {@code RETURNING} clause.
*
* @param returningColumns the list of column names; must not be {@code null}
*/
public void setReturningColumns(final List<String> returningColumns) {
this.returningColumns = returningColumns;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ public class DeleteBuilder {
/** The WHERE conditions. */
private final List<ConditionEntry> conditions = new ArrayList<>();

/** The RETURNING columns (PostgreSQL only). */
private final List<String> returningColumns = new ArrayList<>();

/** The defaults configuration for this builder instance. */
private QueryBuilderDefaults queryBuilderDefaults = QueryBuilderDefaults.global();

Expand Down Expand Up @@ -190,6 +193,20 @@ public DeleteBuilder whereExistsSubquery(Query subquery) {
return this;
}

/**
* Specifies the columns to include in a {@code RETURNING} clause (PostgreSQL only).
*
* <p>This is only rendered when the active dialect supports {@code RETURNING}
* (i.e., {@link com.github.ezframework.javaquerybuilder.query.sql.SqlDialect#POSTGRESQL}).
*
* @param columns one or more column names; must not be {@code null} or empty
* @return this builder instance for chaining
*/
public DeleteBuilder returning(final String... columns) {
returningColumns.addAll(java.util.Arrays.asList(columns));
return this;
}

/**
* Builds the SQL DELETE statement using standard SQL.
*
Expand Down Expand Up @@ -217,6 +234,7 @@ private Query toQuery() {
q.setTable(table);
q.setConditions(new ArrayList<>(conditions));
q.setLimit(-1);
q.setReturningColumns(new ArrayList<>(returningColumns));
return q;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,17 +24,52 @@ public class InsertBuilder {
/** The values to insert. */
private final List<Object> values = new ArrayList<>();

/** The RETURNING columns (PostgreSQL only). */
private final List<String> returningColumns = new ArrayList<>();

/**
* Sets the table to insert into.
*
* @param table the table name
* @return this builder instance for chaining
*/
public InsertBuilder into(String table) {
this.table = table;
return this;
}

/**
* Adds a column-value pair to the INSERT statement.
*
* @param column the column name
* @param value the value to insert
* @return this builder instance for chaining
*/
public InsertBuilder value(String column, Object value) {
columns.add(column);
values.add(value);
return this;
}

/**
* Specifies the columns to include in a {@code RETURNING} clause (PostgreSQL only).
*
* <p>The {@code RETURNING} clause is appended unconditionally to the SQL string;
* it is the caller's responsibility to use a PostgreSQL connection.
*
* @param columns one or more column names; must not be {@code null} or empty
* @return this builder instance for chaining
*/
public InsertBuilder returning(final String... columns) {
returningColumns.addAll(java.util.Arrays.asList(columns));
return this;
}

/**
* Builds the SQL INSERT statement using the default dialect.
*
* @return the SQL result
*/
public SqlResult build() {
return build(null);
}
Expand All @@ -52,6 +87,9 @@ public SqlResult build(SqlDialect dialect) {
sql.append(") VALUES (");
sql.append(String.join(", ", Collections.nCopies(values.size(), "?")));
sql.append(")");
if (!returningColumns.isEmpty()) {
sql.append(" RETURNING ").append(String.join(", ", returningColumns));
}
return new SqlResult() {
@Override
public String getSql() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -284,6 +284,51 @@ public QueryBuilder whereNotLike(String column, String value) {
return this;
}

/**
* Adds an {@code ILIKE} WHERE condition joined with AND (PostgreSQL only).
*
* <p>Produces case-insensitive pattern matching. Rendered correctly only when
* the active dialect is {@link com.github.ezframework.javaquerybuilder.query.sql.SqlDialect#POSTGRESQL}.
* The configured like prefix and suffix are applied to the value.
*
* @param column the column name
* @param value the pattern to match (prefix/suffix applied automatically)
* @return this builder instance for chaining
*/
public QueryBuilder whereILike(final String column, final String value) {
conditions.add(
new ConditionEntry(
column,
new Condition(Operator.ILIKE, value),
conditions.isEmpty() ? Connector.AND : Connector.AND
)
);
return this;
}

/**
* Adds a {@code NOT ILIKE} WHERE condition joined with OR (PostgreSQL only).
*
* <p>Produces negated case-insensitive pattern matching. Rendered correctly only
* when the active dialect is
* {@link com.github.ezframework.javaquerybuilder.query.sql.SqlDialect#POSTGRESQL}.
* The configured like prefix and suffix are applied to the value.
*
* @param column the column name
* @param value the pattern to match (prefix/suffix applied automatically)
* @return this builder instance for chaining
*/
public QueryBuilder orWhereILike(final String column, final String value) {
conditions.add(
new ConditionEntry(
column,
new Condition(Operator.ILIKE, value),
Connector.OR
)
);
return this;
}

/**
* Adds an {@code EXISTS} WHERE condition joined with AND.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,24 @@ public SelectBuilder whereLike(String column, String value) {
return this;
}

/**
* Adds a {@code WHERE ILIKE} condition (PostgreSQL case-insensitive match) joined with AND.
*
* <p>Rendered correctly only when the active dialect is
* {@link com.github.ezframework.javaquerybuilder.query.sql.SqlDialect#POSTGRESQL}.
*
* @param column the column name
* @param value the pattern to match (prefix/suffix applied automatically)
* @return this builder
*/
public SelectBuilder whereILike(final String column, final String value) {
conditions.add(new ConditionEntry(
column,
new Condition(Operator.ILIKE, value),
conditions.isEmpty() ? Connector.AND : Connector.AND));
return this;
}

/**
* Adds a GROUP BY clause.
* @param columns the columns to group by
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@ public class UpdateBuilder {
/** The WHERE conditions. */
private final List<ConditionEntry> conditions = new ArrayList<>();

/** The RETURNING columns (PostgreSQL only). */
private final List<String> returningColumns = new ArrayList<>();

/**
* Sets the table to update.
* @param table the table name
Expand Down Expand Up @@ -85,6 +88,20 @@ public UpdateBuilder whereGreaterThanOrEquals(String column, int value) {
return this;
}

/**
* Specifies the columns to include in a {@code RETURNING} clause (PostgreSQL only).
*
* <p>The {@code RETURNING} clause is appended unconditionally to the SQL string;
* it is the caller's responsibility to use a PostgreSQL connection.
*
* @param columns one or more column names; must not be {@code null} or empty
* @return this builder instance for chaining
*/
public UpdateBuilder returning(final String... columns) {
returningColumns.addAll(java.util.Arrays.asList(columns));
return this;
}

/**
* Builds the SQL UPDATE statement.
* @return the SQL result
Expand Down Expand Up @@ -123,6 +140,9 @@ public SqlResult build(SqlDialect dialect) {
params.add(cond.getCondition().getValue());
}
}
if (!returningColumns.isEmpty()) {
sql.append(" RETURNING ").append(String.join(", ", returningColumns));
}

return new SqlResult() {
@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,5 +44,21 @@ public enum Operator {
* True SQL {@code NOT EXISTS (SELECT ...)} — value must be a
* {@link com.github.ezframework.javaquerybuilder.query.Query}.
*/
NOT_EXISTS_SUBQUERY
NOT_EXISTS_SUBQUERY,
/**
* PostgreSQL case-insensitive {@code ILIKE} substring match.
*
* <p>Only rendered correctly by
* {@link com.github.ezframework.javaquerybuilder.query.sql.postgresql.PostgreSqlDialect};
* using this operator with any other dialect produces no output.
*/
ILIKE,
/**
* PostgreSQL case-insensitive {@code NOT ILIKE} substring match.
*
* <p>Only rendered correctly by
* {@link com.github.ezframework.javaquerybuilder.query.sql.postgresql.PostgreSqlDialect};
* using this operator with any other dialect produces no output.
*/
NOT_ILIKE
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@
*
* <p>Implements the standard (ANSI) SQL dialect and provides shared helpers for
* rendering {@code WHERE} clauses. Subclasses may override
* {@link #quoteIdentifier(String)} to apply dialect-specific identifier quoting
* and {@link #supportsDeleteLimit()} to enable dialect-specific DELETE
* {@code LIMIT} behaviour.
* {@link #quoteIdentifier(String)} to apply dialect-specific identifier quoting,
* {@link #supportsDeleteLimit()} to enable dialect-specific DELETE {@code LIMIT}
* behaviour, and {@link #supportsReturning()} to enable a {@code RETURNING} clause.
*
* <p>Subquery support — parameter ordering contract:
* <ol>
Expand Down Expand Up @@ -67,6 +67,9 @@ public SqlResult renderDelete(Query query) {
if (supportsDeleteLimit() && query.getLimit() != null && query.getLimit() >= 0) {
sql.append(" LIMIT ").append(query.getLimit());
}
if (supportsReturning() && !query.getReturningColumns().isEmpty()) {
sql.append(" RETURNING ").append(String.join(", ", query.getReturningColumns()));
}

final String sqlStr = sql.toString();
final List<Object> paramsCopy = Collections.unmodifiableList(new ArrayList<>(params));
Expand Down Expand Up @@ -95,6 +98,17 @@ protected boolean supportsDeleteLimit() {
return false;
}

/**
* Hook for dialects that support a {@code RETURNING} clause on DELETE statements
* (for example, PostgreSQL). The default implementation returns {@code false}.
* Subclasses that want to enable {@code RETURNING} should override this method.
*
* @return {@code true} if the dialect appends a {@code RETURNING} clause to DELETE statements
*/
protected boolean supportsReturning() {
return false;
}

@Override
public SqlResult render(Query query) {
final StringBuilder sql = new StringBuilder();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,14 @@

import com.github.ezframework.javaquerybuilder.query.Query;
import com.github.ezframework.javaquerybuilder.query.sql.mysql.MySqlDialect;
import com.github.ezframework.javaquerybuilder.query.sql.postgresql.PostgreSqlDialect;
import com.github.ezframework.javaquerybuilder.query.sql.sqlite.SqliteDialect;

/**
* Strategy for rendering a {@link Query} to a SQL string.
*
* <p>Use the built-in constants for the most common dialects:
* {@link #STANDARD}, {@link #MYSQL}, or {@link #SQLITE}.
* {@link #STANDARD}, {@link #MYSQL}, {@link #SQLITE}, or {@link #POSTGRESQL}.
* For custom behaviour, extend {@link AbstractSqlDialect} and override
* {@link AbstractSqlDialect#quoteIdentifier(String)}.
*
Expand All @@ -26,6 +27,13 @@ public interface SqlDialect {
/** SQLite dialect — identifiers are wrapped in double-quote characters. */
SqlDialect SQLITE = new SqliteDialect();

/**
* PostgreSQL dialect — identifiers are wrapped in double-quote characters,
* with additional support for {@code ILIKE}/{@code NOT ILIKE} operators and
* {@code RETURNING} clauses on DELETE statements.
*/
SqlDialect POSTGRESQL = new PostgreSqlDialect();

/**
* Renders the given query to a parameterized {@link SqlResult}.
*
Expand Down
Loading
Loading