refactor/doc/test:引入Model重构,添加测试实例注释,添加快速开始doc

This commit is contained in:
kamosama 2023-08-12 23:18:51 +08:00
parent 45d5d92180
commit 0271234225
14 changed files with 298 additions and 228 deletions

View File

@ -0,0 +1,115 @@
# 基于 Kotlin 扩展 Mybatis-Flex
## 快速开始
在开始之前,我们假定您已经:
- 熟悉 Kotlin 环境配置及其开发
- 熟悉 关系型 数据库,比如 MySQL
- 熟悉 Kotlin 构建工具,比如 Gradle、Maven
> 当前章节涉及到的 [演示源码](https://gitee.com/mybatis-flex/mybatis-flex/tree/main/mybatis-flex-test/mybatis-flex-spring-kotlin-test) 已经全部上传
>
> 在开始之前,您也可以先下载到本地,导入到 idea 开发工具后,在继续看文档。
## 特点
- 本模块基于 Mybatis-Flex 核心库 ,只做扩展不做改变
- 结合 Kotlin 特性、DSL让数据库操作更简单
## Hello World 文档
**第 1 步:创建 Kotlin 项目,并添加 Kotlin 的扩展依赖**
>如何创建 Kotlin 项目可参考 [官方文档](https://www.kotlincn.net/docs/tutorials/jvm-get-started.html)
需要添加的主要依赖:
**【Kotlin】**
```kotlin
dependencies {
implementation("com.mybatis-flex:mybatis-flex-kotlin:1.5.7")
compileOnly("com.mybatis-flex:mybatis-flex-processor:1.5.7")
}
```
**【Maven】**
```xml
<dependency>
<groupId>com.mybatis-flex</groupId>
<artifactId>mybatis-flex-kotlin</artifactId>
<version>${mybatis-flex.version}</version>
</dependency>
```
**第 2 步:创建数据库表与配置数据源**
> 请参考 [快速开始](../intro/getting-started.md) 创建数据库表与配置数据源,
> 或者使用演示源码中的内嵌数据库快速体验
**第 3 步:编写实体类**
```kotlin
@Table("tb_account")
class Account {
@Id
var id: Long
var userName: String
var age: Integer
var birthday: Date
}
```
- 使用 `@Table("tb_account")` 设置实体类与表名的映射关系
- 使用 `@Id` 标识主键
**第 4 步:开始使用**
添加测试类,进行功能测试:
```kotlin
fun main() {
//加载数据源(为了方便演示这里使用了演示源码中的内嵌数据源)
val dataSource: DataSource = EmbeddedDatabaseBuilder()
.setType(EmbeddedDatabaseType.H2)
.addScript("schema.sql")
.addScript("data-kt.sql")
.build()
//启动并配入数据源
buildBootstrap { +dataSource }.start()
//条件过滤查询并打印
filter<Account> {
ACCOUNT.ID `=` 1 and
(ACCOUNT.AGE `in` listOf(18,19) or (ACCOUNT.BIRTHDAY between ("2020-01-10" to "2020-01-12")) )
}.forEach(::println)
//查询全部数据并打印
//ACCOUNT.all<Account>().forEach(::println)
}
```
执行的SQL
```sql
SELECT * FROM `tb_account` WHERE`id` = 1 AND (`age` IN (18, 19) OR `birthday`BETWEEN '2020-01-10' AND '2020-01-12' )
```
控制台输出:
```txt
Account(id=1, userName=张三, age=18, birthday=Sat Jan 11 00:00:00 CST 2020)
```
> 以上的示例中, `ACCOUNT` 为 MyBatis-Flex 通过 APT
> 自动生成,只需通过静态导入即可,无需手动编码。更多查看 [在Kotlin中使用注解处理器](../others/kapt.md)
>
> 若觉得 APT 使用不习惯,也可以使用代码生成器来生成。点击 [代码生成器文档](../others/codegen.md) 了解。
## 更多使用
- 功能 1[Bootstrap简化配置]()
- 功能 2[简单查询]()
- 功能 3[表实体扩展]()
- 功能 4[SQL扩展/中缀]()
- 功能 5[Mapper扩展]()
###### TODO ...

View File

@ -1,36 +1,37 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" <project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<parent> <parent>
<groupId>com.mybatis-flex</groupId> <groupId>com.mybatis-flex</groupId>
<artifactId>parent</artifactId> <artifactId>parent</artifactId>
<version>1.5.6</version> <version>1.5.6</version>
</parent> </parent>
<artifactId>mybatis-flex-kotlin</artifactId> <artifactId>mybatis-flex-kotlin</artifactId>
<properties> <properties>
<maven.compiler.source>8</maven.compiler.source> <maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target> <maven.compiler.target>8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <kotlin.version>1.9.0</kotlin.version>
<kotlin.version>1.9.0</kotlin.version> <kotlin.compiler.incremental>true</kotlin.compiler.incremental>
</properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies> <dependencies>
<dependency> <dependency>
<groupId>com.mybatis-flex</groupId> <groupId>com.mybatis-flex</groupId>
<artifactId>mybatis-flex-core</artifactId> <artifactId>mybatis-flex-core</artifactId>
<version>${mybatis-flex.version}</version> <version>${mybatis-flex.version}</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.jetbrains.kotlin</groupId> <groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-stdlib-jdk8</artifactId> <artifactId>kotlin-stdlib-jdk8</artifactId>
<version>${kotlin.version}</version> <version>${kotlin.version}</version>
<scope>provided</scope> <scope>provided</scope>
</dependency> </dependency>
</dependencies> </dependencies>
@ -46,7 +47,6 @@
<args> <args>
<arg>-Xjvm-default=all</arg> <arg>-Xjvm-default=all</arg>
</args> </args>
<jvmTarget>1.8</jvmTarget>
</configuration> </configuration>
<executions> <executions>
<execution> <execution>

View File

@ -1,64 +0,0 @@
/*
* Copyright (c) 2022-2023, Mybatis-Flex (fuhai999@gmail.com).
* <p>
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.mybatisflex.kotlin.entry
import com.mybatisflex.core.dialect.DialectFactory
import com.mybatisflex.core.row.Db.*
import com.mybatisflex.core.table.TableInfoFactory
import com.mybatisflex.core.util.ArrayUtil
import java.io.Serializable
/**
* 实体类父类继承该类后将赋予实体简单增删改操作
* @author 卡莫sama(yuanjiashuai)
* @date 2023/8/7
*/
open class Entry :Serializable{
fun save(ignoreNulls: Boolean = true): Boolean {
val tableInfo = TableInfoFactory.ofEntityClass(this.javaClass)
//设置乐观锁版本字段的初始化数据
tableInfo.initVersionValueIfNecessary(this)
//设置租户ID
tableInfo.initTenantIdIfNecessary(this)
//设置逻辑删除字段的出初始化数据
tableInfo.initLogicDeleteValueIfNecessary(this)
//执行 onInsert 监听器
tableInfo.invokeOnInsertListener(this)
val values = tableInfo.buildInsertSqlArgs(this, ignoreNulls)
val sql = DialectFactory.getDialect().forInsertEntity(tableInfo, this, ignoreNulls)
return insertBySql(sql, *values) == 1
}
fun update(ignoreNulls: Boolean = true): Boolean {
val tableInfo = TableInfoFactory.ofEntityClass(this.javaClass)
//执行 onUpdate 监听器
tableInfo.invokeOnUpdateListener(this)
val updateValues = tableInfo.buildUpdateSqlArgs(this, ignoreNulls, false)
val primaryValues = tableInfo.buildPkSqlArgs(this)
val tenantIdArgs = tableInfo.buildTenantIdArgs()
val sql = DialectFactory.getDialect().forUpdateEntity(tableInfo, this, ignoreNulls)
return updateBySql(sql, *ArrayUtil.concat(updateValues, primaryValues, tenantIdArgs)) == 1
}
fun deleteById(): Boolean {
val tableInfo = TableInfoFactory.ofEntityClass(this.javaClass)
val primaryValues = tableInfo.buildPkSqlArgs(this)
val allValues = ArrayUtil.concat(primaryValues, tableInfo.buildTenantIdArgs())
val sql = DialectFactory.getDialect().forDeleteEntityById(tableInfo)
return deleteBySql(sql, *allValues) == 1
}
}

View File

@ -15,8 +15,7 @@
*/ */
package com.mybatisflex.kotlin.extensions.db package com.mybatisflex.kotlin.extensions.db
import com.mybatisflex.core.BaseMapper import com.mybatisflex.core.mybatis.Mappers
import com.mybatisflex.core.MybatisFlexBootstrap
import com.mybatisflex.core.query.QueryColumn import com.mybatisflex.core.query.QueryColumn
import com.mybatisflex.core.query.QueryCondition import com.mybatisflex.core.query.QueryCondition
import com.mybatisflex.core.row.Db.selectListByQuery import com.mybatisflex.core.row.Db.selectListByQuery
@ -24,22 +23,18 @@ import com.mybatisflex.core.row.Db.selectOneByQuery
import com.mybatisflex.core.row.Row import com.mybatisflex.core.row.Row
import com.mybatisflex.core.table.TableDef import com.mybatisflex.core.table.TableDef
import com.mybatisflex.core.table.TableInfoFactory import com.mybatisflex.core.table.TableInfoFactory
import com.mybatisflex.kotlin.extensions.entry.filter import com.mybatisflex.kotlin.extensions.model.filter
import com.mybatisflex.kotlin.extensions.entry.toEntities import com.mybatisflex.kotlin.extensions.model.toEntities
import com.mybatisflex.kotlin.scope.QueryScope import com.mybatisflex.kotlin.scope.QueryScope
import com.mybatisflex.kotlin.scope.queryScope import com.mybatisflex.kotlin.scope.queryScope
/** /*
* 数据库简单操作扩展 * 数据库简单操作扩展
* @author 卡莫sama(yuanjiashuai) * @author 卡莫sama(yuanjiashuai)
* @date 2023/8/7
*/ */
inline fun <reified M > mapper(): M = Mappers.ofMapperClass(M::class.java)
inline fun <reified M : BaseMapper<*>> mapper(): M = MybatisFlexBootstrap.getInstance().getMapper(M::class.java)
inline fun <reified T : Any> queryOne( inline fun <reified T : Any> queryOne(
vararg columns: QueryColumn, vararg columns: QueryColumn,
@ -92,7 +87,7 @@ inline fun <reified E> filter(
queryScope(*columns).where(queryCondition) queryScope(*columns).where(queryCondition)
).toEntities() ).toEntities()
inline fun <reified E> filter( inline fun <reified E > filter(
vararg columns: QueryColumn?, vararg columns: QueryColumn?,
init: () -> QueryCondition init: () -> QueryCondition
): List<E> { ): List<E> {
@ -113,4 +108,3 @@ inline fun <reified E, T : TableDef> filter(

View File

@ -22,16 +22,14 @@ import com.mybatisflex.kotlin.scope.queryScope
/* /*
* 映射器操作扩展 * 映射器操作扩展
* @author 卡莫sama(yuanjiashuai) * @author 卡莫sama(yuanjiashuai)
* @date 2023/8/7
*/ */
fun <T> BaseMapper<*>.queryList(init: (QueryScope.() -> Unit)? = null): List<T> = fun <T> BaseMapper<*>.queryList(init: (QueryScope.() -> Unit)?): List<T> =
this.selectListByQuery(queryScope(init = init)) as List<T> this.selectListByQuery(queryScope(init = init)) as List<T>
fun <T> BaseMapper<T>.update(entity: T, init: () -> QueryCondition): Int = fun <T> BaseMapper<T>.update(entity: T, init: () -> QueryCondition): Int =
this.updateByCondition(entity, init()) this.updateByCondition(entity, init())
fun <T> BaseMapper<T>.delete(init: (QueryScope.() -> Unit)? = null): Int = fun <T> BaseMapper<T>.delete(init: (QueryScope.() -> Unit)?): Int =
this.deleteByQuery(queryScope(init = init)) this.deleteByQuery(queryScope(init = init))
fun <T> BaseMapper<T>.delete1(init: () -> QueryCondition): Int =
this.deleteByCondition(init())

View File

@ -13,27 +13,25 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package com.mybatisflex.kotlin.extensions.entry package com.mybatisflex.kotlin.extensions.model
import com.mybatisflex.core.FlexConsts import com.mybatisflex.core.activerecord.Model
import com.mybatisflex.core.dialect.DialectFactory import com.mybatisflex.core.mybatis.Mappers
import com.mybatisflex.core.query.QueryColumn import com.mybatisflex.core.query.QueryColumn
import com.mybatisflex.core.query.QueryCondition import com.mybatisflex.core.query.QueryCondition
import com.mybatisflex.core.row.Db.* import com.mybatisflex.core.row.Db.*
import com.mybatisflex.kotlin.extensions.db.*
import com.mybatisflex.core.row.Row import com.mybatisflex.core.row.Row
import com.mybatisflex.core.row.RowUtil import com.mybatisflex.core.row.RowUtil
import com.mybatisflex.core.table.TableDef import com.mybatisflex.core.table.TableDef
import com.mybatisflex.core.table.TableInfoFactory import com.mybatisflex.core.table.TableInfoFactory
import com.mybatisflex.core.util.ArrayUtil import com.mybatisflex.core.util.SqlUtil
import com.mybatisflex.kotlin.entry.Entry import com.mybatisflex.kotlin.extensions.db.*
import com.mybatisflex.kotlin.scope.QueryScope import com.mybatisflex.kotlin.scope.QueryScope
import java.util.Arrays import java.io.Serializable
/* /*
* 实体操作扩展 * 实体操作扩展
* @author 卡莫sama(yuanjiashuai) * @author 卡莫sama(yuanjiashuai)
* @date 2023/8/7
*/ */
infix fun <T> Row.to(entryClass: Class<T>): T { infix fun <T> Row.to(entryClass: Class<T>): T {
@ -69,31 +67,13 @@ inline fun <reified E> TableDef.all(): List<E> = selectAll(schema, tableName).to
inline fun <reified E> Collection<Row>.toEntities() = map { it to E::class.java }.toList() inline fun <reified E> Collection<Row>.toEntities() = map { it to E::class.java }.toList()
inline fun<reified E:Entry> List<E>.batchInsert(): Boolean { inline fun<reified E:Model<E>> List<E>.batchInsert(): Int = Mappers.ofEntityClass(E::class.java).insertBatch(this)
val entities = this
val tableInfo = TableInfoFactory.ofEntityClass(E::class.java) fun< E:Model<E>> List<E>.batchUpdateById(): Boolean = all(Model<E>::updateById)
for (entity in entities) {
tableInfo.initVersionValueIfNecessary(entity) inline fun<reified E:Model<E>> List<E>. batchDeleteById(): Boolean {
tableInfo.initTenantIdIfNecessary(entity) //拿到集合中所有实体的主键
tableInfo.initLogicDeleteValueIfNecessary(entity) val primaryValues = this.map { it.pkValues() }.flatMap(Array<*>::toMutableList).map { it as Serializable }
//执行 onInsert 监听器 return SqlUtil.toBool(Mappers.ofEntityClass(E::class.java).deleteBatchByIds(primaryValues))
tableInfo.invokeOnInsertListener(entity)
}
var allValues = FlexConsts.EMPTY_ARRAY
for (entity in entities) {
allValues = ArrayUtil.concat(allValues, tableInfo.buildInsertSqlArgs(entity, false))
}
val sql = DialectFactory.getDialect().forInsertEntityBatch(tableInfo, entities)
return insertBySql(sql,*allValues) > 1
} }
fun< E:Entry> List<E>.batchUpdate(): Boolean = all(Entry::update)
inline fun<reified E:Entry> List<E>. batchDeleteById(): Boolean {
val tableInfo = TableInfoFactory.ofEntityClass(E::class.java)
val primaryValues = this.map { tableInfo.buildPkSqlArgs(it) }.stream().flatMap(Arrays::stream).toArray()
val tenantIdArgs = tableInfo.buildTenantIdArgs()
val sql = DialectFactory.getDialect().forDeleteEntityBatchByIds(tableInfo, primaryValues)
return deleteBySql(sql,*ArrayUtil.concat(primaryValues, tenantIdArgs)) > 1
}

View File

@ -15,11 +15,9 @@
*/ */
package com.mybatisflex.kotlin.extensions.sql package com.mybatisflex.kotlin.extensions.sql
import com.mybatisflex.core.query.Joiner import com.mybatisflex.core.query.*
import com.mybatisflex.core.query.QueryColumn
import com.mybatisflex.core.query.QueryCondition
import com.mybatisflex.core.query.QueryWrapper
import java.util.function.Consumer import java.util.function.Consumer
/* /*
* sql操作扩展 * sql操作扩展
* @author 卡莫sama(yuanjiashuai) * @author 卡莫sama(yuanjiashuai)
@ -29,26 +27,14 @@ infix fun QueryColumn.eq(value: Any?): QueryCondition {
return this.eq(value) return this.eq(value)
} }
inline fun QueryCondition.andIf(test: Boolean, block: () -> QueryCondition): QueryCondition { inline fun QueryCondition.andIf(test: Boolean, block: () -> QueryCondition): QueryCondition =
if (test) { if (test) this.and(block()) else this
this.and(block())
}
return this
}
inline fun QueryCondition.orIf(test: Boolean, block: () -> QueryCondition): QueryCondition { inline fun QueryCondition.orIf(test: Boolean, block: () -> QueryCondition): QueryCondition =
if (test) { if (test) this.or(block()) else this
this.or(block())
}
return this
}
inline fun `if`(test: Boolean, block: () -> QueryCondition): QueryCondition { inline fun `if`(test: Boolean, block: () -> QueryCondition): QueryCondition =
if (test) { if (test) block() else QueryCondition.createEmpty()
return block()
}
return QueryCondition.createEmpty()
}
infix fun QueryColumn.like(value: String): QueryCondition = this.like(value) infix fun QueryColumn.like(value: String): QueryCondition = this.like(value)
@ -58,11 +44,29 @@ infix fun QueryCondition.or(other: QueryCondition): QueryCondition = this.or(oth
infix fun QueryColumn.`=`(value: Any?): QueryCondition = this.eq(value) infix fun QueryColumn.`=`(value: Any?): QueryCondition = this.eq(value)
infix fun QueryColumn.`in`(value: Collection<Any>): QueryCondition = this.`in`(value) infix fun QueryColumn.`!=`(value: Any?): QueryCondition = this.ne(value)
fun QueryColumn.`in`(vararg values: Array<Any>): QueryCondition = this.`in`(values.asList()) infix fun QueryColumn.gt(value: Any?): QueryCondition = this.gt(value)
infix fun QueryWrapper.`as`(alias: String) = this.`as`(alias) infix fun QueryColumn.ge(value: Any?): QueryCondition = this.ge(value)
infix fun QueryColumn.le(value: Any?): QueryCondition = this.le(value)
infix fun QueryColumn.lt(value: Any?): QueryCondition = this.lt(value)
infix fun QueryColumn.between(pair: Pair<Any?, Any?>): QueryCondition = this.between(pair.first, pair.second)
infix fun QueryColumn.notBetween(pair: Pair<Any?, Any?>): QueryCondition = this.notBetween(pair.first, pair.second)
infix fun QueryColumn.notIn(value: Collection<Any?>): QueryCondition = this.notIn(value)
infix fun QueryColumn.notIn(values: Array<Any?>): QueryCondition = this.notIn(values)
infix fun QueryColumn.`in`(value: Collection<Any?>): QueryCondition = this.`in`(value)
infix fun QueryColumn.`in`(values: Array<Any?>): QueryCondition = this.`in`(values)
infix fun QueryWrapper.`as`(alias: String?) = this.`as`(alias)
infix fun <M> Joiner<M>.`as`(alias: String?): Joiner<M> = this.`as`(alias) infix fun <M> Joiner<M>.`as`(alias: String?): Joiner<M> = this.`as`(alias)
@ -72,3 +76,8 @@ infix fun <M> Joiner<M>.on(on: QueryCondition?): M = this.on(on)
infix fun <M> Joiner<M>.on(consumer: Consumer<QueryWrapper?>): M = this.on(consumer) infix fun <M> Joiner<M>.on(consumer: Consumer<QueryWrapper?>): M = this.on(consumer)
infix fun QueryWrapper.orderBy(orderBys: Collection<QueryOrderBy?>): QueryWrapper = this.orderBy(*orderBys.toTypedArray())
infix fun QueryWrapper.limit(rows: Number): QueryWrapper = this.limit(rows)
infix fun QueryWrapper.limit(pair: Pair<Number?, Number?>): QueryWrapper = this.limit(pair.first,pair.second)

View File

@ -41,9 +41,6 @@ class DataSourceScope(private val bootstrap: MybatisFlexBootstrap) {
fun dataSource(dataSourceKey: String, dataSource: DataSource) = fun dataSource(dataSourceKey: String, dataSource: DataSource) =
bootstrap.addDataSource(dataSourceKey, dataSource) bootstrap.addDataSource(dataSourceKey, dataSource)
// infix fun String.of(dataSource: DataSource) =
// bootstrap.addDataSource(this, dataSource)
} }

View File

@ -14,6 +14,7 @@
<properties> <properties>
<maven.compiler.source>8</maven.compiler.source> <maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target> <maven.compiler.target>8</maven.compiler.target>
<kotlin.compiler.incremental>true</kotlin.compiler.incremental>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<kotlin.version>1.9.0</kotlin.version> <kotlin.version>1.9.0</kotlin.version>
</properties> </properties>
@ -24,11 +25,6 @@
<artifactId>mybatis-flex-kotlin</artifactId> <artifactId>mybatis-flex-kotlin</artifactId>
<version>${mybatis-flex.version}</version> <version>${mybatis-flex.version}</version>
</dependency> </dependency>
<dependency>
<groupId>com.mybatis-flex</groupId>
<artifactId>mybatis-flex-core</artifactId>
<version>${mybatis-flex.version}</version>
</dependency>
<dependency> <dependency>
<groupId>com.mybatis-flex</groupId> <groupId>com.mybatis-flex</groupId>
@ -40,44 +36,36 @@
<groupId>org.springframework</groupId> <groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId> <artifactId>spring-jdbc</artifactId>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.yaml</groupId> <groupId>org.jetbrains.kotlin</groupId>
<artifactId>snakeyaml</artifactId> <artifactId>kotlin-stdlib-jdk8</artifactId>
<version>2.0</version> <version>${kotlin.version}</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>com.h2database</groupId> <groupId>com.h2database</groupId>
<artifactId>h2</artifactId> <artifactId>h2</artifactId>
<version>2.1.214</version> <version>2.1.214</version>
</dependency> </dependency>
<!--test-->
<dependency> <dependency>
<groupId>org.springframework</groupId> <groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId> <artifactId>spring-test</artifactId>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.assertj</groupId> <groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId> <artifactId>assertj-core</artifactId>
<version>3.22.0</version> <version>3.22.0</version>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-stdlib-jdk8</artifactId>
<version>${kotlin.version}</version>
</dependency>
<dependency> <dependency>
<groupId>org.jetbrains.kotlin</groupId> <groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-test-junit</artifactId> <artifactId>kotlin-test-junit</artifactId>
<version>${kotlin.version}</version> <version>${kotlin.version}</version>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
</dependencies> </dependencies>
<build> <build>
<sourceDirectory>${project.basedir}/src/main/kotlin</sourceDirectory> <sourceDirectory>${project.basedir}/src/main/kotlin</sourceDirectory>
<testSourceDirectory>${project.basedir}/src/test/kotlin</testSourceDirectory> <testSourceDirectory>${project.basedir}/src/test/kotlin</testSourceDirectory>
@ -91,7 +79,26 @@
<!--需要配置此项才能开启接口默认方法--> <!--需要配置此项才能开启接口默认方法-->
<arg>-Xjvm-default=all</arg> <arg>-Xjvm-default=all</arg>
</args> </args>
<compilerPlugins>
<!--适配数据类无无参构造问题-->
<plugin>no-arg</plugin>
</compilerPlugins>
<pluginOptions>
<option>no-arg:annotation=com.mybatisflex.annotation.Table</option>
</pluginOptions>
</configuration> </configuration>
<dependencies>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-maven-sam-with-receiver</artifactId>
<version>${kotlin.version}</version>
</dependency>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-maven-noarg</artifactId>
<version>${kotlin.version}</version>
</dependency>
</dependencies>
<executions> <executions>
<execution> <execution>
<id>kapt</id> <id>kapt</id>
@ -99,7 +106,6 @@
<goal>kapt</goal> <goal>kapt</goal>
</goals> </goals>
<configuration> <configuration>
<testClasspath>${project.basedir}/src/test/kotlin</testClasspath>
<sourceDirs> <sourceDirs>
<sourceDir>${project.basedir}/src/main/kotlin</sourceDir> <sourceDir>${project.basedir}/src/main/kotlin</sourceDir>
</sourceDirs> </sourceDirs>
@ -116,6 +122,7 @@
<execution> <execution>
<id>compile</id> <id>compile</id>
<phase>process-sources</phase>
<goals> <goals>
<goal>compile</goal> <goal>compile</goal>
</goals> </goals>

View File

@ -20,18 +20,17 @@ import com.mybatisflex.core.BaseMapper
import com.mybatisflex.kotlin.extensions.mapper.queryList import com.mybatisflex.kotlin.extensions.mapper.queryList
import com.mybatisflex.kotlin.extensions.sql.* import com.mybatisflex.kotlin.extensions.sql.*
import com.mybatisflex.test.model.Account import com.mybatisflex.test.model.Account
import com.mybatisflex.test.model.table.AccountTableDef.ACCOUNT
@JvmDefaultWithCompatibility @JvmDefaultWithCompatibility
interface AccountMapper : BaseMapper<Account> { interface AccountMapper : BaseMapper<Account> {
fun findByAge(age: Int, vararg ids: Int): List<Account> = queryList { fun findByAge(age: Int, vararg ids: Int): List<Account> = queryList {
select(ACCOUNT.ALL_COLUMNS) select(Account.ALL_COLUMNS)
from(ACCOUNT) from(Account)
where(ACCOUNT) { where(Account) {
(AGE `=` age) and `if`(true) { (AGE `=` age) and `if`(ids.isNotEmpty()) {
ID `in` ids.asList() ID `in` ids.asList()
} }
} }

View File

@ -15,24 +15,26 @@
*/ */
package com.mybatisflex.test.model package com.mybatisflex.test.model
import com.mybatisflex.annotation.Column
import com.mybatisflex.annotation.Id import com.mybatisflex.annotation.Id
import com.mybatisflex.annotation.NoneListener import com.mybatisflex.annotation.NoneListener
import com.mybatisflex.annotation.Table import com.mybatisflex.annotation.Table
import com.mybatisflex.kotlin.entry.Entry import com.mybatisflex.core.activerecord.Model
import com.mybatisflex.test.model.table.AccountTableDef
import java.util.* import java.util.*
/** /**
* 测试用数据类最好不要写成data class否则需要与数据库字段数据顺序一致 * 测试用数据类最好不要写成data class否则没有无参构造需要与数据库字段数据顺序一致
* @author 卡莫sama(yuanjiashuai) * @author 卡莫sama(yuanjiashuai)
* @date 2023/8/7 * @date 2023/8/7
*/ */
@Table(value = "tb_account", onUpdate = [NoneListener::class], onSet = [AccountOnSetListener::class]) @Table(value = "tb_account", onUpdate = [NoneListener::class], onSet = [AccountOnSetListener::class])
data class Account( data class Account(
@Id var id: Int, @Id var id: Int,
@Column("u_name") var userName: String?, var userName: String?,
var age: Int?, var age: Int?,
var birthday: Date?, var birthday: Date?,
) : Entry(){ ) : Model<Account>(){
companion object : AccountTableDef()
override fun toString(): String { override fun toString(): String {
return "Account(id=$id, userName=$userName, birthday=$birthday, age=$age)" return "Account(id=$id, userName=$userName, birthday=$birthday, age=$age)"
} }

View File

@ -1,5 +1,3 @@
INSERT INTO tb_account INSERT INTO tb_account(id, user_name, age, birthday)
VALUES (1, 'Michael Yang', 18, '2020-01-11'); VALUES (1, '张三', 18, '2020-01-11'),
(2, '李四', 19, '2021-03-21');
INSERT INTO tb_account
VALUES (2, 'Michael Zhanng', 20, '2020-01-11');

View File

@ -1,7 +1,7 @@
CREATE TABLE IF NOT EXISTS `tb_account` CREATE TABLE IF NOT EXISTS `tb_account`
( (
`id` INTEGER , `id` INTEGER ,
`u_name` VARCHAR(100) NOT NULL, `user_name` VARCHAR(100) NOT NULL,
`age` INTEGER, `age` INTEGER,
`birthday` DATETIME `birthday` DATETIME
); );

View File

@ -16,13 +16,13 @@
package com.mybatisflex.test package com.mybatisflex.test
import com.mybatisflex.core.FlexConsts import com.mybatisflex.core.FlexConsts
import com.mybatisflex.core.activerecord.Model
import com.mybatisflex.core.audit.AuditManager import com.mybatisflex.core.audit.AuditManager
import com.mybatisflex.core.audit.ConsoleMessageCollector import com.mybatisflex.core.audit.ConsoleMessageCollector
import com.mybatisflex.kotlin.entry.Entry
import com.mybatisflex.kotlin.extensions.db.filter import com.mybatisflex.kotlin.extensions.db.filter
import com.mybatisflex.kotlin.extensions.db.mapper import com.mybatisflex.kotlin.extensions.db.mapper
import com.mybatisflex.kotlin.extensions.db.query import com.mybatisflex.kotlin.extensions.db.query
import com.mybatisflex.kotlin.extensions.entry.* import com.mybatisflex.kotlin.extensions.model.*
import com.mybatisflex.kotlin.extensions.sql.* import com.mybatisflex.kotlin.extensions.sql.*
import com.mybatisflex.kotlin.scope.buildBootstrap import com.mybatisflex.kotlin.scope.buildBootstrap
import com.mybatisflex.test.mapper.AccountMapper import com.mybatisflex.test.mapper.AccountMapper
@ -48,40 +48,75 @@ class KotlinTest {
AuditManager.setMessageCollector(ConsoleMessageCollector()) AuditManager.setMessageCollector(ConsoleMessageCollector())
buildBootstrap { buildBootstrap {
// 此方法体 it 是 MybatisFlexBootstrap 实例
// 配置Mapper
// 1.通过+(重写自增)的方式
+AccountMapper::class.java +AccountMapper::class.java
dataSources { // 2.通过原始的方式
// dataSource(FlexConsts.NAME,dataSource) // it.addMapper(AccountMapper::class.java)
FlexConsts.NAME of dataSource
// 配置单dataSource
// 1.通过+(重写自增)的方式
+dataSource
// 2.通过原始的方式
// it.setDataSource(dataSource)
// 配置多dataSource
// 1.通过of中缀的方式
FlexConsts.NAME of dataSource
// "dataSource1" of dataSource // "dataSource1" of dataSource
// "dataSource2" of dataSource // "dataSource2" of dataSource
// 2.通过dsl中缀的方式
dataSources {
// dataSource(FlexConsts.NAME,dataSource)
// dataSource("dataSource1",dataSource)
// dataSource("dataSource2",dataSource)
} }
// + dataSource // 3.通过原始的方式
// it.addDataSource(FlexConsts.NAME,dataSource)
}.start() }.start()
//
ACCOUNT.query<Account> {}.forEach(::println) // 查询表对象对应的所有实体数据
ACCOUNT.all<Account>().forEach(::println)
// ACCOUNT.query<Account> {}.forEach(::println)
// a and (b or c)
// filter<Account> {
// ACCOUNT.AGE `=` 12 and
// (ACCOUNT.ID `in` listOf(1, 2) or (ACCOUNT.ID `in` listOf(1, 2)))
// }
filter<Account> {
ACCOUNT.ID `=` 1 and
(ACCOUNT.AGE `in` listOf(18,19) or (ACCOUNT.BIRTHDAY between ("2020-01-10" to "2020-01-12")) )
}.forEach(::println)
// 查询表对象对应的实体数据并根据条件过滤
filter<Account> { filter<Account> {
ACCOUNT.AGE `=` 12 or ACCOUNT.AGE `=` 12 or
`if`(true) { ACCOUNT.ID `in` listOf(1, 2) } //if的第一个参数为true时则会调用花括号类的方法返回一个条件对象与上面那个条件对象相连接
}.stream().peek(::println).peek { it.id = it.id.plus(2) }.forEach(Entry::save) `if`(true) { ACCOUNT.ID between (1 to 2) }
//使用表对象filter或者DB对象有两个泛型的filter方法时方法体内this为表对象无需XXX.AA调用直接AA // `if`(false) { ACCOUNT.ID `in` listOf(1, 2) }
// ACCOUNT.filter<Account,AccountTableDef> { }.stream().peek(::println)
// AGE `=` 12 or // 过滤后修改id再次保存
// `if`(true) { ID `in` listOf(1, 2) } .peek { it.id = it.id.plus(2) }.forEach(Model<*>::save)
// }.stream().peek(::println).peek { it.id = it.id.plus(6) }.forEach(Entry::save) // 使用表对象filter或者DB对象有两个泛型的filter方法时方法体内this为表对象无需XXX.AA调用直接AA
// ACCOUNT.filter<Account,AccountTableDef> {
// AGE `=` 12 or
// `if`(true) { ID `in` listOf(1, 2) }
// }.stream().peek(::println).peek { it.id = it.id.plus(6) }.forEach(Entry::save)
println("保存后————————") println("保存后————————")
mapper<AccountMapper>().findByAge(18, 1, 2).stream().peek { println(it) }.forEach(Entry::deleteById) // 获得mapper实例通过自定义的默认方法查并将查到的删除
mapper<AccountMapper>().findByAge(18, 1, 2).stream().peek { println(it) }.forEach{it.removeById()}
println("删除后————————") println("删除后————————")
ACCOUNT.all<Account>().stream().peek { println(it) }.map { Account.all<Account>().stream().peek { println(it) }.map {
it.userName = "sa" it.userName = "kamo"
it it
}.forEach(Entry::update) }.forEach{it.updateById()}
println("更新后————————") println("更新后————————")
ACCOUNT.all<Account>().stream().peek { println(it) }.map { ACCOUNT.all<Account>().stream().peek { println(it) }.map {
it.id = it.id.plus(5) it.id = it.id.plus(5)
it.userName = "423423" it.userName = "akino"
it it
}.toList().batchInsert() }.toList().batchInsert()
@ -91,9 +126,9 @@ class KotlinTest {
println("批量删除后————————") println("批量删除后————————")
//直接使用函数查询时需指定from表 //直接使用函数查询时需指定from表
query<Account> { from(ACCOUNT) }.stream().peek { println(it) }.toList().filter { it.id.rem(3) == 0 }.map { query<Account> { from(ACCOUNT) }.stream().peek { println(it) }.toList().filter { it.id.rem(3) == 0 }.map {
it.userName = "哈哈" it.userName = "cloud-player"
it it
}.batchUpdate() }.batchUpdateById()
println("批量更新后————————") println("批量更新后————————")
//使用表对象查询时无需指定from表 //使用表对象查询时无需指定from表