-
Notifications
You must be signed in to change notification settings - Fork 4
/
KotlinExample.kt
395 lines (361 loc) · 13.5 KB
/
KotlinExample.kt
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
package com.mybatisflex.kotlin.example
import com.mybatisflex.core.activerecord.Model
import com.mybatisflex.core.audit.AuditManager
import com.mybatisflex.core.audit.ConsoleMessageCollector
import com.mybatisflex.core.query.QueryColumn
import com.mybatisflex.core.query.QueryWrapper
import com.mybatisflex.kotlin.example.entity.Account
import com.mybatisflex.kotlin.example.mapper.AccountMapper
import com.mybatisflex.kotlin.extensions.condition.allAnd
import com.mybatisflex.kotlin.extensions.condition.and
import com.mybatisflex.kotlin.extensions.condition.or
import com.mybatisflex.kotlin.extensions.db.*
import com.mybatisflex.kotlin.extensions.kproperty.*
import com.mybatisflex.kotlin.extensions.mapper.*
import com.mybatisflex.kotlin.extensions.model.batchDeleteById
import com.mybatisflex.kotlin.extensions.model.batchInsert
import com.mybatisflex.kotlin.extensions.model.batchUpdateById
import com.mybatisflex.kotlin.extensions.sql.`in`
import com.mybatisflex.kotlin.extensions.sql.like
import com.mybatisflex.kotlin.extensions.wrapper.*
import com.mybatisflex.kotlin.scope.queryScope
import com.mybatisflex.kotlin.scope.runFlex
import com.mybatisflex.kotlin.scope.selectQueryColumn
import org.apache.ibatis.logging.stdout.StdOutImpl
import org.junit.jupiter.api.Test
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType
import java.time.Instant
import java.util.*
import javax.sql.DataSource
import kotlin.streams.toList
class KotlinExample {
private val dataSource: DataSource = EmbeddedDatabaseBuilder().run {
setType(EmbeddedDatabaseType.H2)
addScript("schema.sql")
addScript("data-kt.sql")
build()
}
private val start: Date = Date.from(Instant.parse("2020-01-10T00:00:00Z"))
private val end: Date = Date.from(Instant.parse("2020-01-12T00:00:00Z"))
init {
runFlex {
// 此方法体 it 是 MybatisFlexBootstrap 实例
// 配置Mapper
// 1.通过+(重写自增)的方式
+AccountMapper::class
// 2.通过原始的方式
// it.addMapper(AccountMapper::class.java)
// 3.通过扫描包路径自动注册
// 接口需要继承BaseMapper或打上@Mapper注解, 开启@Mapper注解扫描需要修改第二个参数(needScanAnnotated)为true
// scanPackages("com.mybatisflex.kotlin.example.mapper")
// 配置单dataSource
// 1.通过+(重写自增)的方式
+dataSource
// 2.通过原始的方式
// it.setDataSource(dataSource)
// 3.通过dsl的方式配置简易的内置数据源
// defaultPooledDataSources {
// driver可以不写,默认为第一个注册的驱动
// driver = com.mysql.cj.jdbc.Driver::class
// url = "xxx"
// username = "xxx"
// password = "xxx"
// }
// 配置多dataSource
// 1.通过of(中缀)的方式
// FlexConsts.NAME of dataSource
// "dataSource1" of dataSource
// "dataSource2" of dataSource
// 2.通过dsl的方式配置简易的内置数据源
// defaultPooledDataSources("name") {
// driver可以不写,默认为第一个注册的驱动
// driver = com.mysql.cj.jdbc.Driver::class
// url = "xxx"
// username = "xxx"
// password = "xxx"
// }
// 3.通过原始的方式
// it.addDataSource(FlexConsts.NAME, dataSource)
// 配置日志打印在控制台
logImpl = StdOutImpl::class
}
// 开启sql审计,设置为打印在控制台
AuditManager.setAuditEnable(true)
AuditManager.setMessageCollector(ConsoleMessageCollector())
}
/**
* 对比原生
*/
@Test
fun contrastOriginal() {
// 【原生】
val queryWrapper = QueryWrapper.create()
.select(QueryColumn("id"), QueryColumn("user_name"))
.where(QueryColumn("age").isNotNull()).and(QueryColumn("age").ge(17))
.orderBy(QueryColumn("id").desc())
mapper<AccountMapper>().selectListByQuery(queryWrapper)
// 【扩展后】
// 无需注册Mapper与APT/KSP即可查询操作
query<Account> {
select(Account::id, Account::userName)
where(Account::age.isNotNull) and { Account::age ge 17 } orderBy -Account::id
}
}
/**
* all: 查泛型对应的表的所有数据
*/
@Test
fun testAll() {
val accounts: List<Account> = all()
accounts.forEach(::println)
// 或者 Account::class.all.forEach(::println) (需要注册Mapper接口)
}
@Test
fun testInsert() {
save<Account> {
id = 3
userName = "kamo"
age = 20
birthday = Date()
}
// insert(Account(3, "kamo", 20, Date()))
// Account::class.baseMapper.insert(Account(3, "kamo", 20, Date()))
filterOne<Account> { Account::id eq 3 }?.also(::println)
}
@Test
fun testUpdate() {
// 通过条件查询到后更新(此时会执行两次sql)
filterOne<Account> { Account::id eq 2 }?.apply { age = 20 }?.update {
Account::userName eq it.userName and (Account::age le 18)
}
// 通过id更新
// filterOne<Account> { Account::id eq 2 }?.apply { age = 20 }?.updateById()
filterOne<Account> { Account::id eq 2 }?.also(::println)
}
@Test
fun testUpdate2() {
println("更新前: ${all<Account>().first()}")
update<Account> {
Account::id set Account::id + 2
Account::birthday setRaw Account::birthday
// Account::age setRaw {
// select(Account::age)
// from(Account::class)
// where(Account::age `in` (19..20))
// }
// 或者写成:
Account::age.setRaw(Account::age) {
where(Account::age `in` (19..20))
}
whereWith { Account::id eq 1 and (Account::userName eq "张三") }
}
// SQL:
// UPDATE `tb_account`
// SET `id` = `id` + 2 ,
// `birthday` = `birthday`
// `age` = (
// SELECT `age` FROM `tb_account`
// WHERE `age` BETWEEN 19 AND 20 LIMIT 1
// )
// WHERE `id` = 1 AND `user_name` = '张三'
println("更新后: ${all<Account>().first()}")
}
@Test
fun testDelete() {
// 根据返回的条件删除
deleteWith<Account> { Account::id eq 2 }
// 根据主键删除
deleteById<Account>(2)
// 通过map的key对应的字段比较删除
deleteByMap(Account::id to 2)
// 根据aseMapper删除 (需要注册Mapper接口))
// mapper<AccountMapper>().deleteByCondition { Account::id eq 2 }
// 根据Model的id删除 (需要注册Mapper接口))
// Account(id = 2).removeById()
all<Account>().forEach(::println)
}
/**
* filter: 按条件查泛型对应的表的数据
*/
@Test
fun testFilter() {
val accounts: List<Account> = filter {
allAnd(
Account::id.isNotNull,
(Account::id to Account::userName to Account::age).inTriple(
1 to "张三" to 18,
2 to "李四" to 19
),
Account::age.`in`(17..19)
) or { Account::birthday between (start to end) }
}
accounts.forEach(::println)
}
/**
* filter: 按条件查泛型对应的表的一条数据
*/
@Test
fun testFilterOne() {
val account: Account? = filterOne(Account::age) {
allAnd(
Account::id.isNotNull,
(Account::id to Account::userName to Account::age).inTriple(
1 to "张三" to 18,
2 to "李四" to 19
),
Account::age.`in`(17..19)
) or { Account::birthday between (start to end) }
}
println(account)
}
/**
* query: 较复杂查泛型对应的表的数据,如分组排序等
*/
@Test
fun testQuery() {
val accounts: List<Account> = query {
selectFrom(Account::id, Account::userName)
whereWith {
Account::age `in` (17..19) and (Account::birthday between (start to end))
} orderBy -Account::id
limit(2)
}
accounts.forEach(::println)
}
@Test
fun testDb() {
// 查询表对象对应的实体数据并根据条件过滤
filter<Account> {
(Account::age eq 12)
// or第一个参数为true时则会调用花括号类的方法返回一个条件对象与上面那个条件对象相连接
.or(true) { Account::id between (1 to 2) }
// 可以用以下方法替代
// or(`if`(true) { Account::id between (1 to 2 })
}.stream().peek(::println)
// 过滤后修改id再次保存
.peek { it.id = it.id.plus(2) }.forEach(Model<*>::save)
println("保存后————————")
// 获得mapper实例通过自定义的默认方法查,并将查到的删除
mapper<AccountMapper>().findByAge(18, 1).stream().peek { println(it) }.forEach { it.removeById() }
println("删除后————————")
all<Account>().stream().peek { println(it) }.map {
it.userName = "kamo"
it
}.forEach { it.updateById() }
println("更新后————————")
all<Account>().stream().peek { println(it) }.map {
it.id = it.id.plus(5)
it.userName = "akino"
it
}.toList().batchInsert()
println("批量插入后————————")
all<Account>().stream().peek { println(it) }.toList().filter { it.id.rem(2) == 0 }.batchDeleteById()
println("批量删除后————————")
// 直接使用函数查询时需指定from表
query<Account> { from(Account::class) }.stream().peek { println(it) }.toList().filter { it.id.rem(3) == 0 }
.map {
it.userName = "cloud-player"
it
}.batchUpdateById()
println("批量更新后————————")
all<Account>().forEach(::println)
}
@Test
fun testPaginate() {
paginate<Account>(1, 10) {
select(Account::id, Account::userName)
orderBy(-Account::id)
}.let {
println("${it.pageNumber} - ${it.pageSize} - ${it.totalRow}")
it.records.forEach(::println)
}
// paginateWith<Account>(1, 10) {
// Account::id between (1 to 2)
// }.let {
// println("pageNumber: ${it.pageNumber} - pageSize: ${it.pageSize} - totalRow: ${it.totalRow}")
// it.records.forEach(::println)
// }
}
@Test
fun testModelQuery() {
// from AccountMapper
Account.findByAge(18, 1).forEach(::println)
// from Account
Account.findByAge2(18, 1).forEach(::println)
// from BaseMapper
Account.selectListByCondition(Account::age eq 18 and Account::id.`in`(1)).forEach(::println)
}
@Test
fun testAllCondition() {
query<Account> {
// andAll:
andAll(
Account::id eq 1,
Account::age eq 18,
Account::userName eq "张三",
)
// or
// (Account::id eq 1).andAll(
// Account::age eq 18,
// Account::userName eq "张三",
// )
// orAll:
// orAll(
// Account::id eq 1,
// Account::age `in` (17..20),
// Account::userName eq "张三",
// )
// or
// (Account::id eq 1).orAll(
// Account::age `in` (17..20),
// Account::userName eq "张三",
// )
}.also { println(it) }
}
/**
* 两个表起别名后关联查询与in子查询条件演示
* @since 1.1.0
*/
@Test
fun relatedQueries() {
val sql = queryScope {
val aT = Account::class.queryTable `as` "a"
val bT = Account::class.queryTable `as` "b"
select(aT["*"], bT[Account::userName])
from(aT).leftJoin(bT).on(Account::age, Account::age)
andAll(
bT[Account::userName] like "zs",
aT[Account::age].`in` {
select(Account::age)
from(Account::class)
}
)
}.toSQL()
println(sql)
assert(
"SELECT `a`.*, `b`.`user_name` " +
"FROM `tb_account` AS `a` LEFT JOIN `tb_account` AS `b` ON `b`.`age` = `a`.`age` " +
"WHERE `b`.`user_name` LIKE '%zs%' AND `a`.`age` IN (SELECT `age` FROM `tb_account`)"
== sql
)
}
/**
* 子查询扩展方法演示
* @since 1.1.0
*/
@Test
fun testSubQuery() {
val sql = queryScope {
select(
selectQueryColumn("id") {
select(Account::id)
from(Account::class)
}
)
from(Account::class)
}.toSQL()
assert(sql == "SELECT (SELECT `id` FROM `tb_account`) AS `id` FROM `tb_account`")
println(sql)
}
}