feature #8: Pagination for Query & Function

This commit is contained in:
2019-07-17 10:55:32 +02:00
parent 362a2a6617
commit 09c20fc385
6 changed files with 123 additions and 30 deletions

View File

@@ -17,6 +17,7 @@ interface Executable {
fun <R: EntityI<*>> select(sql: String, typeReference: TypeReference<R>, values: Map<String, Any?>): R?
fun <R: EntityI<*>> select(sql: String, typeReference: TypeReference<List<R>>, values: List<Any?> = emptyList()): List<R>
fun <R: EntityI<*>> select(sql: String, typeReference: TypeReference<List<R>>, values: Map<String, Any?>): List<R>
fun <R: EntityI<*>> select(sql: String, page: Int, limit: Int, typeReference: TypeReference<List<R>>, values: Map<String, Any?>): Paginated<R>
fun exec(sql: String, values: List<Any?> = emptyList()): CompletableFuture<QueryResult>
fun exec(sql: String, values: Map<String, Any?>): CompletableFuture<QueryResult>
}
@@ -77,7 +78,7 @@ class Connection(
inline fun <reified R: EntityI<*>> select(sql: String, values: List<Any?> = emptyList()): List<R> =
select(sql, object: TypeReference<List<R>>() {}, values)
fun <R: EntityI<*>> select(
override fun <R: EntityI<*>> select(
sql: String,
page: Int,
limit: Int,
@@ -108,6 +109,7 @@ class Connection(
)
}
}
inline fun <reified R: EntityI<*>> select(
sql: String,
page: Int,

View File

@@ -10,8 +10,8 @@ import fr.postgresjson.definition.Function as DefinitionFunction
class Requester(
private val connection: Connection,
private val queries: MutableMap<String, Query> = mutableMapOf(),
private val functions: MutableMap<String, Function> = mutableMapOf())
{
private val functions: MutableMap<String, Function> = mutableMapOf()
) {
fun addQuery(name: String, query: Query): Requester {
queries[name] = query
return this
@@ -82,23 +82,33 @@ class Requester (
override fun <R: EntityI<*>> select(typeReference: TypeReference<R>, values: List<Any?>): R? {
return connection.select(this.toString(), typeReference, values)
}
inline fun <reified R: EntityI<*>> selectOne(values: List<Any?> = emptyList()): R? = select(object: TypeReference<R>() {}, values)
override fun <R: EntityI<*>> select(typeReference: TypeReference<R>, values: Map<String, Any?>): R? {
return connection.select(this.toString(), typeReference, values)
}
inline fun <reified R: EntityI<*>> selectOne(values: Map<String, Any?>): R? = select(object: TypeReference<R>() {}, values)
override fun <R: EntityI<*>> select(typeReference: TypeReference<List<R>>, values: List<Any?>): List<R> {
return connection.select(this.toString(), typeReference, values)
}
inline fun <reified R: EntityI<*>> select(values: List<Any?> = emptyList()): List<R> = select(object: TypeReference<List<R>>() {}, values)
override fun <R: EntityI<*>> select(typeReference: TypeReference<List<R>>, values: Map<String, Any?>): List<R> {
return connection.select(this.toString(), typeReference, values)
}
inline fun <reified R: EntityI<*>> select(values: Map<String, Any?>): List<R> = select(object: TypeReference<List<R>>() {}, values)
override fun <R: EntityI<*>> select(page: Int, limit: Int, typeReference: TypeReference<List<R>>, values: Map<String, Any?>): Paginated<R> {
return connection.select(this.toString(), page, limit, typeReference, values)
}
inline fun <reified R: EntityI<*>> select(page: Int, limit: Int, values: Map<String, Any?> = emptyMap()): Paginated<R> =
select(page, limit, object: TypeReference<List<R>>() {}, values)
override fun exec(values: List<Any?>): CompletableFuture<QueryResult> {
return connection.exec(sql, values)
}
@@ -122,6 +132,7 @@ class Requester (
return connection.select(sql, typeReference, values)
}
inline fun <reified R: EntityI<*>> selectOne(values: List<Any?> = emptyList()): R? = select(object: TypeReference<R>() {}, values)
/**
@@ -133,6 +144,7 @@ class Requester (
return connection.select(sql, typeReference, values)
}
inline fun <reified R: EntityI<*>> selectOne(values: Map<String, Any?>): R? = select(object: TypeReference<R>() {}, values)
/**
@@ -144,6 +156,7 @@ class Requester (
return connection.select(sql, typeReference, values)
}
inline fun <reified R: EntityI<*>> select(values: List<Any?> = emptyList()): List<R> = select(object: TypeReference<List<R>>() {}, values)
/**
@@ -155,8 +168,23 @@ class Requester (
return connection.select(sql, typeReference, values)
}
inline fun <reified R: EntityI<*>> select(values: Map<String, Any?>): List<R> = select(object: TypeReference<List<R>>() {}, values)
override fun <R: EntityI<*>> select(page: Int, limit: Int, typeReference: TypeReference<List<R>>, values: Map<String, Any?>): Paginated<R> {
val offset = (page - 1) * limit
val newValues = values
.plus("offset" to offset)
.plus("limit" to limit)
val args = compileArgs(newValues)
val sql = "SELECT * FROM ${definition.name} ($args)"
return connection.select(sql, page, limit, typeReference, values)
}
inline fun <reified R: EntityI<*>> select(page: Int, limit: Int, values: Map<String, Any?> = emptyMap()): Paginated<R> =
select(page, limit, object: TypeReference<List<R>>() {}, values)
override fun exec(values: List<Any?>): CompletableFuture<QueryResult> {
val args = compileArgs(values)
val sql = "SELECT * FROM ${definition.name} ($args)"
@@ -192,7 +220,7 @@ class Requester (
}
.map { entry ->
val parameter = parameters[entry.key]!!
"${parameter.name} := :${parameter.name}::" + parameter.type
""""${parameter.name}" := :${parameter.name}::${parameter.type}"""
}
return placeholders.joinToString(separator = ", ")
@@ -209,6 +237,8 @@ class Requester (
fun <R: EntityI<*>> select(typeReference: TypeReference<List<R>>, values: List<Any?> = emptyList()): List<R>
fun <R: EntityI<*>> select(typeReference: TypeReference<List<R>>, values: Map<String, Any?>): List<R>
fun <R: EntityI<*>> select(page: Int, limit: Int, typeReference: TypeReference<List<R>>, values: Map<String, Any?>): Paginated<R>
fun exec(values: List<Any?> = emptyList()): CompletableFuture<QueryResult>
fun exec(values: Map<String, Any?>): CompletableFuture<QueryResult>
}
@@ -221,18 +251,15 @@ class Requester (
private val password: String = "dc-project",
private val queriesDirectory: File? = null,
private val functionsDirectory: File? = null
)
{
fun createRequester(): Requester
{
) {
fun createRequester(): Requester {
val con = Connection(host = host, port = port, database = database, username = username, password = password)
val req = Requester(con)
return initRequester(req)
}
private fun initRequester(req: Requester): Requester
{
private fun initRequester(req: Requester): Requester {
if (queriesDirectory === null) {
val resource = this::class.java.getResource("/sql/query")
if (resource !== null) {

View File

@@ -2,8 +2,10 @@ package fr.postgresjson
import com.github.jasync.sql.db.QueryResult
import com.github.jasync.sql.db.util.isCompleted
import fr.postgresjson.connexion.Paginated
import fr.postgresjson.connexion.Requester
import fr.postgresjson.entity.IdEntity
import org.junit.Assert
import org.junit.jupiter.api.Assertions
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.Test
@@ -93,4 +95,32 @@ class RequesterTest: TestAbstract() {
assertEquals("myName", obj!![0].name)
}
@Test
fun `call select paginated on query`() {
val resources = File(this::class.java.getResource("/sql/query").toURI())
val result: Paginated<ObjTest> = Requester(getConnextion())
.addQuery(resources)
.getQuery("Test/selectPaginated")
.select(1, 2, mapOf("name" to "ff"))
Assert.assertNotNull(result)
Assert.assertEquals(result.result[0].name, "ff")
Assert.assertEquals(result.result[1].name, "ff-2")
Assert.assertEquals(result.total, 10)
Assert.assertEquals(result.offset, 0)
}
@Test
fun `call select paginated on function`() {
val resources = File(this::class.java.getResource("/sql/function").toURI())
val result: Paginated<ObjTest> = Requester(getConnextion())
.addFunction(resources)
.getFunction("test_function_paginated")
.select(1, 2, mapOf("name" to "ff"))
Assert.assertNotNull(result)
Assert.assertEquals(result.result[0].name, "ff")
Assert.assertEquals(result.result[1].name, "ff-2")
Assert.assertEquals(result.total, 10)
Assert.assertEquals(result.offset, 0)
}
}

View File

@@ -49,3 +49,18 @@ BEGIN
);
END;
$$;
CREATE OR REPLACE FUNCTION test_function_paginated (name text default 'plop', IN "limit" int default 10, IN "offset" int default 0, out result json, out total int)
LANGUAGE plpgsql
AS
$$
BEGIN
SELECT json_build_array(
json_build_object('id', 3, 'name', name::text),
json_build_object('id', 4, 'name', name::text || '-2')
),
10
INTO result, total
LIMIT "limit" OFFSET "offset";
END;
$$

View File

@@ -0,0 +1,14 @@
CREATE OR REPLACE FUNCTION test_function_paginated (name text default 'plop', IN "limit" int default 10, IN "offset" int default 0, out result json, out total int)
LANGUAGE plpgsql
AS
$$
BEGIN
SELECT json_build_array(
json_build_object('id', 3, 'name', name::text),
json_build_object('id', 4, 'name', name::text || '-2')
),
10
INTO result, total
LIMIT "limit" OFFSET "offset";
END;
$$

View File

@@ -0,0 +1,5 @@
SELECT json_build_array(
json_build_object('id', 3, 'name', :name::text),
json_build_object('id', 4, 'name', :name::text || '-2')
), 10 as total
LIMIT :limit OFFSET :offset