Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
43b2b3f
iterate all entities in a table
vincentlauvlwj Mar 22, 2019
9feff75
sequence to list
vincentlauvlwj Mar 22, 2019
25af224
Merge branch 'master' into entity-sequence
vincentlauvlwj Mar 29, 2019
3e2021d
sequence map
vincentlauvlwj Mar 29, 2019
247294d
filter
vincentlauvlwj Mar 29, 2019
594b262
rm sequence map
vincentlauvlwj Mar 29, 2019
4b1ae72
sequence count
vincentlauvlwj Mar 29, 2019
ab4ce13
create entity without references
vincentlauvlwj Mar 30, 2019
5963d6a
keep refrenced entities' ids
vincentlauvlwj Mar 30, 2019
5cb4b89
refactor
vincentlauvlwj Mar 30, 2019
b775fb1
associate
vincentlauvlwj Mar 30, 2019
a405f69
drop & take
vincentlauvlwj Mar 30, 2019
f1798b1
element at
vincentlauvlwj Mar 30, 2019
d890866
first & last
vincentlauvlwj Mar 31, 2019
fde6137
fold & foreach
vincentlauvlwj Mar 31, 2019
cb352cf
sorted
vincentlauvlwj Mar 31, 2019
ce09584
filter columns
vincentlauvlwj Mar 31, 2019
ed77c0d
Merge branch 'master' into entity-sequence
vincentlauvlwj Apr 1, 2019
ecd6fec
entity grouping
vincentlauvlwj Apr 1, 2019
81f3a96
as kotlin grouping
vincentlauvlwj Apr 1, 2019
ff06571
copy entities
vincentlauvlwj Apr 2, 2019
093abef
each count
vincentlauvlwj Apr 2, 2019
9f06c1d
each sum
vincentlauvlwj Apr 2, 2019
73e0ac6
refactor grouping nullable key
vincentlauvlwj Apr 3, 2019
68df348
complete aggregations
vincentlauvlwj Apr 3, 2019
46a903d
refactor aggregation
vincentlauvlwj Apr 5, 2019
0c4b960
to collection
vincentlauvlwj Apr 5, 2019
ee5b4fc
refactor filter
vincentlauvlwj Apr 7, 2019
663de54
map
vincentlauvlwj Apr 7, 2019
d8244c5
associate
vincentlauvlwj Apr 7, 2019
de5bcca
group by
vincentlauvlwj Apr 7, 2019
33bbc77
join to string
vincentlauvlwj Apr 7, 2019
b8805e8
reduce & single
vincentlauvlwj Apr 7, 2019
72b5145
refactor sequence
vincentlauvlwj Apr 7, 2019
f3f66ff
Merge branch 'master' into entity-sequence
vincentlauvlwj Apr 7, 2019
1709356
set gradle opts
vincentlauvlwj Apr 7, 2019
2b5c262
conflict fixed
vincentlauvlwj Apr 10, 2019
a590342
fix bug #10 for adding entities
vincentlauvlwj Apr 11, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@

language: java

env:
- GRADLE_OPTS="-Xms2048m -Xmx2048m"

services:
- mysql

Expand Down
113 changes: 29 additions & 84 deletions ktorm-core/src/main/kotlin/me/liuwj/ktorm/dsl/Aggregation.kt
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
package me.liuwj.ktorm.dsl

import me.liuwj.ktorm.database.Database
import me.liuwj.ktorm.database.prepareStatement
import me.liuwj.ktorm.expression.*
import me.liuwj.ktorm.entity.*
import me.liuwj.ktorm.expression.AggregateExpression
import me.liuwj.ktorm.expression.AggregateType
import me.liuwj.ktorm.schema.ColumnDeclaring
import me.liuwj.ktorm.schema.DoubleSqlType
import me.liuwj.ktorm.schema.IntSqlType
Expand Down Expand Up @@ -40,142 +40,87 @@ fun <C : Number> sumDistinct(column: ColumnDeclaring<C>): AggregateExpression<C>
return AggregateExpression(AggregateType.SUM, column.asExpression(), true, column.sqlType)
}

