添加协程mongo驱动

This commit is contained in:
tursom 2020-03-11 22:44:19 +08:00
parent 395866dc06
commit 655aafdb27
39 changed files with 1261 additions and 457 deletions

View File

@ -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)
}
}
}
}

View File

@ -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");
}
}
}

View File

@ -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.
}
}

View 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'
}

View File

@ -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
}
}

View File

@ -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)
}
}

View File

@ -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
}
}
}

View File

@ -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
}

View File

@ -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
}
}

View File

@ -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
}
}

View File

@ -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
*/

View File

@ -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>>) {
}
}
}

View 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)
}

View 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
}
}
}
}

View File

@ -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)
}
}

View File

@ -0,0 +1,5 @@
package cn.tursom.database
interface SqlTemplate {
fun <T : Any> getHelper(clazz: Class<T>): SqlHelper<T>
}

View 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
}

View File

@ -0,0 +1,6 @@
package cn.tursom.database.annotations
@MustBeDocumented
@Retention(AnnotationRetention.RUNTIME)
@Target(AnnotationTarget.FUNCTION)
annotation class Delete(val sql: String)

View File

@ -0,0 +1,6 @@
package cn.tursom.database.annotations
@MustBeDocumented
@Retention(AnnotationRetention.RUNTIME)
@Target(AnnotationTarget.FUNCTION)
annotation class Insert(val sql: String)

View File

@ -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)

View File

@ -0,0 +1,7 @@
package cn.tursom.database.annotations
@MustBeDocumented
@Retention(AnnotationRetention.RUNTIME)
@Target(AnnotationTarget.FUNCTION)
annotation class Select(val sql: String)

View File

@ -0,0 +1,6 @@
package cn.tursom.database.annotations
@MustBeDocumented
@Retention(AnnotationRetention.RUNTIME)
@Target(AnnotationTarget.FUNCTION)
annotation class TableField(val fieldName: String)

View File

@ -0,0 +1,6 @@
package cn.tursom.database.annotations
@MustBeDocumented
@Retention(AnnotationRetention.RUNTIME)
@Target(AnnotationTarget.CLASS)
annotation class TableName(val value: String)

View File

@ -0,0 +1,7 @@
package cn.tursom.database.annotations
@MustBeDocumented
@Retention(AnnotationRetention.RUNTIME)
@Target(AnnotationTarget.FUNCTION)
annotation class Update(val sql: String)

View File

@ -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
}
}

View File

@ -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
}

View File

@ -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 &lt; 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 &lt; 3")</p>
*
* @this 字段
* @param inValue sql语句 ---&gt; 1,2,3,4,5,6 或者 select id from table where id &lt; 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) &gt; 10")</p>
* <p>例2: having("sum(age) &gt; ?", 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
}

View File

@ -0,0 +1,5 @@
package cn.tursom.database.wrapper
interface IUpdateWrapper<T> : Wrapper<T> {
val sqlSet: Pair<String, Collection<Any?>>
}

View File

@ -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
}

View File

@ -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
}

View 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())
}

View File

@ -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
}
}

View File

@ -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 })
}

View File

@ -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
}
}

View File

@ -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)
}

View File

@ -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'

View 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
}
}
}

View 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)
}
}

View File

@ -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()