Skip to content

Commit 49b9b79

Browse files
use custom query for permissions
1 parent 5bb0a82 commit 49b9b79

File tree

7 files changed

+145
-62
lines changed

7 files changed

+145
-62
lines changed

http/user-app.http

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
11
### Permissions
22

33
###
4-
GET {{host}}/permissions?page=0&size=10&sort=id&direction=ASC
4+
GET {{host}}/permissions?page=0&size=10&sort=id&direction=DESC&search=test&createdFrom=1759429679915&createdBy=78652bda-8e80-432b-ba1b-47b4f7ee98e6
5+
Authorization: Bearer {{oauthToken}}
6+
7+
###
8+
GET {{host}}/permissions/count?search=test&createdFrom=1759429679915&createdBy=78652bda-8e80-432b-ba1b-47b4f7ee98e6
59
Authorization: Bearer {{oauthToken}}
610

711
###
@@ -20,11 +24,11 @@ GET {{host}}/permissions/{{permissionId}}
2024
Authorization: Bearer {{oauthToken}}
2125

2226
###
23-
PUT {{host}}/permissions/1
27+
PUT {{host}}/permissions/{{permissionId}}
2428
Content-Type: application/json
2529
Authorization: Bearer {{oauthToken}}
2630

27-
{"name": "test-coroutine-changed 22", "description": "test description coroutine changed!", "version": 1}
31+
{"name": "test-coroutine-changed", "description": "test description coroutine changed!", "version": 1}
2832

2933
###
3034
DELETE {{host}}/permissions/{{permissionId}}

src/main/kotlin/com/softeno/template/app/config/security/ReactiveAuditorConfig.kt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ import org.springframework.security.core.context.ReactiveSecurityContextHolder
1010
import org.springframework.security.core.context.SecurityContext
1111
import org.springframework.security.oauth2.jwt.Jwt
1212
import reactor.core.publisher.Mono
13-
import kotlin.jvm.javaClass
1413

1514