fun <C : Any> count(column: ColumnDeclaring<C>): AggregateExpression<Int> {
return AggregateExpression(AggregateType.COUNT, column.asExpression(), false, IntSqlType)
fun count(column: ColumnDeclaring<*>? = null): AggregateExpression<Int> {
return AggregateExpression(AggregateType.COUNT, column?.asExpression(), false, IntSqlType)
}

fun <C : Any> countDistinct(column: ColumnDeclaring<C>): AggregateExpression<Int> {
return AggregateExpression(AggregateType.COUNT, column.asExpression(), true, IntSqlType)
fun countDistinct(column: ColumnDeclaring<*>? = null): AggregateExpression<Int> {
return AggregateExpression(AggregateType.COUNT, column?.asExpression(), true, IntSqlType)
}

/**
* 如果表中的所有行都符合指定条件,返回 true,否则 false
*/
fun <T : Table<*>> T.all(block: (T) -> ScalarExpression<Boolean>): Boolean {
return none { !block(this) }
inline fun <E : Entity<E>, T : Table<E>> T.all(predicate: (T) -> ColumnDeclaring<Boolean>): Boolean {
return asSequence().all(predicate)
}

/**
* 如果表中有数据,返回 true,否则 false
*/
fun Table<*>.any(): Boolean {
return count() > 0
fun <E : Entity<E>, T : Table<E>> T.any(): Boolean {
return asSequence().any()
}

/**
* 如果表中存在任何一条记录满足指定条件,返回 true,否则 false
*/
fun <T : Table<*>> T.any(block: (T) -> ScalarExpression<Boolean>): Boolean {
return count(block) > 0
inline fun <E : Entity<E>, T : Table<E>> T.any(predicate: (T) -> ColumnDeclaring<Boolean>): Boolean {
return asSequence().any(predicate)
}

/**
* 如果表中没有数据,返回 true,否则 false
*/
fun Table<*>.none(): Boolean {
return count() == 0
fun <E : Entity<E>, T : Table<E>> T.none(): Boolean {
return asSequence().none()
}

/**
* 如果表中所有记录都不满足指定条件,返回 true,否则 false
*/
fun <T : Table<*>> T.none(block: (T) -> ScalarExpression<Boolean>): Boolean {
return count(block) == 0
inline fun <E : Entity<E>, T : Table<E>> T.none(predicate: (T) -> ColumnDeclaring<Boolean>): Boolean {
return asSequence().none(predicate)
}

/**
* 返回表中的记录数
*/
fun Table<*>.count(): Int {
return doCount(null)
fun <E : Entity<E>, T : Table<E>> T.count(): Int {
return asSequence().count()
}

/**
* 返回表中满足指定条件的记录数
*/
fun <T : Table<*>> T.count(block: (T) -> ScalarExpression<Boolean>): Int {
return doCount(block)
}

private fun <T : Table<*>> T.doCount(block: ((T) -> ScalarExpression<Boolean>)?): Int {
val expression = SelectExpression(
columns = listOf(
ColumnDeclaringExpression(
expression = AggregateExpression(
type = AggregateType.COUNT,
argument = null,
isDistinct = false,
sqlType = IntSqlType
)
)
),
from = this.asExpression(),
where = block?.invoke(this)
)

expression.prepareStatement { statement, logger ->
statement.executeQuery().use { rs ->
if (rs.next()) {
return rs.getInt(1).also { logger.debug("Count: {}", it) }
} else {
val (sql, _) = Database.global.formatExpression(expression, beautifySql = true)
throw IllegalStateException("No result return for sql: $sql")
}
}
}
inline fun <E : Entity<E>, T : Table<E>> T.count(predicate: (T) -> ColumnDeclaring<Boolean>): Int {
return asSequence().count(predicate)
}

/**
* 返回表中指定字段的和,若表中没有数据,返回 null
*/
fun <T : Table<*>, C : Number> T.sumBy(block: (T) -> ColumnDeclaring<C>): C? {
return doAggregation(sum(block(this)))
inline fun <E : Entity<E>, T : Table<E>, C : Number> T.sumBy(selector: (T) -> ColumnDeclaring<C>): C? {
return asSequence().sumBy(selector)
}

/**
* 返回表中指定字段的最大值,若表中没有数据,返回 null
*/
fun <T : Table<*>, C : Number> T.maxBy(block: (T) -> ColumnDeclaring<C>): C? {
return doAggregation(max(block(this)))
inline fun <E : Entity<E>, T : Table<E>, C : Number> T.maxBy(selector: (T) -> ColumnDeclaring<C>): C? {
return asSequence().maxBy(selector)
}

/**
* 返回表中指定字段的最小值,若表中没有数据,返回 null
*/
fun <T : Table<*>, C : Number> T.minBy(block: (T) -> ColumnDeclaring<C>): C? {
return doAggregation(min(block(this)))
inline fun <E : Entity<E>, T : Table<E>, C : Number> T.minBy(selector: (T) -> ColumnDeclaring<C>): C? {
return asSequence().minBy(selector)
}

/**
* 返回表中指定字段的平均值,若表中没有数据,返回 null
*/
fun <T : Table<*>> T.avgBy(block: (T) -> ColumnDeclaring<out Number>): Double? {
return doAggregation(avg(block(this)))
}

private fun <R : Number> Table<*>.doAggregation(aggregation: AggregateExpression<R>): R? {
val expression = SelectExpression(
columns = listOf(
ColumnDeclaringExpression(
expression = aggregation.asExpression()
)
),
from = this.asExpression()
)

expression.prepareStatement { statement, logger ->
statement.executeQuery().use { rs ->
if (rs.next()) {
val result = aggregation.sqlType.getResult(rs, 1)

if (logger.isDebugEnabled) {
logger.debug("{}: {}", aggregation.type.toString().capitalize(), result)
}

return result
} else {
return null
}
}
}
inline fun <E : Entity<E>, T : Table<E>> T.averageBy(selector: (T) -> ColumnDeclaring<out Number>): Double? {
return asSequence().averageBy(selector)
}
13 changes: 1 addition & 12 deletions ktorm-core/src/main/kotlin/me/liuwj/ktorm/dsl/CountExpression.kt
Original file line number Diff line number Diff line change
@@ -1,21 +1,10 @@
package me.liuwj.ktorm.dsl

import me.liuwj.ktorm.expression.*
import me.liuwj.ktorm.schema.IntSqlType

internal fun QueryExpression.toCountExpression(): SelectExpression {
val expression = OrderByRemover.visit(this) as QueryExpression

val countColumns = listOf(
ColumnDeclaringExpression(
expression = AggregateExpression(
type = AggregateType.COUNT,
argument = null,
isDistinct = false,
sqlType = IntSqlType
)
)
)
val countColumns = listOf(count().asDeclaringExpression())

if (expression is SelectExpression && expression.isSimpleSelect()) {
return expression.copy(columns = countColumns, offset = null, limit = null)
Expand Down
12 changes: 6 additions & 6 deletions ktorm-core/src/main/kotlin/me/liuwj/ktorm/dsl/Dml.kt
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ fun <T : Table<*>> T.update(block: UpdateStatementBuilder.(T) -> Unit): Int {
val assignments = ArrayList<ColumnAssignmentExpression<*>>()
val builder = UpdateStatementBuilder(assignments).apply { block(this@update) }

val expression = AliasRemover.visit(UpdateExpression(asExpression(), assignments, builder.where))
val expression = AliasRemover.visit(UpdateExpression(asExpression(), assignments, builder.where?.asExpression()))

expression.prepareStatement { statement, logger ->
return statement.executeUpdate().also { logger.debug("Effects: {}", it) }
Expand Down Expand Up @@ -145,8 +145,8 @@ fun Query.insertTo(table: Table<*>, vararg columns: Column<*>): Int {
/**
* 根据条件删除表中的记录,返回受影响的记录数
*/
fun <T : Table<*>> T.delete(block: (T) -> ScalarExpression<Boolean>): Int {
val expression = AliasRemover.visit(DeleteExpression(asExpression(), block(this)))
fun <T : Table<*>> T.delete(block: (T) -> ColumnDeclaring<Boolean>): Int {
val expression = AliasRemover.visit(DeleteExpression(asExpression(), block(this).asExpression()))

expression.prepareStatement { statement, logger ->
return statement.executeUpdate().also { logger.debug("Effects: {}", it) }
Expand Down Expand Up @@ -191,9 +191,9 @@ open class AssignmentsBuilder(private val assignments: MutableList<ColumnAssignm

@KtormDsl
class UpdateStatementBuilder(assignments: MutableList<ColumnAssignmentExpression<*>>) : AssignmentsBuilder(assignments) {
internal var where: ScalarExpression<Boolean>? = null
internal var where: ColumnDeclaring<Boolean>? = null

fun where(block: () -> ScalarExpression<Boolean>) {
fun where(block: () -> ColumnDeclaring<Boolean>) {
this.where = block()
}
}
Expand All @@ -208,7 +208,7 @@ class BatchUpdateStatementBuilder<T : Table<*>>(internal val table: T) {
val builder = UpdateStatementBuilder(assignments)
builder.block(table)

val expr = UpdateExpression(table.asExpression(), assignments, builder.where)
val expr = UpdateExpression(table.asExpression(), assignments, builder.where?.asExpression())

val (sql, _) = Database.global.formatExpression(expr, beautifySql = true)

Expand Down
41 changes: 21 additions & 20 deletions ktorm-core/src/main/kotlin/me/liuwj/ktorm/dsl/Join.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,68 +4,69 @@
package me.liuwj.ktorm.dsl

import me.liuwj.ktorm.expression.*
import me.liuwj.ktorm.schema.ColumnDeclaring
import me.liuwj.ktorm.schema.Table

fun QuerySourceExpression.crossJoin(right: QuerySourceExpression, on: ScalarExpression<Boolean>? = null): JoinExpression {
return JoinExpression(type = JoinType.CROSS_JOIN, left = this, right = right, condition = on)
fun QuerySourceExpression.crossJoin(right: QuerySourceExpression, on: ColumnDeclaring<Boolean>? = null): JoinExpression {
return JoinExpression(type = JoinType.CROSS_JOIN, left = this, right = right, condition = on?.asExpression())
}

fun QuerySourceExpression.crossJoin(right: Table<*>, on: ScalarExpression<Boolean>? = null): JoinExpression {
fun QuerySourceExpression.crossJoin(right: Table<*>, on: ColumnDeclaring<Boolean>? = null): JoinExpression {
return crossJoin(right.asExpression(), on)
}

fun Table<*>.crossJoin(right: QuerySourceExpression, on: ScalarExpression<Boolean>? = null): JoinExpression {
fun Table<*>.crossJoin(right: QuerySourceExpression, on: ColumnDeclaring<Boolean>? = null): JoinExpression {
return asExpression().crossJoin(right, on)
}

fun Table<*>.crossJoin(right: Table<*>, on: ScalarExpression<Boolean>? = null): JoinExpression {
fun Table<*>.crossJoin(right: Table<*>, on: ColumnDeclaring<Boolean>? = null): JoinExpression {
return crossJoin(right.asExpression(), on)
}

fun QuerySourceExpression.innerJoin(right: QuerySourceExpression, on: ScalarExpression<Boolean>? = null): JoinExpression {
return JoinExpression(type = JoinType.INNER_JOIN, left = this, right = right, condition = on)
fun QuerySourceExpression.innerJoin(right: QuerySourceExpression, on: ColumnDeclaring<Boolean>? = null): JoinExpression {
return JoinExpression(type = JoinType.INNER_JOIN, left = this, right = right, condition = on?.asExpression())
}

fun QuerySourceExpression.innerJoin(right: Table<*>, on: ScalarExpression<Boolean>? = null): JoinExpression {
fun QuerySourceExpression.innerJoin(right: Table<*>, on: ColumnDeclaring<Boolean>? = null): JoinExpression {
return innerJoin(right.asExpression(), on)
}

fun Table<*>.innerJoin(right: QuerySourceExpression, on: ScalarExpression<Boolean>? = null): JoinExpression {
fun Table<*>.innerJoin(right: QuerySourceExpression, on: ColumnDeclaring<Boolean>? = null): JoinExpression {
return asExpression().innerJoin(right, on)
}

fun Table<*>.innerJoin(right: Table<*>, on: ScalarExpression<Boolean>? = null): JoinExpression {
fun Table<*>.innerJoin(right: Table<*>, on: ColumnDeclaring<Boolean>? = null): JoinExpression {
return innerJoin(right.asExpression(), on)
}

fun QuerySourceExpression.leftJoin(right: QuerySourceExpression, on: ScalarExpression<Boolean>? = null): JoinExpression {
return JoinExpression(type = JoinType.LEFT_JOIN, left = this, right = right, condition = on)
fun QuerySourceExpression.leftJoin(right: QuerySourceExpression, on: ColumnDeclaring<Boolean>? = null): JoinExpression {
return JoinExpression(type = JoinType.LEFT_JOIN, left = this, right = right, condition = on?.asExpression())
}

fun QuerySourceExpression.leftJoin(right: Table<*>, on: ScalarExpression<Boolean>? = null): JoinExpression {
fun QuerySourceExpression.leftJoin(right: Table<*>, on: ColumnDeclaring<Boolean>? = null): JoinExpression {
return leftJoin(right.asExpression(), on)
}

fun Table<*>.leftJoin(right: QuerySourceExpression, on: ScalarExpression<Boolean>? = null): JoinExpression {
fun Table<*>.leftJoin(right: QuerySourceExpression, on: ColumnDeclaring<Boolean>? = null): JoinExpression {
return asExpression().leftJoin(right, on)
}

fun Table<*>.leftJoin(right: Table<*>, on: ScalarExpression<Boolean>? = null): JoinExpression {
fun Table<*>.leftJoin(right: Table<*>, on: ColumnDeclaring<Boolean>? = null): JoinExpression {
return leftJoin(right.asExpression(), on)
}

fun QuerySourceExpression.rightJoin(right: QuerySourceExpression, on: ScalarExpression<Boolean>? = null): JoinExpression {
return JoinExpression(type = JoinType.RIGHT_JOIN, left = this, right = right, condition = on)
fun QuerySourceExpression.rightJoin(right: QuerySourceExpression, on: ColumnDeclaring<Boolean>? = null): JoinExpression {
return JoinExpression(type = JoinType.RIGHT_JOIN, left = this, right = right, condition = on?.asExpression())
}

fun QuerySourceExpression.rightJoin(right: Table<*>, on: ScalarExpression<Boolean>? = null): JoinExpression {
fun QuerySourceExpression.rightJoin(right: Table<*>, on: ColumnDeclaring<Boolean>? = null): JoinExpression {
return rightJoin(right.asExpression(), on)
}

fun Table<*>.rightJoin(right: QuerySourceExpression, on: ScalarExpression<Boolean>? = null): JoinExpression {
fun Table<*>.rightJoin(right: QuerySourceExpression, on: ColumnDeclaring<Boolean>? = null): JoinExpression {
return asExpression().rightJoin(right, on)
}

fun Table<*>.rightJoin(right: Table<*>, on: ScalarExpression<Boolean>? = null): JoinExpression {
fun Table<*>.rightJoin(right: Table<*>, on: ColumnDeclaring<Boolean>? = null): JoinExpression {
return rightJoin(right.asExpression(), on)
}
Loading