diff --git a/yawn-api/src/main/kotlin/com/faire/yawn/project/YawnProjections.kt b/yawn-api/src/main/kotlin/com/faire/yawn/project/YawnProjections.kt index 1750a64..16c94b8 100644 --- a/yawn-api/src/main/kotlin/com/faire/yawn/project/YawnProjections.kt +++ b/yawn-api/src/main/kotlin/com/faire/yawn/project/YawnProjections.kt @@ -1,6 +1,6 @@ package com.faire.yawn.project -import com.faire.yawn.YawnTableDef +import com.faire.yawn.YawnDef import com.faire.yawn.query.YawnCompilationContext import org.hibernate.criterion.Projection import org.hibernate.criterion.Projections @@ -28,7 +28,7 @@ object YawnProjections { } internal class Count( - private val columnDef: YawnTableDef.ColumnDef, + private val columnDef: YawnDef.YawnColumnDef, ) : YawnQueryProjection { override fun compile( context: YawnCompilationContext, @@ -38,13 +38,13 @@ object YawnProjections { } fun count( - columnDef: YawnTableDef.ColumnDef, + columnDef: YawnDef.YawnColumnDef, ): YawnQueryProjection { return Count(columnDef) } internal class CountDistinct( - private val columnDef: YawnTableDef.ColumnDef, + private val columnDef: YawnDef.YawnColumnDef, ) : YawnQueryProjection { override fun compile( context: YawnCompilationContext, @@ -54,13 +54,13 @@ object YawnProjections { } fun countDistinct( - columnDef: YawnTableDef.ColumnDef, + columnDef: YawnDef.YawnColumnDef, ): YawnQueryProjection { return CountDistinct(columnDef) } internal class SumNullable( - private val columnDef: YawnTableDef.ColumnDef, + private val columnDef: YawnDef.YawnColumnDef, ) : YawnQueryProjection { override fun compile( context: YawnCompilationContext, @@ -71,13 +71,13 @@ object YawnProjections { @JvmName("sumNullable") fun sum( - columnDef: YawnTableDef.ColumnDef, + columnDef: YawnDef.YawnColumnDef, ): YawnQueryProjection { return SumNullable(columnDef) } internal class Sum( - private val columnDef: YawnTableDef.ColumnDef, + private val columnDef: YawnDef.YawnColumnDef, ) : YawnQueryProjection { override fun compile( context: YawnCompilationContext, @@ -87,13 +87,13 @@ object YawnProjections { } fun sum( - columnDef: YawnTableDef.ColumnDef, + columnDef: YawnDef.YawnColumnDef, ): YawnQueryProjection { return Sum(columnDef) } internal class AvgNullable( - private val columnDef: YawnTableDef.ColumnDef, + private val columnDef: YawnDef.YawnColumnDef, ) : YawnQueryProjection { override fun compile( context: YawnCompilationContext, @@ -104,13 +104,13 @@ object YawnProjections { @JvmName("avgNullable") fun avg( - columnDef: YawnTableDef.ColumnDef, + columnDef: YawnDef.YawnColumnDef, ): YawnQueryProjection { return AvgNullable(columnDef) } internal class Avg( - private val columnDef: YawnTableDef.ColumnDef, + private val columnDef: YawnDef.YawnColumnDef, ) : YawnQueryProjection { override fun compile( context: YawnCompilationContext, @@ -120,13 +120,13 @@ object YawnProjections { } fun avg( - columnDef: YawnTableDef.ColumnDef, + columnDef: YawnDef.YawnColumnDef, ): YawnQueryProjection { return Avg(columnDef) } internal class Max?>( - private val columnDef: YawnTableDef.ColumnDef, + private val columnDef: YawnDef.YawnColumnDef, ) : YawnQueryProjection { override fun compile( context: YawnCompilationContext, @@ -137,13 +137,13 @@ object YawnProjections { } fun ?> max( - columnDef: YawnTableDef.ColumnDef, + columnDef: YawnDef.YawnColumnDef, ): YawnQueryProjection { return Max(columnDef) } internal class Min?>( - private val columnDef: YawnTableDef.ColumnDef, + private val columnDef: YawnDef.YawnColumnDef, ) : YawnQueryProjection { override fun compile( context: YawnCompilationContext, @@ -154,13 +154,13 @@ object YawnProjections { } fun ?> min( - columnDef: YawnTableDef.ColumnDef, + columnDef: YawnDef.YawnColumnDef, ): YawnQueryProjection { return Min(columnDef) } internal class GroupBy( - private val columnDef: YawnTableDef.ColumnDef, + private val columnDef: YawnDef.YawnColumnDef, ) : YawnQueryProjection { override fun compile( context: YawnCompilationContext, @@ -171,7 +171,7 @@ object YawnProjections { } fun groupBy( - columnDef: YawnTableDef.ColumnDef, + columnDef: YawnDef.YawnColumnDef, ): YawnQueryProjection { return GroupBy(columnDef) } diff --git a/yawn-database-test/src/test/kotlin/com/faire/yawn/database/YawnAggregationNullabilityTest.kt b/yawn-database-test/src/test/kotlin/com/faire/yawn/database/YawnAggregationNullabilityTest.kt new file mode 100644 index 0000000..1f523d3 --- /dev/null +++ b/yawn-database-test/src/test/kotlin/com/faire/yawn/database/YawnAggregationNullabilityTest.kt @@ -0,0 +1,106 @@ +package com.faire.yawn.database + +import com.faire.yawn.project.YawnProjections +import com.faire.yawn.setup.entities.BookTable +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.Test + +internal class YawnAggregationNullabilityTest : BaseYawnDatabaseTest() { + @Test + fun `count with addIsNotNull`() { + transactor.open { session -> + val count = session.project(BookTable) { books -> + val notes = addIsNotNull(books.notes) + project(YawnProjections.count(notes)) + }.uniqueResult()!! + + // 3 books have notes: harry potter, lord of the rings, the hobbit + assertThat(count).isEqualTo(3) + } + } + + @Test + fun `countDistinct with addIsNotNull`() { + transactor.open { session -> + val distinctCount = session.project(BookTable) { books -> + val notes = addIsNotNull(books.notes) + project(YawnProjections.countDistinct(notes)) + }.uniqueResult()!! + + // harry potter and the hobbit share the same note + assertThat(distinctCount).isEqualTo(2) + } + } + + @Test + fun `sum with addIsNotNull`() { + transactor.open { session -> + val total = session.project(BookTable) { books -> + val rating = addIsNotNull(books.rating) + project(YawnProjections.sum(rating)) + }.uniqueResult()!! + + // lord of the rings (10) + the hobbit (9) + assertThat(total).isEqualTo(19) + } + } + + @Test + fun `avg with addIsNotNull`() { + transactor.open { session -> + val average = session.project(BookTable) { books -> + val rating = addIsNotNull(books.rating) + project(YawnProjections.avg(rating)) + }.uniqueResult()!! + + // (10 + 9) / 2 + assertThat(average).isEqualTo(9.5) + } + } + + @Test + fun `max with addIsNotNull`() { + transactor.open { session -> + val maxRating = session.project(BookTable) { books -> + val rating = addIsNotNull(books.rating) + project(YawnProjections.max(rating)) + }.uniqueResult()!! + + assertThat(maxRating).isEqualTo(10) + } + } + + @Test + fun `min with addIsNotNull`() { + transactor.open { session -> + val minRating = session.project(BookTable) { books -> + val rating = addIsNotNull(books.rating) + project(YawnProjections.min(rating)) + }.uniqueResult()!! + + assertThat(minRating).isEqualTo(9) + } + } + + @Test + fun `groupBy with addIsNotNull`() { + transactor.open { session -> + val results = session.project(BookTable) { books -> + val notes = addIsNotNull(books.notes) + val rating = addIsNotNull(books.rating) + project( + YawnProjections.pair( + YawnProjections.groupBy(notes), + YawnProjections.sum(rating), + ), + ) + }.list() + + // lord of the rings has rating 10, the hobbit has rating 9 + assertThat(results).containsExactlyInAnyOrder( + "Note for The Hobbit and Harry Potter" to 9L, + "Note for Lord of the Rings" to 10L, + ) + } + } +}