mirror of
https://github.com/tursom/TursomServer.git
synced 2025-01-01 16:00:26 +08:00
添加协程mongo驱动
This commit is contained in:
parent
395866dc06
commit
655aafdb27
@ -1,82 +1,194 @@
|
||||
package cn.tursom.database
|
||||
|
||||
import cn.tursom.database.wrapper.MysqlWrapper
|
||||
import cn.tursom.database.wrapper.IUpdateWrapper
|
||||
import cn.tursom.database.wrapper.Query
|
||||
import cn.tursom.database.wrapper.Wrapper
|
||||
import java.io.Serializable
|
||||
import java.sql.PreparedStatement
|
||||
import java.sql.Types
|
||||
import java.util.*
|
||||
import javax.sql.DataSource
|
||||
|
||||
class MysqlSqlHelper<T : Any>(
|
||||
val clazz: Class<T>,
|
||||
var dataSource: DataSource
|
||||
) : SqlHelper<T> {
|
||||
private val table = SqlUtils { clazz.tableName }
|
||||
private val columns = clazz.declaredFields.map {
|
||||
SqlUtils { it.tableField } to it
|
||||
}
|
||||
private val insert = run {
|
||||
val sql = StringBuilder("INSERT INTO $table (")
|
||||
columns.forEach {
|
||||
sql.append(it.first)
|
||||
sql.append(',')
|
||||
}
|
||||
sql.deleteCharAt(sql.length - 1)
|
||||
sql.append(") VALUES ")
|
||||
sql.toString()
|
||||
}
|
||||
private val valuesTemplate = run {
|
||||
val sql = StringBuilder("(")
|
||||
repeat(columns.size) {
|
||||
sql.append("?,")
|
||||
}
|
||||
sql.deleteCharAt(sql.length - 1)
|
||||
sql.append(")")
|
||||
sql.toString()
|
||||
}
|
||||
private val insertOne = "$insert$valuesTemplate;"
|
||||
|
||||
private val selects = clazz.declaredFields
|
||||
.map { SqlUtils { it.selectField } }
|
||||
.let {
|
||||
val sb = StringBuilder()
|
||||
it.forEach { field ->
|
||||
sb.append(field)
|
||||
sb.append(',')
|
||||
}
|
||||
sb.deleteCharAt(sb.lastIndex)
|
||||
sb.toString()
|
||||
}
|
||||
|
||||
class MysqlSqlHelper<T> : SqlHelper<T, MysqlWrapper<T>> {
|
||||
override fun save(entity: T): Boolean {
|
||||
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||
val conn = dataSource.connection
|
||||
val statement = conn.prepareStatement(insertOne)
|
||||
columns.forEachIndexed { index, (_, field) ->
|
||||
setValue(statement, index, field.get(entity))
|
||||
}
|
||||
return statement.executeUpdate() != 0
|
||||
}
|
||||
|
||||
override fun saveBatch(entityList: Collection<T>, batchSize: Int): Boolean {
|
||||
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||
override fun saveBatch(entityList: Collection<T>): Int {
|
||||
if (entityList.isEmpty()) {
|
||||
return 0
|
||||
}
|
||||
val sqlBuilder = StringBuilder(insert)
|
||||
repeat(entityList.size) {
|
||||
sqlBuilder.append(valuesTemplate)
|
||||
sqlBuilder.append(',')
|
||||
}
|
||||
sqlBuilder.deleteCharAt(sqlBuilder.lastIndex)
|
||||
sqlBuilder.append(';')
|
||||
val sql = sqlBuilder.toString()
|
||||
|
||||
val conn = dataSource.connection
|
||||
val statement = conn.prepareStatement(sql)
|
||||
try {
|
||||
var index = 0
|
||||
entityList.forEach {
|
||||
columns.forEach { (_, field) ->
|
||||
setValue(statement, index, field.get(it))
|
||||
index++
|
||||
}
|
||||
}
|
||||
return statement.executeUpdate()
|
||||
} finally {
|
||||
statement.close()
|
||||
conn.close()
|
||||
}
|
||||
}
|
||||
|
||||
override fun saveOrUpdateBatch(entityList: Collection<T>, batchSize: Int): Boolean {
|
||||
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
//override fun saveOrUpdateBatch(entityList: Collection<T>, batchSize: Int): Boolean {
|
||||
// TODO("Not yet implemented")
|
||||
//}
|
||||
|
||||
override fun removeById(id: Serializable?): Boolean {
|
||||
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override fun removeByMap(columnMap: Map<String, Any?>): Boolean {
|
||||
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override fun remove(queryWrapper: MysqlWrapper<T>): Boolean {
|
||||
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||
override fun remove(queryWrapper: Wrapper<T>): Boolean {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override fun removeByIds(idList: Collection<Serializable>): Boolean {
|
||||
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override fun updateById(entity: T): Boolean {
|
||||
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override fun update(entity: T?, updateWrapper: MysqlWrapper<T>): Boolean {
|
||||
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||
override fun update(entity: T?, updateWrapper: IUpdateWrapper<T>): Boolean {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override fun updateBatchById(entityList: Collection<T>, batchSize: Int): Boolean {
|
||||
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override fun saveOrUpdate(entity: T?): Boolean {
|
||||
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override fun getById(id: Serializable?): T? {
|
||||
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override fun listByIds(idList: Collection<Serializable>): Collection<T> {
|
||||
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override fun listByMap(columnMap: Map<String, Any?>): Collection<T> {
|
||||
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override fun getOne(queryWrapper: MysqlWrapper<T>, throwEx: Boolean): T? {
|
||||
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||
override fun getOne(queryWrapper: Wrapper<T>, throwEx: Boolean): T? {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override fun getMap(queryWrapper: MysqlWrapper<T>): Map<String, Any?> {
|
||||
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||
override fun getMap(queryWrapper: Wrapper<T>): Map<String, Any?> {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override fun count(queryWrapper: MysqlWrapper<T>): Int {
|
||||
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||
override fun count(queryWrapper: Wrapper<T>): Int {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override fun list(queryWrapper: MysqlWrapper<T>): List<T> {
|
||||
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||
override fun list(queryWrapper: Wrapper<T>): List<T> {
|
||||
val select = if (queryWrapper !is Query<*, *>) {
|
||||
selects
|
||||
} else {
|
||||
val select = queryWrapper.sqlSelect
|
||||
if (select.isEmpty()) {
|
||||
selects
|
||||
} else {
|
||||
select
|
||||
}
|
||||
}
|
||||
|
||||
val (where, whereParams) = queryWrapper.where
|
||||
val sql = "SELECT $select FROM $table WHERE (${where});"
|
||||
dataSource.connection.use { conn ->
|
||||
conn.prepareStatement(sql).use { statement ->
|
||||
var index = 0
|
||||
whereParams.forEach {
|
||||
setValue(statement, index, it)
|
||||
index++
|
||||
}
|
||||
val query = statement.executeQuery()
|
||||
val adapter = SqlAdapter(clazz)
|
||||
query.use { adapter.adapt(query) }
|
||||
return adapter
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun getBaseMapper(): Mapper<T> {
|
||||
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun setValue(statement: PreparedStatement, index: Int, value: Any?) {
|
||||
when (value) {
|
||||
null -> statement.setNull(index + 1, Types.NULL)
|
||||
is Date -> statement.setDate(index + 1, java.sql.Date(value.time))
|
||||
else -> statement.setObject(index + 1, value)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
package cn.tursom.database
|
||||
|
||||
import javax.sql.DataSource
|
||||
|
||||
class MysqlSqlTemplate(
|
||||
private val dataSource: DataSource
|
||||
) : SqlTemplate {
|
||||
|
||||
override fun <T : Any> getHelper(clazz: Class<T>): MysqlSqlHelper<T> {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
companion object {
|
||||
init {
|
||||
Class.forName("com.mysql.cj.jdbc.Driver");
|
||||
}
|
||||
}
|
||||
}
|
@ -1,135 +0,0 @@
|
||||
package cn.tursom.database.wrapper
|
||||
|
||||
import java.util.function.BiPredicate
|
||||
import java.util.function.Consumer
|
||||
import kotlin.reflect.KProperty1
|
||||
|
||||
open class MysqlWrapper<T> : AbstractWrapper<T, MysqlWrapper<T>> {
|
||||
override fun <V> allEq(condition: Boolean, params: Map<KProperty1<T, *>, V>?, null2IsNull: Boolean): MysqlWrapper<T> {
|
||||
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
override fun <V> allEq(condition: Boolean, filter: BiPredicate<KProperty1<T, *>, V>?, params: Map<KProperty1<T, *>, V>?, null2IsNull: Boolean): MysqlWrapper<T> {
|
||||
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
override fun eq(condition: Boolean, column: KProperty1<T, *>, `val`: Any?): MysqlWrapper<T> {
|
||||
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
override fun ne(condition: Boolean, column: KProperty1<T, *>, `val`: Any?): MysqlWrapper<T> {
|
||||
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
override fun gt(condition: Boolean, column: KProperty1<T, *>, `val`: Any?): MysqlWrapper<T> {
|
||||
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
override fun ge(condition: Boolean, column: KProperty1<T, *>, `val`: Any?): MysqlWrapper<T> {
|
||||
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
override fun lt(condition: Boolean, column: KProperty1<T, *>, `val`: Any?): MysqlWrapper<T> {
|
||||
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
override fun le(condition: Boolean, column: KProperty1<T, *>, `val`: Any?): MysqlWrapper<T> {
|
||||
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
override fun between(condition: Boolean, column: KProperty1<T, *>, val1: Any?, val2: Any?): MysqlWrapper<T> {
|
||||
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
override fun notBetween(condition: Boolean, column: KProperty1<T, *>, val1: Any?, val2: Any?): MysqlWrapper<T> {
|
||||
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
override fun like(condition: Boolean, column: KProperty1<T, *>, `val`: Any?): MysqlWrapper<T> {
|
||||
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
override fun notLike(condition: Boolean, column: KProperty1<T, *>, `val`: Any?): MysqlWrapper<T> {
|
||||
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
override fun likeLeft(condition: Boolean, column: KProperty1<T, *>, `val`: Any?): MysqlWrapper<T> {
|
||||
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
override fun likeRight(condition: Boolean, column: KProperty1<T, *>, `val`: Any?): MysqlWrapper<T> {
|
||||
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
override fun and(condition: Boolean, consumer: Consumer<MysqlWrapper<T>>?): MysqlWrapper<T> {
|
||||
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
override fun or(condition: Boolean, consumer: Consumer<MysqlWrapper<T>>?): MysqlWrapper<T> {
|
||||
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
override fun or(condition: Boolean): MysqlWrapper<T> {
|
||||
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
override fun nested(condition: Boolean, consumer: Consumer<MysqlWrapper<T>>?): MysqlWrapper<T> {
|
||||
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
override fun apply(condition: Boolean, applySql: String?, vararg value: Any?): MysqlWrapper<T> {
|
||||
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
override fun last(condition: Boolean, lastSql: String?): MysqlWrapper<T> {
|
||||
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
override fun comment(condition: Boolean, comment: String?): MysqlWrapper<T> {
|
||||
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
override fun exists(condition: Boolean, existsSql: String?): MysqlWrapper<T> {
|
||||
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
override fun notExists(condition: Boolean, notExistsSql: String?): MysqlWrapper<T> {
|
||||
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
override fun isNull(condition: Boolean, column: KProperty1<T, *>): MysqlWrapper<T> {
|
||||
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
override fun isNotNull(condition: Boolean, column: KProperty1<T, *>): MysqlWrapper<T> {
|
||||
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
override fun `in`(condition: Boolean, column: KProperty1<T, *>, coll: Collection<*>?): MysqlWrapper<T> {
|
||||
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
override fun notIn(condition: Boolean, column: KProperty1<T, *>, coll: Collection<*>?): MysqlWrapper<T> {
|
||||
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
override fun inSql(condition: Boolean, column: KProperty1<T, *>, inValue: String?): MysqlWrapper<T> {
|
||||
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
override fun notInSql(condition: Boolean, column: KProperty1<T, *>, inValue: String?): MysqlWrapper<T> {
|
||||
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
override fun groupBy(condition: Boolean, vararg columns: KProperty1<T, *>): MysqlWrapper<T> {
|
||||
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
override fun orderBy(condition: Boolean, isAsc: Boolean, vararg columns: KProperty1<T, *>): MysqlWrapper<T> {
|
||||
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
override fun having(condition: Boolean, sqlHaving: String?, vararg params: Any?): MysqlWrapper<T> {
|
||||
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
}
|
11
database/mongodb/mongodb-async/build.gradle
Normal file
11
database/mongodb/mongodb-async/build.gradle
Normal file
@ -0,0 +1,11 @@
|
||||
|
||||
dependencies {
|
||||
implementation project(":")
|
||||
implementation project(":utils")
|
||||
implementation project(":database:mongodb")
|
||||
// https://mvnrepository.com/artifact/org.mongodb/mongodb-driver-reactivestreams
|
||||
compile group: 'org.mongodb', name: 'mongodb-driver-reactivestreams', version: '4.0.0'
|
||||
api group: 'org.jetbrains.kotlin', name: 'kotlin-reflect', version: kotlinVersion
|
||||
// kotlin 协程
|
||||
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.2.1'
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
package cn.tursom.mongodb.async
|
||||
|
||||
import org.reactivestreams.Subscriber
|
||||
import org.reactivestreams.Subscription
|
||||
|
||||
abstract class AbstractSubscriber<T> : Subscriber<T> {
|
||||
var compete = false
|
||||
lateinit var subscription: Subscription
|
||||
|
||||
override fun onComplete() {
|
||||
compete = true
|
||||
}
|
||||
|
||||
override fun onSubscribe(s: Subscription) {
|
||||
subscription = s
|
||||
}
|
||||
}
|
@ -0,0 +1,198 @@
|
||||
package cn.tursom.mongodb.async
|
||||
|
||||
import cn.tursom.core.Disposable
|
||||
import cn.tursom.mongodb.BsonFactoryImpl
|
||||
import cn.tursom.mongodb.MongoUtil
|
||||
import cn.tursom.mongodb.Update
|
||||
import cn.tursom.utils.AsyncIterator
|
||||
import cn.tursom.utils.forEach
|
||||
import com.mongodb.MongoClientSettings
|
||||
import com.mongodb.ServerAddress
|
||||
import com.mongodb.client.model.DeleteOptions
|
||||
import com.mongodb.client.model.InsertManyOptions
|
||||
import com.mongodb.client.model.InsertOneOptions
|
||||
import com.mongodb.client.model.UpdateOptions
|
||||
import com.mongodb.client.result.InsertManyResult
|
||||
import com.mongodb.client.result.InsertOneResult
|
||||
import com.mongodb.client.result.UpdateResult
|
||||
import com.mongodb.reactivestreams.client.MongoClients
|
||||
import com.mongodb.reactivestreams.client.MongoCollection
|
||||
import com.mongodb.reactivestreams.client.MongoDatabase
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import org.bson.Document
|
||||
import org.bson.conversions.Bson
|
||||
import org.reactivestreams.Publisher
|
||||
import org.reactivestreams.Subscriber
|
||||
import org.reactivestreams.Subscription
|
||||
import java.util.concurrent.ConcurrentLinkedQueue
|
||||
import kotlin.coroutines.Continuation
|
||||
import kotlin.coroutines.resume
|
||||
import kotlin.coroutines.resumeWithException
|
||||
import kotlin.coroutines.suspendCoroutine
|
||||
import kotlin.reflect.KProperty1
|
||||
|
||||
class AsyncMongoOperator<T : Any>(
|
||||
@Suppress("MemberVisibilityCanBePrivate") val collection: MongoCollection<Document>,
|
||||
clazz: Class<T>
|
||||
) : MongoCollection<Document> by collection, BsonFactoryImpl<T>(clazz) {
|
||||
constructor(clazz: Class<T>, db: MongoDatabase) : this(db.getCollection(MongoUtil.collectionName(clazz)), clazz)
|
||||
|
||||
suspend fun save(entity: T, options: InsertOneOptions = InsertOneOptions()) {
|
||||
val publisher = collection.insertOne(convertToBson(entity), options)
|
||||
suspendCoroutine<Unit> { cont ->
|
||||
publisher.subscribe(object : Subscriber<InsertOneResult> {
|
||||
override fun onComplete() = cont.resume(Unit)
|
||||
override fun onSubscribe(s: Subscription?) {}
|
||||
override fun onNext(t: InsertOneResult?) {}
|
||||
override fun onError(t: Throwable) = cont.resumeWithException(t)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
suspend fun save(entities: Collection<T>, options: InsertManyOptions = InsertManyOptions()) {
|
||||
val publisher = collection.insertMany(entities.map { convertToBson(it) }, options)
|
||||
suspendCoroutine<Unit> { cont ->
|
||||
publisher.subscribe(object : Subscriber<InsertManyResult> {
|
||||
override fun onComplete() = cont.resume(Unit)
|
||||
override fun onSubscribe(s: Subscription?) {}
|
||||
override fun onNext(t: InsertManyResult) {}
|
||||
override fun onError(t: Throwable) = cont.resumeWithException(t)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun update(update: Bson, where: Bson, options: UpdateOptions = UpdateOptions()): UpdateResult {
|
||||
val publisher = collection.updateOne(where, update, options)
|
||||
return suspendCoroutine { cont ->
|
||||
publisher.subscribe(object : Subscriber<UpdateResult> {
|
||||
override fun onComplete() {}
|
||||
override fun onSubscribe(s: Subscription) {}
|
||||
override fun onNext(t: UpdateResult) = cont.resume(t)
|
||||
override fun onError(t: Throwable) = cont.resumeWithException(t)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun update(entity: T, where: Bson, options: UpdateOptions = UpdateOptions()): UpdateResult {
|
||||
return update(convertToBson(entity), where, options)
|
||||
}
|
||||
|
||||
@Suppress("SpellCheckingInspection")
|
||||
suspend fun upsert(entity: T, where: Bson, options: UpdateOptions = UpdateOptions()): UpdateResult {
|
||||
return update(entity, where, options.upsert(true))
|
||||
}
|
||||
|
||||
@Suppress("SpellCheckingInspection")
|
||||
suspend fun upsert(update: Bson, where: Bson, options: UpdateOptions = UpdateOptions()): UpdateResult {
|
||||
return update(update, where, options.upsert(true))
|
||||
}
|
||||
|
||||
suspend fun add(field: KProperty1<T, Number?>, value: Number, where: Bson, options: UpdateOptions = UpdateOptions()): UpdateResult {
|
||||
return upsert(
|
||||
Update { field inc value },
|
||||
where, options
|
||||
)
|
||||
}
|
||||
|
||||
suspend fun inc(field: KProperty1<T, Number?>, where: Bson): UpdateResult {
|
||||
return add(field, 1, where)
|
||||
}
|
||||
|
||||
suspend fun getOne(where: Bson? = null): T? {
|
||||
val publisher = if (where == null) find() else find(where)
|
||||
return suspendCoroutine { cont ->
|
||||
publisher.subscribe(object : AbstractSubscriber<Document>() {
|
||||
var resumed = false
|
||||
override fun onComplete() {
|
||||
super.onComplete()
|
||||
if (!resumed) cont.resume(null)
|
||||
}
|
||||
|
||||
override fun onSubscribe(s: Subscription) = s.request(1)
|
||||
override fun onNext(t: Document) = cont.resume(parse(t))
|
||||
override fun onError(t: Throwable) = cont.resumeWithException(t)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun list(where: Bson? = null): List<T> {
|
||||
val publisher = if (where == null) find() else find(where)
|
||||
val resultList = ArrayList<T>()
|
||||
suspendCoroutine<Unit> { cont ->
|
||||
publisher.subscribe(object : AbstractSubscriber<Document>() {
|
||||
override fun onComplete() {
|
||||
super.onComplete()
|
||||
cont.resume(Unit)
|
||||
}
|
||||
|
||||
override fun onSubscribe(s: Subscription) = s.request(Int.MAX_VALUE.toLong())
|
||||
override fun onNext(t: Document) {
|
||||
resultList.add(parse(t))
|
||||
}
|
||||
|
||||
override fun onError(t: Throwable) = cont.resumeWithException(t)
|
||||
})
|
||||
}
|
||||
return resultList
|
||||
}
|
||||
|
||||
fun get(where: Bson? = null, bufSize: Int = 32): AsyncIterator<T> {
|
||||
val find = if (where == null) find() else find(where)
|
||||
return iterator(find, bufSize)
|
||||
}
|
||||
|
||||
fun aggregate(vararg pipeline: Bson, bufSize: Int = 32) = iterator(aggregate(pipeline.asList()), bufSize)
|
||||
|
||||
private fun iterator(publisher: Publisher<Document>, bufSize: Int = 32): AsyncIterator<T> {
|
||||
val subscriber = object : AbstractSubscriber<Document>(), AsyncIterator<T> {
|
||||
private var cont = Disposable<Continuation<T>>()
|
||||
private var notify = Disposable<Continuation<Unit>>()
|
||||
private val cache = ConcurrentLinkedQueue<T>()
|
||||
|
||||
override fun onComplete() {
|
||||
super.onComplete()
|
||||
cont.get()?.resumeWithException(Exception())
|
||||
notify.get()?.resume(Unit)
|
||||
}
|
||||
|
||||
override fun onNext(t: Document) {
|
||||
val entity = parse(t)
|
||||
cont.get()?.resume(entity) ?: cache.add(entity)
|
||||
notify.get()?.resume(Unit)
|
||||
}
|
||||
|
||||
override fun onError(t: Throwable) {
|
||||
cont.get()?.resumeWithException(t) ?: t.printStackTrace()
|
||||
}
|
||||
|
||||
override suspend fun next(): T {
|
||||
return cache.poll() ?: suspendCoroutine { cont ->
|
||||
this.cont.set(cont)
|
||||
subscription.request(bufSize.toLong())
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun hasNext(): Boolean = if (cache.isEmpty()) {
|
||||
suspendCoroutine<Unit> {
|
||||
notify.set(it)
|
||||
subscription.request(bufSize.toLong())
|
||||
}
|
||||
!compete
|
||||
} else {
|
||||
!compete
|
||||
}
|
||||
}
|
||||
publisher.subscribe(subscriber)
|
||||
return subscriber
|
||||
}
|
||||
|
||||
fun delete(entity: T, options: DeleteOptions = DeleteOptions()) {
|
||||
deleteOne(convertToBson(entity), options)
|
||||
}
|
||||
|
||||
suspend fun saveIfNotExists(entity: T) {
|
||||
val document = convertToBson(entity)
|
||||
upsert(document, document)
|
||||
}
|
||||
}
|
@ -0,0 +1,57 @@
|
||||
package cn.tursom.mongodb.async
|
||||
|
||||
import cn.tursom.core.cast
|
||||
import com.mongodb.MongoClientSettings
|
||||
import com.mongodb.ServerAddress
|
||||
import com.mongodb.client.model.InsertManyOptions
|
||||
import com.mongodb.client.model.InsertOneOptions
|
||||
import com.mongodb.client.model.UpdateOptions
|
||||
import com.mongodb.reactivestreams.client.MongoClient
|
||||
import com.mongodb.reactivestreams.client.MongoClients
|
||||
import org.bson.conversions.Bson
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
|
||||
class AsyncMongoTemplate(
|
||||
val mongoClient: MongoClient,
|
||||
db: String
|
||||
) {
|
||||
constructor(db: String, vararg servers: ServerAddress) : this(MongoClientSettings.builder().let {
|
||||
it.applyToClusterSettings { builder ->
|
||||
builder.hosts(servers.asList())
|
||||
}
|
||||
MongoClients.create(it.build())
|
||||
}, db)
|
||||
|
||||
constructor(host: String, port: Int, db: String) : this(db, ServerAddress(host, port))
|
||||
|
||||
val db = mongoClient.getDatabase(db)
|
||||
private val operatorMap = ConcurrentHashMap<Class<*>, AsyncMongoOperator<*>>()
|
||||
|
||||
|
||||
suspend fun <T : Any> save(entity: T, options: InsertOneOptions = InsertOneOptions()) {
|
||||
getCollection(entity.javaClass).save(entity, options)
|
||||
}
|
||||
|
||||
suspend inline fun <reified T : Any> save(entities: Collection<T>, options: InsertManyOptions = InsertManyOptions()) {
|
||||
getCollection<T>().save(entities, options)
|
||||
}
|
||||
|
||||
suspend fun <T : Any> update(entity: T, where: Bson, options: UpdateOptions = UpdateOptions()) {
|
||||
getCollection(entity.javaClass).update(entity, where, options)
|
||||
}
|
||||
|
||||
@Suppress("SpellCheckingInspection")
|
||||
suspend fun <T : Any> upsert(entity: T, where: Bson, options: UpdateOptions = UpdateOptions()) {
|
||||
getCollection(entity.javaClass).upsert(entity, where, options)
|
||||
}
|
||||
|
||||
inline fun <reified T : Any> getCollection(): AsyncMongoOperator<T> = getCollection(T::class.java)
|
||||
|
||||
fun <T : Any> getCollection(clazz: Class<T>): AsyncMongoOperator<T> {
|
||||
return operatorMap[clazz]?.cast() ?: run {
|
||||
val operator = AsyncMongoOperator(clazz, db)
|
||||
operatorMap[clazz] = operator
|
||||
operator
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
package cn.tursom.mongodb
|
||||
|
||||
import cn.tursom.core.Parser
|
||||
import org.bson.Document
|
||||
|
||||
interface BsonFactory<T> {
|
||||
val clazz: Class<T>
|
||||
|
||||
fun parse(document: Document) = Parser.parse(document, clazz)!!
|
||||
|
||||
fun convertToBson(entity: Any): Document
|
||||
|
||||
//fun convertToEntity(bson: Document): T
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
package cn.tursom.mongodb
|
||||
|
||||
import cn.tursom.core.Unsafe
|
||||
import cn.tursom.core.cast
|
||||
import cn.tursom.core.isStatic
|
||||
import cn.tursom.core.isTransient
|
||||
import cn.tursom.mongodb.annotation.Ignore
|
||||
import org.bson.Document
|
||||
|
||||
open class BsonFactoryImpl<T>(final override val clazz: Class<T>) : BsonFactory<T> {
|
||||
private val fields = clazz.declaredFields.filter {
|
||||
it.isAccessible = true
|
||||
!it.isStatic() && !it.isTransient() && it.getAnnotation(Ignore::class.java) == null
|
||||
}
|
||||
|
||||
override fun convertToBson(entity: Any): Document {
|
||||
val bson = Document()
|
||||
fields.forEach {
|
||||
MongoUtil.injectValue(bson, it.get(entity) ?: return@forEach, it)
|
||||
}
|
||||
return bson
|
||||
}
|
||||
}
|
@ -16,14 +16,12 @@ import org.bson.conversions.Bson
|
||||
import kotlin.reflect.KProperty1
|
||||
|
||||
@Suppress("MemberVisibilityCanBePrivate", "CanBeParameter", "unused")
|
||||
class MongoOperator<T : Any>(
|
||||
open class MongoOperator<T : Any>(
|
||||
val collection: MongoCollection<Document>,
|
||||
val clazz: Class<T>
|
||||
) : MongoCollection<Document> by collection {
|
||||
clazz: Class<T>
|
||||
) : MongoCollection<Document> by collection, BsonFactoryImpl<T>(clazz) {
|
||||
constructor(clazz: Class<T>, database: MongoDatabase) : this(database.getCollection(MongoUtil.collectionName(clazz)), clazz)
|
||||
|
||||
fun parse(document: Document) = Parser.parse(document, clazz)
|
||||
|
||||
private val fields = clazz.declaredFields.filter {
|
||||
it.isAccessible = true
|
||||
!it.isStatic() && !it.isTransient() && it.getAnnotation(Ignore::class.java) == null
|
||||
@ -120,26 +118,5 @@ class MongoOperator<T : Any>(
|
||||
val document = convertToBson(entity)
|
||||
upsert(document, document)
|
||||
}
|
||||
}
|
||||
|
||||
fun convertToBson(entity: Any): Document {
|
||||
val bson = Document()
|
||||
fields.forEach {
|
||||
MongoUtil.injectValue(bson, it.get(entity) ?: return@forEach, it)
|
||||
}
|
||||
return bson
|
||||
}
|
||||
|
||||
fun convertToEntity(bson: Document): T {
|
||||
val entity = try {
|
||||
clazz.newInstance()
|
||||
} catch (e: Exception) {
|
||||
Unsafe.unsafe.allocateInstance(clazz)
|
||||
}.cast<T>()
|
||||
fields.forEach {
|
||||
val value = bson[MongoUtil.fieldName(it)] ?: return@forEach
|
||||
MongoUtil.injectValue(bson, value, it)
|
||||
}
|
||||
return entity
|
||||
}
|
||||
|
||||
}
|
@ -13,7 +13,7 @@ object Constants {
|
||||
/**
|
||||
* project name
|
||||
*/
|
||||
const val MYBATIS_PLUS = "mybatis-plus"
|
||||
const val TABLE = "table"
|
||||
/**
|
||||
* MD5
|
||||
*/
|
||||
@ -34,38 +34,7 @@ object Constants {
|
||||
* wrapper 类 带后缀 ==> .
|
||||
*/
|
||||
const val WRAPPER_DOT = WRAPPER + DOT
|
||||
/**
|
||||
* wrapper 类的属性 entity
|
||||
*/
|
||||
const val WRAPPER_ENTITY = WRAPPER_DOT + "entity"
|
||||
/**
|
||||
* wrapper 类的属性 sqlSegment
|
||||
*/
|
||||
const val WRAPPER_SQLSEGMENT = WRAPPER_DOT + "sqlSegment"
|
||||
/**
|
||||
* wrapper 类的属性 emptyOfNormal
|
||||
*/
|
||||
const val WRAPPER_EMPTYOFNORMAL = WRAPPER_DOT + "emptyOfNormal"
|
||||
/**
|
||||
* wrapper 类的属性 nonEmptyOfNormal
|
||||
*/
|
||||
const val WRAPPER_NONEMPTYOFNORMAL = WRAPPER_DOT + "nonEmptyOfNormal"
|
||||
/**
|
||||
* wrapper 类的属性 nonEmptyOfEntity
|
||||
*/
|
||||
const val WRAPPER_NONEMPTYOFENTITY = WRAPPER_DOT + "nonEmptyOfEntity"
|
||||
/**
|
||||
* wrapper 类的属性 emptyOfWhere
|
||||
*/
|
||||
const val WRAPPER_EMPTYOFWHERE = WRAPPER_DOT + "emptyOfWhere"
|
||||
/**
|
||||
* wrapper 类的判断属性 nonEmptyOfWhere
|
||||
*/
|
||||
const val WRAPPER_NONEMPTYOFWHERE = WRAPPER_DOT + "nonEmptyOfWhere"
|
||||
/**
|
||||
* wrapper 类的属性 entity 带后缀 ==> .
|
||||
*/
|
||||
const val WRAPPER_ENTITY_DOT = WRAPPER_DOT + "entity" + DOT
|
||||
const val WRAPPER_WHERE = WRAPPER_DOT + "where"
|
||||
/**
|
||||
* UpdateWrapper 类的属性 sqlSet
|
||||
*/
|
||||
|
@ -1,5 +1,7 @@
|
||||
package cn.tursom.database
|
||||
|
||||
import cn.tursom.database.annotations.Delete
|
||||
import cn.tursom.database.annotations.Insert
|
||||
import cn.tursom.database.annotations.Param
|
||||
import cn.tursom.database.wrapper.Wrapper
|
||||
import java.io.Serializable
|
||||
@ -18,20 +20,23 @@ interface Mapper<T> {
|
||||
*
|
||||
* @param entity 实体对象
|
||||
*/
|
||||
fun insert(entity: T): Int
|
||||
@Insert("insert into \${${Constants.TABLE}} #{${Constants.ENTITY}}")
|
||||
fun insert(@Param(Constants.ENTITY) entity: T): Int
|
||||
|
||||
/**
|
||||
* 根据 ID 删除
|
||||
*
|
||||
* @param id 主键ID
|
||||
*/
|
||||
fun deleteById(id: Serializable): Int
|
||||
@Delete("delete from \${${Constants.TABLE}} where id=#{id}")
|
||||
fun deleteById(@Param("id") id: Serializable): Int
|
||||
|
||||
/**
|
||||
* 根据 columnMap 条件,删除记录
|
||||
*
|
||||
* @param columnMap 表字段 map 对象
|
||||
*/
|
||||
@Delete("delete from \${${Constants.TABLE}} where #{${Constants.COLUMN_MAP}}")
|
||||
fun deleteByMap(@Param(Constants.COLUMN_MAP) columnMap: Map<String, Any?>): Int
|
||||
|
||||
/**
|
||||
@ -39,6 +44,7 @@ interface Mapper<T> {
|
||||
*
|
||||
* @param wrapper 实体对象封装操作类(可以为 null)
|
||||
*/
|
||||
@Delete("delete from \${${Constants.TABLE}} where #{${Constants.WRAPPER_WHERE}}")
|
||||
fun delete(@Param(Constants.WRAPPER) wrapper: Wrapper<T>): Int
|
||||
|
||||
/**
|
||||
@ -120,4 +126,9 @@ interface Mapper<T> {
|
||||
* @param queryWrapper 实体对象封装操作类(可以为 null)
|
||||
*/
|
||||
fun selectObjs(@Param(Constants.WRAPPER) queryWrapper: Wrapper<T>): List<Any>
|
||||
|
||||
companion object {
|
||||
fun <T> instance(clazz: Class<out Mapper<T>>) {
|
||||
}
|
||||
}
|
||||
}
|
17
database/src/main/kotlin/cn/tursom/database/ResultSetMap.kt
Normal file
17
database/src/main/kotlin/cn/tursom/database/ResultSetMap.kt
Normal file
@ -0,0 +1,17 @@
|
||||
package cn.tursom.database
|
||||
|
||||
import java.sql.ResultSet
|
||||
|
||||
class ResultSetMap(
|
||||
val resultSet: ResultSet
|
||||
) : Map<String, Any?> {
|
||||
override val entries: Set<Map.Entry<String, Any?>> get() = TODO("Not yet implemented")
|
||||
override val keys: Set<String> get() = TODO("Not yet implemented")
|
||||
override val size: Int get() = resultSet.fetchSize
|
||||
override val values: Collection<Any?> get() = TODO("Not yet implemented")
|
||||
override fun containsKey(key: String): Boolean = TODO("Not yet implemented")
|
||||
override fun containsValue(value: Any?): Boolean = TODO("Not yet implemented")
|
||||
override fun isEmpty(): Boolean = TODO("Not yet implemented")
|
||||
|
||||
override fun get(key: String): Any? = resultSet.getObject(key)
|
||||
}
|
22
database/src/main/kotlin/cn/tursom/database/SqlAdapter.kt
Normal file
22
database/src/main/kotlin/cn/tursom/database/SqlAdapter.kt
Normal file
@ -0,0 +1,22 @@
|
||||
package cn.tursom.database
|
||||
|
||||
import cn.tursom.core.Parser
|
||||
import java.sql.ResultSet
|
||||
import java.sql.SQLException
|
||||
|
||||
open class SqlAdapter<T : Any>(private val clazz: Class<T>) : ArrayList<T>() {
|
||||
open fun adapt(resultSet: ResultSet) {
|
||||
clear() //清空已储存的数据
|
||||
val resultMap = ResultSetMap(resultSet)
|
||||
// 遍历ResultSet
|
||||
while (resultSet.next()) {
|
||||
try {
|
||||
add(Parser.parse(resultMap, clazz) ?: continue)
|
||||
} catch (e: SQLException) {
|
||||
// ignored
|
||||
} catch (e: IllegalStateException) {
|
||||
// ignored
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,10 +1,11 @@
|
||||
package cn.tursom.database
|
||||
|
||||
import cn.tursom.database.wrapper.IUpdateWrapper
|
||||
import cn.tursom.database.wrapper.Wrapper
|
||||
import java.io.Serializable
|
||||
|
||||
@Suppress("unused")
|
||||
interface SqlHelper<T, W : Wrapper<T>> {
|
||||
interface SqlHelper<T> {
|
||||
/**
|
||||
* 插入一条记录(选择字段,策略插入)
|
||||
*
|
||||
@ -17,34 +18,24 @@ interface SqlHelper<T, W : Wrapper<T>> {
|
||||
*
|
||||
* @param entityList 实体对象集合
|
||||
*/
|
||||
fun saveBatch(entityList: Collection<T>): Boolean {
|
||||
return saveBatch(entityList, 1000)
|
||||
}
|
||||
fun saveBatch(entityList: Collection<T>): Int
|
||||
|
||||
/**
|
||||
* 插入(批量)
|
||||
*
|
||||
* @param entityList 实体对象集合
|
||||
* @param batchSize 插入批次数量
|
||||
*/
|
||||
fun saveBatch(entityList: Collection<T>, batchSize: Int): Boolean
|
||||
|
||||
/**
|
||||
* 批量修改插入
|
||||
*
|
||||
* @param entityList 实体对象集合
|
||||
*/
|
||||
fun saveOrUpdateBatch(entityList: Collection<T>): Boolean {
|
||||
return saveOrUpdateBatch(entityList, 1000)
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量修改插入
|
||||
*
|
||||
* @param entityList 实体对象集合
|
||||
* @param batchSize 每次的数量
|
||||
*/
|
||||
fun saveOrUpdateBatch(entityList: Collection<T>, batchSize: Int): Boolean
|
||||
///**
|
||||
// * 批量修改插入
|
||||
// *
|
||||
// * @param entityList 实体对象集合
|
||||
// */
|
||||
//fun saveOrUpdateBatch(entityList: Collection<T>): Boolean {
|
||||
// return saveOrUpdateBatch(entityList, 1000)
|
||||
//}
|
||||
//
|
||||
///**
|
||||
// * 批量修改插入
|
||||
// *
|
||||
// * @param entityList 实体对象集合
|
||||
// * @param batchSize 每次的数量
|
||||
// */
|
||||
//fun saveOrUpdateBatch(entityList: Collection<T>, batchSize: Int): Boolean
|
||||
|
||||
/**
|
||||
* 根据 ID 删除
|
||||
@ -63,7 +54,7 @@ interface SqlHelper<T, W : Wrapper<T>> {
|
||||
/**
|
||||
* 根据 entity 条件,删除记录
|
||||
*/
|
||||
fun remove(queryWrapper: W): Boolean
|
||||
fun remove(queryWrapper: Wrapper<T>): Boolean
|
||||
|
||||
/**
|
||||
* 删除(根据ID 批量删除)
|
||||
@ -85,14 +76,14 @@ interface SqlHelper<T, W : Wrapper<T>> {
|
||||
* @param entity 实体对象
|
||||
* @param updateWrapper 实体对象封装操作类
|
||||
*/
|
||||
fun update(entity: T?, updateWrapper: W): Boolean
|
||||
fun update(entity: T?, updateWrapper: IUpdateWrapper<T>): Boolean
|
||||
|
||||
/**
|
||||
* 根据 UpdateWrapper 条件,更新记录 需要设置sqlset
|
||||
*
|
||||
* @param updateWrapper 实体对象封装操作类
|
||||
*/
|
||||
fun update(updateWrapper: W): Boolean {
|
||||
fun update(updateWrapper: IUpdateWrapper<T>): Boolean {
|
||||
return update(null, updateWrapper)
|
||||
}
|
||||
|
||||
@ -147,14 +138,14 @@ interface SqlHelper<T, W : Wrapper<T>> {
|
||||
* @param queryWrapper 实体对象封装操作类
|
||||
* @param throwEx 有多个 result 是否抛出异常
|
||||
*/
|
||||
fun getOne(queryWrapper: W, throwEx: Boolean = true): T?
|
||||
fun getOne(queryWrapper: Wrapper<T>, throwEx: Boolean = true): T?
|
||||
|
||||
/**
|
||||
* 根据 Wrapper,查询一条记录
|
||||
*
|
||||
* @param queryWrapper 实体对象封装操作类
|
||||
*/
|
||||
fun getMap(queryWrapper: W): Map<String, Any?>
|
||||
fun getMap(queryWrapper: Wrapper<T>): Map<String, Any?>
|
||||
|
||||
///**
|
||||
// * 根据 Wrapper,查询一条记录
|
||||
@ -169,14 +160,14 @@ interface SqlHelper<T, W : Wrapper<T>> {
|
||||
*
|
||||
* @param queryWrapper 实体对象封装操作类
|
||||
*/
|
||||
fun count(queryWrapper: W): Int
|
||||
fun count(queryWrapper: Wrapper<T>): Int
|
||||
|
||||
/**
|
||||
* 查询列表
|
||||
*
|
||||
* @param queryWrapper 实体对象封装操作类
|
||||
*/
|
||||
fun list(queryWrapper: W): List<T>
|
||||
fun list(queryWrapper: Wrapper<T>): List<T>
|
||||
|
||||
/**
|
||||
* 获取对应 entity 的 BaseMapper
|
||||
@ -194,7 +185,7 @@ interface SqlHelper<T, W : Wrapper<T>> {
|
||||
*
|
||||
* @param entity 实体对象
|
||||
*/
|
||||
fun saveOrUpdate(entity: T?, updateWrapper: W): Boolean {
|
||||
fun saveOrUpdate(entity: T?, updateWrapper: IUpdateWrapper<T>): Boolean {
|
||||
return update(entity, updateWrapper) || saveOrUpdate(entity)
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,5 @@
|
||||
package cn.tursom.database
|
||||
|
||||
interface SqlTemplate {
|
||||
fun <T : Any> getHelper(clazz: Class<T>): SqlHelper<T>
|
||||
}
|
66
database/src/main/kotlin/cn/tursom/database/SqlUtils.kt
Normal file
66
database/src/main/kotlin/cn/tursom/database/SqlUtils.kt
Normal file
@ -0,0 +1,66 @@
|
||||
package cn.tursom.database
|
||||
|
||||
import cn.tursom.database.annotations.TableField
|
||||
import cn.tursom.database.annotations.TableName
|
||||
import java.lang.reflect.Field
|
||||
import java.sql.Types
|
||||
import kotlin.reflect.KClass
|
||||
import kotlin.reflect.KProperty
|
||||
import kotlin.reflect.full.findAnnotation
|
||||
import kotlin.reflect.jvm.javaField
|
||||
|
||||
@Suppress("MemberVisibilityCanBePrivate", "unused")
|
||||
object SqlUtils {
|
||||
inline operator fun <T> invoke(action: SqlUtils.() -> T) = this.action()
|
||||
|
||||
val String.sqlName: String
|
||||
get() {
|
||||
val sb = StringBuilder()
|
||||
val iterator = iterator()
|
||||
sb.append(iterator.nextChar().toLowerCase())
|
||||
iterator.forEach {
|
||||
if (it.isUpperCase()) {
|
||||
sb.append('_')
|
||||
sb.append(it.toLowerCase())
|
||||
} else {
|
||||
sb.append(it)
|
||||
}
|
||||
}
|
||||
return sb.toString()
|
||||
}
|
||||
|
||||
val KProperty<*>.tableField: String
|
||||
get() {
|
||||
val tableField = findAnnotation() ?: javaField?.getAnnotation(TableField::class.java)
|
||||
return tableField?.fieldName ?: name.sqlName
|
||||
}
|
||||
|
||||
val KProperty<*>.selectField: String
|
||||
get() {
|
||||
val tableField = findAnnotation() ?: javaField?.getAnnotation(TableField::class.java)
|
||||
return if (tableField != null) {
|
||||
"${tableField.fieldName} as ${name.sqlName}"
|
||||
} else {
|
||||
name.sqlName
|
||||
}
|
||||
}
|
||||
|
||||
val Field.tableField: String
|
||||
get() {
|
||||
val tableField = getAnnotation(TableField::class.java)
|
||||
return tableField?.fieldName ?: name.sqlName
|
||||
}
|
||||
|
||||
val Field.selectField: String
|
||||
get() {
|
||||
val tableField = getAnnotation(TableField::class.java)
|
||||
return if (tableField != null) {
|
||||
"${tableField.fieldName} as ${name.sqlName}"
|
||||
} else {
|
||||
name.sqlName
|
||||
}
|
||||
}
|
||||
|
||||
val KClass<*>.tableName: String get() = findAnnotation<TableName>()?.value ?: simpleName!!.sqlName
|
||||
val Class<*>.tableName: String get() = getAnnotation(TableName::class.java)?.value ?: simpleName!!.sqlName
|
||||
}
|
@ -0,0 +1,6 @@
|
||||
package cn.tursom.database.annotations
|
||||
|
||||
@MustBeDocumented
|
||||
@Retention(AnnotationRetention.RUNTIME)
|
||||
@Target(AnnotationTarget.FUNCTION)
|
||||
annotation class Delete(val sql: String)
|
@ -0,0 +1,6 @@
|
||||
package cn.tursom.database.annotations
|
||||
|
||||
@MustBeDocumented
|
||||
@Retention(AnnotationRetention.RUNTIME)
|
||||
@Target(AnnotationTarget.FUNCTION)
|
||||
annotation class Insert(val sql: String)
|
@ -3,4 +3,5 @@ package cn.tursom.database.annotations
|
||||
@MustBeDocumented
|
||||
@Retention(AnnotationRetention.RUNTIME)
|
||||
@Target(AnnotationTarget.VALUE_PARAMETER)
|
||||
annotation class Param(val value: String)
|
||||
annotation class Param(val value: String)
|
||||
|
||||
|
@ -0,0 +1,7 @@
|
||||
package cn.tursom.database.annotations
|
||||
|
||||
@MustBeDocumented
|
||||
@Retention(AnnotationRetention.RUNTIME)
|
||||
@Target(AnnotationTarget.FUNCTION)
|
||||
annotation class Select(val sql: String)
|
||||
|
@ -0,0 +1,6 @@
|
||||
package cn.tursom.database.annotations
|
||||
|
||||
@MustBeDocumented
|
||||
@Retention(AnnotationRetention.RUNTIME)
|
||||
@Target(AnnotationTarget.FUNCTION)
|
||||
annotation class TableField(val fieldName: String)
|
@ -0,0 +1,6 @@
|
||||
package cn.tursom.database.annotations
|
||||
|
||||
@MustBeDocumented
|
||||
@Retention(AnnotationRetention.RUNTIME)
|
||||
@Target(AnnotationTarget.CLASS)
|
||||
annotation class TableName(val value: String)
|
@ -0,0 +1,7 @@
|
||||
package cn.tursom.database.annotations
|
||||
|
||||
@MustBeDocumented
|
||||
@Retention(AnnotationRetention.RUNTIME)
|
||||
@Target(AnnotationTarget.FUNCTION)
|
||||
annotation class Update(val sql: String)
|
||||
|
@ -1,8 +1,261 @@
|
||||
package cn.tursom.database.wrapper
|
||||
|
||||
interface AbstractWrapper<T, Children : AbstractWrapper<T, Children>> :
|
||||
Wrapper<T>,
|
||||
Compare<Children, T>,
|
||||
Nested<Children, Children>,
|
||||
Join<Children>,
|
||||
Func<Children, T>
|
||||
import java.util.*
|
||||
|
||||
|
||||
abstract class AbstractWrapper<T, Children : AbstractWrapper<T, Children>> : Wrapper<T>,
|
||||
Compare<T, Children>,
|
||||
Join<T, Children>,
|
||||
Func<T, Children> {
|
||||
@Suppress("UNCHECKED_CAST", "LeakingThis")
|
||||
private val typedThis = this as Children
|
||||
|
||||
override val table: String get() = TODO()
|
||||
override val where: Pair<String, Collection<Any?>>
|
||||
get() {
|
||||
if (whereBuilder.endsWith(") OR (")) {
|
||||
repeat(") OR (".length) {
|
||||
whereBuilder.deleteCharAt(whereBuilder.length - 1)
|
||||
}
|
||||
}
|
||||
return whereBuilder.toString() to whereParams
|
||||
}
|
||||
|
||||
protected val whereBuilder = StringBuilder()
|
||||
protected val whereParams = LinkedList<Any?>()
|
||||
|
||||
protected fun newWhere() = when {
|
||||
whereBuilder.endsWith(") OR (") -> whereBuilder
|
||||
whereBuilder.isNotEmpty() -> whereBuilder.append(" AND ")
|
||||
else -> whereBuilder.append("(")
|
||||
}
|
||||
|
||||
override fun allEq(params: Map<String, Any?>): Children {
|
||||
params.forEach { (t, u) ->
|
||||
t eq u
|
||||
}
|
||||
return typedThis
|
||||
}
|
||||
|
||||
override fun String.eq(value: Any?): Children {
|
||||
newWhere()
|
||||
if (value != null) {
|
||||
whereBuilder.append("$this=?")
|
||||
whereParams.add(value)
|
||||
} else {
|
||||
whereBuilder.append("$this IS NULL")
|
||||
}
|
||||
return typedThis
|
||||
}
|
||||
|
||||
override fun String.ne(value: Any?): Children {
|
||||
newWhere()
|
||||
if (value != null) {
|
||||
whereBuilder.append("$this <> ?")
|
||||
whereParams.add(value)
|
||||
} else {
|
||||
whereBuilder.append("$this IS NOT NULL")
|
||||
}
|
||||
return typedThis
|
||||
}
|
||||
|
||||
override fun String.gt(value: Any): Children {
|
||||
newWhere()
|
||||
whereBuilder.append("$this > ?")
|
||||
whereParams.add(value)
|
||||
return typedThis
|
||||
}
|
||||
|
||||
override fun String.ge(value: Any): Children {
|
||||
newWhere()
|
||||
whereBuilder.append("$this >= ?")
|
||||
whereParams.add(value)
|
||||
return typedThis
|
||||
}
|
||||
|
||||
override fun String.le(value: Any): Children {
|
||||
newWhere()
|
||||
whereBuilder.append("$this < ?")
|
||||
whereParams.add(value)
|
||||
return typedThis
|
||||
}
|
||||
|
||||
override fun String.lt(value: Any): Children {
|
||||
newWhere()
|
||||
whereBuilder.append("$this <= ?")
|
||||
whereParams.add(value)
|
||||
return typedThis
|
||||
}
|
||||
|
||||
override fun String.between(val1: Any, val2: Any): Children {
|
||||
newWhere()
|
||||
whereBuilder.append("$this BETWEEN ? AND ?")
|
||||
whereParams.add(val1)
|
||||
whereParams.add(val2)
|
||||
return typedThis
|
||||
}
|
||||
|
||||
override fun String.notBetween(val1: Any, val2: Any): Children {
|
||||
newWhere()
|
||||
whereBuilder.append("$this NOT BETWEEN ? AND ?")
|
||||
whereParams.add(val1)
|
||||
whereParams.add(val2)
|
||||
return typedThis
|
||||
}
|
||||
|
||||
override fun String.like(value: Any): Children {
|
||||
newWhere()
|
||||
whereBuilder.append("$this LIKE ?")
|
||||
whereParams.add(value)
|
||||
return typedThis
|
||||
}
|
||||
|
||||
override fun String.notLike(value: Any): Children {
|
||||
newWhere()
|
||||
whereBuilder.append("$this NOT LIKE ?")
|
||||
whereParams.add(value)
|
||||
return typedThis
|
||||
}
|
||||
|
||||
override fun String.likeLeft(value: Any): Children {
|
||||
newWhere()
|
||||
whereBuilder.append("$this LIKE ?")
|
||||
whereParams.add("${value}%")
|
||||
return typedThis
|
||||
}
|
||||
|
||||
override fun String.likeRight(value: Any): Children {
|
||||
newWhere()
|
||||
whereBuilder.append("$this LIKE ?")
|
||||
whereParams.add("%${value}")
|
||||
return typedThis
|
||||
}
|
||||
|
||||
override fun String.isNull(): Children {
|
||||
newWhere()
|
||||
whereBuilder.append("$this IS NULL")
|
||||
return typedThis
|
||||
}
|
||||
|
||||
override fun String.isNotNull(): Children {
|
||||
newWhere()
|
||||
whereBuilder.append("$this IS NOT NULL")
|
||||
return typedThis
|
||||
}
|
||||
|
||||
override fun String.`in`(coll: Collection<Any?>): Children {
|
||||
newWhere()
|
||||
if (coll.isEmpty()) return typedThis
|
||||
whereBuilder.append("$this IN (")
|
||||
coll.forEach {
|
||||
whereBuilder.append("?,")
|
||||
whereParams.add(it)
|
||||
}
|
||||
whereBuilder.deleteCharAt(whereBuilder.length - 1)
|
||||
whereBuilder.append(")")
|
||||
return typedThis
|
||||
}
|
||||
|
||||
override fun String.notIn(coll: Collection<Any?>): Children {
|
||||
newWhere()
|
||||
if (coll.isEmpty()) return typedThis
|
||||
whereBuilder.append("$this NOT IN (")
|
||||
coll.forEach {
|
||||
whereBuilder.append("?,")
|
||||
whereParams.add(it)
|
||||
}
|
||||
whereBuilder.deleteCharAt(whereBuilder.length - 1)
|
||||
whereBuilder.append(")")
|
||||
return typedThis
|
||||
}
|
||||
|
||||
override fun String.inSql(inValue: String): Children {
|
||||
newWhere()
|
||||
whereBuilder.append("$this IN $inValue")
|
||||
return typedThis
|
||||
}
|
||||
|
||||
override fun String.notInSql(inValue: String): Children {
|
||||
newWhere()
|
||||
whereBuilder.append("$this NOT IN $inValue")
|
||||
return typedThis
|
||||
}
|
||||
|
||||
protected val groupByBuilder = StringBuilder()
|
||||
override val groupBy: String?
|
||||
get() = if (groupByBuilder.isEmpty()) null
|
||||
else groupByBuilder.toString()
|
||||
|
||||
override fun groupBy(columns: Collection<String>): Children {
|
||||
if (columns.isEmpty()) return typedThis
|
||||
if (groupByBuilder.isEmpty()) groupByBuilder.append("GROUP BY ")
|
||||
else groupByBuilder.append(',')
|
||||
columns.forEach {
|
||||
groupByBuilder.append(it)
|
||||
groupByBuilder.append(',')
|
||||
}
|
||||
groupByBuilder.deleteCharAt(groupByBuilder.length - 1)
|
||||
return typedThis
|
||||
}
|
||||
|
||||
protected val orderByBuilder = StringBuilder()
|
||||
override val orderBy: String?
|
||||
get() = if (orderByBuilder.isEmpty()) null
|
||||
else orderByBuilder.toString()
|
||||
|
||||
override fun orderByAsc(columns: Collection<String>): Children {
|
||||
if (columns.isEmpty()) return typedThis
|
||||
if (orderByBuilder.isEmpty()) orderByBuilder.append("ORDER BY ")
|
||||
else orderByBuilder.append(',')
|
||||
columns.forEach {
|
||||
orderByBuilder.append(it)
|
||||
orderByBuilder.append(" ASC,")
|
||||
}
|
||||
orderByBuilder.deleteCharAt(orderByBuilder.length - 1)
|
||||
return typedThis
|
||||
}
|
||||
|
||||
override fun orderByDesc(columns: Collection<String>): Children {
|
||||
if (columns.isEmpty()) return typedThis
|
||||
if (orderByBuilder.isEmpty()) orderByBuilder.append("ORDER BY ")
|
||||
else orderByBuilder.append(',')
|
||||
columns.forEach {
|
||||
orderByBuilder.append(it)
|
||||
orderByBuilder.append(" DESC,")
|
||||
}
|
||||
orderByBuilder.deleteCharAt(orderByBuilder.length - 1)
|
||||
return typedThis
|
||||
}
|
||||
|
||||
override fun orderBy(isAsc: Boolean, columns: Collection<String>): Children {
|
||||
if (columns.isEmpty()) return typedThis
|
||||
return if (isAsc) {
|
||||
orderByAsc(columns)
|
||||
} else {
|
||||
orderByDesc(columns)
|
||||
}
|
||||
}
|
||||
|
||||
protected val havingBuilder = StringBuilder()
|
||||
override val having: String?
|
||||
get() = if (havingBuilder.isEmpty()) null
|
||||
else havingBuilder.toString()
|
||||
override val havingParams = LinkedList<Any?>()
|
||||
override fun having(sqlHaving: String, vararg params: Any?): Children {
|
||||
havingBuilder.append(sqlHaving)
|
||||
havingParams.addAll(params)
|
||||
return typedThis
|
||||
}
|
||||
|
||||
override fun or(): Children {
|
||||
whereBuilder.append(") OR (")
|
||||
return typedThis
|
||||
}
|
||||
|
||||
override var last: String = ""
|
||||
|
||||
override fun last(lastSql: String): Children {
|
||||
last = lastSql
|
||||
return typedThis
|
||||
}
|
||||
}
|
@ -1,86 +1,53 @@
|
||||
package cn.tursom.database.wrapper
|
||||
|
||||
import cn.tursom.database.SqlUtils
|
||||
import java.io.Serializable
|
||||
import java.util.function.BiPredicate
|
||||
import kotlin.reflect.KProperty1
|
||||
|
||||
interface Compare<Children, T> : Serializable {
|
||||
fun <V> allEq(params: Map<KProperty1<T,*>, V>?): Children {
|
||||
return this.allEq(params, true)
|
||||
}
|
||||
interface Compare<T, Children> : Serializable {
|
||||
/**
|
||||
* map 所有属性等于 =
|
||||
*
|
||||
* @param params map 类型的参数, key 是字段名, value 是字段值
|
||||
* @return children
|
||||
*/
|
||||
fun allEq(params: Map<String, Any?>): Children
|
||||
fun Map<KProperty1<T, *>, Any?>.eq(): Children = allEq(SqlUtils { mapKeys { it.key.tableField } })
|
||||
|
||||
fun <V> allEq(params: Map<KProperty1<T,*>, V>?, null2IsNull: Boolean): Children {
|
||||
return this.allEq(true, params, null2IsNull)
|
||||
}
|
||||
infix fun String.eq(value: Any?): Children
|
||||
infix fun <V> KProperty1<T, V>.eq(value: V): Children = SqlUtils { tableField }.eq(value)
|
||||
|
||||
fun <V> allEq(condition: Boolean, params: Map<KProperty1<T,*>, V>?, null2IsNull: Boolean): Children
|
||||
fun <V> allEq(filter: BiPredicate<KProperty1<T,*>, V>?, params: Map<KProperty1<T,*>, V>?): Children {
|
||||
return this.allEq(filter, params, true)
|
||||
}
|
||||
infix fun String.ne(value: Any?): Children
|
||||
infix fun <V> KProperty1<T, V>.ne(value: V): Children = SqlUtils { tableField }.ne(value)
|
||||
|
||||
fun <V> allEq(filter: BiPredicate<KProperty1<T,*>, V>?, params: Map<KProperty1<T,*>, V>?, null2IsNull: Boolean): Children {
|
||||
return this.allEq(true, filter, params, null2IsNull)
|
||||
}
|
||||
infix fun String.gt(value: Any): Children
|
||||
infix fun <V : Any> KProperty1<T, V>.gt(value: V): Children = SqlUtils { tableField }.gt(value)
|
||||
|
||||
fun <V> allEq(condition: Boolean, filter: BiPredicate<KProperty1<T,*>, V>?, params: Map<KProperty1<T,*>, V>?, null2IsNull: Boolean): Children
|
||||
fun eq(column: KProperty1<T,*>, `val`: Any?): Children {
|
||||
return this.eq(true, column, `val`)
|
||||
}
|
||||
infix fun String.ge(value: Any): Children
|
||||
infix fun <V : Any> KProperty1<T, V>.ge(value: V): Children = SqlUtils { tableField }.ge(value)
|
||||
|
||||
fun eq(condition: Boolean, column: KProperty1<T,*>, `val`: Any?): Children
|
||||
fun ne(column: KProperty1<T,*>, `val`: Any?): Children {
|
||||
return this.ne(true, column, `val`)
|
||||
}
|
||||
infix fun String.le(value: Any): Children
|
||||
infix fun <V : Any> KProperty1<T, V>.le(value: V): Children = SqlUtils { tableField }.le(value)
|
||||
|
||||
fun ne(condition: Boolean, column: KProperty1<T,*>, `val`: Any?): Children
|
||||
fun gt(column: KProperty1<T,*>, `val`: Any?): Children {
|
||||
return this.gt(true, column, `val`)
|
||||
}
|
||||
infix fun String.lt(value: Any): Children
|
||||
infix fun <V : Any> KProperty1<T, V>.lt(value: V): Children = SqlUtils { tableField }.lt(value)
|
||||
|
||||
fun gt(condition: Boolean, column: KProperty1<T,*>, `val`: Any?): Children
|
||||
fun ge(column: KProperty1<T,*>, `val`: Any?): Children {
|
||||
return this.ge(true, column, `val`)
|
||||
}
|
||||
fun String.between(val1: Any, val2: Any): Children
|
||||
fun <V : Any> KProperty1<T, V>.between(val1: V, val2: V): Children = SqlUtils { tableField }.between(val1, val2)
|
||||
|
||||
fun ge(condition: Boolean, column: KProperty1<T,*>, `val`: Any?): Children
|
||||
fun lt(column: KProperty1<T,*>, `val`: Any?): Children {
|
||||
return this.lt(true, column, `val`)
|
||||
}
|
||||
fun String.notBetween(val1: Any, val2: Any): Children
|
||||
fun <V : Any> KProperty1<T, V>.notBetween(val1: V, val2: V): Children = SqlUtils { tableField }.notBetween(val1, val2)
|
||||
|
||||
fun lt(condition: Boolean, column: KProperty1<T,*>, `val`: Any?): Children
|
||||
fun le(column: KProperty1<T,*>, `val`: Any?): Children {
|
||||
return this.le(true, column, `val`)
|
||||
}
|
||||
infix fun String.like(value: Any): Children
|
||||
infix fun <V : Any> KProperty1<T, V>.like(value: V): Children = SqlUtils { tableField }.like(value)
|
||||
|
||||
fun le(condition: Boolean, column: KProperty1<T,*>, `val`: Any?): Children
|
||||
fun between(column: KProperty1<T,*>, val1: Any?, val2: Any?): Children {
|
||||
return this.between(true, column, val1, val2)
|
||||
}
|
||||
infix fun String.notLike(value: Any): Children
|
||||
infix fun <V : Any> KProperty1<T, V>.notLike(value: V): Children = SqlUtils { tableField }.notLike(value)
|
||||
|
||||
fun between(condition: Boolean, column: KProperty1<T,*>, val1: Any?, val2: Any?): Children
|
||||
fun notBetween(column: KProperty1<T,*>, val1: Any?, val2: Any?): Children {
|
||||
return this.notBetween(true, column, val1, val2)
|
||||
}
|
||||
infix fun String.likeLeft(value: Any): Children
|
||||
infix fun <V : Any> KProperty1<T, V>.likeLeft(value: V): Children = SqlUtils { tableField }.likeLeft(value)
|
||||
|
||||
fun notBetween(condition: Boolean, column: KProperty1<T,*>, val1: Any?, val2: Any?): Children
|
||||
fun like(column: KProperty1<T,*>, `val`: Any?): Children {
|
||||
return this.like(true, column, `val`)
|
||||
}
|
||||
infix fun String.likeRight(value: Any): Children
|
||||
infix fun <V : Any> KProperty1<T, V>.likeRight(value: V): Children = SqlUtils { tableField }.likeRight(value)
|
||||
|
||||
fun like(condition: Boolean, column: KProperty1<T,*>, `val`: Any?): Children
|
||||
fun notLike(column: KProperty1<T,*>, `val`: Any?): Children {
|
||||
return this.notLike(true, column, `val`)
|
||||
}
|
||||
|
||||
fun notLike(condition: Boolean, column: KProperty1<T,*>, `val`: Any?): Children
|
||||
fun likeLeft(column: KProperty1<T,*>, `val`: Any?): Children {
|
||||
return this.likeLeft(true, column, `val`)
|
||||
}
|
||||
|
||||
fun likeLeft(condition: Boolean, column: KProperty1<T,*>, `val`: Any?): Children
|
||||
fun likeRight(column: KProperty1<T,*>, `val`: Any?): Children {
|
||||
return this.likeRight(true, column, `val`)
|
||||
}
|
||||
|
||||
fun likeRight(condition: Boolean, column: KProperty1<T,*>, `val`: Any?): Children
|
||||
}
|
@ -1,92 +1,171 @@
|
||||
package cn.tursom.database.wrapper
|
||||
|
||||
import cn.tursom.database.SqlUtils
|
||||
import java.io.Serializable
|
||||
import kotlin.reflect.KProperty1
|
||||
|
||||
interface Func<Children, T> : Serializable {
|
||||
fun isNull(column: KProperty1<T, *>): Children {
|
||||
return this.isNull(true, column)
|
||||
}
|
||||
interface Func<T, Children> : Serializable {
|
||||
/**
|
||||
* 字段 IS NULL
|
||||
* <p>例: isNull("name")</p>
|
||||
*
|
||||
* @this 字段
|
||||
* @return children
|
||||
*/
|
||||
fun KProperty1<T, *>.isNull(): Children = SqlUtils { tableField }.isNull()
|
||||
fun String.isNull(): Children
|
||||
|
||||
fun isNull(condition: Boolean, column: KProperty1<T,*>): Children
|
||||
fun isNotNull(column: KProperty1<T,*>): Children {
|
||||
return this.isNotNull(true, column)
|
||||
}
|
||||
/**
|
||||
* 字段 IS NOT NULL
|
||||
* <p>例: isNotNull("name")</p>
|
||||
*
|
||||
* @this 字段
|
||||
* @return children
|
||||
*/
|
||||
fun KProperty1<T, *>.isNotNull(): Children = SqlUtils { tableField }.isNotNull()
|
||||
fun String.isNotNull(): Children
|
||||
|
||||
fun isNotNull(condition: Boolean, column: KProperty1<T,*>): Children
|
||||
fun `in`(column: KProperty1<T,*>, coll: Collection<*>?): Children {
|
||||
return this.`in`(true, column, coll)
|
||||
}
|
||||
/**
|
||||
* 字段 IN (value.get(0), value.get(1), ...)
|
||||
* <p>例: in("id", Arrays.asList(1, 2, 3, 4, 5))</p>
|
||||
*
|
||||
* <li> 如果集合为 empty 则不会进行 sql 拼接 </li>
|
||||
*
|
||||
* @this 字段
|
||||
* @param coll 数据集合
|
||||
* @return children
|
||||
*/
|
||||
infix fun <R> KProperty1<T, R>.`in`(coll: Collection<R>): Children = SqlUtils { tableField }.`in`(coll as Collection<Any?>)
|
||||
fun String.`in`(coll: Collection<Any?>): Children
|
||||
|
||||
fun `in`(condition: Boolean, column: KProperty1<T,*>, coll: Collection<*>?): Children
|
||||
fun `in`(column: KProperty1<T,*>, vararg values: Any?): Children {
|
||||
return this.`in`(true, column, *values)
|
||||
}
|
||||
/**
|
||||
* 字段 IN (v0, v1, ...)
|
||||
* <p>例: in("id", 1, 2, 3, 4, 5)</p>
|
||||
*
|
||||
* <li> 如果动态数组为 empty 则不会进行 sql 拼接 </li>
|
||||
*
|
||||
* @this 字段
|
||||
* @param values 数据数组
|
||||
* @return children
|
||||
*/
|
||||
fun <R> KProperty1<T, R>.`in`(vararg values: R): Children = SqlUtils { tableField }.`in`(values.asList())
|
||||
fun String.`in`(vararg values: Any?): Children = `in`(values.asList())
|
||||
|
||||
fun `in`(condition: Boolean, column: KProperty1<T,*>, vararg values: Any?): Children {
|
||||
return this.`in`(condition, column, values.asList())
|
||||
}
|
||||
|
||||
fun notIn(column: KProperty1<T,*>, coll: Collection<*>?): Children {
|
||||
return this.notIn(true, column, coll)
|
||||
}
|
||||
/**
|
||||
* 字段 NOT IN (value.get(0), value.get(1), ...)
|
||||
* <p>例: notIn("id", Arrays.asList(1, 2, 3, 4, 5))</p>
|
||||
*
|
||||
* @this 字段
|
||||
* @param coll 数据集合
|
||||
* @return children
|
||||
*/
|
||||
infix fun <R> KProperty1<T, R>.notIn(coll: Collection<R>): Children = SqlUtils { tableField }.notIn(coll)
|
||||
fun String.notIn(coll: Collection<Any?>): Children
|
||||
|
||||
fun notIn(condition: Boolean, column: KProperty1<T,*>, coll: Collection<*>?): Children
|
||||
fun notIn(column: KProperty1<T,*>, vararg value: Any?): Children {
|
||||
return this.notIn(true, column, *value)
|
||||
}
|
||||
/**
|
||||
* 字段 NOT IN (v0, v1, ...)
|
||||
* <p>例: notIn("id", 1, 2, 3, 4, 5)</p>
|
||||
*
|
||||
* @this 字段
|
||||
* @param values 数据数组
|
||||
* @return children
|
||||
*/
|
||||
fun <R> KProperty1<T, R>.notIn(vararg values: R): Children = notIn(values.asList())
|
||||
fun String.notIn(vararg value: Any?): Children = notIn(value.asList())
|
||||
|
||||
fun notIn(condition: Boolean, column: KProperty1<T,*>, vararg values: Any?): Children {
|
||||
return this.notIn(condition, column, values.asList())
|
||||
}
|
||||
/**
|
||||
* 字段 IN ( sql语句 )
|
||||
* <p>!! sql 注入方式的 in 方法 !!</p>
|
||||
* <p>例1: inSql("id", "1, 2, 3, 4, 5, 6")</p>
|
||||
* <p>例2: inSql("id", "select id from table where id < 3")</p>
|
||||
*
|
||||
* @this 字段
|
||||
* @param inValue sql语句
|
||||
* @return children
|
||||
*/
|
||||
infix fun KProperty1<T, *>.inSql(inValue: String): Children = SqlUtils { tableField }.inSql(inValue)
|
||||
fun String.inSql(inValue: String): Children
|
||||
|
||||
fun inSql(column: KProperty1<T,*>, inValue: String?): Children {
|
||||
return this.inSql(true, column, inValue)
|
||||
}
|
||||
/**
|
||||
* 字段 NOT IN ( sql语句 )
|
||||
* <p>!! sql 注入方式的 not in 方法 !!</p>
|
||||
* <p>例1: notInSql("id", "1, 2, 3, 4, 5, 6")</p>
|
||||
* <p>例2: notInSql("id", "select id from table where id < 3")</p>
|
||||
*
|
||||
* @this 字段
|
||||
* @param inValue sql语句 ---> 1,2,3,4,5,6 或者 select id from table where id < 3
|
||||
* @return children
|
||||
*/
|
||||
infix fun KProperty1<T, *>.notInSql(inValue: String): Children = SqlUtils { tableField }.notInSql(inValue)
|
||||
fun String.notInSql(inValue: String): Children
|
||||
|
||||
fun inSql(condition: Boolean, column: KProperty1<T,*>, inValue: String?): Children
|
||||
fun notInSql(column: KProperty1<T,*>, inValue: String?): Children {
|
||||
return this.notInSql(true, column, inValue)
|
||||
}
|
||||
val groupBy: String?
|
||||
|
||||
fun notInSql(condition: Boolean, column: KProperty1<T,*>, inValue: String?): Children
|
||||
fun groupBy(column: KProperty1<T,*>): Children {
|
||||
return this.groupBy(true, column)
|
||||
}
|
||||
/**
|
||||
* 分组:GROUP BY 字段, ...
|
||||
* <p>例: groupBy("id", "name")</p>
|
||||
*
|
||||
* @param columns 字段数组
|
||||
* @return children
|
||||
*/
|
||||
fun groupBy(columns: Iterable<KProperty1<T, *>>): Children = groupBy(SqlUtils { columns.map { it.tableField } })
|
||||
fun groupBy(vararg columns: KProperty1<T, *>): Children = groupBy(columns.asList())
|
||||
fun groupBy(columns: Collection<String>): Children
|
||||
fun groupBy(vararg columns: String): Children = groupBy(columns.asList())
|
||||
|
||||
fun groupBy(vararg columns: KProperty1<T,*>): Children {
|
||||
return this.groupBy(true, *columns)
|
||||
}
|
||||
val orderBy: String?
|
||||
|
||||
fun groupBy(condition: Boolean, vararg columns: KProperty1<T,*>): Children
|
||||
fun orderByAsc(column: KProperty1<T,*>): Children {
|
||||
return this.orderByAsc(true, column)
|
||||
}
|
||||
/**
|
||||
* 排序:ORDER BY 字段, ... ASC
|
||||
* <p>例: orderByAsc("id", "name")</p>
|
||||
*
|
||||
* @param columns 字段数组
|
||||
* @return children
|
||||
*/
|
||||
fun orderByAsc(columns: Iterable<KProperty1<T, *>>): Children = orderByAsc(SqlUtils { columns.map { it.tableField } })
|
||||
fun orderByAsc(vararg columns: KProperty1<T, *>): Children = orderByAsc(columns.asList())
|
||||
fun orderByAsc(columns: Collection<String>): Children
|
||||
fun orderByAsc(vararg columns: String): Children = orderByAsc(columns.asList())
|
||||
|
||||
fun orderByAsc(vararg columns: KProperty1<T,*>): Children {
|
||||
return this.orderByAsc(true, *columns)
|
||||
}
|
||||
/**
|
||||
* 排序:ORDER BY 字段, ... DESC
|
||||
* <p>例: orderByDesc("id", "name")</p>
|
||||
*
|
||||
* @param columns 字段数组
|
||||
* @return children
|
||||
*/
|
||||
fun orderByDesc(columns: Iterable<KProperty1<T, *>>): Children = orderByDesc(SqlUtils { columns.map { it.tableField } })
|
||||
fun orderByDesc(vararg columns: KProperty1<T, *>): Children = orderByDesc(columns.asList())
|
||||
fun orderByDesc(columns: Collection<String>): Children
|
||||
fun orderByDesc(vararg columns: String): Children = orderByDesc(columns.asList())
|
||||
|
||||
fun orderByAsc(condition: Boolean, vararg columns: KProperty1<T,*>): Children {
|
||||
return orderBy(condition, true, *columns)
|
||||
}
|
||||
/**
|
||||
* 排序:ORDER BY 字段, ...
|
||||
* <p>例: orderBy("id", "name")</p>
|
||||
*
|
||||
* @param isAsc 是否是 ASC 排序
|
||||
* @param columns 字段数组
|
||||
* @return children
|
||||
*/
|
||||
fun orderBy(isAsc: Boolean, columns: Iterable<KProperty1<T, *>>): Children = orderBy(isAsc, SqlUtils { columns.map { it.tableField } })
|
||||
fun orderBy(isAsc: Boolean, vararg columns: KProperty1<T, *>): Children = orderBy(isAsc, columns.asList())
|
||||
fun orderBy(isAsc: Boolean, columns: Collection<String>): Children
|
||||
fun orderBy(isAsc: Boolean, vararg columns: String): Children = orderBy(isAsc, columns.asList())
|
||||
|
||||
fun orderByDesc(column: KProperty1<T,*>): Children {
|
||||
return this.orderByDesc(true, column)
|
||||
}
|
||||
val having: String?
|
||||
val havingParams: Collection<Any?>
|
||||
|
||||
fun orderByDesc(vararg columns: KProperty1<T,*>): Children {
|
||||
return this.orderByDesc(true, *columns)
|
||||
}
|
||||
/**
|
||||
* HAVING ( sql语句 )
|
||||
* <p>例1: having("sum(age) > 10")</p>
|
||||
* <p>例2: having("sum(age) > ?", 10)</p>
|
||||
*
|
||||
* @param sqlHaving sql 语句
|
||||
* @param params 参数数组
|
||||
* @return children
|
||||
*/
|
||||
fun having(sqlHaving: String, vararg params: Any?): Children
|
||||
|
||||
fun orderByDesc(condition: Boolean, vararg columns: KProperty1<T,*>): Children {
|
||||
return orderBy(condition, false, *columns)
|
||||
}
|
||||
|
||||
fun orderBy(condition: Boolean, isAsc: Boolean, vararg columns: KProperty1<T,*>): Children
|
||||
fun having(sqlHaving: String?, vararg params: Any?): Children {
|
||||
return this.having(true, sqlHaving, *params)
|
||||
}
|
||||
|
||||
fun having(condition: Boolean, sqlHaving: String?, vararg params: Any?): Children
|
||||
}
|
@ -0,0 +1,5 @@
|
||||
package cn.tursom.database.wrapper
|
||||
|
||||
interface IUpdateWrapper<T> : Wrapper<T> {
|
||||
val sqlSet: Pair<String, Collection<Any?>>
|
||||
}
|
@ -2,32 +2,12 @@ package cn.tursom.database.wrapper
|
||||
|
||||
import java.io.Serializable
|
||||
|
||||
interface Join<Children> : Serializable {
|
||||
fun or(condition: Boolean = true): Children
|
||||
|
||||
fun apply(applySql: String?, vararg value: Any?): Children {
|
||||
return this.apply(true, applySql, *value)
|
||||
}
|
||||
|
||||
fun apply(condition: Boolean, applySql: String?, vararg value: Any?): Children
|
||||
fun last(lastSql: String?): Children {
|
||||
return this.last(true, lastSql)
|
||||
}
|
||||
|
||||
fun last(condition: Boolean, lastSql: String?): Children
|
||||
fun comment(comment: String?): Children {
|
||||
return this.comment(true, comment)
|
||||
}
|
||||
|
||||
fun comment(condition: Boolean, comment: String?): Children
|
||||
fun exists(existsSql: String?): Children {
|
||||
return this.exists(true, existsSql)
|
||||
}
|
||||
|
||||
fun exists(condition: Boolean, existsSql: String?): Children
|
||||
fun notExists(notExistsSql: String?): Children {
|
||||
return this.notExists(true, notExistsSql)
|
||||
}
|
||||
|
||||
fun notExists(condition: Boolean, notExistsSql: String?): Children
|
||||
interface Join<T, Children> : Serializable {
|
||||
fun or(): Children
|
||||
//fun apply(applySql: String, vararg value: Any?): Children
|
||||
var last: String
|
||||
fun last(lastSql: String): Children
|
||||
//fun comment(comment: String): Children
|
||||
//fun exists(existsSql: String): Children
|
||||
//fun notExists(notExistsSql: String): Children
|
||||
}
|
@ -1,22 +0,0 @@
|
||||
package cn.tursom.database.wrapper
|
||||
|
||||
import java.io.Serializable
|
||||
import java.util.function.Consumer
|
||||
|
||||
interface Nested<Param, Children> : Serializable {
|
||||
fun and(consumer: Consumer<Param>?): Children {
|
||||
return this.and(true, consumer)
|
||||
}
|
||||
|
||||
fun and(condition: Boolean, consumer: Consumer<Param>?): Children
|
||||
fun or(consumer: Consumer<Param>?): Children {
|
||||
return this.or(true, consumer)
|
||||
}
|
||||
|
||||
fun or(condition: Boolean, consumer: Consumer<Param>?): Children
|
||||
fun nested(consumer: Consumer<Param>?): Children {
|
||||
return this.nested(true, consumer)
|
||||
}
|
||||
|
||||
fun nested(condition: Boolean, consumer: Consumer<Param>?): Children
|
||||
}
|
27
database/src/main/kotlin/cn/tursom/database/wrapper/Query.kt
Normal file
27
database/src/main/kotlin/cn/tursom/database/wrapper/Query.kt
Normal file
@ -0,0 +1,27 @@
|
||||
package cn.tursom.database.wrapper
|
||||
|
||||
import cn.tursom.database.SqlUtils
|
||||
import java.io.Serializable
|
||||
import kotlin.reflect.KProperty
|
||||
|
||||
/**
|
||||
* @author miemie
|
||||
* @since 2018-12-12
|
||||
*/
|
||||
interface Query<T, Children> : Serializable {
|
||||
/**
|
||||
* 查询条件 SQL 片段
|
||||
*/
|
||||
val sqlSelect: String
|
||||
|
||||
/**
|
||||
* 设置查询字段
|
||||
*
|
||||
* @param columns 字段数组
|
||||
* @return children
|
||||
*/
|
||||
fun select(columns: Collection<String>): Children
|
||||
fun select(vararg columns: String): Children = select(columns.asList())
|
||||
fun select(columns: Iterable<KProperty<T>>): Children = select(columns.map { SqlUtils { it.selectField } })
|
||||
fun select(vararg columns: KProperty<T>): Children = select(columns.asList())
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
package cn.tursom.database.wrapper
|
||||
|
||||
class QueryWrapper<T> : AbstractWrapper<T, QueryWrapper<T>>(), Query<T, QueryWrapper<T>> {
|
||||
private val selectBuilder = StringBuilder()
|
||||
override val sqlSelect: String get() = selectBuilder.dropLast(1).toString()
|
||||
|
||||
override fun select(columns: Collection<String>): QueryWrapper<T> {
|
||||
columns.forEach {
|
||||
selectBuilder.append(it)
|
||||
selectBuilder.append(',')
|
||||
}
|
||||
return this
|
||||
}
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
package cn.tursom.database.wrapper
|
||||
|
||||
import cn.tursom.database.SqlUtils
|
||||
import java.io.Serializable
|
||||
import kotlin.reflect.KProperty1
|
||||
|
||||
interface Update<T, Children> : Serializable {
|
||||
fun setSql(sql: String, values: Collection<Any?>): Children
|
||||
fun setSql(sql: String, vararg values: Any?): Children = setSql(sql, values.asList())
|
||||
|
||||
infix fun String.set(value: T): Children
|
||||
infix fun <R> KProperty1<T, R>.set(value: R): Children = set(SqlUtils { tableField })
|
||||
}
|
||||
|
@ -0,0 +1,25 @@
|
||||
package cn.tursom.database.wrapper
|
||||
|
||||
import java.util.*
|
||||
|
||||
class UpdateWrapper<T> : AbstractWrapper<T, UpdateWrapper<T>>(), IUpdateWrapper<T>, Update<T, UpdateWrapper<T>> {
|
||||
private val setBuilder = StringBuilder()
|
||||
private val params = LinkedList<Any?>()
|
||||
|
||||
override val sqlSet: Pair<String, Collection<Any?>>
|
||||
get() = setBuilder.toString() to params
|
||||
|
||||
override fun String.set(value: T): UpdateWrapper<T> {
|
||||
if (setBuilder.isNotEmpty()) setBuilder.append(",")
|
||||
setBuilder.append("$this=?")
|
||||
params.add(value)
|
||||
return this@UpdateWrapper
|
||||
}
|
||||
|
||||
override fun setSql(sql: String, values: Collection<Any?>): UpdateWrapper<T> {
|
||||
setBuilder.append(sql)
|
||||
params.addAll(values)
|
||||
return this
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,10 @@
|
||||
package cn.tursom.database.wrapper
|
||||
|
||||
interface Wrapper<T>
|
||||
interface Wrapper<T> {
|
||||
val table: String
|
||||
val where: Pair<String, Collection<Any?>>
|
||||
|
||||
data class Where(val sql: String, val params: Collection<Any?>? = null)
|
||||
}
|
||||
|
||||
|
||||
|
@ -9,6 +9,7 @@ include 'web:web-coroutine'
|
||||
include 'microservices'
|
||||
include 'database:database-mysql'
|
||||
include 'database:mongodb'
|
||||
include 'database:mongodb:mongodb-async'
|
||||
include 'utils:ws-client'
|
||||
include 'utils:mail'
|
||||
include 'utils:csv'
|
19
src/main/kotlin/cn/tursom/core/Disposable.kt
Normal file
19
src/main/kotlin/cn/tursom/core/Disposable.kt
Normal file
@ -0,0 +1,19 @@
|
||||
package cn.tursom.core
|
||||
|
||||
import java.util.concurrent.atomic.AtomicReference
|
||||
|
||||
class Disposable<T> {
|
||||
private var value = AtomicReference<T>()
|
||||
fun set(value: T) {
|
||||
this.value.set(value)
|
||||
}
|
||||
|
||||
fun get(): T? {
|
||||
val value = value.get() ?: return null
|
||||
return if (this.value.compareAndSet(value, null)) {
|
||||
value
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
}
|
20
utils/src/main/kotlin/cn/tursom/utils/AsyncIterator.kt
Normal file
20
utils/src/main/kotlin/cn/tursom/utils/AsyncIterator.kt
Normal file
@ -0,0 +1,20 @@
|
||||
package cn.tursom.utils
|
||||
|
||||
interface AsyncIterator<T> {
|
||||
/**
|
||||
* Returns the next element in the iteration.
|
||||
*/
|
||||
suspend operator fun next(): T
|
||||
|
||||
/**
|
||||
* Returns `true` if the iteration has more elements.
|
||||
*/
|
||||
suspend operator fun hasNext(): Boolean
|
||||
}
|
||||
|
||||
suspend inline fun <T> AsyncIterator<T>.forEach(action: (T) -> Unit) {
|
||||
while (hasNext()) {
|
||||
val element = next()
|
||||
action(element)
|
||||
}
|
||||
}
|
@ -3,13 +3,17 @@ package cn.tursom.utils
|
||||
import com.google.gson.Gson
|
||||
import com.google.gson.GsonBuilder
|
||||
import kotlinx.coroutines.*
|
||||
import java.lang.reflect.InvocationHandler
|
||||
import java.lang.reflect.Method
|
||||
import java.lang.reflect.Proxy
|
||||
import java.util.concurrent.Executor
|
||||
import kotlin.coroutines.resume
|
||||
import kotlin.coroutines.resumeWithException
|
||||
import kotlin.coroutines.suspendCoroutine
|
||||
import kotlin.reflect.jvm.javaMethod
|
||||
|
||||
@Suppress("unused", "SpellCheckingInspection")
|
||||
val gson =GsonBuilder()
|
||||
val gson = GsonBuilder()
|
||||
.registerTypeAdapterFactory(GsonDataTypeAdaptor.FACTORY)
|
||||
.create()
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user