diff --git a/mybatis-flex-kotlin/pom.xml b/mybatis-flex-kotlin/pom.xml new file mode 100755 index 00000000..08d61f65 --- /dev/null +++ b/mybatis-flex-kotlin/pom.xml @@ -0,0 +1,112 @@ + + + 4.0.0 + + com.mybatis-flex + parent + 1.4.8 + + + mybatis-flex-kotlin + + + 8 + 8 + UTF-8 + 1.9.0 + + + + + com.mybatis-flex + mybatis-flex-core + 1.4.8 + + + org.jetbrains.kotlin + kotlin-test + ${kotlin.version} + test + + + org.jetbrains.kotlin + kotlin-stdlib-jdk8 + ${kotlin.version} + compile + + + org.testng + testng + 7.7.1 + test + + + org.springframework + spring-jdbc + test + + + com.h2database + h2 + 2.1.214 + test + + + + + + + + org.jetbrains.kotlin + kotlin-maven-plugin + ${kotlin.version} + + 1.8 + + -Xjvm-default=all + + + + + kapt + + kapt + + + + src/main/kotlin + src/main/java + + + + + com.google.dagger + dagger-compiler + 2.9 + + + + + + compile + process-sources + + compile + + + + test-compile + test-compile + + test-compile + + + + + + + + + diff --git a/mybatis-flex-kotlin/src/main/java/com/mybatisflex/kotlin/db/DbConfig.kt b/mybatis-flex-kotlin/src/main/java/com/mybatisflex/kotlin/db/DbConfig.kt new file mode 100644 index 00000000..c10dca34 --- /dev/null +++ b/mybatis-flex-kotlin/src/main/java/com/mybatisflex/kotlin/db/DbConfig.kt @@ -0,0 +1,37 @@ +package com.mybatisflex.kotlin.db + +import kotlin.properties.ReadWriteProperty +import kotlin.reflect.KProperty +/** + * 数据库配置对象,暂时未启用 + * @author 卡莫sama(yuanjiashuai) + * @date 2023/8/7 + */ +object DbConfig { + + var url: String by IfNullVar { "" } + var username: String by IfNullVar { "" } + var password: String by IfNullVar { "" } + + +} + +class IfNullVar(private var init: (() -> T)?) : ReadWriteProperty { + private var _value: T? = null + + override fun getValue(thisRef: Any?, property: KProperty<*>): T { + if (_value == null) { + synchronized(this) { + if (_value == null) { + _value = init!!() + init = null + } + } + } + return this._value!! + } + + override fun setValue(thisRef: Any?, property: KProperty<*>, value: T) { + _value = value + } +} diff --git a/mybatis-flex-kotlin/src/main/java/com/mybatisflex/kotlin/entry/Entry.kt b/mybatis-flex-kotlin/src/main/java/com/mybatisflex/kotlin/entry/Entry.kt new file mode 100644 index 00000000..2e48c5e9 --- /dev/null +++ b/mybatis-flex-kotlin/src/main/java/com/mybatisflex/kotlin/entry/Entry.kt @@ -0,0 +1,49 @@ +package com.mybatisflex.kotlin.entry + +import com.mybatisflex.core.dialect.DialectFactory +import com.mybatisflex.core.table.TableInfoFactory +import com.mybatisflex.core.util.ArrayUtil +import com.mybatisflex.kotlin.extend.db.DB +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 DB.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 DB.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 DB.deleteBySql(sql, *allValues) == 1 + } + +} diff --git a/mybatis-flex-kotlin/src/main/java/com/mybatisflex/kotlin/extend/db/DbExtend.kt b/mybatis-flex-kotlin/src/main/java/com/mybatisflex/kotlin/extend/db/DbExtend.kt new file mode 100644 index 00000000..ecde6b81 --- /dev/null +++ b/mybatis-flex-kotlin/src/main/java/com/mybatisflex/kotlin/extend/db/DbExtend.kt @@ -0,0 +1,588 @@ +package com.mybatisflex.kotlin.extend.db + +import com.mybatisflex.core.BaseMapper +import com.mybatisflex.core.MybatisFlexBootstrap +import com.mybatisflex.core.paginate.Page +import com.mybatisflex.core.query.QueryColumn +import com.mybatisflex.core.query.QueryCondition +import com.mybatisflex.core.query.QueryWrapper +import com.mybatisflex.core.row.* +import com.mybatisflex.core.table.TableDef +import com.mybatisflex.core.table.TableInfoFactory +import com.mybatisflex.core.transaction.Propagation +import com.mybatisflex.kotlin.extend.entry.filter +import com.mybatisflex.kotlin.extend.entry.toEntities +import com.mybatisflex.kotlin.scope.QueryScope +import com.mybatisflex.kotlin.scope.queryScope +import java.util.function.BiConsumer +import java.util.function.Supplier + +/** + * 数据库操作对象 + * @author 卡莫sama(yuanjiashuai) + * @date 2023/8/7 + */ +object DB { + + fun invoker(): RowMapperInvoker = Db.invoker() + + fun invoker(environmentId: String): RowMapperInvoker = Db.invoker(environmentId) + + inline fun > mapper(): M = MybatisFlexBootstrap.getInstance().getMapper(M::class.java) + + inline fun queryOne( + vararg columns: QueryColumn, + schema: String? = null, + tableName: String? = null, + noinline init: QueryScope.() -> Unit + ): T = queryRow(schema = schema, tableName = tableName, columns = columns, init = init).toEntity(T::class.java) + + + fun queryRow( + vararg columns: QueryColumn?, + schema: String? = null, + tableName: String? = null, + init: QueryScope.() -> Unit + ): Row = + selectOneByQuery( + schema = schema, + tableName = tableName, + queryWrapper = queryScope(columns = columns, init = init) + ) + + + inline fun query( + vararg columns: QueryColumn?, + schema: String? = null, + tableName: String? = null, + noinline init: QueryScope.() -> Unit + ): List = + queryRows(schema = schema, tableName = tableName, columns = columns, init = init) + .toEntities() + + fun queryRows( + vararg columns: QueryColumn?, + schema: String? = null, + tableName: String? = null, + init: QueryScope.() -> Unit + ): List = selectListByQuery( + schema = schema, tableName = tableName, + queryWrapper = queryScope(columns = columns, init = init) + ) + + // filter----------- + inline fun filter( + tableName: String, + schema: String, + vararg columns: QueryColumn?, + queryCondition: QueryCondition = QueryCondition.createEmpty() + ): List = selectListByQuery( + schema, + tableName, + queryScope(*columns).where(queryCondition) + ).toEntities() + + inline fun filter( + vararg columns: QueryColumn?, + init: () -> QueryCondition + ): List { + val tableInfo = TableInfoFactory.ofEntityClass(E::class.java) + return filter( + columns = columns, + schema = tableInfo.schema, + tableName = tableInfo.tableName, + queryCondition = init() + ) + } + + inline fun filter( + tableDef: T, + vararg columns: QueryColumn?, + init: T.() -> QueryCondition + ): List = tableDef.filter(columns = columns, init = init) + + + // ---------------------- + fun insert(schema: String?, tableName: String?, row: Row?): Int { + return Db.insert(schema, tableName, row) + } + + fun insert(tableName: String?, row: Row?): Int { + return Db.insert(null as String?, tableName, row) + } + + fun insertBySql(sql: String?, vararg args: Any?): Int { + return Db.insertBySql(sql, *args) + } + + fun insertBatch(schema: String?, tableName: String?, rows: Collection): IntArray { + return insertBatch(schema, tableName, rows, rows.size) + } + + fun insertBatch(tableName: String?, rows: Collection): IntArray { + return insertBatch(null as String?, tableName, rows, rows.size) + } + + fun insertBatch(schema: String?, tableName: String?, rows: Collection, batchSize: Int): IntArray { + return Db.insertBatch(schema, tableName, rows, batchSize) + } + + fun insertBatch(tableName: String?, rows: Collection, batchSize: Int): IntArray { + return Db.insertBatch(tableName, rows) + } + + fun insertBatchWithFirstRowColumns(schema: String?, tableName: String?, rows: List?): Int { + return Db.insertBatchWithFirstRowColumns(schema, tableName, rows) + } + + fun insertBatchWithFirstRowColumns(tableName: String?, rows: List?): Int { + return Db.insertBatchWithFirstRowColumns(null as String?, tableName, rows) + } + + fun deleteBySql(sql: String?, vararg args: Any?): Int { + return Db.deleteBySql(sql, *args) + } + + fun deleteById(schema: String?, tableName: String?, row: Row?): Int { + return Db.deleteById(schema, tableName, row) + } + + fun deleteById(tableName: String?, row: Row?): Int { + return Db.deleteById(null as String?, tableName, row) + } + + fun deleteById(schema: String?, tableName: String?, primaryKey: String?, id: Any?): Int { + return Db.deleteById(schema, tableName, primaryKey, id) + } + + fun deleteById(tableName: String?, primaryKey: String?, id: Any?): Int { + return Db.deleteById(null as String?, tableName, primaryKey, id) + } + + fun deleteBatchByIds(schema: String?, tableName: String?, primaryKey: String?, ids: Collection<*>?): Int { + return Db.deleteBatchByIds(schema, tableName, primaryKey, ids) + } + + fun deleteBatchByIds(tableName: String?, primaryKey: String?, ids: Collection<*>?): Int { + return Db.deleteBatchByIds(null as String?, tableName, primaryKey, ids) + } + + fun deleteByMap(schema: String?, tableName: String?, whereColumns: Map?): Int { + return Db.deleteByQuery( + schema, tableName, QueryWrapper() + .where(whereColumns) + ) + } + + fun deleteByMap(tableName: String?, whereColumns: Map?): Int { + return Db.deleteByQuery( + null as String?, tableName, QueryWrapper() + .where(whereColumns) + ) + } + + fun deleteByCondition(schema: String?, tableName: String?, condition: QueryCondition?): Int { + return Db.deleteByQuery( + schema, tableName, QueryWrapper() + .where(condition) + ) + } + + fun deleteByCondition(tableName: String?, condition: QueryCondition?): Int { + return Db.deleteByQuery( + null as String?, tableName, QueryWrapper() + .where(condition) + ) + } + + fun deleteByQuery(schema: String?, tableName: String?, queryWrapper: QueryWrapper?): Int { + return Db.deleteByQuery(schema, tableName, queryWrapper) + } + + fun deleteByQuery(tableName: String?, queryWrapper: QueryWrapper?): Int { + return Db.deleteByQuery(null as String?, tableName, queryWrapper) + } + + fun updateBySql(sql: String?, vararg args: Any?): Int { + return Db.updateBySql(sql, *args) + } + + fun updateBatch(sql: String?, batchArgsSetter: BatchArgsSetter): IntArray { + return Db.updateBatch(sql, batchArgsSetter) + } + + + fun updateById(schema: String?, tableName: String?, row: Row?): Int { + return Db.updateById(schema, tableName, row) + } + + fun updateById(tableName: String?, row: Row?): Int { + return Db.updateById(null as String?, tableName, row) + } + + fun updateByMap(schema: String?, tableName: String?, data: Row?, whereColumns: Map?): Int { + return Db.updateByQuery( + schema, tableName, data, QueryWrapper() + .where(whereColumns) + ) + } + + fun updateByMap(tableName: String?, data: Row?, whereColumns: Map?): Int { + return Db.updateByQuery( + null as String?, tableName, data, QueryWrapper() + .where(whereColumns) + ) + } + + fun updateByCondition(schema: String?, tableName: String?, data: Row?, condition: QueryCondition?): Int { + return Db.updateByQuery( + schema, tableName, data, QueryWrapper() + .where(condition) + ) + } + + fun updateByCondition(tableName: String?, data: Row?, condition: QueryCondition?): Int { + return Db.updateByQuery( + null as String?, tableName, data, QueryWrapper() + .where(condition) + ) + } + + fun updateByQuery(schema: String?, tableName: String?, data: Row?, queryWrapper: QueryWrapper?): Int { + return Db.updateByQuery(schema, tableName, data, queryWrapper) + } + + fun updateByQuery(tableName: String?, data: Row?, queryWrapper: QueryWrapper?): Int { + return Db.updateByQuery(null as String?, tableName, data, queryWrapper) + } + + fun updateBatchById(schema: String?, tableName: String?, rows: List?): Int { + return Db.updateBatchById(schema, tableName, rows) + } + + fun updateBatchById(tableName: String?, rows: List?): Int { + return Db.updateBatchById(null as String?, tableName, rows) + } + + fun updateEntitiesBatch(entities: Collection?, batchSize: Int): Int { + return Db.updateEntitiesBatch(entities, batchSize) + } + + fun updateEntitiesBatch(entities: Collection?): Int { + return updateEntitiesBatch(entities, 1000) + } + + fun updateNumberAddByQuery( + schema: String?, + tableName: String?, + fieldName: String?, + value: Number?, + queryWrapper: QueryWrapper? + ): Int { + return Db.updateNumberAddByQuery(schema, tableName, fieldName, value, queryWrapper) + } + + fun updateNumberAddByQuery( + tableName: String?, + fieldName: String?, + value: Number?, + queryWrapper: QueryWrapper? + ): Int { + return Db.updateNumberAddByQuery(null as String?, tableName, fieldName, value, queryWrapper) + } + + fun executeBatch( + totalSize: Int, + batchSize: Int, + mapperClass: Class?, + consumer: BiConsumer? + ): IntArray { + return Db.executeBatch(totalSize, batchSize, mapperClass, consumer) + } + + fun selectOneBySql(sql: String?, vararg args: Any?): Row { + return Db.selectOneBySql(sql, *args) + } + + + fun selectOneById(schema: String?, tableName: String?, row: Row?): Row { + return Db.selectOneById(schema, tableName, row) + } + + fun selectOneById(tableName: String?, row: Row?): Row { + return Db.selectOneById(null as String?, tableName, row) + } + + fun selectOneById(schema: String?, tableName: String?, primaryKey: String?, id: Any?): Row { + return Db.selectOneById(schema, tableName, primaryKey, id) + } + + fun selectOneById(tableName: String?, primaryKey: String?, id: Any?): Row { + return Db.selectOneById(null as String?, tableName, primaryKey, id) + } + + fun selectOneByMap(schema: String?, tableName: String?, whereColumns: Map?): Row { + return Db.selectOneByQuery( + schema, tableName, QueryWrapper() + .where(whereColumns).limit(1) + ) + } + + fun selectOneByMap(tableName: String?, whereColumns: Map?): Row { + return Db.selectOneByQuery( + null as String?, tableName, QueryWrapper().where(whereColumns).limit(1) + ) + } + + fun selectOneByCondition(schema: String?, tableName: String?, condition: QueryCondition?): Row { + return Db.selectOneByQuery( + schema, tableName, QueryWrapper() + .where(condition).limit(1) + ) + } + + fun selectOneByCondition(tableName: String?, condition: QueryCondition?): Row { + return Db.selectOneByQuery( + null as String?, tableName, QueryWrapper() + .where(condition).limit(1) + ) + } + + fun selectOneByQuery(schema: String?, tableName: String?, queryWrapper: QueryWrapper?): Row { + return Db.selectOneByQuery(schema, tableName, queryWrapper) + } + + fun selectOneByQuery(tableName: String?, queryWrapper: QueryWrapper?): Row { + return Db.selectOneByQuery(null as String?, tableName, queryWrapper) + } + + fun selectOneByQuery(queryWrapper: QueryWrapper?): Row { + return Db.selectOneByQuery(queryWrapper) + } + + fun selectListBySql(sql: String?, vararg args: Any?): List { + return Db.selectListBySql(sql, *args) + } + + fun selectListByMap(schema: String?, tableName: String?, whereColumns: Map?): List { + return Db.selectListByQuery( + schema, tableName, QueryWrapper() + .where(whereColumns) + ) + } + + fun selectListByMap(tableName: String?, whereColumns: Map?): List { + return Db.selectListByMap(tableName, whereColumns) + } + + fun selectListByMap(schema: String?, tableName: String?, whereColumns: Map?, count: Int): List { + return Db.selectListByMap(schema, tableName, whereColumns, count) + } + + fun selectListByMap(tableName: String?, whereColumns: Map?, count: Int): List { + return Db.selectListByMap(tableName, whereColumns, count) + } + + fun selectListByCondition(schema: String?, tableName: String?, condition: QueryCondition?): List { + return Db.selectListByCondition(schema, tableName, condition) + } + + fun selectListByCondition(tableName: String?, condition: QueryCondition?): List { + return Db.selectListByQuery( + null as String?, tableName, QueryWrapper() + .where(condition) + ) + } + + fun selectListByCondition(schema: String?, tableName: String?, condition: QueryCondition?, count: Int): List { + return Db.selectListByQuery( + schema, tableName, QueryWrapper() + .where(condition).limit(count) + ) + } + + fun selectListByCondition(tableName: String?, condition: QueryCondition?, count: Int): List { + return Db.selectListByQuery( + null as String?, tableName, QueryWrapper() + .where(condition).limit(count) + ) + } + + fun selectListByQuery(schema: String?, tableName: String?, queryWrapper: QueryWrapper?): List { + return Db.selectListByQuery(schema, tableName, queryWrapper) + } + + fun selectListByQuery(tableName: String?, queryWrapper: QueryWrapper?): List { + return Db.selectListByQuery(null as String?, tableName, queryWrapper) + } + + fun selectListByQuery(queryWrapper: QueryWrapper?): List { + return Db.selectListByQuery(queryWrapper) + } + + fun selectAll(schema: String?, tableName: String?): List { + return Db.selectAll(schema, tableName) + } + + fun selectAll(tableName: String?): List { + return Db.selectAll(null as String?, tableName) + } + + fun selectObject(sql: String?, vararg args: Any?): Any { + return Db.selectObject(sql, *args) + } + + fun selectObject(schema: String?, tableName: String?, queryWrapper: QueryWrapper?): Any { + return Db.selectObject(schema, tableName, queryWrapper) + } + + fun selectObject(tableName: String?, queryWrapper: QueryWrapper?): Any { + return Db.selectObject(null as String?, tableName, queryWrapper) + } + + fun selectObject(queryWrapper: QueryWrapper?): Any { + return Db.selectObject(queryWrapper) + } + + fun selectObjectList(sql: String?, vararg args: Any?): List { + return Db.selectObjectList(sql, *args) + } + + fun selectObjectList(schema: String?, tableName: String?, queryWrapper: QueryWrapper?): Any { + return Db.selectObjectList(schema, tableName, queryWrapper) + } + + fun selectObjectList(tableName: String?, queryWrapper: QueryWrapper?): Any { + return Db.selectObjectList(tableName, queryWrapper) + } + + fun selectObjectList(queryWrapper: QueryWrapper?): Any { + return Db.selectObjectList(queryWrapper) + } + + fun selectCount(sql: String?, vararg args: Any?): Long { + return Db.selectCount(sql, *args) + } + + fun selectCountByCondition(schema: String?, tableName: String?, condition: QueryCondition?): Long { + return Db.selectCountByQuery( + schema, tableName, QueryWrapper() + .where(condition) + ) + } + + fun selectCountByCondition(tableName: String?, condition: QueryCondition?): Long { + return Db.selectCountByCondition( + tableName, condition + ) + } + + fun selectCountByQuery(schema: String?, tableName: String?, queryWrapper: QueryWrapper?): Long { + return Db.selectCountByQuery(schema, tableName, queryWrapper) + } + + fun selectCountByQuery(tableName: String?, queryWrapper: QueryWrapper?): Long { + return Db.selectCountByQuery(null as String?, tableName, queryWrapper) + } + + fun selectCountByQuery(queryWrapper: QueryWrapper?): Long = Db.selectCountByQuery(queryWrapper) + + + fun paginate( + schema: String?, + tableName: String?, + pageNumber: Int, + pageSize: Int, + condition: QueryCondition? + ): Page = Db.paginate(schema, tableName, Page(pageNumber, pageSize), QueryWrapper.create().where(condition)) + + + fun paginate(tableName: String?, pageNumber: Int, pageSize: Int, condition: QueryCondition?): Page = + Db.paginate(tableName, pageNumber, pageSize, condition) + + + fun paginate( + schema: String?, + tableName: String?, + pageNumber: Int, + pageSize: Int, + totalRow: Int, + condition: QueryCondition? + ): Page { + return Db.paginate( + schema, tableName, pageNumber, pageSize, totalRow, condition + ) + } + + fun paginate( + tableName: String?, + pageNumber: Int, + pageSize: Int, + totalRow: Int, + condition: QueryCondition? + ): Page = Db.paginate(tableName, pageNumber, pageSize, totalRow, condition) + + fun paginate( + schema: String?, + tableName: String?, + pageNumber: Int, + pageSize: Int, + queryWrapper: QueryWrapper? + ): Page = Db.paginate(schema, tableName, pageNumber, pageSize, queryWrapper) + + fun paginate(tableName: String?, pageNumber: Int, pageSize: Int, queryWrapper: QueryWrapper?): Page = + Db.paginate(tableName, pageNumber, pageSize, queryWrapper) + + fun paginate( + schema: String?, + tableName: String?, + pageNumber: Int, + pageSize: Int, + totalRow: Int, + queryWrapper: QueryWrapper? + ): Page { + return Db + .paginate(schema, tableName, pageNumber, pageSize, totalRow, queryWrapper) + } + + fun paginate( + tableName: String?, + pageNumber: Int, + pageSize: Int, + totalRow: Int, + queryWrapper: QueryWrapper? + ): Page { + return Db + .paginate(tableName, pageNumber, pageSize, totalRow, queryWrapper) + } + + fun paginate(schema: String?, tableName: String?, page: Page?, queryWrapper: QueryWrapper?): Page { + return Db.paginate(schema, tableName, page, queryWrapper) + } + + fun paginate(tableName: String?, page: Page?, queryWrapper: QueryWrapper?): Page { + return Db.paginate(tableName, page, queryWrapper) + } + + fun tx(supplier: Supplier?): Boolean { + return tx(supplier, Propagation.REQUIRED) + } + + fun tx(supplier: Supplier?, propagation: Propagation?): Boolean { + return Db.tx(supplier, propagation) + } + + fun txWithResult(supplier: Supplier?): T { + return txWithResult(supplier, Propagation.REQUIRED) + } + + fun txWithResult(supplier: Supplier?, propagation: Propagation?): T { + return Db.txWithResult(supplier, propagation) + } + + +} + + + + diff --git a/mybatis-flex-kotlin/src/main/java/com/mybatisflex/kotlin/extend/entry/EntryExtend.kt b/mybatis-flex-kotlin/src/main/java/com/mybatisflex/kotlin/extend/entry/EntryExtend.kt new file mode 100644 index 00000000..c17321d8 --- /dev/null +++ b/mybatis-flex-kotlin/src/main/java/com/mybatisflex/kotlin/extend/entry/EntryExtend.kt @@ -0,0 +1,85 @@ +package com.mybatisflex.kotlin.extend.entry + +import com.mybatisflex.core.FlexConsts +import com.mybatisflex.core.dialect.DialectFactory +import com.mybatisflex.core.query.QueryColumn +import com.mybatisflex.core.query.QueryCondition +import com.mybatisflex.core.row.Row +import com.mybatisflex.core.row.RowUtil +import com.mybatisflex.core.table.TableDef +import com.mybatisflex.core.table.TableInfoFactory +import com.mybatisflex.core.util.ArrayUtil +import com.mybatisflex.kotlin.entry.Entry +import com.mybatisflex.kotlin.extend.db.DB +import com.mybatisflex.kotlin.scope.QueryScope +import java.util.Arrays + +/* + * 实体操作扩展 + * @author 卡莫sama(yuanjiashuai) + * @date 2023/8/7 + */ + +infix fun Row.to(entryClass: Class): T { + return RowUtil.toEntity(this, entryClass) +} + +inline fun T.filter( + vararg columns: QueryColumn?, + init: T.() -> QueryCondition +): List { + val tableInfo = TableInfoFactory.ofEntityClass(E::class.java) + return DB.filter( + columns = columns, + schema = tableInfo.schema, + tableName = tableInfo.tableName, + queryCondition = init() + ) +} + +inline fun TableDef.query( + vararg columns: QueryColumn?, + noinline init: QueryScope.() -> Unit +): List { + return DB.query( + columns = columns, + schema = this.schema, + tableName = this.tableName, + init = init + ) +} + +inline fun TableDef.all( + vararg columns: QueryColumn? +): List = DB.selectAll(schema, tableName).toEntities() + +inline fun Collection.toEntities() = map { it to E::class.java }.toList() + +inline fun List.batchInsert(): Boolean { + val entities = this + val tableInfo = TableInfoFactory.ofEntityClass(E::class.java) + for (entity in entities) { + tableInfo.initVersionValueIfNecessary(entity) + tableInfo.initTenantIdIfNecessary(entity) + tableInfo.initLogicDeleteValueIfNecessary(entity) + //执行 onInsert 监听器 + 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 DB.insertBySql(sql,*allValues) > 1 +} + + +fun< E:Entry> List.batchUpdate(): Boolean = all(Entry::update) + +inline fun List. 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 DB.deleteBySql(sql,*ArrayUtil.concat(primaryValues, tenantIdArgs)) > 1 +} diff --git a/mybatis-flex-kotlin/src/main/java/com/mybatisflex/kotlin/extend/mapper/MaaperExtend.kt b/mybatis-flex-kotlin/src/main/java/com/mybatisflex/kotlin/extend/mapper/MaaperExtend.kt new file mode 100644 index 00000000..d14af29a --- /dev/null +++ b/mybatis-flex-kotlin/src/main/java/com/mybatisflex/kotlin/extend/mapper/MaaperExtend.kt @@ -0,0 +1,22 @@ +package com.mybatisflex.kotlin.extend.mapper + +import com.mybatisflex.core.BaseMapper +import com.mybatisflex.core.query.QueryCondition +import com.mybatisflex.kotlin.scope.QueryScope +import com.mybatisflex.kotlin.scope.queryScope +/* + * 映射器操作扩展 + * @author 卡莫sama(yuanjiashuai) + * @date 2023/8/7 + */ +fun BaseMapper<*>.queryList(init: (QueryScope.() -> Unit)? = null): List = + this.selectListByQuery(queryScope(init = init)) as List + +fun BaseMapper.update(entity: T, init: () -> QueryCondition): Int = + this.updateByCondition(entity, init()) + +fun BaseMapper.delete(init: (QueryScope.() -> Unit)? = null): Int = + this.deleteByQuery(queryScope(init = init)) + +fun BaseMapper.delete1(init: () -> QueryCondition): Int = + this.deleteByCondition(init()) diff --git a/mybatis-flex-kotlin/src/main/java/com/mybatisflex/kotlin/extend/sql/SqlExtend.kt b/mybatis-flex-kotlin/src/main/java/com/mybatisflex/kotlin/extend/sql/SqlExtend.kt new file mode 100644 index 00000000..3dc0e19b --- /dev/null +++ b/mybatis-flex-kotlin/src/main/java/com/mybatisflex/kotlin/extend/sql/SqlExtend.kt @@ -0,0 +1,59 @@ +package com.mybatisflex.kotlin.extend.sql + +import com.mybatisflex.core.query.Joiner +import com.mybatisflex.core.query.QueryColumn +import com.mybatisflex.core.query.QueryCondition +import com.mybatisflex.core.query.QueryWrapper +import java.util.function.Consumer +/* + * sql操作扩展 + * @author 卡莫sama(yuanjiashuai) + * @date 2023/8/7 + */ +infix fun QueryColumn.eq(value: Any?): QueryCondition { + return this.eq(value) +} + +inline fun QueryCondition.andIf(test: Boolean, block: () -> QueryCondition): QueryCondition { + if (test) { + this.and(block()) + } + return this +} + +inline fun QueryCondition.orIf(test: Boolean, block: () -> QueryCondition): QueryCondition { + if (test) { + this.or(block()) + } + return this +} + +inline fun `if`(test: Boolean, block: () -> QueryCondition): QueryCondition { + if (test) { + return block() + } + return QueryCondition.createEmpty() +} + +infix fun QueryColumn.like(value: String): QueryCondition = this.like(value) + +infix fun QueryCondition.and(other: QueryCondition): QueryCondition = this.and(other) + +infix fun QueryCondition.or(other: QueryCondition): QueryCondition = this.or(other) + +infix fun QueryColumn.`=`(value: Any?): QueryCondition = this.eq(value) + +infix fun QueryColumn.`in`(value: Collection): QueryCondition = this.`in`(value) + +fun QueryColumn.`in`(vararg values: Array): QueryCondition = this.`in`(values.asList()) + +infix fun QueryWrapper.`as`(alias: String) = this.`as`(alias) + +infix fun Joiner.`as`(alias: String?): Joiner = this.`as`(alias) + +infix fun Joiner.on(on: String?): M = this.on(on) + +infix fun Joiner.on(on: QueryCondition?): M = this.on(on) + +infix fun Joiner.on(consumer: Consumer): M = this.on(consumer) + diff --git a/mybatis-flex-kotlin/src/main/java/com/mybatisflex/kotlin/scope/QueryScope.kt b/mybatis-flex-kotlin/src/main/java/com/mybatisflex/kotlin/scope/QueryScope.kt new file mode 100755 index 00000000..70a88d3d --- /dev/null +++ b/mybatis-flex-kotlin/src/main/java/com/mybatisflex/kotlin/scope/QueryScope.kt @@ -0,0 +1,45 @@ +package com.mybatisflex.kotlin.scope + +import com.mybatisflex.core.query.QueryColumn +import com.mybatisflex.core.query.QueryCondition +import com.mybatisflex.core.query.QueryWrapper +import com.mybatisflex.core.table.TableDef +/** + * 查询作用域 + * @author 卡莫sama(yuanjiashuai) + * @date 2023/8/7 + */ +class QueryScope :QueryWrapper() { + companion object CurrentQueryScope : ThreadLocal() + + fun from(init: (QueryScope.() -> Unit)? = null): QueryWrapper = this.from(queryScope(init = init)) + + fun where(tableDef: T, build: T.() -> QueryCondition): QueryWrapper = this.where(build(tableDef)) + + fun where(build: QueryScope.() -> QueryCondition): QueryWrapper = this.where(build(this)) + + operator fun String.get(name: String): QueryColumn = QueryColumn(this, name) + + operator fun String.unaryMinus(): QueryColumn = QueryColumn(this) + +} + + +fun queryScope(vararg columns: QueryColumn?, init: (QueryScope.() -> Unit)? = null): QueryWrapper { + val builder = QueryScope() + + if (columns.isNotEmpty()) { + builder.select(columns) + } + //用于嵌套查询拿到上层查询包装对象 + init?.also { + val prentQueryScope = QueryScope.get() + QueryScope.set(builder) + it(builder) + QueryScope.set(prentQueryScope) + } + + return builder +} + + diff --git a/mybatis-flex-kotlin/src/test/java/com/mybatisflex/kotlintest/ExtensionTest.kt b/mybatis-flex-kotlin/src/test/java/com/mybatisflex/kotlintest/ExtensionTest.kt new file mode 100755 index 00000000..e54fb6be --- /dev/null +++ b/mybatis-flex-kotlin/src/test/java/com/mybatisflex/kotlintest/ExtensionTest.kt @@ -0,0 +1,76 @@ +package com.myba + +import com.mybatisflex.kotlin.extend.entry.batchDeleteById + +import com.mybatisflex.core.BaseMapper +import com.mybatisflex.core.MybatisFlexBootstrap +import com.mybatisflex.core.audit.AuditManager +import com.mybatisflex.core.audit.ConsoleMessageCollector +import com.mybatisflex.kotlin.entry.Entry +import com.mybatisflex.kotlin.extend.db.DB +import com.mybatisflex.kotlin.extend.db.DB.filter +import com.mybatisflex.kotlin.extend.entry.all +import com.mybatisflex.kotlin.extend.entry.batchInsert +import com.mybatisflex.kotlin.extend.entry.batchUpdate +import com.mybatisflex.kotlin.extend.mapper.queryList +import com.mybatisflex.kotlin.extend.sql.* +import com.mybatisflex.kotlintest.entry.Account +import com.mybatisflex.kotlintest.entry.table.AccountTableDef.ACCOUNT +import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder +import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType +import javax.sql.DataSource +import kotlin.streams.toList + + +fun main() { + val dataSource: DataSource = EmbeddedDatabaseBuilder() + .setType(EmbeddedDatabaseType.H2) + .addScript("schema.sql") + .addScript("data.sql") + .build() + + AuditManager.setAuditEnable(true); + AuditManager.setMessageCollector(ConsoleMessageCollector()) + MybatisFlexBootstrap.getInstance() + .addMapper(AccountMapper::class.java) + .setDataSource(dataSource) + .start() + filter { + ACCOUNT.AGE `=` 12 or + `if`(true) { ACCOUNT.ID `in` listOf(1, 2) } + }.stream().peek(::println).peek { it.id = it.id!!.plus(2) }.forEach(Entry::save) + println("保存后————————") + DB.mapper().findByAge(18,1,2).stream().peek { println(it) }.forEach(Entry::deleteById) + println("删除后————————") + ACCOUNT.all().stream().peek { println(it) }.map { it.userName = "sa" + it }.forEach(Entry::update) + println("更新后————————") + ACCOUNT.all().stream().peek { println(it) }.map { + it.id = it.id!!.plus(5) + it.userName = "423423" + it }.toList().batchInsert() + println("批量插入后————————") + ACCOUNT.all().stream().peek { println(it) }.toList().filter { it.id!!.rem(2) == 0 }.batchDeleteById() + println("批量删除后————————") + ACCOUNT.all().stream().peek { println(it) }.toList().filter { it.id!!.rem(3) == 0 }.map { it.userName = "哈哈" + it }.batchUpdate() + println("批量更新后————————") + ACCOUNT.all().stream().forEach { println(it) } +} + + +@JvmDefaultWithCompatibility +interface AccountMapper : BaseMapper { + + fun findByAge(age: Int, vararg ids: Int): List = queryList { + select(ACCOUNT.ALL_COLUMNS) + from(ACCOUNT) + where(ACCOUNT) { + (AGE `=` age) and `if`(true) { + ID `in` ids.asList() + } + } + } + +} + diff --git a/mybatis-flex-kotlin/src/test/java/com/mybatisflex/kotlintest/entry/Account.kt b/mybatis-flex-kotlin/src/test/java/com/mybatisflex/kotlintest/entry/Account.kt new file mode 100755 index 00000000..22242832 --- /dev/null +++ b/mybatis-flex-kotlin/src/test/java/com/mybatisflex/kotlintest/entry/Account.kt @@ -0,0 +1,25 @@ +package com.mybatisflex.kotlintest.entry + +import com.mybatisflex.annotation.Column +import com.mybatisflex.annotation.Id +import com.mybatisflex.annotation.NoneListener +import com.mybatisflex.annotation.Table +import com.mybatisflex.kotlin.entry.Entry +import java.util.* + +/** + * 测试用数据类(最好不要写成data class,否则需要与数据库字段数据顺序一致) + * @author 卡莫sama(yuanjiashuai) + * @date 2023/8/7 + */ +@Table(value = "tb_account", onUpdate = [NoneListener::class]) +data class Account( + @Id var id: Int?, + @Column("u_name") var userName: String?, + var age: Int?, + var birthday: Date?, + ) : Entry(){ + override fun toString(): String { + return "Account(id=$id, userName=$userName, birthday=$birthday, age=$age)" + } +} diff --git a/mybatis-flex-kotlin/src/test/resources/data.sql b/mybatis-flex-kotlin/src/test/resources/data.sql new file mode 100755 index 00000000..228b8319 --- /dev/null +++ b/mybatis-flex-kotlin/src/test/resources/data.sql @@ -0,0 +1,4 @@ +INSERT INTO tb_account +VALUES (1, 'Michael Yang', 18, '2020-01-11'); +INSERT INTO tb_account +VALUES (2, 'Michael Zhanng', 20, '2020-01-11'); diff --git a/mybatis-flex-kotlin/src/test/resources/mybatis-flex.properties b/mybatis-flex-kotlin/src/test/resources/mybatis-flex.properties new file mode 100755 index 00000000..b25cdd95 --- /dev/null +++ b/mybatis-flex-kotlin/src/test/resources/mybatis-flex.properties @@ -0,0 +1,4 @@ +processor.mappersGenerateEnable=false +processor.tablesNameStyle=upCase +processor.tablesDefSuffix=Def +processor.allInTables=true diff --git a/mybatis-flex-kotlin/src/test/resources/schema.sql b/mybatis-flex-kotlin/src/test/resources/schema.sql new file mode 100755 index 00000000..40881a74 --- /dev/null +++ b/mybatis-flex-kotlin/src/test/resources/schema.sql @@ -0,0 +1,15 @@ +CREATE TABLE IF NOT EXISTS `tb_account` +( + `id` INTEGER PRIMARY KEY, + `u_name` VARCHAR(100) NOT NULL, + `age` INTEGER, + `birthday` DATETIME +); + +CREATE TABLE IF NOT EXISTS `tb_account1` +( + `id` INTEGER PRIMARY KEY, + `u_name` VARCHAR(100) NOT NULL, + `age` INTEGER, + `birthday` DATETIME +); diff --git a/pom.xml b/pom.xml index b456525c..8ba1dd98 100644 --- a/pom.xml +++ b/pom.xml @@ -48,6 +48,7 @@ mybatis-flex-solon-plugin mybatis-flex-test mybatis-flex-processor + mybatis-flex-kotlin