feature #12: Add constitution Entity, repository and route
This commit is contained in:
@@ -7,7 +7,10 @@ import com.fasterxml.jackson.databind.PropertyNamingStrategy
|
||||
import com.fasterxml.jackson.databind.SerializationFeature
|
||||
import com.fasterxml.jackson.datatype.joda.JodaModule
|
||||
import fr.dcproject.entity.Article
|
||||
import fr.dcproject.entity.Constitution
|
||||
import fr.dcproject.routes.article
|
||||
import fr.dcproject.routes.constitution
|
||||
import fr.postgresjson.migration.Migrations
|
||||
import io.ktor.application.Application
|
||||
import io.ktor.application.install
|
||||
import io.ktor.auth.Authentication
|
||||
@@ -23,6 +26,7 @@ import org.koin.ktor.ext.Koin
|
||||
import org.koin.ktor.ext.get
|
||||
import java.util.*
|
||||
import fr.dcproject.repository.Article as RepositoryArticle
|
||||
import fr.dcproject.repository.Constitution as RepositoryConstitution
|
||||
|
||||
fun main(args: Array<String>): Unit = io.ktor.server.netty.EngineMain.main(args)
|
||||
|
||||
@@ -36,6 +40,7 @@ fun Application.module() {
|
||||
}
|
||||
|
||||
install(DataConversion) {
|
||||
// TODO move to postgresJson lib
|
||||
convert<UUID> {
|
||||
decode { values, _ ->
|
||||
values.singleOrNull()?.let { UUID.fromString(it) }
|
||||
@@ -49,6 +54,8 @@ fun Application.module() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// create generic convert for entityI
|
||||
convert<Article> {
|
||||
decode { values, _ ->
|
||||
val id = values.singleOrNull()?.let { UUID.fromString(it) }
|
||||
@@ -56,6 +63,13 @@ fun Application.module() {
|
||||
get<RepositoryArticle>().findById(id) ?: throw InternalError("Article $values not found")
|
||||
}
|
||||
}
|
||||
convert<Constitution> {
|
||||
decode { values, _ ->
|
||||
val id = values.singleOrNull()?.let { UUID.fromString(it) }
|
||||
?: throw InternalError("Cannot convert $values to UUID")
|
||||
get<RepositoryConstitution>().findById(id) ?: throw InternalError("Constitution $values not found")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
install(Locations) {
|
||||
@@ -84,5 +98,9 @@ fun Application.module() {
|
||||
|
||||
install(Routing) {
|
||||
article(get())
|
||||
constitution(get())
|
||||
}
|
||||
|
||||
// TODO move to postgresJson lib
|
||||
get<Migrations>().run()
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ import fr.postgresjson.migration.Migrations
|
||||
import io.ktor.util.KtorExperimentalAPI
|
||||
import org.koin.dsl.module
|
||||
import fr.dcproject.repository.Article as ArticleRepository
|
||||
import fr.dcproject.repository.Constitution as ConstitutionRepository
|
||||
|
||||
val config = Config()
|
||||
|
||||
@@ -21,6 +22,9 @@ val Module = module {
|
||||
functionsDirectory = config.sqlFiles.resolve("functions")
|
||||
).createRequester() }
|
||||
|
||||
// create generic declaration
|
||||
single { ArticleRepository(get()) }
|
||||
single { ConstitutionRepository(get()) }
|
||||
|
||||
single { Migrations(connection = get(), directory = config.sqlFiles) }
|
||||
}
|
||||
|
||||
@@ -5,15 +5,14 @@ import java.util.*
|
||||
|
||||
class Article(
|
||||
id: UUID = UUID.randomUUID(),
|
||||
var versionId: UUID = UUID.randomUUID(),
|
||||
var versionNumber: Int? = null,
|
||||
var title: String?,
|
||||
var annonymous: Boolean? = true,
|
||||
var content: String?,
|
||||
var description: String?,
|
||||
var tags: List<String> = emptyList(),
|
||||
override var createdBy: Citizen?
|
||||
createdBy: Citizen?
|
||||
):
|
||||
UuidEntity(id),
|
||||
EntityVersioning<UUID, Int> by UuidEntityVersioning(),
|
||||
EntityCreatedAt by EntityCreatedAtImp(),
|
||||
CreatedBy<Citizen> by EntityCreatedByImp()
|
||||
CreatedBy<Citizen> by EntityCreatedByImp(createdBy)
|
||||
32
src/main/kotlin/fr/dcproject/entity/Constitution.kt
Normal file
32
src/main/kotlin/fr/dcproject/entity/Constitution.kt
Normal file
@@ -0,0 +1,32 @@
|
||||
package fr.dcproject.entity
|
||||
|
||||
import fr.postgresjson.entity.*
|
||||
import java.util.*
|
||||
|
||||
class Constitution(
|
||||
id: UUID = UUID.randomUUID(),
|
||||
var title: String?,
|
||||
var annonymous: Boolean?,
|
||||
var titles: List<Title>,
|
||||
createdBy: Citizen?
|
||||
): UuidEntity(id),
|
||||
EntityVersioning<UUID, Int> by UuidEntityVersioning(),
|
||||
EntityCreatedAt by EntityCreatedAtImp(),
|
||||
CreatedBy<Citizen> by EntityCreatedByImp(createdBy) {
|
||||
|
||||
init{
|
||||
titles.forEachIndexed { index, title ->
|
||||
title.createdBy = this.createdBy
|
||||
title.rank = index
|
||||
}
|
||||
}
|
||||
|
||||
class Title(
|
||||
id: UUID = UUID.randomUUID(),
|
||||
var name: String?,
|
||||
var rank: Int? = null,
|
||||
createdBy: Citizen? = null
|
||||
): UuidEntity(id),
|
||||
EntityCreatedAt by EntityCreatedAtImp(),
|
||||
CreatedBy<Citizen> by EntityCreatedByImp(createdBy)
|
||||
}
|
||||
@@ -2,8 +2,8 @@ package fr.dcproject.repository
|
||||
|
||||
import fr.postgresjson.connexion.Paginated
|
||||
import fr.postgresjson.connexion.Requester
|
||||
import fr.postgresjson.entity.EntitiesCollections
|
||||
import fr.postgresjson.repository.RepositoryI
|
||||
import fr.postgresjson.repository.RepositoryI.Direction
|
||||
import net.pearx.kasechange.toSnakeCase
|
||||
import java.util.*
|
||||
import fr.dcproject.entity.Article as ArticleEntity
|
||||
@@ -13,12 +13,7 @@ class Article(override var requester: Requester) : RepositoryI<ArticleEntity> {
|
||||
|
||||
fun findById(id: UUID): ArticleEntity? {
|
||||
val function = requester.getFunction("find_article_by_id")
|
||||
return when (val e = EntitiesCollections().get(id) as ArticleEntity?) {
|
||||
null -> {
|
||||
function.selectOne("id" to id)
|
||||
}
|
||||
else -> e
|
||||
}
|
||||
return function.selectOne("id" to id)
|
||||
}
|
||||
|
||||
fun find(
|
||||
@@ -41,13 +36,6 @@ class Article(override var requester: Requester) : RepositoryI<ArticleEntity> {
|
||||
fun upsert(article: ArticleEntity): ArticleEntity? {
|
||||
return requester
|
||||
.getFunction("upsert_article")
|
||||
.selectOne<ArticleEntity>("resource" to article)?.also {
|
||||
EntitiesCollections().set(it)
|
||||
}
|
||||
}
|
||||
|
||||
enum class Direction {
|
||||
asc,
|
||||
desc
|
||||
.selectOne("resource" to article)
|
||||
}
|
||||
}
|
||||
|
||||
41
src/main/kotlin/fr/dcproject/repository/Constitution.kt
Normal file
41
src/main/kotlin/fr/dcproject/repository/Constitution.kt
Normal file
@@ -0,0 +1,41 @@
|
||||
package fr.dcproject.repository
|
||||
|
||||
import fr.postgresjson.connexion.Paginated
|
||||
import fr.postgresjson.connexion.Requester
|
||||
import fr.postgresjson.repository.RepositoryI
|
||||
import fr.postgresjson.repository.RepositoryI.Direction
|
||||
import net.pearx.kasechange.toSnakeCase
|
||||
import java.util.*
|
||||
import fr.dcproject.entity.Constitution as ConstitutionEntity
|
||||
|
||||
class Constitution(override var requester: Requester) : RepositoryI<ConstitutionEntity> {
|
||||
override val entityName = ConstitutionEntity::class
|
||||
|
||||
fun findById(id: UUID): ConstitutionEntity? {
|
||||
val function = requester.getFunction("find_constitution_by_id")
|
||||
return function.selectOne("id" to id)
|
||||
}
|
||||
|
||||
fun find(
|
||||
page: Int = 1,
|
||||
limit: Int = 50,
|
||||
sort: String? = null,
|
||||
direction: Direction? = null,
|
||||
search: String? = null
|
||||
): Paginated<ConstitutionEntity> {
|
||||
return requester
|
||||
.getFunction("find_constitutions")
|
||||
.select(
|
||||
page, limit,
|
||||
"sort" to sort?.toSnakeCase(),
|
||||
"direction" to direction,
|
||||
"search" to search
|
||||
)
|
||||
}
|
||||
|
||||
fun upsert(article: ConstitutionEntity): ConstitutionEntity? {
|
||||
return requester
|
||||
.getFunction("upsert_constitution")
|
||||
.selectOne("resource" to article)
|
||||
}
|
||||
}
|
||||
30
src/main/kotlin/fr/dcproject/routes/Constitution.kt
Normal file
30
src/main/kotlin/fr/dcproject/routes/Constitution.kt
Normal file
@@ -0,0 +1,30 @@
|
||||
package fr.dcproject.routes
|
||||
|
||||
import Paths
|
||||
import io.ktor.application.call
|
||||
import io.ktor.locations.KtorExperimentalLocationsAPI
|
||||
import io.ktor.locations.get
|
||||
import io.ktor.locations.post
|
||||
import io.ktor.request.receive
|
||||
import io.ktor.response.respond
|
||||
import io.ktor.routing.Route
|
||||
import fr.dcproject.entity.Constitution as ConstitutionEntity
|
||||
import fr.dcproject.repository.Constitution as ConstitutionRepository
|
||||
|
||||
@KtorExperimentalLocationsAPI
|
||||
fun Route.constitution(repo: ConstitutionRepository) {
|
||||
get<Paths.ConstitutionsRequest> {
|
||||
val constitutions = repo.find(it.page, it.limit, it.sort, it.direction, it.search)
|
||||
call.respond(constitutions)
|
||||
}
|
||||
|
||||
get<Paths.ConstitutionRequest> {
|
||||
call.respond(it.constitution)
|
||||
}
|
||||
|
||||
post<Paths.PostConstitutionRequest>() {
|
||||
val constitution = call.receive<ConstitutionEntity>()
|
||||
repo.upsert(constitution)
|
||||
call.respond(constitution)
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
import fr.dcproject.entity.Article
|
||||
import fr.dcproject.repository.Article.Direction
|
||||
import fr.dcproject.entity.Constitution
|
||||
import fr.postgresjson.repository.RepositoryI.Direction
|
||||
import io.ktor.locations.KtorExperimentalLocationsAPI
|
||||
import io.ktor.locations.Location
|
||||
|
||||
@@ -11,4 +12,12 @@ object Paths {
|
||||
}
|
||||
@Location("/articles/{article}") class ArticleRequest(val article: Article)
|
||||
@Location("/articles") class PostArticleRequest
|
||||
|
||||
|
||||
@Location("/constitutions") class ConstitutionsRequest(page: Int = 1, limit: Int = 50, val sort: String? = null, val direction: Direction? = null, val search: String? = null) {
|
||||
val page: Int = if (page < 1) 1 else page
|
||||
val limit: Int = if (limit > 50) 50 else if (limit < 1) 1 else limit
|
||||
}
|
||||
@Location("/constitutions/{constitution}") class ConstitutionRequest(val constitution: Constitution)
|
||||
@Location("/constitutions") class PostConstitutionRequest
|
||||
}
|
||||
@@ -17,6 +17,9 @@ begin
|
||||
returning id into new_id;
|
||||
|
||||
if resource->>'relations' is not null then
|
||||
delete from article_relations
|
||||
where source_id = (resource->>'id')::uuid;
|
||||
|
||||
insert into article_relations (source_id, target_id, created_by_id)
|
||||
select
|
||||
(resource->>'id')::uuid,
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
create or replace function find_constitutions(
|
||||
search text default null,
|
||||
direction text default 'desc',
|
||||
sort text default 'created_at',
|
||||
"limit" int default 50,
|
||||
"offset" int default 0,
|
||||
out resource json,
|
||||
out total int
|
||||
) language plpgsql as
|
||||
$$
|
||||
begin
|
||||
select json_agg(t), (select count(id) from constitution)
|
||||
into resource, total
|
||||
from (
|
||||
select
|
||||
c.*,
|
||||
find_citizen_by_id(c.created_by_id) as created_by,
|
||||
find_constitution_titles_by_id(c.id) as titles
|
||||
from constitution as c
|
||||
where "search" is null or title ilike '%'||"search"||'%'
|
||||
order by
|
||||
case direction when 'asc' then
|
||||
case sort
|
||||
when 'title' then c.title
|
||||
when 'created_at' then c.created_at::text
|
||||
else null
|
||||
end
|
||||
end,
|
||||
case direction when 'desc' then
|
||||
case sort
|
||||
when 'title' then c.title
|
||||
when 'created_at' then c.created_at::text
|
||||
end
|
||||
end
|
||||
desc,
|
||||
c.created_at desc
|
||||
limit "limit" offset "offset"
|
||||
) as t;
|
||||
end;
|
||||
$$;
|
||||
|
||||
-- drop function if exists find_constitutions(json, int, int);
|
||||
Reference in New Issue
Block a user