Skip to content

Add BoundValue Implementation #738

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 2 commits into from
Jan 30, 2024
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: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ types - which is a rare usage. Please let us know if this causes an undo hardshi
initial enhancement request that inspired this change. As a result of the changes, one method is deprecated
in the `BasicColumn` object. If you have implemented any custom functions, please note this deprecation and update
your code accordingly. ([#662](https://github.com/mybatis/mybatis-dynamic-sql/pull/662))
2. Added the ability to code a bound value in rendered SQL. This is similar to a constant, but the value is added to
the parameter map and a bind parameter marker is rendered. ([#738](https://github.com/mybatis/mybatis-dynamic-sql/pull/738))

## Release 1.5.0 - April 21, 2023

Expand Down
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--

Copyright 2016-2023 the original author or authors.
Copyright 2016-2024 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 Down
71 changes: 71 additions & 0 deletions src/main/java/org/mybatis/dynamic/sql/BoundValue.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
/*
* Copyright 2016-2024 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
*
* https://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.mybatis.dynamic.sql;

import java.util.Objects;
import java.util.Optional;

import org.mybatis.dynamic.sql.exception.InvalidSqlException;
import org.mybatis.dynamic.sql.render.RenderedParameterInfo;
import org.mybatis.dynamic.sql.render.RenderingContext;
import org.mybatis.dynamic.sql.util.FragmentAndParameters;
import org.mybatis.dynamic.sql.util.Messages;

/**
* BoundValues are added to rendered SQL as a parameter marker only.
*
* <p>BoundValues are most useful in the context of functions. For example, a column value could be
* incremented with an update statement like this:
* <code>
* UpdateStatementProvider updateStatement = update(person)
* .set(age).equalTo(add(age, value(1)))
* .where(id, isEqualTo(5))
* .build()
* .render(RenderingStrategies.MYBATIS3);
* </code>
*
* @param <T> the column type
* @since 1.5.1
*/
public class BoundValue<T> implements BindableColumn<T> {
private final T value;

private BoundValue(T value) {
this.value = Objects.requireNonNull(value);
}

@Override
public FragmentAndParameters render(RenderingContext renderingContext) {
RenderedParameterInfo rpi = renderingContext.calculateParameterInfo(this);
return FragmentAndParameters.withFragment(rpi.renderedPlaceHolder())
.withParameter(rpi.parameterMapKey(), value)
.build();
}

@Override
public Optional<String> alias() {
return Optional.empty();
}

@Override
public BoundValue<T> as(String alias) {
throw new InvalidSqlException(Messages.getString("ERROR.38")); //$NON-NLS-1$
}

public static <T> BoundValue<T> of(T value) {
return new BoundValue<>(value);
}
}
6 changes: 5 additions & 1 deletion src/main/java/org/mybatis/dynamic/sql/SqlBuilder.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2016-2023 the original author or authors.
* Copyright 2016-2024 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 Down Expand Up @@ -492,6 +492,10 @@ static StringConstant stringConstant(String constant) {
return StringConstant.of(constant);
}

static <T> BoundValue<T> value(T value) {
return BoundValue.of(value);
}

// functions
static <T> Add<T> add(BindableColumn<T> firstColumn, BasicColumn secondColumn,
BasicColumn... subsequentColumns) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2016-2023 the original author or authors.
* Copyright 2016-2024 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 @@ -19,6 +19,7 @@ package org.mybatis.dynamic.sql.util.kotlin.elements
import org.mybatis.dynamic.sql.AndOrCriteriaGroup
import org.mybatis.dynamic.sql.BasicColumn
import org.mybatis.dynamic.sql.BindableColumn
import org.mybatis.dynamic.sql.BoundValue
import org.mybatis.dynamic.sql.Constant
import org.mybatis.dynamic.sql.SortSpecification
import org.mybatis.dynamic.sql.SqlBuilder
Expand Down Expand Up @@ -117,6 +118,8 @@ fun <T> constant(constant: String): Constant<T> = SqlBuilder.constant(constant)

fun stringConstant(constant: String): StringConstant = SqlBuilder.stringConstant(constant)

fun <T> value(value: T): BoundValue<T> = SqlBuilder.value(value)

// functions
fun <T> add(
firstColumn: BindableColumn<T>,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#
# Copyright 2016-2023 the original author or authors.
# Copyright 2016-2024 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 Down Expand Up @@ -54,4 +54,5 @@ ERROR.34=You must specify "select" or "selectDistinct" before any other clauses
ERROR.35=Multi-select statements must have at least one "union" or "union all" expression
ERROR.36=You must either implement the "render" or "renderWithTableAlias" method in a column or function
ERROR.37=The "{0}" function does not support conditions that fail to render
ERROR.38=Bound values cannot be aliased
INTERNAL.ERROR=Internal Error {0}
20 changes: 19 additions & 1 deletion src/test/java/examples/simple/PersonMapperTest.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2016-2023 the original author or authors.
* Copyright 2016-2024 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 @@ -25,6 +25,7 @@
import static examples.simple.PersonDynamicSqlSupport.occupation;
import static examples.simple.PersonDynamicSqlSupport.person;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.entry;
import static org.mybatis.dynamic.sql.SqlBuilder.*;

import java.io.InputStream;
Expand Down Expand Up @@ -56,6 +57,7 @@
import org.mybatis.dynamic.sql.select.CountDSLCompleter;
import org.mybatis.dynamic.sql.select.SelectDSLCompleter;
import org.mybatis.dynamic.sql.select.render.SelectStatementProvider;
import org.mybatis.dynamic.sql.update.render.UpdateStatementProvider;

class PersonMapperTest {

Expand Down Expand Up @@ -973,4 +975,20 @@ void testMultiSelectPagingVariation() {

assertThat(selectStatement.getSelectStatement()).isEqualTo(expected);
}

@Test
void gh737() {
UpdateStatementProvider updateStatement = update(person)
.set(addressId).equalTo(add(addressId, value(4)))
.where(id, isEqualTo(5))
.build()
.render(RenderingStrategies.MYBATIS3);

String expected = "update Person " +
"set address_id = (address_id + #{parameters.p1}) " +
"where id = #{parameters.p2,jdbcType=INTEGER}";

assertThat(updateStatement.getUpdateStatement()).isEqualTo(expected);
assertThat(updateStatement.getParameters()).containsExactly(entry("p1", 4), entry("p2", 5));
}
}
13 changes: 12 additions & 1 deletion src/test/java/org/mybatis/dynamic/sql/InvalidSQLTest.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2016-2023 the original author or authors.
* Copyright 2016-2024 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 @@ -21,6 +21,7 @@
import static org.mybatis.dynamic.sql.SqlBuilder.insertInto;
import static org.mybatis.dynamic.sql.SqlBuilder.select;
import static org.mybatis.dynamic.sql.SqlBuilder.update;
import static org.mybatis.dynamic.sql.SqlBuilder.value;

import java.util.ArrayList;
import java.util.Collections;
Expand Down Expand Up @@ -253,6 +254,16 @@ void testInvalidPagingModel() {
.withMessage(Messages.getInternalErrorString(InternalError.INTERNAL_ERROR_13));
}

@Test
void testInvalidValueAlias() {
BoundValue<Integer> foo = value(1);

assertThat(foo.alias()).isEmpty();
assertThatExceptionOfType(InvalidSqlException.class)
.isThrownBy(() -> foo.as("foo"))
.withMessage(Messages.getString("ERROR.38"));
}

@Test
void testBadColumn() {
SelectModel selectModel = select(new BadCount<>()).from(person).build();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2016-2023 the original author or authors.
* Copyright 2016-2024 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 @@ -15,13 +15,16 @@
*/
package examples.kotlin.spring.canonical

import examples.kotlin.spring.canonical.PersonDynamicSqlSupport.addressId
import examples.kotlin.spring.canonical.PersonDynamicSqlSupport.employed
import examples.kotlin.spring.canonical.PersonDynamicSqlSupport.person
import examples.kotlin.spring.canonical.PersonDynamicSqlSupport.firstName
import examples.kotlin.spring.canonical.PersonDynamicSqlSupport.id
import examples.kotlin.spring.canonical.PersonDynamicSqlSupport.lastName
import org.assertj.core.api.Assertions.assertThat
import org.assertj.core.api.Assertions.entry
import org.junit.jupiter.api.Test
import org.mybatis.dynamic.sql.util.kotlin.elements.add
import org.mybatis.dynamic.sql.util.kotlin.elements.applyOperator
import org.mybatis.dynamic.sql.util.kotlin.elements.avg
import org.mybatis.dynamic.sql.util.kotlin.elements.concat
Expand Down Expand Up @@ -50,9 +53,11 @@ import org.mybatis.dynamic.sql.util.kotlin.elements.stringConstant
import org.mybatis.dynamic.sql.util.kotlin.elements.substring
import org.mybatis.dynamic.sql.util.kotlin.elements.subtract
import org.mybatis.dynamic.sql.util.kotlin.elements.sum
import org.mybatis.dynamic.sql.util.kotlin.elements.value
import org.mybatis.dynamic.sql.util.kotlin.spring.select
import org.mybatis.dynamic.sql.util.kotlin.spring.selectList
import org.mybatis.dynamic.sql.util.kotlin.spring.selectOne
import org.mybatis.dynamic.sql.util.kotlin.spring.update
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig
Expand Down Expand Up @@ -654,4 +659,19 @@ open class KotlinElementsTest {
assertThat(rows).hasSize(6)
assertThat(rows[0]).isEqualTo("Fred")
}

@Test
fun testValue() {
val updateStatement = update(person) {
set(addressId) equalTo add(addressId, value(4))
where {
id isEqualTo 5
}
}

assertThat(updateStatement.updateStatement).isEqualTo(
"update Person set address_id = (address_id + :p1) where id = :p2"
)
assertThat(updateStatement.parameters).containsExactly(entry("p1", 4), entry("p2", 5))
}
}