-
Notifications
You must be signed in to change notification settings - Fork 212
/
Copy pathCHANGELOG.html
586 lines (549 loc) · 49.4 KB
/
CHANGELOG.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
<!DOCTYPE html>
<!--
| Generated by Apache Maven Doxia Site Renderer 2.0.0-M18 from target/generated-site/markdown/docs/CHANGELOG.md at 03 Jun 2024
| Rendered using Apache Maven Fluido Skin 2.0.0-M9
-->
<html xmlns="http://www.w3.org/1999/xhtml" lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="generator" content="Apache Maven Doxia Site Renderer 2.0.0-M18" />
<title>MyBatis Dynamic SQL</title>
<link rel="stylesheet" href="../css/apache-maven-fluido-2.0.0-M9.min.css" />
<link rel="stylesheet" href="../css/site.css" />
<link rel="stylesheet" href="../css/print.css" media="print" />
<script src="../js/apache-maven-fluido-2.0.0-M9.min.js"></script>
</head>
<body>
<div class="container-fluid container-fluid-top">
<header>
<div id="banner">
<div class="pull-left"><div id="bannerLeft"><h1><a href="../docs/introduction.html">MyBatis Dynamic SQL</a></h1></div></div>
<div class="pull-right"><div id="bannerRight"><h1><a href="http://www.mybatis.org/" class="externalLink"><img class="imageLink" src="https://mybatis.org/images/mybatis-logo.png" alt="MyBatis logo" /> MyBatis</a></h1></div></div>
<div class="clear"><hr/></div>
</div>
<div id="breadcrumbs">
<ul class="breadcrumb">
<li id="publishDate">Last Published: 03 Jun 2024<span class="divider">|</span>
</li>
<li id="projectVersion">Version: 1.5.2</li>
</ul>
</div>
</header>
<div class="row-fluid">
<header id="leftColumn" class="span2">
<nav class="well sidebar-nav">
<ul class="nav nav-list">
<li class="nav-header">User's Guide</li>
<li><a href="../docs/introduction.html">Introduction</a></li>
<li class="active"><a>Change Log</a></li>
<li><a href="../docs/quickStart.html">Quick Start</a></li>
<li><a href="../docs/exceptions.html">Exceptions thrown by the Library</a></li>
<li><a href="../docs/configuration.html">Configuration of the Library</a></li>
<li><a href="../docs/databaseObjects.html">Modeling Database Objects</a></li>
<li><a href="../docs/whereClauses.html"><span class="icon-chevron-down"></span>WHERE Clause Support</a>
<ul class="nav nav-list">
<li><a href="../docs/conditions.html">WHERE Conditions</a></li>
</ul></li>
<li><a href="../docs/select.html"><span class="icon-chevron-down"></span>SELECT Statements</a>
<ul class="nav nav-list">
<li><a href="../docs/caseExpressions.html">Case Expressions</a></li>
<li><a href="../docs/complexQueries.html">Complex Queries</a></li>
</ul></li>
<li><a href="../docs/delete.html">DELETE Statements</a></li>
<li><a href="../docs/insert.html">INSERT Statements</a></li>
<li><a href="../docs/update.html">UPDATE Statements</a></li>
<li><a href="../docs/subQueries.html">SubQuery Support</a></li>
<li><a href="../docs/functions.html">Database Functions</a></li>
<li><a href="../docs/mybatis3.html">MyBatis3 Support</a></li>
<li><a href="../docs/spring.html">Spring Support</a></li>
<li><a href="../docs/springBatch.html">Spring Batch Support</a></li>
<li><a href="../docs/kotlinOverview.html"><span class="icon-chevron-right"></span>Kotlin Support</a></li>
<li><a href="../docs/howItWorks.html">How it Works</a></li>
<li><a href="../docs/extending.html">Extending the Library</a></li>
<li><a href="../docs/codingStandards.html">Coding Standards</a></li>
<li><a href="../docs/motivation.html">Motivation</a></li>
<li class="nav-header">Project Documentation</li>
<li><a href="../project-info.html"><span class="icon-chevron-right"></span>Project Information</a></li>
<li><a href="../project-reports.html"><span class="icon-chevron-right"></span>Project Reports</a></li>
</ul>
</nav>
<div class="well sidebar-nav">
<div id="poweredBy">
<div class="clear"></div>
<div class="clear"></div>
<a href="https://maven.apache.org/" class="builtBy" target="_blank"><img class="builtBy" alt="Built by Maven" src="../images/logos/maven-feather.png" /></a>
</div>
</div>
</header>
<main id="bodyColumn" class="span10">
<section><a id="Change_Log"></a>
<h1>Change Log</h1>
<p>This log will detail notable changes to MyBatis Dynamic SQL. Full details are available on the GitHub milestone pages.</p><section><a id="Release_1.5.2_-_June_3.2C_2024"></a>
<h2>Release 1.5.2 - June 3, 2024</h2>
<p>This is a small maintenance release with the following changes:</p>
<ol style="list-style-type: decimal;">
<li>Improvements to the Kotlin DSL for CASE expressions (infix methods for “else” and “then”). See this PR for
details: (<a href="https://github.com/mybatis/mybatis-dynamic-sql/pull/785" class="externalLink">#785</a>)</li>
<li><strong>Potentially Breaking Change</strong>: the “in” conditions (“isIn”, “isNotIn”, “isInCaseInsensitive”,
“isNotInCaseInsensitive”) will now render if the input list of values is empty. This will lead
to a runtime exception. This change was made out of an abundance of caution and is the safest choice.
If you wish to allow “in” conditions to be removed from where clauses when the list is empty,
then use the “when present” versions of those conditions. If you are unsure how this works, please
read the documentation here: <a href="https://mybatis.org/mybatis-dynamic-sql/docs/conditions.html#optionality-with-the-%E2%80%9Cin%E2%80%9D-conditions" class="externalLink">https://mybatis.org/mybatis-dynamic-sql/docs/conditions.html#optionality-with-the-%E2%80%9Cin%E2%80%9D-conditions</a>
For background on the reason for the change, see the discussion here: <a href="https://github.com/mybatis/mybatis-dynamic-sql/issues/788" class="externalLink">https://github.com/mybatis/mybatis-dynamic-sql/issues/788</a></li>
</ol>
<p>GitHub milestone: <a href="https://github.com/mybatis/mybatis-dynamic-sql/milestone/14?closed=1" class="externalLink">https://github.com/mybatis/mybatis-dynamic-sql/milestone/14?closed=1</a></p>
<p><strong>Important:</strong> This is the last release that will be compatible with Java 8.</p></section><section><a id="Release_1.5.1_-_April_30.2C_2024"></a>
<h2>Release 1.5.1 - April 30, 2024</h2>
<p>This is a minor release with several enhancements.</p>
<p>GitHub milestone: <a href="https://github.com/mybatis/mybatis-dynamic-sql/milestone/13?closed=1" class="externalLink">https://github.com/mybatis/mybatis-dynamic-sql/milestone/13?closed=1</a></p><section><a id="Case_Expressions_and_Cast_Function"></a>
<h3>Case Expressions and Cast Function</h3>
<p>We've added support for CASE expressions to the library. Both simple and searched case expressions are supported.
This is a fairly extensive enhancement as case expressions are quite complex, but we were able to reuse many of the
building blocks from the WHERE and HAVING support already in the library. You should be able to build CASE expressions
with relatively few limitations.</p>
<p>It is also common to use a CAST function with CASE expressions, so we have added CAST as a built-in function
in the library.</p>
<p>The DSL for both Java and Kotlin has been updated to fully support CASE expressions in the same idiomatic forms
as other parts of the library.</p>
<p>We've tested this extensively and the code is, of course, 100% covered by test code. But it is possible that we've not
covered every scenario. Please let us know if you find issues.</p>
<p>Full documentation is available here:</p>
<ul>
<li><a href="https://mybatis.org/mybatis-dynamic-sql/docs/caseExpressions.html" class="externalLink">Java Case Expression DSL Documentation</a></li>
<li><a href="https://mybatis.org/mybatis-dynamic-sql/docs/kotlinCaseExpressions.html" class="externalLink">Kotlin Case Expression DSL Documentation</a></li>
</ul>
<p>The pull request for this change is (<a href="https://github.com/mybatis/mybatis-dynamic-sql/pull/761" class="externalLink">#761</a>)</p></section><section><a id="Parameter_Values_in_Joins"></a>
<h3>Parameter Values in Joins</h3>
<p>We've added the ability to specify typed values in equi-joins. This allows you to avoid the use of constants, and it is
type safe. For example:</p>
<pre><code class="language-java">SelectStatementProvider selectStatement = select(orderLine.orderId, orderLine.quantity, itemMaster.itemId, itemMaster.description)
.from(itemMaster, "im")
.join(orderLine, "ol").on(orderLine.itemId, equalTo(itemMaster.itemId))
.and(orderLine.orderId, equalTo(1))
.build()
.render(RenderingStrategies.MYBATIS3);
</code></pre>
<p>Note the phrase <code>and(orderLine.orderId, equalTo(1))</code> which will be rendered with a bound SQL parameter. Currently, this
capability is limited to equality only. If you have a use for other functions (not equal, less then, greater than, etc.)
please let us know.</p>
<p>In order to add this capability, we've modified the join DSL to add type information to the join columns. This should
be source code compatible with most uses. There could be an issue if you are joining tables with columns of different
types - which is a rare usage. Please let us know if this causes an undo hardship.</p></section><section><a id="Other_Changes"></a>
<h3>Other Changes</h3>
<ol style="list-style-type: decimal;">
<li>Rendering of conditions and columns was refactored. One benefit of this change is that
it is now easier to support more complex functions - such as the aggregate function <code>sum(id < 5)</code> which is the
initial enhancement request that inspired this change. As a result of the changes, one method is deprecated
in the <code>BasicColumn</code> object. If you have implemented any custom functions, please note this deprecation and update
your code accordingly. (<a href="https://github.com/mybatis/mybatis-dynamic-sql/pull/662" class="externalLink">#662</a>)</li>
<li>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. (<a href="https://github.com/mybatis/mybatis-dynamic-sql/pull/738" class="externalLink">#738</a>)</li>
<li>Refactored the conditions to separate the concept of an empty condition from that of a renderable condition. This
will enable a future change where conditions could decide to allow rendering even if they are considered empty (such
as rendering empty lists). This change should be transparent to users unless they have implemented custom conditions.</li>
<li>Added a configuration setting to allow empty list conditions to render. This could generate invalid SQL, but might be
a good safety measure in some cases.</li>
<li>Added Array based functions for the “in” and “not in” conditions in the Kotlin DSL. These functions allow a more
natural use of an Array as an input for an “in” condition. They also allow easy reuse of a vararg argument in a
function. (<a href="https://github.com/mybatis/mybatis-dynamic-sql/pull/781" class="externalLink">#781</a>)</li>
</ol></section></section><section><a id="Release_1.5.0_-_April_21.2C_2023"></a>
<h2>Release 1.5.0 - April 21, 2023</h2>
<p>GitHub milestone: <a href="https://github.com/mybatis/mybatis-dynamic-sql/milestone/12?closed=1" class="externalLink">https://github.com/mybatis/mybatis-dynamic-sql/milestone/12?closed=1</a></p><section><a id="Potentially_Breaking_Changes"></a>
<h3>Potentially Breaking Changes</h3>
<p>This release includes a major refactoring of the “where” clause support. This is done to support common code for
“having” clauses which is a new feature (see below). Most changes are source code compatible with previous
releases and should be transparent with no impact. Following is a list of some more visible changes…</p>
<p>First, the “where” methods in <code>SqlBuilder</code> now return an instance of <code>WhereDSL.StandaloneWhereFinisher</code> rather than
<code>WhereDSL</code>. This will only impact you if you are using the WhereDSL directly which is a rare use case.</p>
<p>Second, if you are using independent or reusable where clauses you will need to make changes. Previously you might have
coded an independent where clause like this:</p>
<pre><code class="language-java">private WhereApplier commonWhere = d -> d.where(id, isEqualTo(1)).or(occupation, isNull());
</code></pre>
<p>Code like this will no longer compile. There are two options for updates. The simplest change to make is to
replace “where” with “and” or “or” in the above code. For example…</p>
<pre><code class="language-java">private WhereApplier commonWhere = d -> d.and(id, isEqualTo(1)).or(occupation, isNull());
</code></pre>
<p>This will function as before, but you may think it looks a bit strange because the phrase starts with “and”. If you
want this to look more like true SQL, you can write code like this:</p>
<pre><code class="language-java">private final WhereApplier commonWhere = where(id, isEqualTo(1)).or(occupation, isNull()).toWhereApplier();
</code></pre>
<p>This uses a <code>where</code> method from the <code>SqlBuilder</code> class.</p></section><section><a id="a.E2.80.9CHaving.E2.80.9D_Clause_Support"></a>
<h3>“Having” Clause Support</h3>
<p>This release adds support for “having” clauses in select statements. This includes a refactoring of the “where”
support, so we can reuse the and/or logic and rendering that is already present in the “where” clause support.
This because “having” and “where” are essentially the same.</p>
<p>One slight behavior change with this refactoring is that the renderer will now remove a useless open/close
parentheses around certain rendered where clauses. Previously it was possible to have a rendered where clause like
this:</p>
<pre><code class="language-sql">where (a < 2 and b > 3)
</code></pre>
<p>The renderer will now remove the open/close parentheses in a case like this.</p>
<p>In the Java DSL, a “having” clause can only be coded after a “group by” clause - which is a reasonable restriction
as “having” is only needed if there is a “group by”.</p>
<p>In the Kotlin DSL, the “group by” restriction is not present because of the free form nature of that DSL - but you
should probably only use “having” if there is a “group by”. Also note that the freestanding “and” and “or”
functions in the Kotlin DSL still only apply to the where clause. For this reason, the freestanding “and” and “or”
methods are deprecated. Please only use the “and” and “or” methods inside a “where” or “having” lambda.</p>
<p>The pull request for this change is (<a href="https://github.com/mybatis/mybatis-dynamic-sql/pull/550" class="externalLink">#550</a>)</p></section><section><a id="Multi-Select_Queries"></a>
<h3>Multi-Select Queries</h3>
<p>A multi-select query is a special case of a union select statement. The difference is that it allows “order by” and
paging clauses to be applied to the nested queries. A multi-select query looks like this:</p>
<pre><code class="language-java">SelectStatementProvider selectStatement = multiSelect(
select(id.as("A_ID"), firstName, lastName, birthDate, employed, occupation, addressId)
.from(person)
.where(id, isLessThanOrEqualTo(2))
.orderBy(id)
.limit(1)
).unionAll(
select(id.as("A_ID"), firstName, lastName, birthDate, employed, occupation, addressId)
.from(person)
.where(id, isGreaterThanOrEqualTo(4))
.orderBy(id.descending())
.limit(1)
).orderBy(sortColumn("A_ID"))
.fetchFirst(2).rowsOnly()
.build()
.render(RenderingStrategies.MYBATIS3);
</code></pre>
<p>Notice how both inner queries have <code>order by</code> and <code>limit</code> phrases, then there is an <code>order by</code> phrase
for the entire query.</p>
<p>The pull request for this change is (<a href="https://github.com/mybatis/mybatis-dynamic-sql/pull/591" class="externalLink">#591</a>)</p></section><section><a id="Other_Changes_1"></a>
<h3>Other Changes</h3>
<ol style="list-style-type: decimal;">
<li>Added support for specifying “limit” and “order by” on the DELETE and UPDATE statements. Not all databases support
this SQL extension, and different databases have different levels of support. For example, MySQL/MariaDB have full
support but HSQLDB only supports limit as an extension to the WHERE clause. If you choose to use this new capability,
please test to make sure it is supported in your database. (<a href="https://github.com/mybatis/mybatis-dynamic-sql/pull/544" class="externalLink">#544</a>)</li>
<li>Deprecated Kotlin DSL functions have been removed, as well as deprecated support for “EmptyListCallback” in the “in”
conditions. (<a href="https://github.com/mybatis/mybatis-dynamic-sql/pull/548" class="externalLink">#548</a>)</li>
<li>Refactored the common insert mapper support for MyBatis3 by adding a CommonGeneralInsertMapper that can be used
without a class that matches the table row. It includes methods for general insert and insert select.
(<a href="https://github.com/mybatis/mybatis-dynamic-sql/pull/570" class="externalLink">#570</a>)</li>
<li>Added the ability to change a table name on AliasableSqlTable - this creates a new instance of the object with a new
name. This is useful in sharded databases where the name of the table is calculated based on some sharding
algorithm. Also deprecated the constructors on SqlTable that accept Suppliers for table name - this creates an
effectively mutable object and goes against the principles of immutability that we strive for in the library.
(<a href="https://github.com/mybatis/mybatis-dynamic-sql/pull/572" class="externalLink">#572</a>)</li>
<li>Add <code>SqlBuilder.concat</code> and the equivalent in Kotlin. This is a concatenate function that works on more databases.
(<a href="https://github.com/mybatis/mybatis-dynamic-sql/pull/573" class="externalLink">#573</a>)</li>
<li>Several classes and methods in the Kotlin DSL are deprecated in response to the new “having” support</li>
<li>Added support for inserting a list of simple classes like Integers, Strings, etc. This is via a new “map to row”
function on the insert, batch insert, and multirow insert statements. (<a href="https://github.com/mybatis/mybatis-dynamic-sql/pull/612" class="externalLink">#612</a>)</li>
</ol></section></section><section><a id="Release_1.4.1_-_October_7.2C_2022"></a>
<h2>Release 1.4.1 - October 7, 2022</h2>
<p>GitHub milestone: <a href="https://github.com/mybatis/mybatis-dynamic-sql/issues?q=milestone%3A1.4.1+" class="externalLink">https://github.com/mybatis/mybatis-dynamic-sql/issues?q=milestone%3A1.4.1+</a></p><section><a id="Potentially_Breaking_Change"></a>
<h3>Potentially Breaking Change</h3>
<p>In this release we have changed the default behavior of the library in one key area. If a where clause is coded,
but fails to render because all the optional conditionals drop out of the where clause, then the library will now
throw a <code>NonRenderingWhereClauseException</code>. We have made this change out of an abundance of caution. The prior
behavior would allow generation of statements that inadvertently affected all rows in a table.</p>
<p>We have also deprecated the “empty callback” functions in the “in” conditions in favor of this new configuration
strategy. The “empty callback” methods were effective for “in” conditions that failed to render, but they offered
no help for other conditions that failed to render, or if all conditions fail to render - which is arguably a more
dangerous outcome. If you were using any of these methods, you should remove the calls to those methods and catch the
new <code>NonRenderingWhereClauseException</code>.</p>
<p>If you desire the prior behavior where non rendering where clauses are allowed, you can change the global configuration
of the library or - even better - change the configuration of individual statements where this behavior should be allowed.</p>
<p>For examples of global and statement configuration, see the “Configuration of the Library” page.</p></section><section><a id="Other_Changes_2"></a>
<h3>Other Changes</h3>
<ol style="list-style-type: decimal;">
<li>Added support for criteria groups without an initial criteria. This makes it possible to create an independent list
of pre-created criteria and then add the list to a where clause. See the tests in the related pull request for
usage examples. (<a href="https://github.com/mybatis/mybatis-dynamic-sql/pull/462" class="externalLink">#462</a>)</li>
<li>Added the ability to specify a table alias on DELETE and UPDATE statements.
This is especially useful when working with a sub-query with an exists or not exists condition.
(<a href="https://github.com/mybatis/mybatis-dynamic-sql/pull/489" class="externalLink">#489</a>)</li>
<li>Updated the Kotlin DSL to use Kotlin 1.7's new “definitely non-null” types where appropriate. This helps us to more
accurately represent the nullable/non-nullable expectations for API method calls.
(<a href="https://github.com/mybatis/mybatis-dynamic-sql/pull/496" class="externalLink">#496</a>)</li>
<li>Added the ability to configure the library and change some default behaviors. Currently, this is limited to changing
the behavior of the library in regard to where clauses that will not render. See the “Configuration of the Library”
page for details. (<a href="https://github.com/mybatis/mybatis-dynamic-sql/pull/515" class="externalLink">#515</a>)</li>
<li>Added several checks for invalid SQL (<a href="https://github.com/mybatis/mybatis-dynamic-sql/pull/516" class="externalLink">#516</a>)</li>
<li>Added documentation for the various exceptions thrown by the library (<a href="https://github.com/mybatis/mybatis-dynamic-sql/pull/517" class="externalLink">#517</a>)</li>
<li>Update the “insertSelect” method in the Kotlin DSL to make it consistent with the other insert methods (<a href="https://github.com/mybatis/mybatis-dynamic-sql/pull/524" class="externalLink">#524</a>)</li>
</ol></section></section><section><a id="Release_1.4.0_-_March_3.2C_2022"></a>
<h2>Release 1.4.0 - March 3, 2022</h2>
<p>The release includes new functionality in the Where Clause DSL to support arbitrary grouping of conditions, and also use
of a “not” condition. It should now be possible to write any type of where clause.</p>
<p>Additionally, there were significant updates to the Kotlin DSL - both to support the new functionality in the
where clause, and significant updates to insert statements. There were also many minor updates in Kotlin
to make more use of Kotlin language features like infix functions and operator overloads.</p>
<p>GitHub milestone: <a href="https://github.com/mybatis/mybatis-dynamic-sql/issues?q=milestone%3A1.4.0+" class="externalLink">https://github.com/mybatis/mybatis-dynamic-sql/issues?q=milestone%3A1.4.0+</a></p>
<ol style="list-style-type: decimal;">
<li>Added support for arbitrary placement of nested criteria. For example, it is now
possible to write a where clause like this: <code>where (a < 5 and B = 3) and ((C = 4 or D = 5) and E = 6)</code>. Previously
we did not support the grouping of criteria at the beginning of a where clause or the beginning of an and/or
condition. Adding this support required significant refactoring, but that should be transparent to most users.
(<a href="https://github.com/mybatis/mybatis-dynamic-sql/pull/434" class="externalLink">#434</a>)</li>
<li>Remove deprecated “when” and “then” methods on all conditions. The methods have been replaced by more appropriately
named “filter” and “map” methods that function as expected for method chaining.
(<a href="https://github.com/mybatis/mybatis-dynamic-sql/pull/435" class="externalLink">#435</a>)</li>
<li>Added support for a “not” criteria grouping on a where clause. It is now possible to write a where clause like
<code>where (a < 5 and B = 3) and (not (C = 4 or D = 5) and E = 6)</code>. With this enhancement (and the enhancement for
arbitrary grouping) it should now be possible to write virtually any where clause imaginable.
(<a href="https://github.com/mybatis/mybatis-dynamic-sql/pull/438" class="externalLink">#438</a>)</li>
<li>Major update to the Kotlin where clause DSL. Where clauses now support the “group” and “not” features from above. In
addition, the where clause DSL has been fully updated to make it feel more like natural SQL. The previous version
of the where clause DSL would have yielded almost unreadable code had the “group” and “not” functions been added.
This update is better all around and yields a DSL that is very similar to native SQL. The new DSL includes many
Kotlin DSL construction features including infix functions, operator overloads, and functions with receivers.
We believe it will be well worth the effort to migrate to the new DSL. The prior where clause DSL remains in the
library for now, but is deprecated. It will be removed in version 1.5.0 of the library. Documentation for the new
DSL is here: <a href="https://github.com/mybatis/mybatis-dynamic-sql/blob/master/src/site/markdown/docs/kotlinWhereClauses.md" class="externalLink">https://github.com/mybatis/mybatis-dynamic-sql/blob/master/src/site/markdown/docs/kotlinWhereClauses.md</a>
(<a href="https://github.com/mybatis/mybatis-dynamic-sql/pull/442" class="externalLink">#442</a>)</li>
<li>General cleanup of the Kotlin DSL. The Kotlin DSL functions are now mostly Unit functions. This should have
no impact on most users and is source code compatible with prior versions of the library when the library was used
as described in the documentation. This change greatly simplifies the type hierarchy of the Kotlin builders.
(<a href="https://github.com/mybatis/mybatis-dynamic-sql/pull/446" class="externalLink">#446</a>)</li>
<li>Minor update the Kotlin join DSL to make it closer to natural SQL. The existing join methods are deprecated and
will be removed in version 1.5.0. (<a href="https://github.com/mybatis/mybatis-dynamic-sql/pull/447" class="externalLink">#447</a>)</li>
<li>Updated most of the Kotlin insert DSL functions to be more like natural SQL. The main difference is that for insert,
insertBatch, and insertMultiple, the “into” function is moved inside the completer lambda. The old methods are now
deprecated and will be removed in version 1.5.0 of the library. This also allowed us to make some insert DSL
methods into infix functions. (<a href="https://github.com/mybatis/mybatis-dynamic-sql/pull/452" class="externalLink">#452</a>)</li>
<li>Updated the where clause to expose table aliases specified in an outer query to sub queries in the where clause
(either an “exists” clause, or a sub query to column comparison condition) This makes it easier to use these types
of sub queries without having to re-specify the aliases for columns from the outer query.
(<a href="https://github.com/mybatis/mybatis-dynamic-sql/pull/459" class="externalLink">#459</a>)</li>
</ol></section><section><a id="Release_1.3.1_-_December_18.2C_2021"></a>
<h2>Release 1.3.1 - December 18, 2021</h2>
<p>This is a minor release with a few small enhancements. Most deprecated methods will be removed in the next release.</p>
<p>GitHub milestone: <a href="https://github.com/mybatis/mybatis-dynamic-sql/issues?q=milestone%3A1.3.1+" class="externalLink">https://github.com/mybatis/mybatis-dynamic-sql/issues?q=milestone%3A1.3.1+</a></p><section><a id="Added"></a>
<h3>Added</h3>
<ul>
<li>Added the ability to specify a JavaType associated with a column. The JavaType will be rendered properly for MyBatis (<a href="https://github.com/mybatis/mybatis-dynamic-sql/pull/386" class="externalLink">#386</a>)</li>
<li>Added a few missing groupBy and orderBy methods on the <code>select</code> statement (<a href="https://github.com/mybatis/mybatis-dynamic-sql/pull/409" class="externalLink">#409</a>)</li>
<li>Added a check for when a table alias is re-used in error (typically in a self-join) (<a href="https://github.com/mybatis/mybatis-dynamic-sql/pull/425" class="externalLink">#425</a>)</li>
<li>Added a new extension of SqlTable that supports setting a table alias directly within the table definition (<a href="https://github.com/mybatis/mybatis-dynamic-sql/pull/426" class="externalLink">#426</a>)</li>
</ul></section></section><section><a id="Release_1.3.0_-_May_6.2C_2021"></a>
<h2>Release 1.3.0 - May 6, 2021</h2>
<p>GitHub milestone: <a href="https://github.com/mybatis/mybatis-dynamic-sql/issues?q=milestone%3A1.3.0+" class="externalLink">https://github.com/mybatis/mybatis-dynamic-sql/issues?q=milestone%3A1.3.0+</a></p><section><a id="Release_Themes"></a>
<h3>Release Themes</h3>
<p>The major themes of this release include the following:</p>
<ol style="list-style-type: decimal;">
<li>Add support for subqueries in select statements - both in a from clause and a join clause.</li>
<li>Add support for the “exists” and “not exists” operator. This will work in “where” clauses anywhere
they are supported.</li>
<li>Refactor and improve the built-in conditions for consistency (see below). There is one breaking change also
detailed below.</li>
<li>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.</li>
<li>Remove deprecated code from prior releases.</li>
</ol></section><section><a id="Built-In_Condition_Refactoring_and_Breaking_Change"></a>
<h3>Built-In Condition Refactoring and Breaking Change</h3>
<p>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.</p>
<ol style="list-style-type: decimal;">
<li>
<p>Internally, the conditions no longer hold value Suppliers, they now hold the values themselves. The SqlBuilder
methods that accept Suppliers will call the <code>Supplier.get()</code> method when the condition is constructed. This should
have no impact unless you were somehow relying on the delay in obtaining a value until the condition was rendered.</p></li>
<li>
<p>The existing “then” and “when” methods have been deprecated and replaced with “map” and “filter” respectively.
The new method names are more familiar and more representative of what these methods actually do. In effect
these methods mimic the function of the “map” and “filter” methods on “java.util.Optional” and they are used
for a similar purpose.</p></li>
<li>
<p>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. This allows you to construct map/filter pipelines as you would
expect.</p></li>
<li>
<p>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.</p></li>
<li>
<p>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.</p></li>
<li>
<p>One <strong>breaking change</strong> 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</p>
<pre><code class="language-java"> public static IsIn<String> isIn(String...values) {
return new IsIn.Builder<String>()
.withValues(Arrays.asList(values))
.withValueStreamTransformer(s -> s.filter(Objects::nonNull)
.map(String::trim)
.filter(st -> !st.isEmpty()))
.build();
}
</code></pre>
<p>New code should look like this:</p>
<pre><code class="language-java"> public static IsIn<String> isIn(String...values) {
return SqlBuilder.isIn(values)
.filter(Objects::nonNull)
.map(String::trim)
.filter(st -> !st.isEmpty());
}
</code></pre>
<p>We think this is a marked improvement!</p></li>
</ol></section><section><a id="Kotlin_DSL_Update_and_Breaking_Change_for_Kotlin"></a>
<h3>Kotlin DSL Update and Breaking Change for Kotlin</h3>
<p>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 <code>org.mybatis.dynamic.sql.SqlBuilder</code>. The advantages of this are many and are detailed on the
Kotlin overview page in the documentation. Many functions in <code>SqlBuilder</code> have been replaced by
top level functions the <code>org.mybatis.dynamic.sql.util.kotlin.elements</code> 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 <code>isEqualTo</code>
function by changing</p>
<pre><code class="language-kotlin">import org.mybatis.dynamic.sql.SqlBuilder.isEqualTo
</code></pre>
<p>to</p>
<pre><code class="language-kotlin">import org.mybatis.dynamic.sql.util.kotlin.elements.isEqualTo
</code></pre>
<p>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.</p>
<p>A <strong>breaking change</strong> is that Kotlin support for <code>select</code> and <code>count</code> 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 <code>from</code> clause has been moved inside the lambda for select
and count statements.</p>
<p>Previously, code looked like this:</p>
<pre><code class="language-kotlin"> val selectStatement = select(foo).from(bar) {
where(id, isLessThan(3))
}
</code></pre>
<p>The new code looks like this:</p>
<pre><code class="language-kotlin"> val selectStatement = select(foo) {
from(bar)
where(id, isLessThan(3))
}
</code></pre>
<p>This change makes the Kotlin DSL more consistent and also makes it easier to implement subquery support in the
Kotlin DSL.</p></section><section><a id="Added_1"></a>
<h3>Added</h3>
<ul>
<li>Added a new sort specification that is useful in selects with joins (<a href="https://github.com/mybatis/mybatis-dynamic-sql/pull/269" class="externalLink">#269</a>)</li>
<li>Added the capability to generate a camel cased alias for a column (<a href="https://github.com/mybatis/mybatis-dynamic-sql/issues/272" class="externalLink">#272</a>)</li>
<li>Added subquery support for “from” clauses in a select statement (<a href="https://github.com/mybatis/mybatis-dynamic-sql/pull/282" class="externalLink">#282</a>)</li>
<li>Added Kotlin DSL updates to support sub-queries in select statements, where clauses, and insert statements (<a href="https://github.com/mybatis/mybatis-dynamic-sql/pull/282" class="externalLink">#282</a>)</li>
<li>Added subquery support for “join” clauses in a select statement (<a href="https://github.com/mybatis/mybatis-dynamic-sql/pull/293" class="externalLink">#293</a>)</li>
<li>Added support for the “exists” and “not exists” operator in where clauses (<a href="https://github.com/mybatis/mybatis-dynamic-sql/pull/296" class="externalLink">#296</a>)</li>
<li>Refactored the built-in conditions (<a href="https://github.com/mybatis/mybatis-dynamic-sql/pull/331" class="externalLink">#331</a>) (<a href="https://github.com/mybatis/mybatis-dynamic-sql/pull/336" class="externalLink">#336</a>)</li>
<li>Added composition functions for WhereApplier (<a href="https://github.com/mybatis/mybatis-dynamic-sql/pull/335" class="externalLink">#335</a>)</li>
<li>Added a mapping for general insert and update statements that will render null values as “null” in the SQL (<a href="https://github.com/mybatis/mybatis-dynamic-sql/pull/343" class="externalLink">#343</a>)</li>
<li>Allow the “in when present” conditions to accept a null Collection as a parameter (<a href="https://github.com/mybatis/mybatis-dynamic-sql/pull/346" class="externalLink">#346</a>)</li>
<li>Add Better Support for MyBatis Multi-Row Inserts that Return Generated Keys (<a href="https://github.com/mybatis/mybatis-dynamic-sql/pull/349" class="externalLink">#349</a>)</li>
<li>Major improvement to the Kotlin DSL (<a href="https://github.com/mybatis/mybatis-dynamic-sql/pull/353" class="externalLink">#353</a>)</li>
<li>Remove use of “record” as an identifier (it is restricted in JDK16) (<a href="https://github.com/mybatis/mybatis-dynamic-sql/pull/357" class="externalLink">#357</a>)</li>
</ul></section></section><section><a id="Release_1.2.1_-_September_29.2C_2020"></a>
<h2>Release 1.2.1 - September 29, 2020</h2>
<p>GitHub milestone: <a href="https://github.com/mybatis/mybatis-dynamic-sql/issues?q=milestone%3A1.2.1+" class="externalLink">https://github.com/mybatis/mybatis-dynamic-sql/issues?q=milestone%3A1.2.1+</a></p><section><a id="Fixed"></a>
<h3>Fixed</h3>
<ul>
<li>Fixed a bug where the In conditions could render incorrectly in certain circumstances. (<a href="https://github.com/mybatis/mybatis-dynamic-sql/issues/239" class="externalLink">#239</a>)</li>
</ul></section><section><a id="Added_2"></a>
<h3>Added</h3>
<ul>
<li>Added a callback capability to the “In” conditions that will be called before rendering when the conditions are empty. Also, removed the option that forced the library to render invalid SQL in that case. (<a href="https://github.com/mybatis/mybatis-dynamic-sql/pull/241" class="externalLink">#241</a>)</li>
<li>Added a utility mapper for MyBatis that allows you to run any select query without having to predefine a result mapping. (<a href="https://github.com/mybatis/mybatis-dynamic-sql/pull/255" class="externalLink">#255</a>)</li>
<li>Added utility mappers for MyBatis that allow you to run generic CRUD operations. (<a href="https://github.com/mybatis/mybatis-dynamic-sql/pull/263" class="externalLink">#263</a>)</li>
</ul></section></section><section><a id="Release_1.2.0_-_August_19.2C_2020"></a>
<h2>Release 1.2.0 - August 19, 2020</h2>
<p>GitHub milestone: <a href="https://github.com/mybatis/mybatis-dynamic-sql/issues?q=milestone%3A1.2.0+" class="externalLink">https://github.com/mybatis/mybatis-dynamic-sql/issues?q=milestone%3A1.2.0+</a></p><section><a id="General_Announcements"></a>
<h3>General Announcements</h3>
<p>This release includes major improvements to the Spring support in the library. Spring support is now functionally equivalent to MyBatis support.</p>
<p>This release includes a significant refactoring of the classes in the “org.mybatis.dynamic.sql.select.function” package. The new classes are more consistent and flexible and should be compatible with existing code at the source level (meaning code should be recompiled for the new version of the library). If you have written your own set of functions to extend the library, you will notice that the base classes 'AbstractFunction" and “AbstractMultipleColumnArithmeticFunction” are now deprecated. Their replacement classes are “AbstractUniTypeFunction” and “OperatorFunction” respectively.</p>
<p>With this release, we deprecated several insert methods because they were inconsistently named or awkward. All deprecated methods have documented direct replacements.</p>
<p>All deprecated code will be removed in the next minor release.</p></section><section><a id="Added_3"></a>
<h3>Added</h3>
<ul>
<li>Added a general insert statement that does not require a separate record class to hold values for the insert. (<a href="https://github.com/mybatis/mybatis-dynamic-sql/issues/201" class="externalLink">#201</a>)</li>
<li>Added the capability to specify a rendering strategy on a column to override the default rendering strategy for a statement. This will allow certain edge cases where a parameter marker needs to be formatted uniquely (for example, “::jsonb” needs to be added to parameter markers for JSON fields in PostgreSQL) (<a href="https://github.com/mybatis/mybatis-dynamic-sql/issues/200" class="externalLink">#200</a>)</li>
<li>Added the ability to write a function that will change the column data type (<a href="https://github.com/mybatis/mybatis-dynamic-sql/issues/197" class="externalLink">#197</a>)</li>
<li>Added the <code>applyOperator</code> function to make it easy to use non-standard database operators in expressions (<a href="https://github.com/mybatis/mybatis-dynamic-sql/issues/220" class="externalLink">#220</a>)</li>
<li>Added convenience methods for count(column) and count(distinct column) (<a href="https://github.com/mybatis/mybatis-dynamic-sql/issues/221" class="externalLink">#221</a>)</li>
<li>Added support for union queries in Kotlin (<a href="https://github.com/mybatis/mybatis-dynamic-sql/issues/187" class="externalLink">#187</a>)</li>
<li>Added the ability to write “in” conditions that will render even if empty (<a href="https://github.com/mybatis/mybatis-dynamic-sql/issues/228" class="externalLink">#228</a>)</li>
<li>Many enhancements for Spring including:
<ul>
<li>Fixed a bug where multi-row insert statements did not render properly for Spring (<a href="https://github.com/mybatis/mybatis-dynamic-sql/issues/224" class="externalLink">#224</a>)</li>
<li>Added support for a parameter type converter for use cases where the Java type of a column does not match the database column type (<a href="https://github.com/mybatis/mybatis-dynamic-sql/issues/131" class="externalLink">#131</a>)</li>
<li>Added a utility class which simplifies the use of the named parameter JDBC template for Java code - <code>org.mybatis.dynamic.sql.util.spring.NamedParameterJdbcTemplateExtensions</code></li>
<li>Added support for general inserts, multi-row inserts, batch inserts in the Kotlin DSL for Spring (<a href="https://github.com/mybatis/mybatis-dynamic-sql/issues/225" class="externalLink">#225</a>)</li>
<li>Added support for generated keys in the Kotlin DSL for Spring (<a href="https://github.com/mybatis/mybatis-dynamic-sql/issues/226" class="externalLink">#226</a>)</li>
</ul></li>
</ul></section></section><section><a id="Release_1.1.4_-_November_23.2C_2019"></a>
<h2>Release 1.1.4 - November 23, 2019</h2>
<p>GitHub milestone: <a href="https://github.com/mybatis/mybatis-dynamic-sql/issues?q=milestone%3A1.1.4+" class="externalLink">https://github.com/mybatis/mybatis-dynamic-sql/issues?q=milestone%3A1.1.4+</a></p><section><a id="Added_4"></a>
<h3>Added</h3>
<ul>
<li>Added support for reusing WHERE clauses among count, delete, select, and update statements (<a href="https://github.com/mybatis/mybatis-dynamic-sql/pull/152" class="externalLink">#152</a>)</li>
<li>Improved Kotlin support. Previously, several overloaded methods could collide causing queries to be fragile and very dependent on having the correct imports in a Kotlin file. With this improved support there is no longer any ambiguity. (<a href="https://github.com/mybatis/mybatis-dynamic-sql/pull/154" class="externalLink">#154</a>)</li>
</ul></section><section><a id="Bugs_Fixed"></a>
<h3>Bugs Fixed</h3>
<ul>
<li>Fixed issue where limit and offset in sub-queries could cause a parameter name collision (<a href="https://github.com/mybatis/mybatis-dynamic-sql/pull/142" class="externalLink">#142</a>)</li>
</ul></section></section><section><a id="Release_1.1.3_-_September_16.2C_2019"></a>
<h2>Release 1.1.3 - September 16, 2019</h2>
<p>GitHub milestone: <a href="https://github.com/mybatis/mybatis-dynamic-sql/issues?q=milestone%3A1.1.3+" class="externalLink">https://github.com/mybatis/mybatis-dynamic-sql/issues?q=milestone%3A1.1.3+</a></p><section><a id="Added_5"></a>
<h3>Added</h3>
<ul>
<li>Added support for <code>count(distinct ...)</code> (<a href="https://github.com/mybatis/mybatis-dynamic-sql/issues/112" class="externalLink">#112</a>)</li>
<li>Added support for multiple row inserts (<a href="https://github.com/mybatis/mybatis-dynamic-sql/issues/116" class="externalLink">#116</a>)</li>
<li>Utility classes and a new canonical pattern for MyBatis Generator (CRUD) mappers (<a href="https://github.com/mybatis/mybatis-dynamic-sql/issues/118" class="externalLink">#118</a>) (<a href="https://github.com/mybatis/mybatis-dynamic-sql/pull/125" class="externalLink">#125</a>) (<a href="https://github.com/mybatis/mybatis-dynamic-sql/pull/128" class="externalLink">#128</a>)</li>
<li>Kotlin Extensions and Kotlin DSL (<a href="https://github.com/mybatis/mybatis-dynamic-sql/pull/133" class="externalLink">#133</a>) (<a href="https://github.com/mybatis/mybatis-dynamic-sql/pull/139" class="externalLink">#139</a>)</li>
</ul></section></section><section><a id="Release_1.1.2_-_July_5.2C_2019"></a>
<h2>Release 1.1.2 - July 5, 2019</h2>
<p>GitHub milestone: <a href="https://github.com/mybatis/mybatis-dynamic-sql/issues?q=milestone%3A1.1.2+" class="externalLink">https://github.com/mybatis/mybatis-dynamic-sql/issues?q=milestone%3A1.1.2+</a></p><section><a id="Added_6"></a>
<h3>Added</h3>
<ul>
<li>Changed the public SQLBuilder API to accept Collection instead of List for in conditions and batch record inserts. This should have no impact on existing code, but allow for some future flexibility (<a href="https://github.com/mybatis/mybatis-dynamic-sql/pull/88" class="externalLink">#88</a>)</li>
<li>Added the ability to have table catalog and/or schema calculated at runtime. This is useful for situations where there are different database schemas for different environments, or in some sharding situations (<a href="https://github.com/mybatis/mybatis-dynamic-sql/pull/92" class="externalLink">#92</a>)</li>
<li>Add support for paging queries with “offset” and “fetch first” - this seems to be standard on most databases (<a href="https://github.com/mybatis/mybatis-dynamic-sql/pull/96" class="externalLink">#96</a>)</li>
<li>Added the ability to call a builder method on any intermediate object in a select statement and receive a fully rendered statement. This makes it easier to build very dynamic queries (<a href="https://github.com/mybatis/mybatis-dynamic-sql/pull/106" class="externalLink">#106</a>)</li>
<li>Add the ability to modify values on any condition before they are placed in the parameter map (<a href="https://github.com/mybatis/mybatis-dynamic-sql/issues/105" class="externalLink">#105</a>)</li>
<li>Add the ability to call <code>where()</code> with no parameters. This aids in constructing very dynamic queries (<a href="https://github.com/mybatis/mybatis-dynamic-sql/issues/107" class="externalLink">#107</a>)</li>
</ul></section></section><section><a id="Release_1.1.1_-_April_7.2C_2019"></a>
<h2>Release 1.1.1 - April 7, 2019</h2>
<p>GitHub milestone: <a href="https://github.com/mybatis/mybatis-dynamic-sql/issues?q=milestone%3A1.1.1+" class="externalLink">https://github.com/mybatis/mybatis-dynamic-sql/issues?q=milestone%3A1.1.1+</a></p><section><a id="Added_7"></a>
<h3>Added</h3>
<ul>
<li>Limit and offset support in the select statement</li>
<li>Utilities for Spring Batch</li>
<li>All conditions now support conditional rendering with lambdas</li>
<li>Select * support</li>
<li>Union all support</li>
</ul></section><section><a id="Bugs_Fixed_1"></a>
<h3>Bugs Fixed</h3>
<ul>
<li>Fixed self joins</li>
</ul></section></section><section><a id="Release_1.1.0_-_April_24.2C_2018"></a>
<h2>Release 1.1.0 - April 24, 2018</h2>
<p>GitHub milestone: <a href="https://github.com/mybatis/mybatis-dynamic-sql/issues?q=milestone%3A1.1.0+" class="externalLink">https://github.com/mybatis/mybatis-dynamic-sql/issues?q=milestone%3A1.1.0+</a></p><section><a id="Added_8"></a>
<h3>Added</h3>
<ul>
<li>Support for optional conditions</li>
<li>Support for column comparison conditions</li>
<li>Support for sub-queries in the update statement</li>
<li>Support for expressions and constants in the select statement</li>
<li>Support for function in the update statement</li>
</ul></section><section><a id="Bugs_Fixed_2"></a>
<h3>Bugs Fixed</h3>
<ul>
<li>Support group by after where</li>
</ul></section></section><section><a id="Initial_Release_-_December_17.2C_2017"></a>
<h2>Initial Release - December 17, 2017</h2></section></section>
</main>
</div>
</div>
<hr/>
<footer>
<div class="container-fluid">
<div class="row-fluid">
<p>© 2016–2024
<a href="https://www.mybatis.org/">MyBatis.org</a>
</p>
</div>
</div>
</footer>
<script>
if(anchors) {
anchors.add();
}
</script>
</body>
</html>