Skip to content

Commit aba2e6e

Browse files
authored
Merge pull request #221 from jeffgbutler/gh_192
Add convenience methods for count and countDistinct
2 parents 9ac3446 + 3ae221c commit aba2e6e

25 files changed

+414
-107
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ If you have written your own set of functions to extend the library, you will no
1818
- 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))
1919
- Added the ability to write a function that will change the column data type ([#197](https://github.com/mybatis/mybatis-dynamic-sql/issues/197))
2020
- 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))
21+
- Added convenience methods for count(column) and count(distinct column)([#221](https://github.com/mybatis/mybatis-dynamic-sql/issues/221))
2122

2223
## Release 1.1.4 - November 23, 2019
2324

src/main/java/org/mybatis/dynamic/sql/SqlBuilder.java

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,24 @@
107107
public interface SqlBuilder {
108108

109109
// statements
110+
111+
/**
112+
* Renders as select count(distinct column) from table...
113+
*/
114+
static CountDSL.FromGatherer<SelectModel> countDistinctColumn(BasicColumn column) {
115+
return CountDSL.countDistinct(column);
116+
}
117+
118+
/**
119+
* Renders as select count(column) from table...
120+
*/
121+
static CountDSL.FromGatherer<SelectModel> countColumn(BasicColumn column) {
122+
return CountDSL.count(column);
123+
}
124+
125+
/**
126+
* Renders as select count(*) from table...
127+
*/
110128
static CountDSL<SelectModel> countFrom(SqlTable table) {
111129
return CountDSL.countFrom(table);
112130
}
@@ -292,8 +310,8 @@ static <T> Concatenate<T> concatenate(BindableColumn<T> firstColumn, BasicColumn
292310
return Concatenate.concatenate(firstColumn, secondColumn, subsequentColumns);
293311
}
294312

295-
static <T> OperatorFunction<T> applyOperator(String operator, BindableColumn<T> firstColumn, BasicColumn secondColumn,
296-
BasicColumn... subsequentColumns) {
313+
static <T> OperatorFunction<T> applyOperator(String operator, BindableColumn<T> firstColumn,
314+
BasicColumn secondColumn, BasicColumn... subsequentColumns) {
297315
return OperatorFunction.of(operator, firstColumn, secondColumn, subsequentColumns);
298316
}
299317

src/main/java/org/mybatis/dynamic/sql/insert/render/BatchInsertRenderer.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,8 @@ private BatchInsertRenderer(Builder<T> builder) {
3636

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

4243
return BatchInsert.withRecords(model.records())

src/main/java/org/mybatis/dynamic/sql/insert/render/MultiRowInsertRenderer.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,10 @@ private MultiRowInsertRenderer(Builder<T> builder) {
3636
}
3737

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

4345
return new DefaultMultiRowInsertStatementProvider.Builder<T>().withRecords(model.records())

src/main/java/org/mybatis/dynamic/sql/insert/render/MultiRowRenderingUtilities.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,8 @@ public static Function<AbstractColumnMapping, FieldAndValue> toFieldAndValue(Mul
2929
return insertMapping -> MultiRowRenderingUtilities.toFieldAndValue(visitor, insertMapping);
3030
}
3131

32-
public static FieldAndValue toFieldAndValue(MultiRowValuePhraseVisitor visitor, AbstractColumnMapping insertMapping) {
32+
public static FieldAndValue toFieldAndValue(MultiRowValuePhraseVisitor visitor,
33+
AbstractColumnMapping insertMapping) {
3334
return insertMapping.accept(visitor);
3435
}
3536

src/main/java/org/mybatis/dynamic/sql/select/CountDSL.java

Lines changed: 37 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/**
2-
* Copyright 2016-2019 the original author or authors.
2+
* Copyright 2016-2020 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -18,6 +18,7 @@
1818
import java.util.Objects;
1919
import java.util.function.Function;
2020

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

4243
private Function<SelectModel, R> adapterFunction;
4344
private CountWhereBuilder whereBuilder = new CountWhereBuilder();
45+
private BasicColumn countColumn;
4446

45-
private CountDSL(SqlTable table, Function<SelectModel, R> adapterFunction) {
47+
private CountDSL(BasicColumn countColumn, SqlTable table, Function<SelectModel, R> adapterFunction) {
4648
super(table);
49+
this.countColumn = Objects.requireNonNull(countColumn);
4750
this.adapterFunction = Objects.requireNonNull(adapterFunction);
4851
}
4952

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

6972
private SelectModel buildModel() {
7073
QueryExpressionModel.Builder b = new QueryExpressionModel.Builder()
71-
.withSelectColumn(SqlBuilder.count())
74+
.withSelectColumn(countColumn)
7275
.withTable(table())
7376
.withTableAliases(tableAliases)
7477
.withWhereModel(whereBuilder.buildWhereModel());
@@ -85,14 +88,44 @@ public static CountDSL<SelectModel> countFrom(SqlTable table) {
8588
}
8689

8790
public static <R> CountDSL<R> countFrom(Function<SelectModel, R> adapterFunction, SqlTable table) {
88-
return new CountDSL<>(table, adapterFunction);
91+
return new CountDSL<>(SqlBuilder.count(), table, adapterFunction);
92+
}
93+
94+
public static FromGatherer<SelectModel> count(BasicColumn column) {
95+
return count(Function.identity(), column);
96+
}
97+
98+
public static <R> FromGatherer<R> count(Function<SelectModel, R> adapterFunction, BasicColumn column) {
99+
return new FromGatherer<>(adapterFunction, SqlBuilder.count(column));
100+
}
101+
102+
public static FromGatherer<SelectModel> countDistinct(BasicColumn column) {
103+
return countDistinct(Function.identity(), column);
104+
}
105+
106+
public static <R> FromGatherer<R> countDistinct(Function<SelectModel, R> adapterFunction, BasicColumn column) {
107+
return new FromGatherer<>(adapterFunction, SqlBuilder.countDistinct(column));
89108
}
90109

91110
@Override
92111
protected CountDSL<R> getThis() {
93112
return this;
94113
}
95114

115+
public static class FromGatherer<R> {
116+
private BasicColumn column;
117+
private Function<SelectModel, R> adapterFunction;
118+
119+
public FromGatherer(Function<SelectModel, R> adapterFunction, BasicColumn column) {
120+
this.adapterFunction = adapterFunction;
121+
this.column = column;
122+
}
123+
124+
public CountDSL<R> from(SqlTable table) {
125+
return new CountDSL<>(column, table, adapterFunction);
126+
}
127+
}
128+
96129
public class CountWhereBuilder extends AbstractWhereDSL<CountWhereBuilder>
97130
implements Buildable<R> {
98131
private <T> CountWhereBuilder() {}

src/main/java/org/mybatis/dynamic/sql/select/function/AbstractFunction.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@
2222
import org.mybatis.dynamic.sql.BindableColumn;
2323

2424
/**
25+
* Represents a database function.
26+
*
2527
* @deprecated in favor of {@link AbstractUniTypeFunction}
2628
*
2729
* @author Jeff Butler

src/main/java/org/mybatis/dynamic/sql/select/function/AbstractMultipleColumnArithmeticFunction.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@
2727
import org.mybatis.dynamic.sql.render.TableAliasCalculator;
2828

2929
/**
30+
* Represents a function with multiple numeric columns.
31+
*
3032
* @deprecated in favor of {@link OperatorFunction}.
3133
*
3234
* @author Jeff Butler

src/main/java/org/mybatis/dynamic/sql/update/render/SetPhraseVisitor.java

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -80,24 +80,6 @@ public <T> Optional<FragmentAndParameters> visit(ValueWhenPresentMapping<T> mapp
8080
return mapping.value().flatMap(v -> buildFragment(mapping, v));
8181
}
8282

83-
private <T> Optional<FragmentAndParameters> buildFragment(AbstractColumnMapping mapping, T value) {
84-
String mapKey = RenderingStrategy.formatParameterMapKey(sequence);
85-
86-
String jdbcPlaceholder = mapping.mapColumn(toJdbcPlaceholder(mapKey));
87-
String setPhrase = mapping.mapColumn(SqlColumn::name)
88-
+ " = " //$NON-NLS-1$
89-
+ jdbcPlaceholder;
90-
91-
return FragmentAndParameters.withFragment(setPhrase)
92-
.withParameter(mapKey, value)
93-
.buildOptional();
94-
}
95-
96-
private Function<SqlColumn<?>, String> toJdbcPlaceholder(String parameterName) {
97-
return column -> column.renderingStrategy().orElse(renderingStrategy)
98-
.getFormattedJdbcPlaceholder(column, RenderingStrategy.DEFAULT_PARAMETER_PREFIX, parameterName);
99-
}
100-
10183
@Override
10284
public Optional<FragmentAndParameters> visit(SelectMapping mapping) {
10385
SelectStatementProvider selectStatement = SelectRenderer.withSelectModel(mapping.selectModel())
@@ -125,4 +107,22 @@ public Optional<FragmentAndParameters> visit(ColumnToColumnMapping mapping) {
125107
return FragmentAndParameters.withFragment(setPhrase)
126108
.buildOptional();
127109
}
110+
111+
private <T> Optional<FragmentAndParameters> buildFragment(AbstractColumnMapping mapping, T value) {
112+
String mapKey = RenderingStrategy.formatParameterMapKey(sequence);
113+
114+
String jdbcPlaceholder = mapping.mapColumn(toJdbcPlaceholder(mapKey));
115+
String setPhrase = mapping.mapColumn(SqlColumn::name)
116+
+ " = " //$NON-NLS-1$
117+
+ jdbcPlaceholder;
118+
119+
return FragmentAndParameters.withFragment(setPhrase)
120+
.withParameter(mapKey, value)
121+
.buildOptional();
122+
}
123+
124+
private Function<SqlColumn<?>, String> toJdbcPlaceholder(String parameterName) {
125+
return column -> column.renderingStrategy().orElse(renderingStrategy)
126+
.getFormattedJdbcPlaceholder(column, RenderingStrategy.DEFAULT_PARAMETER_PREFIX, parameterName);
127+
}
128128
}

src/main/java/org/mybatis/dynamic/sql/update/render/UpdateRenderer.java

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,8 @@ public UpdateStatementProvider render() {
6060

6161
private UpdateStatementProvider renderWithWhereClause(List<Optional<FragmentAndParameters>> fragmentsAndParameters,
6262
WhereClauseProvider whereClause) {
63-
return DefaultUpdateStatementProvider.withUpdateStatement(calculateUpdateStatement(fragmentsAndParameters, whereClause))
63+
return DefaultUpdateStatementProvider
64+
.withUpdateStatement(calculateUpdateStatement(fragmentsAndParameters, whereClause))
6465
.withParameters(calculateParameters(fragmentsAndParameters))
6566
.withParameters(whereClause.getParameters())
6667
.build();
@@ -78,7 +79,8 @@ private String calculateUpdateStatement(List<Optional<FragmentAndParameters>> fr
7879
+ spaceBefore(calculateSetPhrase(fragmentsAndParameters));
7980
}
8081

81-
private UpdateStatementProvider renderWithoutWhereClause(List<Optional<FragmentAndParameters>> fragmentsAndParameters) {
82+
private UpdateStatementProvider renderWithoutWhereClause(
83+
List<Optional<FragmentAndParameters>> fragmentsAndParameters) {
8284
return DefaultUpdateStatementProvider.withUpdateStatement(calculateUpdateStatement(fragmentsAndParameters))
8385
.withParameters(calculateParameters(fragmentsAndParameters))
8486
.build();
@@ -109,7 +111,8 @@ private Optional<WhereClauseProvider> renderWhereClause(WhereModel whereModel) {
109111
.render();
110112
}
111113

112-
private Function<AbstractColumnMapping, Optional<FragmentAndParameters>> toFragmentAndParameters(SetPhraseVisitor visitor) {
114+
private Function<AbstractColumnMapping, Optional<FragmentAndParameters>> toFragmentAndParameters(
115+
SetPhraseVisitor visitor) {
113116
return updateMapping -> toFragmentAndParameters(visitor, updateMapping);
114117
}
115118

0 commit comments

Comments
 (0)