From 6b0a3f7ca7183c0f32a4f05216913a54745af1ed Mon Sep 17 00:00:00 2001 From: "kamila.myczkowska" Date: Thu, 9 Aug 2018 15:18:04 +0200 Subject: [PATCH] Version 1.0.2 --- LICENSE.md | 2 +- README.md | 9 ++- build.gradle | 4 +- .../kotlin/com/kameocode/anydao/AnyDao.kt | 78 +++++++++---------- .../com/kameocode/anydao/AnyDaoClasses.kt | 11 ++- .../anydao/context/QueryPathContext.kt | 4 +- .../com/kameocode/anydao/wraps/PathWrap.kt | 5 +- .../com/kameocode/anydao/test/ClausesTest.kt | 6 +- .../com/kameocode/anydao/test/PagesTest.kt | 24 +++--- .../kameocode/anydao/test/SingleSelectTest.kt | 58 ++++++++++++++ 10 files changed, 131 insertions(+), 70 deletions(-) create mode 100644 src/test/kotlin/com/kameocode/anydao/test/SingleSelectTest.kt diff --git a/LICENSE.md b/LICENSE.md index 60e9b83..b81fb94 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -183,7 +183,7 @@ the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier + same "printed KPage" as the copyright notice for easier identification within third-party archives. Copyright [2018] [Kameo] diff --git a/README.md b/README.md index dc2c85d..7a13fd3 100644 --- a/README.md +++ b/README.md @@ -77,11 +77,11 @@ Add to your project maven/gradle dependency: com.kameocode any-dao - 1.0.1 + 1.0.2 ``` ``` -compile 'com.kameocode:any-dao:1.0.1' +compile 'com.kameocode:any-dao:1.0.2' ``` Create instance of AnyDao: ``` @@ -276,7 +276,7 @@ These expressions should be accessible directly on expression/path elements: > Paging ``` - val pagedListOfUsers = anyDao.pages(UserODB::class, Page(100)) { + val pagedListOfUsers = anyDao.pages(UserODB::class, KPage(100)) { it[UserODB::email] like "email1" } pagedListOfUsers.forEach { list-> @@ -321,4 +321,5 @@ For more examples, see: [tests](src/test/kotlin/com/kameocode/anydao/test/) * added support for pure java classes for anyDao.exist and anyDao.count **v 1.0.2** -* Support for nullable select \ No newline at end of file +* Support for nullable select +* Page is now KPage \ No newline at end of file diff --git a/build.gradle b/build.gradle index 339198f..23fc88c 100644 --- a/build.gradle +++ b/build.gradle @@ -17,7 +17,7 @@ plugins { group 'com.kameocode' archivesBaseName = "any-dao" -version '1.0.1' +version '1.0.2' description 'AnyDAO is an Kotlin JPA wrapper library which makes your database queries short, clean and easy to read.' @@ -113,7 +113,7 @@ uploadArchives { snapshotRepository(url: "https://oss.sonatype.org/content/repositories/snapshots/") { authentication(userName: tossrhUsername, password: tossrhPassword) } - // repository(url: mavenLocal().url) + //repository(url: mavenLocal().url) pom.project { diff --git a/src/main/kotlin/com/kameocode/anydao/AnyDao.kt b/src/main/kotlin/com/kameocode/anydao/AnyDao.kt index 41912a1..4859d4f 100644 --- a/src/main/kotlin/com/kameocode/anydao/AnyDao.kt +++ b/src/main/kotlin/com/kameocode/anydao/AnyDao.kt @@ -125,7 +125,7 @@ class AnyDao(val em: EntityManager) { } - fun all(clz: Class, resultClass: Class, query: (KRoot.(KRoot) -> KSelect)? = null): List { + fun all(clz: Class, resultClass: Class, query: (KRoot.(KRoot) -> KSelect)? = null): List { val qq: (KRoot.(KRoot) -> KSelect) = query ?: { this as KSelect } val pc = QueryPathContext(clz, em) val res = pc.invokeQuery(qq).resultList @@ -136,23 +136,23 @@ class AnyDao(val em: EntityManager) { return all(clz.java, E::class.java) } - inline fun all(clz: KClass, noinline query: (KRoot.(KRoot) -> KSelect)? = null): List { + inline fun all(clz: KClass, noinline query: (KRoot.(KRoot) -> KSelect)? = null): List { return all(clz.java, RESULT::class.java, query) } @Throws(NoResultException::class) - fun one(clz: Class, resultClass: Class, query: (KRoot.(KRoot) -> KSelect)): RESULT { + fun one(clz: Class, resultClass: Class, query: (KRoot.(KRoot) -> KSelect)): RESULT { val pc = QueryPathContext(clz, em) val jpaQuery = pc.invokeQuery(query) return pc.mapToPluralsIfNeeded(jpaQuery.singleResult) } @Throws(NoResultException::class) - inline fun one(clz: KClass, noinline query: (KRoot.(KRoot) -> KSelect)): RESULT { + inline fun one(clz: KClass, noinline query: (KRoot.(KRoot) -> KSelect)): RESULT { return one(clz.java, RESULT::class.java, query) } - fun first(clz: Class, resultClass: Class, query: (KRoot.(KRoot) -> KSelect)): RESULT? { + fun first(clz: Class, resultClass: Class, query: (KRoot.(KRoot) -> KSelect)): RESULT? { val pc = QueryPathContext(clz, em) val jpaQuery = pc.invokeQuery(query) jpaQuery.maxResults = 1 @@ -192,29 +192,29 @@ class AnyDao(val em: EntityManager) { return one(clz, Long::class.java, wrapperQuery) } - inline fun first(clz: KClass, noinline query: (KRoot.(KRoot) -> KSelect)): RESULT? { + inline fun first(clz: KClass, noinline query: (KRoot.(KRoot) -> KSelect)): RESULT? { return first(clz.java, RESULT::class.java, query) } - inline fun allMutable(clz: KClass, noinline query: (KRoot.(KRoot) -> KSelect)? = null): MutableList { + inline fun allMutable(clz: KClass, noinline query: (KRoot.(KRoot) -> KSelect)? = null): MutableList { return all(clz.java, RESULT::class.java, query) as MutableList } - inline fun pages(clz: KClass, page: Page = Page(), - noinline query: (KRoot.(KRoot) -> KSelect) - ): PagesResult { + inline fun pages(clz: KClass, KPage: KPage = KPage(), + noinline query: (KRoot.(KRoot) -> KSelect) + ): KPagesResult { - return pages(clz.java, RESULT::class.java, page, query) + return pages(clz.java, RESULT::class.java, KPage, query) } - fun pages(clz: Class, resultClz: Class, page: Page = Page(), - query: (KRoot.(KRoot) -> KSelect) - ): PagesResult { - return object : PagesResult(page.pageSize) { - var currentpage = page; + fun pages(clz: Class, resultClz: Class, KPage: KPage = KPage(), + query: (KRoot.(KRoot) -> KSelect) + ): KPagesResult { + return object : KPagesResult(KPage.pageSize) { + var currentpage = KPage; override fun beforeForeach() { - currentpage = page + currentpage = KPage } override fun invoke(): List { @@ -225,39 +225,39 @@ class AnyDao(val em: EntityManager) { }; } - inline fun page(clz: KClass, page: Page, - noinline query: (KRoot.(KRoot) -> KSelect)): List { + inline fun page(clz: KClass, KPage: KPage, + noinline query: (KRoot.(KRoot) -> KSelect)): List { - return page(clz.java, RESULT::class.java, page, query) + return page(clz.java, RESULT::class.java, KPage, query) } - fun page(clz: Class, resultClass: Class, page: Page, - query: (KRoot.(KRoot) -> KSelect)): List { + fun page(clz: Class, resultClass: Class, KPage: KPage, + query: (KRoot.(KRoot) -> KSelect)): List { val wrapperQuery: KRoot.(KRoot) -> (KSelect) = { val result = query.invoke(this, this); - this.limit(page.pageSize); - this.skip(page.offset) + this.limit(KPage.pageSize); + this.skip(KPage.offset) result; } return all(clz, resultClass, wrapperQuery) } - inline fun pageSorted(clz: KClass, prop: KProperty1, num: NUM?, page: Page, - noinline query: (KRoot.(KRoot) -> KSelect)): List where NUM : Number, NUM : Comparable { - return pageSorted(clz.java, RESULT::class.java, prop, num, page, query); + inline fun pageSorted(clz: KClass, prop: KProperty1, num: NUM?, KPage: KPage, + noinline query: (KRoot.(KRoot) -> KSelect)): List where NUM : Number, NUM : Comparable { + return pageSorted(clz.java, RESULT::class.java, prop, num, KPage, query); } - fun pageSorted(clz: Class, resultClz: Class, prop: KProperty1, num: NUM?, page: Page, - query: (KRoot.(KRoot) -> KSelect)): List where NUM : Number, NUM : Comparable { + fun pageSorted(clz: Class, resultClz: Class, prop: KProperty1, num: NUM?, KPage: KPage, + query: (KRoot.(KRoot) -> KSelect)): List where NUM : Number, NUM : Comparable { val wrapperQuery: KRoot.(KRoot) -> (KSelect) = { if (num != null) this[prop].greaterThan(num) this.orderBy(prop) val result = query.invoke(this, this); - this.limit(page.pageSize); + this.limit(KPage.pageSize); this.skip(0) result; @@ -267,22 +267,22 @@ class AnyDao(val em: EntityManager) { } - inline fun pagesSorted(clz: KClass, prop: KProperty1, page: Page = Page(), + inline fun pagesSorted(clz: KClass, prop: KProperty1, KPage: KPage = KPage(), noinline query: (KRoot.(KRoot) -> KSelect) - ): PagesResult where NUM : Number, NUM : Comparable { - return pagesSorted(clz.java, E::class.java, prop, page, query); + ): KPagesResult where NUM : Number, NUM : Comparable { + return pagesSorted(clz.java, E::class.java, prop, KPage, query); } - fun pagesSorted(clz: Class, resultClass: Class, prop: KProperty1, page: Page = Page(), + fun pagesSorted(clz: Class, resultClass: Class, prop: KProperty1, KPage: KPage = KPage(), query: (KRoot.(KRoot) -> KSelect) - ): PagesResult where NUM : Number, NUM : Comparable { + ): KPagesResult where NUM : Number, NUM : Comparable { - return object : PagesResult(page.pageSize) { - var currentpage = page; + return object : KPagesResult(KPage.pageSize) { + var currentpage = KPage; var num: NUM? = null; override fun beforeForeach() { - currentpage = page + currentpage = KPage num = null } @@ -318,7 +318,7 @@ class AnyDao(val em: EntityManager) { companion object { @JvmStatic - fun getPredicate(root: Root, criteriaQuery: CriteriaQuery<*>, cb: CriteriaBuilder, + fun getPredicate(root: Root, criteriaQuery: CriteriaQuery<*>, cb: CriteriaBuilder, query: KRoot.(KRoot) -> KSelect): Predicate { val pc = PredicatePathContext(root as Root, criteriaQuery, cb); return pc.toPredicate(query) diff --git a/src/main/kotlin/com/kameocode/anydao/AnyDaoClasses.kt b/src/main/kotlin/com/kameocode/anydao/AnyDaoClasses.kt index f87d01d..5fc7e3f 100644 --- a/src/main/kotlin/com/kameocode/anydao/AnyDaoClasses.kt +++ b/src/main/kotlin/com/kameocode/anydao/AnyDaoClasses.kt @@ -4,7 +4,6 @@ import com.kameocode.anydao.context.PathContext import com.kameocode.anydao.wraps.FromWrap import com.kameocode.anydao.wraps.PathWrap import com.kameocode.anydao.wraps.RootWrap -import com.kameocode.anydao.wraps.RootWrapUpdate import java.io.Serializable import javax.persistence.Tuple import javax.persistence.TupleElement @@ -16,7 +15,7 @@ import kotlin.reflect.KProperty1 typealias KRoot = RootWrap typealias QueryUnit = T.(T) -> Unit -typealias KQuery = KRoot.(KRoot) -> (KSelect) +typealias KQuery = RootWrap.(RootWrap) -> (KSelect) typealias KClause = PathWrap.(PathWrap) -> Unit typealias KFromClause = FromWrap.(FromWrap) -> Unit @@ -116,12 +115,12 @@ class TupleWrap(private val arr: Array, } -data class Page(val pageSize: Int = 10, val offset: Int = 0) { - fun next() = Page(pageSize, offset + pageSize) +data class KPage(val pageSize: Int = 10, val offset: Int = 0) { + fun next() = KPage(pageSize, offset + pageSize) } -abstract class PagesResult(val pageSize: Int) { - abstract fun invoke(): List +abstract class KPagesResult(val pageSize: Int) { + internal abstract fun invoke(): List abstract protected fun beforeForeach() diff --git a/src/main/kotlin/com/kameocode/anydao/context/QueryPathContext.kt b/src/main/kotlin/com/kameocode/anydao/context/QueryPathContext.kt index bd629fd..56ad3c1 100644 --- a/src/main/kotlin/com/kameocode/anydao/context/QueryPathContext.kt +++ b/src/main/kotlin/com/kameocode/anydao/context/QueryPathContext.kt @@ -61,7 +61,7 @@ class QueryPathContext(clz: Class<*>, - fun mapToPluralsIfNeeded(res: RESULT): RESULT { + fun mapToPluralsIfNeeded(res: RESULT): RESULT { if (selector is com.kameocode.anydao.AnyDao.PathArraySelect ) { return res; } @@ -82,7 +82,7 @@ class QueryPathContext(clz: Class<*>, return res } - fun mapToPluralsIfNeeded(res: List): List { + fun mapToPluralsIfNeeded(res: List): List { if (selector is com.kameocode.anydao.AnyDao.PathArraySelect) { return res; } diff --git a/src/main/kotlin/com/kameocode/anydao/wraps/PathWrap.kt b/src/main/kotlin/com/kameocode/anydao/wraps/PathWrap.kt index de36f92..7ed0f62 100644 --- a/src/main/kotlin/com/kameocode/anydao/wraps/PathWrap.kt +++ b/src/main/kotlin/com/kameocode/anydao/wraps/PathWrap.kt @@ -41,7 +41,6 @@ open class PathWrap constructor( return this } - infix fun select(pw: KProperty1): SelectWrap { return select(get(pw)) } @@ -55,6 +54,10 @@ open class PathWrap constructor( } + infix fun selectNullable(pw: ExpressionWrap): SelectWrap { + return pw.getDirectSelection() as SelectWrap + } + fun select(pw1: ISelectExpressionProvider, pw2: ISelectExpressionProvider): com.kameocode.anydao.AnyDao.PathPairSelect { return com.kameocode.anydao.AnyDao.PathPairSelect(pw1.getDirectSelection(), pw2.getDirectSelection(), false, pc.cb) } diff --git a/src/test/kotlin/com/kameocode/anydao/test/ClausesTest.kt b/src/test/kotlin/com/kameocode/anydao/test/ClausesTest.kt index 55f4ee6..08ddd96 100644 --- a/src/test/kotlin/com/kameocode/anydao/test/ClausesTest.kt +++ b/src/test/kotlin/com/kameocode/anydao/test/ClausesTest.kt @@ -4,7 +4,7 @@ import com.kameocode.anydao.KClause import com.kameocode.anydao.KFromClause import com.kameocode.anydao.KQuery import com.kameocode.anydao.KRoot -import com.kameocode.anydao.Page +import com.kameocode.anydao.KPage import com.kameocode.anydao.test.helpers.AddressODB import com.kameocode.anydao.test.helpers.BaseTest import com.kameocode.anydao.test.helpers.TaskODB @@ -320,8 +320,8 @@ class ClausesTest : BaseTest() { // expected } val first = anyDao.first(UserODB::class, query) - val page = anyDao.page(UserODB::class, Page(), query) - val pages = anyDao.pages(UserODB::class, Page(), query) + val page = anyDao.page(UserODB::class, KPage(), query) + val pages = anyDao.pages(UserODB::class, KPage(), query) Assert.assertEquals(setOf(u2.task, u3.task).map { it.id }.toSet(), res1.map { it.id }.toSet()) Assert.assertEquals(2, count) diff --git a/src/test/kotlin/com/kameocode/anydao/test/PagesTest.kt b/src/test/kotlin/com/kameocode/anydao/test/PagesTest.kt index 7ac4e78..dd0a14d 100644 --- a/src/test/kotlin/com/kameocode/anydao/test/PagesTest.kt +++ b/src/test/kotlin/com/kameocode/anydao/test/PagesTest.kt @@ -1,6 +1,6 @@ package com.kameocode.anydao.test -import com.kameocode.anydao.Page +import com.kameocode.anydao.KPage import com.kameocode.anydao.test.helpers.BaseTest import com.kameocode.anydao.test.helpers.TaskODB import com.kameocode.anydao.test.helpers.UserODB @@ -19,26 +19,26 @@ class PagesTest : BaseTest() { anyDao.persist(UserODB(email = "email$i", task = TaskODB(name = "task$i"), counter = i)) } - val res1 = anyDao.page(UserODB::class, Page()) { it[UserODB::email] like "email1" } - val res1a = anyDao.page(UserODB::class, Page()) { it } - val res1b = anyDao.page(UserODB::class, Page().next()) { it } + val res1 = anyDao.page(UserODB::class, KPage()) { it[UserODB::email] like "email1" } + val res1a = anyDao.page(UserODB::class, KPage()) { it } + val res1b = anyDao.page(UserODB::class, KPage().next()) { it } Assert.assertEquals(1, res1.size) Assert.assertEquals(10, res1a.size) Assert.assertEquals(9, res1b.size) - val res2 = anyDao.page(UserODB::class, Page()) { it[UserODB::counter].mod(3) eq 1 } + val res2 = anyDao.page(UserODB::class, KPage()) { it[UserODB::counter].mod(3) eq 1 } Assert.assertEquals(7, res2.size) - val sup = anyDao.pages(UserODB::class, Page(3)) { it[UserODB::counter].mod(3) eq 1 } + val sup = anyDao.pages(UserODB::class, KPage(3)) { it[UserODB::counter].mod(3) eq 1 } Assert.assertEquals(3, sup.invoke().size) Assert.assertEquals(3, sup.invoke().size) Assert.assertEquals(1, sup.invoke().size) Assert.assertEquals(0, sup.invoke().size) - val sup2 = anyDao.pages(UserODB::class, Page(3)) { it[UserODB::counter].mod(3) eq 1 } + val sup2 = anyDao.pages(UserODB::class, KPage(3)) { it[UserODB::counter].mod(3) eq 1 } val chunkSizes2 = mutableListOf() sup2.forEach { chunkSizes2.add(it.size) } Assert.assertEquals(listOf(3, 3, 1), chunkSizes2) @@ -49,19 +49,19 @@ class PagesTest : BaseTest() { Assert.assertEquals("Should return same results second time", listOf(3, 3, 1), chunkSizes2b) - val sup3 = anyDao.pages(UserODB::class, Page(3)) { it[UserODB::counter].mod(3) eq 1 } + val sup3 = anyDao.pages(UserODB::class, KPage(3)) { it[UserODB::counter].mod(3) eq 1 } val chunkSizes3 = mutableListOf() sup3.forEachFlat { chunkSizes3.add(1) } Assert.assertEquals(listOf(1, 1, 1, 1, 1, 1, 1), chunkSizes3) - val sup4 = anyDao.pages(UserODB::class, Page(3)) { it[UserODB::counter].mod(3) eq 1 } + val sup4 = anyDao.pages(UserODB::class, KPage(3)) { it[UserODB::counter].mod(3) eq 1 } val chunkSizes4 = mutableListOf() sup4.forEachUntil { chunkSizes4.add(it.size); false } Assert.assertEquals(listOf(3), chunkSizes4) - val sup5 = anyDao.pages(UserODB::class, Page(3)) { it[UserODB::counter].mod(3) eq 1 } + val sup5 = anyDao.pages(UserODB::class, KPage(3)) { it[UserODB::counter].mod(3) eq 1 } val chunkSizes5 = mutableListOf() sup5.forEachFlatUntil { chunkSizes5.add(1); chunkSizes5.size < 2 } Assert.assertEquals(listOf(1, 1), chunkSizes5) @@ -75,12 +75,12 @@ class PagesTest : BaseTest() { anyDao.persist(UserODB(email = "email$i", task = TaskODB(name = "task$i"))) } - val res1 = anyDao.pagesSorted(UserODB::class, UserODB::id, Page(3)) { not { it[UserODB::email] like "n" } } + val res1 = anyDao.pagesSorted(UserODB::class, UserODB::id, KPage(3)) { not { it[UserODB::email] like "n" } } val chunkSizes1 = mutableListOf() res1.forEach { chunkSizes1.add(it.size) } Assert.assertEquals(listOf(3, 3, 3, 1), chunkSizes1) - val res2 = anyDao.pagesSorted(UserODB::class, UserODB::id, Page(10)) { not { it[UserODB::email] like "n" } } + val res2 = anyDao.pagesSorted(UserODB::class, UserODB::id, KPage(10)) { not { it[UserODB::email] like "n" } } val chunkSizes2 = mutableListOf() res2.forEach { chunkSizes2.add(it.size) } Assert.assertEquals(listOf(10), chunkSizes2) diff --git a/src/test/kotlin/com/kameocode/anydao/test/SingleSelectTest.kt b/src/test/kotlin/com/kameocode/anydao/test/SingleSelectTest.kt new file mode 100644 index 0000000..18d0acc --- /dev/null +++ b/src/test/kotlin/com/kameocode/anydao/test/SingleSelectTest.kt @@ -0,0 +1,58 @@ +package com.kameocode.anydao.test + +import com.kameocode.anydao.test.helpers.BaseTest +import com.kameocode.anydao.test.helpers.TaskODB +import com.kameocode.anydao.test.helpers.UserODB +import com.kameocode.anydao.wraps.JoinWrap +import org.junit.Assert +import org.junit.Test +import javax.persistence.criteria.JoinType + + +class SingleSelectTest : BaseTest() { + + @Test + fun `should return plain select with nullable`() { + anyDao.persist( + UserODB(email = "email1", task = TaskODB(name = "t1"), taskNullable = TaskODB(name = "t1n")), + UserODB(email = "email2", task = TaskODB(name = "t1")), + UserODB(email = "email3", task = TaskODB(name = "t2"))) + + val res1: List = anyDao.all(UserODB::class) { + it.select(UserODB::task) + } + Assert.assertEquals(3, res1.size) + + + + val res2: List = anyDao.all(UserODB::class) { + val task: JoinWrap = it.join(UserODB::taskNullable, JoinType.LEFT) + it.selectNullable(task) + } + Assert.assertEquals(3, res2.size) + Assert.assertNotNull(res2[0]) + Assert.assertNull(res2[1]) + Assert.assertNull(res2[2]) + + + val res3: List = anyDao.all(UserODB::class) { + val task: JoinWrap = it.join(UserODB::taskNullable, JoinType.LEFT) + it.select(task) + } + Assert.assertEquals(3, res3.size) + Assert.assertNotNull(res3[0]) + Assert.assertNull(res2[1]) + Assert.assertNull(res3[2]) + + val res4: List = anyDao.all(UserODB::class) { + val task: JoinWrap = it.join(UserODB::taskNullable, JoinType.LEFT) + it.select(task) + } + Assert.assertEquals(3, res4.size) + Assert.assertNotNull(res4[0]) + Assert.assertNull(res4[1]) + Assert.assertNull(res4[2]) + } + +} +