Skip to content

Add convenience methods for count and countDistinct #221

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Jul 27, 2020
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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ If you have written your own set of functions to extend the library, you will no
- Added the capability to specify a rendering strategy on a column to override the defaut rendering strategy for a statement. This will allow certain edge cases where a parameter marker needs to be formatted in a unique way (for example, "::jsonb" needs to be added to parameter markers for JSON fields in PostgreSQL) ([#200](https://github.com/mybatis/mybatis-dynamic-sql/issues/200))
- Added the ability to write a function that will change the column data type ([#197](https://github.com/mybatis/mybatis-dynamic-sql/issues/197))
- Added the `applyOperator` function to make it easy to use non-standard database operators in expressions ([#220](https://github.com/mybatis/mybatis-dynamic-sql/issues/220))
- Added convenience methods for count(column) and count(distinct column)([#221](https://github.com/mybatis/mybatis-dynamic-sql/issues/221))

## Release 1.1.4 - November 23, 2019

Expand Down
22 changes: 20 additions & 2 deletions src/main/java/org/mybatis/dynamic/sql/SqlBuilder.java
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,24 @@
public interface SqlBuilder {

// statements

/**
* Renders as select count(distinct column) from table...
*/
static CountDSL.FromGatherer<SelectModel> countDistinctColumn(BasicColumn column) {
return CountDSL.countDistinct(column);
}

/**
* Renders as select count(column) from table...
*/
static CountDSL.FromGatherer<SelectModel> countColumn(BasicColumn column) {
return CountDSL.count(column);
}

/**
* Renders as select count(*) from table...
*/
static CountDSL<SelectModel> countFrom(SqlTable table) {
return CountDSL.countFrom(table);
}
Expand Down Expand Up @@ -292,8 +310,8 @@ static <T> Concatenate<T> concatenate(BindableColumn<T> firstColumn, BasicColumn
return Concatenate.concatenate(firstColumn, secondColumn, subsequentColumns);
}

static <T> OperatorFunction<T> applyOperator(String operator, BindableColumn<T> firstColumn, BasicColumn secondColumn,
BasicColumn... subsequentColumns) {
static <T> OperatorFunction<T> applyOperator(String operator, BindableColumn<T> firstColumn,
BasicColumn secondColumn, BasicColumn... subsequentColumns) {
return OperatorFunction.of(operator, firstColumn, secondColumn, subsequentColumns);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,8 @@ private BatchInsertRenderer(Builder<T> builder) {

public BatchInsert<T> render() {
MultiRowValuePhraseVisitor visitor = new MultiRowValuePhraseVisitor(renderingStrategy, "record"); //$NON-NLS-1$)
List<FieldAndValue> fieldsAndValues = model.mapColumnMappings(MultiRowRenderingUtilities.toFieldAndValue(visitor))
List<FieldAndValue> fieldsAndValues = model
.mapColumnMappings(MultiRowRenderingUtilities.toFieldAndValue(visitor))
.collect(Collectors.toList());

return BatchInsert.withRecords(model.records())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,10 @@ private MultiRowInsertRenderer(Builder<T> builder) {
}

public MultiRowInsertStatementProvider<T> render() {
MultiRowValuePhraseVisitor visitor = new MultiRowValuePhraseVisitor(renderingStrategy, "records[%s]"); //$NON-NLS-1$
List<FieldAndValue> fieldsAndValues = model.mapColumnMappings(MultiRowRenderingUtilities.toFieldAndValue(visitor))
MultiRowValuePhraseVisitor visitor =
new MultiRowValuePhraseVisitor(renderingStrategy, "records[%s]"); //$NON-NLS-1$
List<FieldAndValue> fieldsAndValues = model
.mapColumnMappings(MultiRowRenderingUtilities.toFieldAndValue(visitor))
.collect(Collectors.toList());

return new DefaultMultiRowInsertStatementProvider.Builder<T>().withRecords(model.records())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@ public static Function<AbstractColumnMapping, FieldAndValue> toFieldAndValue(Mul
return insertMapping -> MultiRowRenderingUtilities.toFieldAndValue(visitor, insertMapping);
}

public static FieldAndValue toFieldAndValue(MultiRowValuePhraseVisitor visitor, AbstractColumnMapping insertMapping) {
public static FieldAndValue toFieldAndValue(MultiRowValuePhraseVisitor visitor,
AbstractColumnMapping insertMapping) {
return insertMapping.accept(visitor);
}

Expand Down
41 changes: 37 additions & 4 deletions src/main/java/org/mybatis/dynamic/sql/select/CountDSL.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/**
* Copyright 2016-2019 the original author or authors.
* Copyright 2016-2020 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.
Expand All @@ -18,6 +18,7 @@
import java.util.Objects;
import java.util.function.Function;

import org.mybatis.dynamic.sql.BasicColumn;
import org.mybatis.dynamic.sql.BindableColumn;
import org.mybatis.dynamic.sql.SqlBuilder;
import org.mybatis.dynamic.sql.SqlCriterion;
Expand All @@ -41,9 +42,11 @@ public class CountDSL<R> extends AbstractQueryExpressionDSL<CountDSL<R>, R> impl

private Function<SelectModel, R> adapterFunction;
private CountWhereBuilder whereBuilder = new CountWhereBuilder();
private BasicColumn countColumn;

private CountDSL(SqlTable table, Function<SelectModel, R> adapterFunction) {
private CountDSL(BasicColumn countColumn, SqlTable table, Function<SelectModel, R> adapterFunction) {
super(table);
this.countColumn = Objects.requireNonNull(countColumn);
this.adapterFunction = Objects.requireNonNull(adapterFunction);
}

Expand All @@ -68,7 +71,7 @@ public R build() {

private SelectModel buildModel() {
QueryExpressionModel.Builder b = new QueryExpressionModel.Builder()
.withSelectColumn(SqlBuilder.count())
.withSelectColumn(countColumn)
.withTable(table())
.withTableAliases(tableAliases)
.withWhereModel(whereBuilder.buildWhereModel());
Expand All @@ -85,14 +88,44 @@ public static CountDSL<SelectModel> countFrom(SqlTable table) {
}

public static <R> CountDSL<R> countFrom(Function<SelectModel, R> adapterFunction, SqlTable table) {
return new CountDSL<>(table, adapterFunction);
return new CountDSL<>(SqlBuilder.count(), table, adapterFunction);
}

public static FromGatherer<SelectModel> count(BasicColumn column) {
return count(Function.identity(), column);
}

public static <R> FromGatherer<R> count(Function<SelectModel, R> adapterFunction, BasicColumn column) {
return new FromGatherer<>(adapterFunction, SqlBuilder.count(column));
}

public static FromGatherer<SelectModel> countDistinct(BasicColumn column) {
return countDistinct(Function.identity(), column);
}

public static <R> FromGatherer<R> countDistinct(Function<SelectModel, R> adapterFunction, BasicColumn column) {
return new FromGatherer<>(adapterFunction, SqlBuilder.countDistinct(column));
}

@Override
protected CountDSL<R> getThis() {
return this;
}

public static class FromGatherer<R> {
private BasicColumn column;
private Function<SelectModel, R> adapterFunction;

public FromGatherer(Function<SelectModel, R> adapterFunction, BasicColumn column) {
this.adapterFunction = adapterFunction;
this.column = column;
}

public CountDSL<R> from(SqlTable table) {
return new CountDSL<>(column, table, adapterFunction);
}
}

public class CountWhereBuilder extends AbstractWhereDSL<CountWhereBuilder>
implements Buildable<R> {
private <T> CountWhereBuilder() {}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@
import org.mybatis.dynamic.sql.BindableColumn;

/**
* Represents a database function.
*
* @deprecated in favor of {@link AbstractUniTypeFunction}
*
* @author Jeff Butler
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@
import org.mybatis.dynamic.sql.render.TableAliasCalculator;

/**
* Represents a function with multiple numeric columns.
*
* @deprecated in favor of {@link OperatorFunction}.
*
* @author Jeff Butler
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,24 +80,6 @@ public <T> Optional<FragmentAndParameters> visit(ValueWhenPresentMapping<T> mapp
return mapping.value().flatMap(v -> buildFragment(mapping, v));
}

private <T> Optional<FragmentAndParameters> buildFragment(AbstractColumnMapping mapping, T value) {
String mapKey = RenderingStrategy.formatParameterMapKey(sequence);

String jdbcPlaceholder = mapping.mapColumn(toJdbcPlaceholder(mapKey));
String setPhrase = mapping.mapColumn(SqlColumn::name)
+ " = " //$NON-NLS-1$
+ jdbcPlaceholder;

return FragmentAndParameters.withFragment(setPhrase)
.withParameter(mapKey, value)
.buildOptional();
}

private Function<SqlColumn<?>, String> toJdbcPlaceholder(String parameterName) {
return column -> column.renderingStrategy().orElse(renderingStrategy)
.getFormattedJdbcPlaceholder(column, RenderingStrategy.DEFAULT_PARAMETER_PREFIX, parameterName);
}

@Override
public Optional<FragmentAndParameters> visit(SelectMapping mapping) {
SelectStatementProvider selectStatement = SelectRenderer.withSelectModel(mapping.selectModel())
Expand Down Expand Up @@ -125,4 +107,22 @@ public Optional<FragmentAndParameters> visit(ColumnToColumnMapping mapping) {
return FragmentAndParameters.withFragment(setPhrase)
.buildOptional();
}

private <T> Optional<FragmentAndParameters> buildFragment(AbstractColumnMapping mapping, T value) {
String mapKey = RenderingStrategy.formatParameterMapKey(sequence);

String jdbcPlaceholder = mapping.mapColumn(toJdbcPlaceholder(mapKey));
String setPhrase = mapping.mapColumn(SqlColumn::name)
+ " = " //$NON-NLS-1$
+ jdbcPlaceholder;

return FragmentAndParameters.withFragment(setPhrase)
.withParameter(mapKey, value)
.buildOptional();
}

private Function<SqlColumn<?>, String> toJdbcPlaceholder(String parameterName) {
return column -> column.renderingStrategy().orElse(renderingStrategy)
.getFormattedJdbcPlaceholder(column, RenderingStrategy.DEFAULT_PARAMETER_PREFIX, parameterName);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,8 @@ public UpdateStatementProvider render() {

private UpdateStatementProvider renderWithWhereClause(List<Optional<FragmentAndParameters>> fragmentsAndParameters,
WhereClauseProvider whereClause) {
return DefaultUpdateStatementProvider.withUpdateStatement(calculateUpdateStatement(fragmentsAndParameters, whereClause))
return DefaultUpdateStatementProvider
.withUpdateStatement(calculateUpdateStatement(fragmentsAndParameters, whereClause))
.withParameters(calculateParameters(fragmentsAndParameters))
.withParameters(whereClause.getParameters())
.build();
Expand All @@ -78,7 +79,8 @@ private String calculateUpdateStatement(List<Optional<FragmentAndParameters>> fr
+ spaceBefore(calculateSetPhrase(fragmentsAndParameters));
}

private UpdateStatementProvider renderWithoutWhereClause(List<Optional<FragmentAndParameters>> fragmentsAndParameters) {
private UpdateStatementProvider renderWithoutWhereClause(
List<Optional<FragmentAndParameters>> fragmentsAndParameters) {
return DefaultUpdateStatementProvider.withUpdateStatement(calculateUpdateStatement(fragmentsAndParameters))
.withParameters(calculateParameters(fragmentsAndParameters))
.build();
Expand Down Expand Up @@ -109,7 +111,8 @@ private Optional<WhereClauseProvider> renderWhereClause(WhereModel whereModel) {
.render();
}

private Function<AbstractColumnMapping, Optional<FragmentAndParameters>> toFragmentAndParameters(SetPhraseVisitor visitor) {
private Function<AbstractColumnMapping, Optional<FragmentAndParameters>> toFragmentAndParameters(
SetPhraseVisitor visitor) {
return updateMapping -> toFragmentAndParameters(visitor, updateMapping);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,25 @@
public class MyBatis3Utils {
private MyBatis3Utils() {}

public static long count(ToLongFunction<SelectStatementProvider> mapper, BasicColumn column, SqlTable table,
CountDSLCompleter completer) {
return mapper.applyAsLong(count(column, table, completer));
}

public static SelectStatementProvider count(BasicColumn column, SqlTable table, CountDSLCompleter completer) {
return countFrom(SqlBuilder.countColumn(column).from(table), completer);
}

public static long countDistinct(ToLongFunction<SelectStatementProvider> mapper, BasicColumn column, SqlTable table,
CountDSLCompleter completer) {
return mapper.applyAsLong(countDistinct(column, table, completer));
}

public static SelectStatementProvider countDistinct(BasicColumn column, SqlTable table,
CountDSLCompleter completer) {
return countFrom(SqlBuilder.countDistinctColumn(column).from(table), completer);
}

public static SelectStatementProvider countFrom(SqlTable table, CountDSLCompleter completer) {
return countFrom(SqlBuilder.countFrom(table), completer);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,12 @@ import org.mybatis.dynamic.sql.select.render.SelectStatementProvider
import org.mybatis.dynamic.sql.update.render.UpdateStatementProvider
import org.mybatis.dynamic.sql.util.kotlin.*

fun count(mapper: (SelectStatementProvider) -> Long, column: BasicColumn, table: SqlTable, completer: CountCompleter) =
mapper(SqlBuilder.countColumn(column).from(table, completer))

fun countDistinct(mapper: (SelectStatementProvider) -> Long, column: BasicColumn, table: SqlTable, completer: CountCompleter) =
mapper(SqlBuilder.countDistinctColumn(column).from(table, completer))

fun countFrom(mapper: (SelectStatementProvider) -> Long, table: SqlTable, completer: CountCompleter) =
mapper(countFrom(table, completer))

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import org.mybatis.dynamic.sql.insert.render.GeneralInsertStatementProvider
import org.mybatis.dynamic.sql.insert.render.InsertStatementProvider
import org.mybatis.dynamic.sql.insert.render.MultiRowInsertStatementProvider
import org.mybatis.dynamic.sql.render.RenderingStrategies
import org.mybatis.dynamic.sql.select.CountDSL
import org.mybatis.dynamic.sql.select.QueryExpressionDSL
import org.mybatis.dynamic.sql.select.SelectModel
import org.mybatis.dynamic.sql.select.render.SelectStatementProvider
Expand Down Expand Up @@ -52,6 +53,15 @@ fun <T> MultiRowInsertDSL.IntoGatherer<T>.into(
): MultiRowInsertStatementProvider<T> =
completer(into(table)).build().render(RenderingStrategies.MYBATIS3)

fun CountDSL.FromGatherer<SelectModel>.from(
table: SqlTable,
completer: CountCompleter
): SelectStatementProvider {
val builder = KotlinCountBuilder(from(table))
completer(builder)
return builder.build().render(RenderingStrategies.MYBATIS3)
}

fun QueryExpressionDSL.FromGatherer<SelectModel>.from(
table: SqlTable,
completer: SelectCompleter
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import org.mybatis.dynamic.sql.SqlTable
import org.mybatis.dynamic.sql.delete.render.DeleteStatementProvider
import org.mybatis.dynamic.sql.insert.render.GeneralInsertStatementProvider
import org.mybatis.dynamic.sql.insert.render.InsertStatementProvider
import org.mybatis.dynamic.sql.select.CountDSL
import org.mybatis.dynamic.sql.select.render.SelectStatementProvider
import org.mybatis.dynamic.sql.update.render.UpdateStatementProvider
import org.mybatis.dynamic.sql.util.kotlin.*
Expand All @@ -31,6 +32,12 @@ import java.sql.ResultSet
fun NamedParameterJdbcTemplate.count(selectStatement: SelectStatementProvider) =
queryForObject(selectStatement.selectStatement, selectStatement.parameters, Long::class.java)!!

fun NamedParameterJdbcTemplate.count(column: BasicColumn) =
CountFromGatherer(column, this)

fun NamedParameterJdbcTemplate.countDistinct(column: BasicColumn) =
CountDistinctFromGatherer(column, this)

fun NamedParameterJdbcTemplate.countFrom(table: SqlTable, completer: CountCompleter) =
count(org.mybatis.dynamic.sql.util.kotlin.spring.countFrom(table, completer))

Expand Down Expand Up @@ -79,6 +86,23 @@ fun NamedParameterJdbcTemplate.update(updateStatement: UpdateStatementProvider)
fun NamedParameterJdbcTemplate.update(table: SqlTable, completer: UpdateCompleter) =
update(org.mybatis.dynamic.sql.util.kotlin.spring.update(table, completer))

// support classes for count DSL
class CountFromGatherer(
private val column: BasicColumn,
private val template: NamedParameterJdbcTemplate
) {
fun from(table: SqlTable, completer: CountCompleter) =
template.count(CountDSL.count(column).from(table, completer))
}

class CountDistinctFromGatherer(
private val column: BasicColumn,
private val template: NamedParameterJdbcTemplate
) {
fun from(table: SqlTable, completer: CountCompleter) =
template.count(CountDSL.countDistinct(column).from(table, completer))
}

// support classes for select DSL
class SelectListFromGatherer(
private val selectList: List<BasicColumn>,
Expand Down
Loading