1615
class AuditorAwareImpl : ReactiveAuditorAware<String> {
Lines changed: 49 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,18 @@
11
package com.softeno.template.app.permission.api
22

33
import com.softeno.template.app.common.PrincipalHandler
4-
import com.softeno.template.app.permission.db.getPageRequest
54
import com.softeno.template.app.permission.mapper.PermissionDto
65
import com.softeno.template.app.permission.service.PermissionService
76
import io.micrometer.tracing.Tracer
87
import kotlinx.coroutines.flow.Flow
98
import kotlinx.coroutines.reactor.awaitSingle
10-
import kotlinx.coroutines.reactor.awaitSingleOrNull
119
import org.apache.commons.logging.LogFactory
1210
import org.slf4j.MDC
11+
import org.springframework.data.domain.PageRequest
12+
import org.springframework.data.domain.Sort
1313
import org.springframework.http.ResponseEntity
1414
import org.springframework.validation.annotation.Validated
15-
import org.springframework.web.bind.annotation.DeleteMapping
16-
import org.springframework.web.bind.annotation.GetMapping
17-
import org.springframework.web.bind.annotation.PathVariable
18-
import org.springframework.web.bind.annotation.PostMapping
19-
import org.springframework.web.bind.annotation.PutMapping
20-
import org.springframework.web.bind.annotation.RequestBody
21-
import org.springframework.web.bind.annotation.RequestParam
22-
import org.springframework.web.bind.annotation.RestController
15+
import org.springframework.web.bind.annotation.*
2316
import reactor.core.publisher.Mono
2417
import java.security.Principal
2518

@@ -31,11 +24,24 @@ class PermissionController(
3124
) : PrincipalHandler {
3225
private val log = LogFactory.getLog(javaClass)
3326

27+
data class PermissionSearch(
28+
val search: String?,
29+
val createdBy: String?,
30+
val createdFrom: Long?,
31+
val createdTo: Long?
32+
)
33+
3434
@GetMapping("/permissions")
35-
suspend fun getPermissions(@RequestParam(required = false, defaultValue = "0") page: Int,
36-
@RequestParam(required = false, defaultValue = "10") size: Int,
37-
@RequestParam(required = false, defaultValue = "id") sort: String,
38-
@RequestParam(required = false, defaultValue = "ASC") direction: String, monoPrincipal: Mono<Principal>
35+
suspend fun getPermissions(
36+
@RequestParam(required = false, defaultValue = "0") page: Int,
37+
@RequestParam(required = false, defaultValue = "10") size: Int,
38+
@RequestParam(required = false, defaultValue = "id") sort: String,
39+
@RequestParam(required = false, defaultValue = "ASC") direction: String,
40+
@RequestParam(required = false) search: String? = null,
41+
@RequestParam(required = false) createdBy: String? = null,
42+
@RequestParam(required = false) createdFrom: Long? = null,
43+
@RequestParam(required = false) createdTo: Long? = null,
44+
monoPrincipal: Mono<Principal>
3945
): Flow<PermissionDto> {
4046
showPrincipal(log, monoPrincipal)
4147

@@ -45,7 +51,25 @@ class PermissionController(
4551
val mdcSpan = MDC.get("spanId")
4652
log.debug("Show traceId=$traceId, mdcTraceId=$mdc and mdcSpanId=$mdcSpan")
4753

48-
return permissionService.getAllPermissions(getPageRequest(page, size, sort, direction))
54+
log.debug("Show request params: " +
55+
"page=$page, size=$size, sort=$sort, direction=$direction, " +
56+
"search=$search, createdBy=$createdBy, createdFrom=$createdFrom, createdTo=$createdTo"
57+
)
58+
59+
return permissionService.getAllPermissions(
60+
getPageRequest(page, size, sort, direction),
61+
PermissionSearch(search, createdBy, createdFrom, createdTo)
62+
)
63+
}
64+
65+
@GetMapping("/permissions/count")
66+
suspend fun getPermissionsCount(
67+
@RequestParam(required = false) search: String? = null,
68+
@RequestParam(required = false) createdBy: String? = null,
69+
@RequestParam(required = false) createdFrom: Long? = null,
70+
@RequestParam(required = false) createdTo: Long? = null,
71+
): Long {
72+
return permissionService.countPermissions(PermissionSearch(search, createdBy, createdFrom, createdTo))
4973
}
5074

5175
@GetMapping("/permissions/{id}")
@@ -62,7 +86,11 @@ class PermissionController(
6286
}
6387

6488
@PutMapping("/permissions/{id}")
65-
suspend fun updatePermission(@PathVariable id: Long, @RequestBody permissionDto: PermissionDto, monoPrincipal: Mono<Principal>): ResponseEntity<PermissionDto> {
89+
suspend fun updatePermission(
90+
@PathVariable id: Long,
91+
@RequestBody permissionDto: PermissionDto,
92+
monoPrincipal: Mono<Principal>
93+
): ResponseEntity<PermissionDto> {
6694
val result = permissionService.updatePermission(id, permissionDto, principal = monoPrincipal.awaitSingle())
6795
return ResponseEntity.ok(result)
6896
}
@@ -71,4 +99,8 @@ class PermissionController(
7199
suspend fun deletePermission(@PathVariable id: Long) {
72100
permissionService.deletePermission(id)
73101
}
74-
}
102+
}
103+
104+
fun getPageRequest(page: Int, size: Int, sort: String, direction: String) =
105+
Sort.by(Sort.Order(if (direction == "ASC") Sort.Direction.ASC else Sort.Direction.DESC, sort))
106+
.let { PageRequest.of(page, size, it) }

src/main/kotlin/com/softeno/template/app/permission/db/PermissionRepository.kt

Lines changed: 33 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,20 +2,19 @@ package com.softeno.template.app.permission.db
22

33
import com.softeno.template.app.permission.BaseEntity
44
import com.softeno.template.app.permission.Permission
5+
import com.softeno.template.app.permission.api.PermissionController
6+
import kotlinx.coroutines.flow.Flow
57
import kotlinx.coroutines.reactor.awaitSingle
6-
import org.springframework.data.domain.PageRequest
78
import org.springframework.data.domain.Pageable
8-
import org.springframework.data.domain.Sort
99
import org.springframework.data.r2dbc.repository.Query
10-
import org.springframework.data.r2dbc.repository.R2dbcRepository
1110
import org.springframework.data.relational.core.mapping.Column
1211
import org.springframework.data.relational.core.mapping.Table
12+
import org.springframework.data.repository.kotlin.CoroutineCrudRepository
1313
import org.springframework.data.repository.query.Param
1414
import org.springframework.r2dbc.core.DatabaseClient
1515
import org.springframework.r2dbc.core.bind
1616
import org.springframework.stereotype.Component
1717
import org.springframework.stereotype.Repository
18-
import reactor.core.publisher.Flux
1918
import reactor.core.publisher.Mono
2019
import java.util.*
2120
import kotlin.reflect.KProperty1
@@ -24,8 +23,36 @@ import kotlin.reflect.full.memberProperties
2423
import kotlin.reflect.jvm.javaField
2524

2625
@Repository
27-
interface PermissionRepository : R2dbcRepository<Permission, Long>, BatchPermissionRepository<Permission> {
28-
fun findBy(pageable: Pageable): Flux<Permission>
26+
interface PermissionRepository : CoroutineCrudRepository<Permission, Long>, BatchPermissionRepository<Permission> {
27+
28+
@Query("""
29+
SELECT p.* FROM permissions p
30+
WHERE (:#{#search.search} IS NULL OR (
31+
p.name LIKE CONCAT('%', :#{#search.search}, '%') OR
32+
p.description LIKE CONCAT('%', :#{#search.search}, '%')
33+
))
34+
AND (:#{#search.createdFrom} IS NULL OR p.created_date >= :#{#search.createdFrom})
35+
AND (:#{#search.createdTo} IS NULL OR p.created_date <= :#{#search.createdTo})
36+
AND (:#{#search.createdBy} IS NULL OR p.created_by = :#{#search.createdBy})
37+
ORDER BY
38+
CASE WHEN :#{#pageable.sort.toString()} = 'id: ASC' THEN p.id END ASC,
39+
CASE WHEN :#{#pageable.sort.toString()} = 'id: DESC' THEN p.id END DESC
40+
LIMIT :#{#pageable.pageSize}
41+
OFFSET :#{#pageable.offset}
42+
""")
43+
suspend fun findBy(search: PermissionController.PermissionSearch, pageable: Pageable): Flow<Permission>
44+
45+
@Query("""
46+
SELECT COUNT(*) FROM permissions p
47+
WHERE (:#{#search.search} IS NULL OR (
48+
p.name LIKE CONCAT('%', :#{#search.search}, '%') OR
49+
p.description LIKE CONCAT('%', :#{#search.search}, '%')
50+
))
51+
AND (:#{#search.createdFrom} IS NULL OR p.created_date >= :#{#search.createdFrom})
52+
AND (:#{#search.createdTo} IS NULL OR p.created_date <= :#{#search.createdTo})
53+
AND (:#{#search.createdBy} IS NULL OR p.created_by = :#{#search.createdBy})
54+
""")
55+
suspend fun countBy(search: PermissionController.PermissionSearch): Long
2956

3057
@Query("SELECT p.version FROM permissions as p WHERE p.id = :id")
3158
fun findVersionById(@Param("id") id: Long): Mono<Long>
@@ -159,7 +186,3 @@ class BatchPermissionRepositoryImpl<T : BaseEntity>(private val databaseClient:
159186
}
160187

161188
class OperationNotPermittedException(message: String) : RuntimeException(message)
162-
163-
fun getPageRequest(page: Int, size: Int, sort: String, direction: String) =
164-
Sort.by(Sort.Order(if (direction == "ASC") Sort.Direction.ASC else Sort.Direction.DESC, sort))
165-
.let { PageRequest.of(page, size, it) }

src/main/kotlin/com/softeno/template/app/permission/service/PermissionService.kt

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,12 @@ package com.softeno.template.app.permission.service
33
import com.softeno.template.app.kafka.ReactiveKafkaSampleProducer
44
import com.softeno.template.app.kafka.dto.KafkaMessage
55
import com.softeno.template.app.permission.Permission
6+
import com.softeno.template.app.permission.api.PermissionController
67
import com.softeno.template.app.permission.db.PermissionRepository
78
import com.softeno.template.app.permission.mapper.PermissionDto
89
import com.softeno.template.app.permission.mapper.toDto
910
import kotlinx.coroutines.flow.Flow
10-
import kotlinx.coroutines.reactive.asFlow
11-
import kotlinx.coroutines.reactive.awaitFirstOrElse
11+
import kotlinx.coroutines.flow.map
1212
import kotlinx.coroutines.reactive.awaitSingle
1313
import kotlinx.coroutines.reactor.awaitSingleOrNull
1414
import kotlinx.coroutines.slf4j.MDCContext
@@ -33,20 +33,26 @@ class PermissionService(
3333
) {
3434
private val log = LogFactory.getLog(javaClass)
3535

36-
suspend fun getAllPermissions(pageable: Pageable): Flow<PermissionDto> =
36+
suspend fun getAllPermissions(pageable: Pageable, search: PermissionController.PermissionSearch): Flow<PermissionDto> =
3737
withContext(MDCContext()) {
38-
return@withContext permissionRepository.findBy(pageable).map { it.toDto() }.asFlow()
38+
return@withContext permissionRepository.findBy(search, pageable).map { it.toDto() }
39+
}
40+
41+
suspend fun countPermissions(search: PermissionController.PermissionSearch): Long =
42+
withContext(MDCContext()) {
43+
return@withContext permissionRepository.countBy(search)
3944
}
4045

4146
suspend fun getPermission(id: Long): PermissionDto =
4247
withContext(MDCContext()) {
43-
return@withContext permissionRepository.findById(id).awaitFirstOrElse { throw Exception("Not Found: $id") }.toDto()
48+
val result = permissionRepository.findById(id) ?: throw Exception("Not Found: $id")
49+
return@withContext result.toDto()
4450
}
4551

4652
@Transactional
4753
suspend fun createPermission(permissionDto: PermissionDto): PermissionDto =
4854
withContext(MDCContext()) {
49-
val created = permissionRepository.save(Permission(name = permissionDto.name, description = permissionDto.description)).awaitSingle().toDto()
55+
val created = permissionRepository.save(Permission(name = permissionDto.name, description = permissionDto.description)).toDto()
5056
kafkaPublisher.send(KafkaMessage(content = "CREATED_PREMISSION: ${created.id}", traceId = MDC.get("traceId"), spanId = MDC.get("spanId")))
5157
return@withContext created
5258
}
@@ -75,6 +81,6 @@ class PermissionService(
7581

7682
suspend fun deletePermission(id: Long) =
7783
withContext(MDCContext()) {
78-
permissionRepository.deleteById(id).awaitSingleOrNull()
84+
permissionRepository.deleteById(id)
7985
}
8086
}

0 commit comments

Comments
 (0)