From 269b189201563048b86b94f2298bd7bc74ad7bd3 Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Sat, 1 May 2021 20:41:51 -0400 Subject: [PATCH 1/7] Update CHANGELOG.md --- CHANGELOG.md | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d86bab92f..7dedc2ccc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,7 +14,7 @@ The major themes of this release include the following: 1. Add support for the "exists" and "not exists" operator. This will work in "where" clauses anywhere they are supported. 1. Refactor and improve the built-in conditions for consistency (see below) -1. Continue to refine the Kotlin DSL. Most changes to the Kotlin DSL are internal and should be source code +1. Continue to refine the Kotlin DSL. Many changes to the Kotlin DSL are internal and should be source code compatible with existing code. There is one breaking change detailed below. 1. Remove deprecated code from prior releases. @@ -31,7 +31,8 @@ However, there are some changes in behavior and one breaking change. for a similar purpose. 1. The new "filter" method works a bit differently than the "when" method it replaces. The old "when" method could not be chained - if it was called multiple times, only the last call would take effect. The new "filter" methods works - as it should and every call will take effect. + as it should and every call will take effect. This allows you to construct map/filter pipelines as you would + expect. 1. The new "map" method will allow you to change the datatype of a condition as is normal for a "map" method. You can use this method to apply a type conversion directly within condition. 1. All the "WhenPresent" conditions have been removed as separate classes. The methods that produced these conditions @@ -62,9 +63,26 @@ However, there are some changes in behavior and one breaking change. ``` We think this is a marked improvement! -### Breaking Change for Kotlin +### Kotlin DSL Update and Breaking Change for Kotlin -In this release the Kotlin support for `select` and `count` statements has been refactored. This will not impact code +The Kotlin DSL continues to evolve. With this release we have fully built out the DSL, and it is no longer necessary +to use any functions in `org.mybatis.dynamic.sql.SqlBuilder`. The advantages of this are many and are detailed on the +Kotlin overview page in the documentation. Many functions in `SqlBuilder` have been replaced by +top level functions the `org.mybatis.dynamic.sql.util.kotlin.elements` package. In most cases you can switch to the +native Kotlin DSL by simply changing the import statements. For example, you can switch usage of the `isEqualTo` +function by changing + +```kotlin +import org.mybatis.dynamic.sql.SqlBuilder.isEqualTo +``` + +to + +```kotlin +import org.mybatis.dynamic.sql.util.kotlin.elements.isEqualTo +``` + +A breaking change is that Kotlin support for `select` and `count` statements has been refactored. This will not impact code created by MyBatis generator. It will have an impact on Spring/Kotlin users as well as MyBatis users that coded joins or other queries directly in Kotlin. The difference is that the `from` clause has been moved inside the lambda for select and count statements. From 3b3e83206159eff62af5d6c934e57db544293641 Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Mon, 3 May 2021 14:37:01 -0400 Subject: [PATCH 2/7] Update CHANGELOG.md --- CHANGELOG.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7dedc2ccc..7b7252ad1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,7 +19,7 @@ The major themes of this release include the following: 1. Remove deprecated code from prior releases. ### Built-In Condition Refactoring -All built-in conditions have been refactored. The changes should have no impact for the vast majority of users. +All built-in conditions have been refactored. The changes should have little impact for the vast majority of users. However, there are some changes in behavior and one breaking change. 1. Internally, the conditions no longer hold value Suppliers, they now hold the values themselves. The SqlBuilder @@ -82,6 +82,11 @@ to import org.mybatis.dynamic.sql.util.kotlin.elements.isEqualTo ``` +Several functions that accepted supplier arguments are not present in the Kotlin DSL. This is to avoid difficult +and confusing method overload problems for methods that did not offer any real benefit. If you were using one of these +methods in the Java DSL, then in the Kotlin DSL you will have to change the function argument from a supplier to the +actual value itself. + A breaking change is that Kotlin support for `select` and `count` statements has been refactored. This will not impact code created by MyBatis generator. It will have an impact on Spring/Kotlin users as well as MyBatis users that coded joins or other queries directly in Kotlin. The difference is that the `from` clause has been moved inside the lambda for select From cb61b4662454c25beb138faed2ed9ea6a3626349 Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Tue, 4 May 2021 14:34:03 -0400 Subject: [PATCH 3/7] Documentation --- CHANGELOG.md | 13 ++-- src/site/markdown/docs/complexQueries.md | 42 +++++++---- src/site/markdown/docs/conditions.md | 90 ++++++++++++++++++----- src/site/markdown/docs/databaseObjects.md | 86 +++++++++++++++------- src/site/markdown/docs/delete.md | 3 +- src/site/markdown/docs/introduction.md | 12 +-- 6 files changed, 174 insertions(+), 72 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7b7252ad1..b0e2a298b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,7 @@ This log will detail notable changes to MyBatis Dynamic SQL. Full details are available on the GitHub milestone pages. -## Release 1.3.0 - Unreleased +## Release 1.3.0 - May 4, 2021 GitHub milestone: [https://github.com/mybatis/mybatis-dynamic-sql/issues?q=milestone%3A1.3.0+](https://github.com/mybatis/mybatis-dynamic-sql/issues?q=milestone%3A1.3.0+) @@ -13,12 +13,13 @@ The major themes of this release include the following: 1. Add support for subqueries in select statements - both in a from clause and a join clause. 1. Add support for the "exists" and "not exists" operator. This will work in "where" clauses anywhere they are supported. -1. Refactor and improve the built-in conditions for consistency (see below) +1. Refactor and improve the built-in conditions for consistency (see below). There is one breaking change also + detailed below. 1. Continue to refine the Kotlin DSL. Many changes to the Kotlin DSL are internal and should be source code compatible with existing code. There is one breaking change detailed below. 1. Remove deprecated code from prior releases. -### Built-In Condition Refactoring +### Built-In Condition Refactoring and Breaking Change All built-in conditions have been refactored. The changes should have little impact for the vast majority of users. However, there are some changes in behavior and one breaking change. @@ -38,7 +39,7 @@ However, there are some changes in behavior and one breaking change. 1. All the "WhenPresent" conditions have been removed as separate classes. The methods that produced these conditions in the SqlBuilder remain, and they will now produce a condition with a "NotNull" filter applied. So at the API level things will function exactly as before, but the intermediate classes will be different. -1. One breaking change is that the builder for List value conditions has been removed without replacement. If you +1. One **breaking change** is that the builder for List value conditions has been removed without replacement. If you were using this builder to supply a "value stream transformer", then the replacement is to build a new List value condition and then call the "map" and "filter" methods as needed. For example, prior code looked like this @@ -87,7 +88,7 @@ and confusing method overload problems for methods that did not offer any real b methods in the Java DSL, then in the Kotlin DSL you will have to change the function argument from a supplier to the actual value itself. -A breaking change is that Kotlin support for `select` and `count` statements has been refactored. This will not impact code +A **breaking change** is that Kotlin support for `select` and `count` statements has been refactored. This will not impact code created by MyBatis generator. It will have an impact on Spring/Kotlin users as well as MyBatis users that coded joins or other queries directly in Kotlin. The difference is that the `from` clause has been moved inside the lambda for select and count statements. @@ -107,7 +108,7 @@ The new code looks like this: } ``` -This change makes the Kotlin DSL a bit more consistent and also makes it easier to implement subquery support in the +This change makes the Kotlin DSL more consistent and also makes it easier to implement subquery support in the Kotlin DSL. ### Added diff --git a/src/site/markdown/docs/complexQueries.md b/src/site/markdown/docs/complexQueries.md index 3d87ed8d9..5171ed109 100644 --- a/src/site/markdown/docs/complexQueries.md +++ b/src/site/markdown/docs/complexQueries.md @@ -1,7 +1,13 @@ # Complex Queries -Enhancements in version 1.1.2 make it easier to code complex queries. The Select DSL is implemented as a set of related objects. As the select statement is built, intermediate objects of various types are returned from the various methods that implement the DSL. The select statement can be completed by calling the `build()` method many of the intermediate objects. Prior to version 1.1.2, it was necessary to call `build()` on the **last** intermediate object. This restriction has been removed, and it is now possible to call `build()` on **any** intermediate object. This, along with several other enhancements, has simplified the coding of complex queries. +Enhancements in version 1.1.2 make it easier to code complex queries. The Select DSL is implemented as a set of related +objects. As the select statement is built, intermediate objects of various types are returned from the various methods +that implement the DSL. The select statement can be completed by calling the `build()` method many of the intermediate +objects. Prior to version 1.1.2, it was necessary to call `build()` on the **last** intermediate object. This +restriction has been removed, and it is now possible to call `build()` on **any** intermediate object. This, along with +several other enhancements, has simplified the coding of complex queries. -For example, suppose you want to code a complex search on a Person table. The search parameters are id, first name, and last name. The rules are: +For example, suppose you want to code a complex search on a Person table. The search parameters are id, first name, +and last name. The rules are: 1. If an id is entered, use the id and ignore the other search parameters 1. If an id is not entered, then do a fuzzy search based on the other parameters @@ -19,15 +25,15 @@ public SelectStatementProvider search(Integer targetId, String fName, String lNa .and(id, isEqualTo(targetId)); } else { builder - .and(firstName, isLike(fName).when(Objects::nonNull).then(s -> "%" + s + "%")) // (4) - .and(lastName, isLikeWhenPresent(lName).then(this::addWildcards)); // (5) + .and(firstName, isLike(fName).filter(Objects::nonNull).map(s -> "%" + s + "%")) // (4) (5) + .and(lastName, isLikeWhenPresent(lName).map(this::addWildcards)); // (6) } builder .orderBy(lastName, firstName) - .fetchFirst(50).rowsOnly(); // (6) + .fetchFirst(50).rowsOnly(); // (7) - return builder.build().render(RenderingStrategies.MYBATIS3); // (7) + return builder.build().render(RenderingStrategies.MYBATIS3); // (8) } public String addWildcards(String s) { @@ -37,11 +43,21 @@ public String addWildcards(String s) { Notes: -1. Note the use of the `var` keyword here. If you are using an older version of Java, the actual type is `QueryExpressionDSL.QueryExpressionWhereBuilder` -1. Here we are calling `where()` with no parameters. This sets up the builder to accept conditions further along in the code. If no conditions are added, then the where clause will not be rendered -1. This `if` statement implements the rules of the search. If an ID is entered , use it. Otherwise, do a fuzzy search based on first name and last name. -1. The `then` statement on this line allows you to change the parameter value before it is placed in the parameter Map. In this case we are adding SQL wildcards to the start and end of the search String - but only if the search String is not null. If the search String is null, the lambda will not be called and the condition will not render -1. This shows using a method reference instead of a lambda on the `then`. Method references allow you to more clearly express intent. Note also the use of the `isLikeWhenPresent` condition which is a built in condition that checks for nulls -1. It is a good idea to limit the number of rows returned from a search. The library now supports `fetch first` syntax for limiting rows -1. Note that we are calling the `build` method from the intermediate object retrieved in step 1. It is no longer necessary to call `build` on the last object returned from a select builder +1. Note the use of the `var` keyword here. If you are using an older version of Java, the actual type is + `QueryExpressionDSL.QueryExpressionWhereBuilder` +1. Here we are calling `where()` with no parameters. This sets up the builder to accept conditions further along in the + code. If no conditions are added, then the where clause will not be rendered +1. This `if` statement implements the rules of the search. If an ID is entered , use it. Otherwise, do a fuzzy search + based on first name and last name. +1. The `filter` method on this line will mark the condition as unrenderable if the filter is not satisfied. +1. The `map` statement on this line allows you to change the parameter value before it is placed in the parameter Map. + In this case we are adding SQL wildcards to the start and end of the search String - but only if the search String + is not null. If the search String is null, the lambda will not be called and the condition will not render +1. This line shows the use of a method reference instead of a lambda on the `map`. Method references allow you to more + clearly express intent. Note also the use of the `isLikeWhenPresent` function which is a built-in function that + applies a non-null filter +1. It is a good idea to limit the number of rows returned from a search. The library now supports `fetch first` syntax + for limiting rows +1. Note that we are calling the `build` method from the intermediate object retrieved in step 1. It is no longer + necessary to call `build` on the last object returned from a select builder diff --git a/src/site/markdown/docs/conditions.md b/src/site/markdown/docs/conditions.md index 7a83acb96..2a0e459ae 100644 --- a/src/site/markdown/docs/conditions.md +++ b/src/site/markdown/docs/conditions.md @@ -33,9 +33,9 @@ Simple conditions are the most common - they render the basic SQL operators. | Null | where(foo, isNull()) | `where foo is null` | -## Sub-Selects +## Subqueries -Many conditions can be rendered with sub selects. +Many conditions can be rendered with subqueries. | Condition | Example | Result | |-----------|---------|--------| @@ -62,6 +62,58 @@ Column comparison conditions can be used to write where clauses comparing the va | Less Than or Equals | where(foo, isLessThanOrEqualTo(bar)) | `where foo <= bar` | | Not Equals | where(foo, isNotEqualTo(bar)) | `where foo <> bar` | +## Value Transformation + +All conditions (except `isNull` and `isNotNull`) support a `map` function that allows you to transform the value(s) +associated with the condition before the statement is rendered. The map function functions similarly to the JDK +standard `map` functions on Streams and Optionals - it allows you to transform a value and change the data type. + +For example, suppose you want to code a wild card search with the SQL `like` operator. To make this work, you will +need to append SQL wildcards to the search value. This can be accomplished directly i the condition with a `map` +method as follows: + +```java +List search(String searchName) { + SelectStatementProvider selectStatement=select(id,animalName,bodyWeight,brainWeight) + .from(animalData) + .where(animalName,isLike(searchName).map(s->"%"+s+"%")) + .orderBy(id) + .build() + .render(RenderingStrategies.MYBATIS3); + + ... +} +``` + +You can see the `map` method accepts a lambda that adds SQL wildcards to the `searchName` field. This is more succint +if you use a method reference: + +```java +List search(String searchName){ + SelectStatementProvider selectStatement=select(id,animalName,bodyWeight,brainWeight) + .from(animalData) + .where(animalName,isLike(searchName).map(this::appendWildCards)) + .orderBy(id) + .build() + .render(RenderingStrategies.MYBATIS3); +} + +String appendWildCards(String in) { + return "%" + in + "%"; +} +``` + +The `map` on each condition accepts a lambda expression that can be used to transform the value(s) associated with the +condition. The lambda is the standard JDK type `Function<T,R>` where `T` is the type of the condition and `R` +is the output type. For most conditions this should be fairly simple to understand. The unusual cases are detailed +below: + +1. The `Between` and `NotBetween` conditions have `map` methods that accept one or two map functions. If you pass + one function, it will be applied to both values in the condition. If you supply two functions, then they will be + applied to the first and second values respectively. +1. The `In` and `NotIn` conditions accept a single mapping function and it will be applied to all values in the + collection of values in the condition. + ## Optional Conditions All conditions support optionality - meaning they can be configured to render into the final SQL if a configured test @@ -78,8 +130,8 @@ For example, you could code a search like this: SelectStatementProvider selectStatement = select(id, animalName, bodyWeight, brainWeight) .from(animalData) .where(animalName, isEqualTo(animalName_).filter(Objects::nonNull)) - .and(bodyWeight, isEqualToWhen(bodyWeight_).filter(Objects::nonNull)) - .and(brainWeight, isEqualToWhen(brainWeight_).filter(Objects::nonNull)) + .and(bodyWeight, isEqualTo(bodyWeight_).filter(Objects::nonNull)) + .and(brainWeight, isEqualTo(brainWeight_).filter(Objects::nonNull)) .build() .render(RenderingStrategies.MYBATIS3); ... @@ -96,20 +148,22 @@ table lists the optional conditions and shows how to use them: | Condition | Example | Rendering Rules | |-----------|---------|-----------------| -| Between| where(foo, isBetween(x).and(y).when(BiPredicate)) | The library will pass x and y to the BiPredicate's test method. The condition will render if BiPredicate.test(x, y) returns true | -| Equals | where(foo, isEqualTo(x).when(Predicate)) | The library will pass x to the Predicate's test method. The condition will render if Predicate.test(x) returns true | -| Greater Than | where(id, isGreaterThan(x).when(Predicate)) | The library will pass x to the Predicate's test method. The condition will render if Predicate.test(x) returns true | -| Greater Than or Equals | where(id, isGreaterThanOrEqualTo(x).when(Predicate)) | The library will pass x to the Predicate's test method. The condition will render if Predicate.test(x) returns true | -| Less Than | where(id, isLessThan(x).when(Predicate)) | The library will pass x to the Predicate's test method. The condition will render if Predicate.test(x) returns true | -| Less Than or Equals | where(id, isLessThanOrEqualTo(x).when(Predicate)) | The library will pass x to the Predicate's test method. The condition will render if Predicate.test(x) returns true | -| Like | where(id, isLike(x).when(Predicate)) | The library will pass x to the Predicate's test method. The condition will render if Predicate.test(x) returns true | -| Like Case Insensitive | where(id, isLikeCaseInsensitive(x).when(Predicate<String>)) | The library will pass x to the Predicate's test method. The condition will render if Predicate.test(x) returns true | -| Not Between | where(id, isNotBetween(x).and(y).when(BiPredicate)) | The library will pass x and y to the BiPredicate's test method. The condition will render if BiPredicate.test(x, y) returns true | -| Not Equals | where(id, isNotEqualTo(x).when(Predicate)) | The library will pass x to the Predicate's test method. The condition will render if Predicate.test(x) returns true | -| Not Like | where(id, isNotLike(x).when(Predicate)) | The library will pass x to the Predicate's test method. The condition will render if Predicate.test(x) returns true | -| Not Like Case Insensitive | where(id, isNotLikeCaseInsensitive(x).when(Predicate<String>)) | The library will pass x to the Predicate's test method. The condition will render if Predicate.test(x) returns true | -| Not Null | where(id, isNotNull().when(BooleanSupplier) | The condition will render if BooleanSupplier.getAsBoolean() returns true | -| Null | where(id, isNull().when(BooleanSupplier) | The condition will render if BooleanSupplier.getAsBoolean() returns true | +| Between| where(foo, isBetween(x).and(y).filter(BiPredicate)) | The library will pass x and y to the BiPredicate's test method. The condition will render if BiPredicate.test(x, y) returns true | +| Between| where(foo, isBetween(x).and(y).filter(Predicate)) | The library will invoke the Predicate's test method twice - once with x, once with y. The condition will render if both function calls return true | +| Equals | where(foo, isEqualTo(x).filter(Predicate)) | The library will pass x to the Predicate's test method. The condition will render if Predicate.test(x) returns true | +| Greater Than | where(id, isGreaterThan(x).filter(Predicate)) | The library will pass x to the Predicate's test method. The condition will render if Predicate.test(x) returns true | +| Greater Than or Equals | where(id, isGreaterThanOrEqualTo(x).filter(Predicate)) | The library will pass x to the Predicate's test method. The condition will render if Predicate.test(x) returns true | +| Less Than | where(id, isLessThan(x).filter(Predicate)) | The library will pass x to the Predicate's test method. The condition will render if Predicate.test(x) returns true | +| Less Than or Equals | where(id, isLessThanOrEqualTo(x).filter(Predicate)) | The library will pass x to the Predicate's test method. The condition will render if Predicate.test(x) returns true | +| Like | where(id, isLike(x).filter(Predicate)) | The library will pass x to the Predicate's test method. The condition will render if Predicate.test(x) returns true | +| Like Case Insensitive | where(id, isLikeCaseInsensitive(x).filter(Predicate<String>)) | The library will pass x to the Predicate's test method. The condition will render if Predicate.test(x) returns true | +| Not Between | where(id, isNotBetween(x).and(y).filter(BiPredicate)) | The library will pass x and y to the BiPredicate's test method. The condition will render if BiPredicate.test(x, y) returns true | +| Not Between| where(foo, isNotBetween(x).and(y).filter(Predicate)) | The library will invoke the Predicate's test method twice - once with x, once with y. The condition will render if both function calls return true | +| Not Equals | where(id, isNotEqualTo(x).filter(Predicate)) | The library will pass x to the Predicate's test method. The condition will render if Predicate.test(x) returns true | +| Not Like | where(id, isNotLike(x).filter(Predicate)) | The library will pass x to the Predicate's test method. The condition will render if Predicate.test(x) returns true | +| Not Like Case Insensitive | where(id, isNotLikeCaseInsensitive(x).filter(Predicate<String>)) | The library will pass x to the Predicate's test method. The condition will render if Predicate.test(x) returns true | +| Not Null | where(id, isNotNull().filter(BooleanSupplier) | The condition will render if BooleanSupplier.getAsBoolean() returns true | +| Null | where(id, isNull().filter(BooleanSupplier) | The condition will render if BooleanSupplier.getAsBoolean() returns true | ### "When Present" Condition Builders The library supplies several methods that supply conditions to be used in the common case of checking for null diff --git a/src/site/markdown/docs/databaseObjects.md b/src/site/markdown/docs/databaseObjects.md index 2d217c0c8..66a200290 100644 --- a/src/site/markdown/docs/databaseObjects.md +++ b/src/site/markdown/docs/databaseObjects.md @@ -3,19 +3,23 @@ MyBatis Dynamic SQL works with Java objects that represent relational tables or ## Table or View Representation -The class `org.mybatis.dynamic.sql.SqlTable` is used to represent a table or view in a database. An `SqlTable` holds a name, and a collection of `SqlColumn` objects that represent the columns in a table or view. +The class `org.mybatis.dynamic.sql.SqlTable` is used to represent a table or view in a database. An `SqlTable` holds a +name, and a collection of `SqlColumn` objects that represent the columns in a table or view. A table or view name in SQL has three parts: -1. The catalog - which is optional and is rarely used outside of Microsoft SQL Server. If unspecified the default catalog will be used - and many databases only have one catalog -1. The schema - which is optional but is very often specified. If unspecified the default schema will be used +1. The catalog - which is optional and is rarely used outside of Microsoft SQL Server. If unspecified the default + catalog will be used - and many databases only have one catalog +1. The schema - which is optional but is very often specified. If unspecified, the default schema will be used 1. The table name - which is required Typical examples of names are as follows: - `"dbo..bar"` - a name with a catalog (dbo) and a table name (bar). This is typical for SQL Server -- `"foo.bar"` - a name with a schema (foo) and a table name (bar). This is typical in many databases when you want to access tables that are not in the default schema -- `"bar"` - a name with just a table name (bar). This will access a table or view in the default catalog and schema for a connection +- `"foo.bar"` - a name with a schema (foo) and a table name (bar). This is typical in many databases when you want to + access tables that are not in the default schema +- `"bar"` - a name with just a table name (bar). This will access a table or view in the default catalog and schema for + a connection In MyBatis Dynamic SQL, the table or view name can be specified in different ways: @@ -46,9 +50,13 @@ public class MyTable extends SqlTable { ``` ### Dynamic Catalog and/or Schema Names -MyBatis Dynamic SQL allows you to dynamically specify a catalog and/or schema. This is useful for applications where the schema may change for different users or environments, or if you are using different schemas to shard the database. Dynamic names are used when you use a `SqlTable` constructor that accepts one or more `java.util.function.Supplier` arguments. +MyBatis Dynamic SQL allows you to dynamically specify a catalog and/or schema. This is useful for applications where +the schema may change for different users or environments, or if you are using different schemas to shard the database. +Dynamic names are used when you use a `SqlTable` constructor that accepts one or more `java.util.function.Supplier` +arguments. -For example, suppose you wanted to change the schema based on the value of a system property. You could write a class like this: +For example, suppose you wanted to change the schema based on the value of a system property. You could write a class +like this: ```java public class SchemaSupplier { @@ -60,7 +68,8 @@ public class SchemaSupplier { } ``` -This class has a static method `schemaPropertyReader` that will return an `Optional` containing the value of a system property. You could then reference this method in the constructor of the `SqlTable` like this: +This class has a static method `schemaPropertyReader` that will return an `Optional` containing the value of a +system property. You could then reference this method in the constructor of the `SqlTable` like this: ```java public static final class User extends SqlTable { @@ -70,14 +79,18 @@ public static final class User extends SqlTable { } ``` -Whenever the table is referenced for rendering SQL, the name will be calculated based on the current value of the system property. +Whenever the table is referenced for rendering SQL, the name will be calculated based on the current value of the +system property. There are two constructors that can be used for dynamic names: -1. A constructor that accepts `Supplier>` for the schema, and `String` for the name. This constructor assumes that the catalog is always empty or not used -1. A constructor that accepts `Supplier>` for the catalog, `Supplier>` for the schema, and `String` for the name +1. A constructor that accepts `Supplier>` for the schema, and `String` for the name. This constructor + assumes that the catalog is always empty or not used +1. A constructor that accepts `Supplier>` for the catalog, `Supplier>` for the schema, + and `String` for the name -If you are using Microsoft SQL Server and want to use a dynamic catalog name and ignore the schema, then you should use the second constructor like this: +If you are using Microsoft SQL Server and want to use a dynamic catalog name and ignore the schema, then you should use +the second constructor like this: ```java public static final class User extends SqlTable { @@ -98,11 +111,12 @@ Catalog Supplier Value | Schema Supplier Value | Name | Fully Qualified Name ### Fully Dynamic Names -MyBatis Dynamic SQL allows you to dynamically specify a full table name. This is useful for applications where the database is sharded with different tables representing different shards of the whole. Dynamic names are used when you use a `SqlTable` constructor that accepts a single `java.util.function.Supplier` argument. - -Note that this functionality should only be used for tables that have different names, but are otherwise identical. +MyBatis Dynamic SQL allows you to dynamically specify a full table name. This is useful for applications where the +database is sharded with different tables representing different shards of the whole. Dynamic names are used when you +use a `SqlTable` constructor that accepts a single `java.util.function.Supplier` argument. -For example, suppose you wanted to change the name based on the value of a system property. You could write a class like this: +For example, suppose you wanted to change the name based on the value of a system property. You could write a class +like this: ```java public class NameSupplier { @@ -114,7 +128,8 @@ public class NameSupplier { } ``` -This class has a static method `namePropertyReader` that will return an `String` containing the value of a system property. You could then reference this method in the constructor of the `SqlTable` like this: +This class has a static method `namePropertyReader` that will return an `String` containing the value of a system +property. You could then reference this method in the constructor of the `SqlTable` like this: ```java public static final class User extends SqlTable { @@ -126,23 +141,38 @@ public static final class User extends SqlTable { Whenever the table is referenced for rendering SQL, the name will be calculated based on the current value of the system property. - - ## Column Representation -The class `org.mybatis.dynamic.sql.SqlColumn` is used to represent a column in a table or view. An `SqlColumn` is always associated with a `SqlTable`. In its most basic form, the `SqlColumn` class holds a name and a reference to the `SqlTable` it is associated with. The table reference is required so that table aliases can be applied to columns in the rendering phase. +The class `org.mybatis.dynamic.sql.SqlColumn` is used to represent a column in a table or view. An `SqlColumn` is always +associated with a `SqlTable`. In its most basic form, the `SqlColumn` class holds a name and a reference to the +`SqlTable` it is associated with. The table reference is required so that table aliases can be applied to columns in the +rendering phase. -The `SqlColumn` will be rendered in SQL based on the `RenderingStrategy` applied to the SQL statement. Typically the rendering strategy generates a string that represents a parameter marker in whatever SQL engine you are using. For example, MyBatis3 parameter markers are formatted as "#{some_attribute}". By default, all columns are rendered with the same strategy. The library supplies rendering strategies that are appropriate for several SQL execution engines including MyBatis3 and Spring JDBC template. +The `SqlColumn` will be rendered in SQL based on the `RenderingStrategy` applied to the SQL statement. Typically the +rendering strategy generates a string that represents a parameter marker in whatever SQL engine you are using. For +example, MyBatis3 parameter markers are formatted as "#{some_attribute}". By default, all columns are rendered with the +same strategy. The library supplies rendering strategies that are appropriate for several SQL execution engines +including MyBatis3 and Spring JDBC template. -In some cases it is necessary to override the rendering strategy for a particular column - so the `SqlColumn` class supports specifying a rendering strategy for a column that will override the rendering strategy applied to a statement. A good example of this use case is with PostgreSQL. In that database it is required to add the string "::jsonb" to a prepared statement parameter marker when inserting or updating JSON fields, but not for other fields. A column based rendering strategy enables this. +In some cases it is necessary to override the rendering strategy for a particular column - so the `SqlColumn` class +supports specifying a rendering strategy for a column that will override the rendering strategy applied to a statement. +A good example of this use case is with PostgreSQL. In that database it is required to add the string "::jsonb" to a +prepared statement parameter marker when inserting or updating JSON fields, but not for other fields. A column based +rendering strategy enables this. -The `SqlColumn` class has additional optional attributes that are useful for SQL rendering - especially in MyBatis3. These include: +The `SqlColumn` class has additional optional attributes that are useful for SQL rendering - especially in MyBatis3. +These include: -* The `java.sql.JDBCType` of the column. This will be rendered into the MyBatis3 compatible parameter marker - which helps with picking type handlers and also inserting or updating null capable fields -* A String containing a type handler - either a type handler alias or the fully qualified type of a type handler. This will be rendered into the MyBatis3 compatible parameter marker +* The `java.sql.JDBCType` of the column. This will be rendered into the MyBatis3 compatible parameter marker - which + helps with picking type handlers and also inserting or updating null capable fields +* A String containing a type handler - either a type handler alias or the fully qualified type of a type handler. This + will be rendered into the MyBatis3 compatible parameter marker -If you are not using MyBatis3, then you will not need to specify the JDBC Type or type handler as those attributes are ignored by other rendering strategies. +If you are not using MyBatis3, then you do not need to specify the JDBC Type or type handler as those attributes are +ignored by other rendering strategies. -Finally, the `SqlColumn` class has methods to designate a column alias or sort order for use in different SQL statements. +Finally, the `SqlColumn` class has methods to designate a column alias or sort order for use in different SQL +statements. -We recommend a usage pattern for creating table and column objects that provides quite a bit of flexibility for usage. See the [Quick Start](quickStart.html) page for a complete example. +We recommend a usage pattern for creating table and column objects that provides quite a bit of flexibility for usage. +See the [Quick Start](quickStart.html) page for a complete example. diff --git a/src/site/markdown/docs/delete.md b/src/site/markdown/docs/delete.md index 6c421c5e5..b7dd9cec3 100644 --- a/src/site/markdown/docs/delete.md +++ b/src/site/markdown/docs/delete.md @@ -37,7 +37,8 @@ import org.mybatis.dynamic.sql.util.SqlProviderAdapter; ## XML Mapper for Delete Statements -We do not recommend using an XML mapper for delete statements, but if you want to do so the DeleteStatementProvider object can be used as a parameter to a MyBatis mapper method directly. +We do not recommend using an XML mapper for delete statements, but if you want to do so, the DeleteStatementProvider +object can be used as a parameter to a MyBatis mapper method directly. If you are using an XML mapper, the delete method should look like this in the Java interface: diff --git a/src/site/markdown/docs/introduction.md b/src/site/markdown/docs/introduction.md index 45c789de6..e9b8b2c9e 100644 --- a/src/site/markdown/docs/introduction.md +++ b/src/site/markdown/docs/introduction.md @@ -13,16 +13,16 @@ parameters required for that statement. The SQL statement object can be used di The library will generate these types of SQL statements: +- COUNT statements - specialized SELECT statements that return a Long value - DELETE statements with flexible WHERE clauses - INSERT statements of several types: - - A statement that inserts a single record and will insert null values into columns (a "full" insert) - - A statement that inserts a single record that will ignore null input values and their associated columns (a "selective" insert) + - A statement that inserts a single row with values supplied from a corresponding Object + - A statement that inserts a single row with values supplied directly in the statement + - A statement that inserts multiple rows using multiple VALUES clauses + - A statement that inserts multiple rows using a JDBC batch - A statement that inserts into a table using the results of a SELECT statement - - A parameter object is designed for inserting multiple objects with a JDBC batch - SELECT statements with a flexible column list, a flexible WHERE clause, and support for distinct, "group by", joins, unions, "order by", etc. -- UPDATE statements with a flexible WHERE clause. Like the INSERT statement, there are two varieties of UPDATE statements: - - A "full" update that will set null values - - A "selective" update that will ignore null input values +- UPDATE statements with a flexible WHERE clause, and flexible SET clauses The primary goals of the library are: From 257f62d5e3014d6e265cbee6b1a609e1951b2c93 Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Thu, 6 May 2021 16:39:25 -0400 Subject: [PATCH 4/7] Remove Jacoco version override - no longer needed --- pom.xml | 1 - 1 file changed, 1 deletion(-) diff --git a/pom.xml b/pom.xml index 8a3a6071c..1a9215d4d 100644 --- a/pom.xml +++ b/pom.xml @@ -39,7 +39,6 @@ 1.2.0 org.mybatis.dynamic.sql 1.5.0 - 0.8.7 1.8 pom.xml,src/main/java,src/main/kotlin src/test/java,src/test/kotlin From dbe72719efddd17e99727c7c602b7cba6bb6ce2e Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Thu, 6 May 2021 16:39:51 -0400 Subject: [PATCH 5/7] Fix checkstyle override --- checkstyle-override.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/checkstyle-override.xml b/checkstyle-override.xml index 20b51ba16..5cd619479 100644 --- a/checkstyle-override.xml +++ b/checkstyle-override.xml @@ -1,7 +1,7 @@