feature #6: implement PostgresJson

add Article, Citien and User Entities
implement Article.findById()
This commit is contained in:
2019-07-30 23:18:10 +02:00
parent 358c3edb0e
commit ea835d8e9a
16 changed files with 246 additions and 44 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -4,6 +4,8 @@ import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
val ktor_version: String by project val ktor_version: String by project
val kotlin_version: String by project val kotlin_version: String by project
val logback_version: String by project val logback_version: String by project
val koinVersion: String by project
val postgresjson_version: String by project
plugins { plugins {
application application
@@ -32,6 +34,8 @@ dependencies {
compile("io.ktor:ktor-auth:$ktor_version") compile("io.ktor:ktor-auth:$ktor_version")
compile("io.ktor:ktor-auth-jwt:$ktor_version") compile("io.ktor:ktor-auth-jwt:$ktor_version")
compile("io.ktor:ktor-gson:$ktor_version") compile("io.ktor:ktor-gson:$ktor_version")
compile("org.koin:koin-ktor:$koinVersion")
compile("fr.postgresjson:postgresjson:$postgresjson_version")
testCompile("io.ktor:ktor-server-tests:$ktor_version") testCompile("io.ktor:ktor-server-tests:$ktor_version")
} }

View File

@@ -2,3 +2,5 @@ ktor_version=1.2.2
kotlin.code.style=official kotlin.code.style=official
kotlin_version=1.3.40 kotlin_version=1.3.40
logback_version=1.2.1 logback_version=1.2.1
postgresjson_version=0.1
koinVersion=2.0.1

View File

@@ -7,3 +7,15 @@ ktor {
modules = [ fr.dcproject.ApplicationKt.module ] modules = [ fr.dcproject.ApplicationKt.module ]
} }
} }
app {
envName = prod
}
db {
host = localhost
database = dc-project
username = dc-project
password = dc-project
port = 5432
}

View File

@@ -15,4 +15,6 @@ begin
end; end;
$$; $$;
-- drop function if exists find_article_by_id(uuid, out json); -- drop function if exists find_article_by_id(uuid, out json);
select find_article_by_id('12fed2f3-2a7d-434b-87e6-5a9895f9d12d')

View File

@@ -1,34 +0,0 @@
package fr.dcproject
import fr.dcproject.routes.article
import io.ktor.application.Application
import io.ktor.application.install
import io.ktor.auth.Authentication
import io.ktor.features.ContentNegotiation
import io.ktor.gson.gson
import io.ktor.locations.KtorExperimentalLocationsAPI
import io.ktor.locations.Locations
import io.ktor.routing.Routing
fun main(args: Array<String>): Unit = io.ktor.server.netty.EngineMain.main(args)
@KtorExperimentalLocationsAPI
@Suppress("unused") // Referenced in application.conf
@kotlin.jvm.JvmOverloads
fun Application.module(testing: Boolean = false) {
install(Locations) {
}
install(Authentication) {
}
install(ContentNegotiation) {
gson {
}
}
install(Routing) {
article()
}
}

View File

@@ -0,0 +1,68 @@
package fr.dcproject
import fr.dcproject.entity.Article
import fr.dcproject.routes.article
import io.ktor.application.Application
import io.ktor.application.install
import io.ktor.auth.Authentication
import io.ktor.features.ContentNegotiation
import io.ktor.features.DataConversion
import io.ktor.gson.gson
import io.ktor.locations.KtorExperimentalLocationsAPI
import io.ktor.locations.Locations
import io.ktor.routing.Routing
import io.ktor.util.KtorExperimentalAPI
import org.koin.ktor.ext.Koin
import org.koin.ktor.ext.get
import java.util.*
import fr.dcproject.repository.Article as RepositoryArticle
fun main(args: Array<String>): Unit = io.ktor.server.netty.EngineMain.main(args)
@KtorExperimentalAPI
@KtorExperimentalLocationsAPI
@Suppress("unused") // Referenced in application.conf
fun Application.module() {
install(Koin) {
// Slf4jLog()
modules(Module)
}
install(DataConversion) {
convert<UUID> {
decode { values, _ ->
values.singleOrNull()?.let { UUID.fromString(it) }
}
encode { value ->
when (value) {
null -> listOf()
is UUID -> listOf(value.toString())
else -> throw InternalError("Cannot convert $value as UUID")
}
}
}
convert<Article> {
decode { values, _ ->
val id = values.singleOrNull()?.let { UUID.fromString(it) }
?: throw InternalError("Cannot convert $values to Article")
get<RepositoryArticle>().findById(id)
}
}
}
install(Locations) {
}
install(Authentication) {
}
install(ContentNegotiation) {
gson {
}
}
install(Routing) {
article()
}
}

View File

@@ -0,0 +1,14 @@
package fr.dcproject
import com.typesafe.config.ConfigFactory
class Config {
private var config = ConfigFactory.load()
val envName: String = config.getString("app.envName")
val host: String = config.getString("db.host")
val database: String = config.getString("db.database")
val username: String = config.getString("db.username")
val password: String = config.getString("db.password")
val port: Int = config.getInt("db.port")
}

View File

@@ -0,0 +1,25 @@
package fr.dcproject
import fr.postgresjson.connexion.Requester
import io.ktor.util.KtorExperimentalAPI
import org.koin.dsl.module
import java.io.File
import fr.dcproject.repository.Article as ArticleRepository
@KtorExperimentalAPI
val Module = module {
val config = Config()
single { config }
single { Requester.RequesterFactory(
host = config.host,
database = config.database,
username = config.username,
password = config.password,
port = config.port,
functionsDirectory = File(this::class.java.getResource("/sql/functions").toURI())
).createRequester() }
single { ArticleRepository(get<Requester>()) }
}

View File

@@ -0,0 +1,18 @@
package fr.dcproject.entity
import fr.postgresjson.entity.*
import java.util.*
class Article(
id: UUID,
var versionId: UUID,
var versionNumber: Int,
var title: String,
var annonymous: Boolean,
var content: String,
var description: String,
var tags: List<String>
):
UuidEntity(id),
EntityCreatedAt by EntityCreatedAtImp(),
CreatedBy<User> by EntityCreatedByImp()

View File

@@ -0,0 +1,24 @@
package fr.dcproject.entity
import fr.postgresjson.entity.EntityCreatedAt
import fr.postgresjson.entity.EntityCreatedAtImp
import fr.postgresjson.entity.UuidEntity
import java.util.*
class Citizen(
id: UUID,
var name: Name,
var birthday: String,
var userId: String,
var voteAnnonymous: Boolean,
var followAnnonymous: Boolean,
var user: User
) : UuidEntity(id),
EntityCreatedAt by EntityCreatedAtImp() {
data class Name(
var civility: String,
var lastName: String,
var firstName: String
)
}

View File

@@ -0,0 +1,17 @@
package fr.dcproject.entity
import fr.postgresjson.entity.*
import fr.postgresjson.entity.User
import org.joda.time.DateTime
import java.util.*
class User(
id: UUID?,
var username: String,
var blockedAt: DateTime?,
override var createdAt: DateTime?,
override var updatedAt: DateTime?
) : UuidEntity(id),
EntityCreatedAt by EntityCreatedAtImp(),
EntityUpdatedAt by EntityUpdatedAtImp(),
User<UUID?>

View File

@@ -0,0 +1,22 @@
package fr.dcproject.repository
import fr.postgresjson.connexion.Requester
import fr.postgresjson.entity.EntitiesCollections
import fr.postgresjson.repository.RepositoryI
import java.util.*
import kotlin.reflect.KClass
import fr.dcproject.entity.Article as ArticleEntity
class Article(override var requester: Requester) : RepositoryI<ArticleEntity> {
override val entityName: KClass<fr.dcproject.entity.Article> = ArticleEntity::class
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
}
}
}

View File

@@ -1,6 +1,7 @@
package fr.dcproject.routes package fr.dcproject.routes
import Paths import Paths
import fr.postgresjson.serializer.serialize
import io.ktor.application.call import io.ktor.application.call
import io.ktor.locations.KtorExperimentalLocationsAPI import io.ktor.locations.KtorExperimentalLocationsAPI
import io.ktor.locations.get import io.ktor.locations.get
@@ -12,4 +13,7 @@ fun Route.article() {
get<Paths.ArticlesRequest> { get<Paths.ArticlesRequest> {
call.respondText("todo") call.respondText("todo")
} }
get<Paths.ArticleRequest> {
call.respondText(it.article.serialize())
}
} }

View File

@@ -1,8 +1,10 @@
import fr.dcproject.entity.Article
import io.ktor.locations.KtorExperimentalLocationsAPI import io.ktor.locations.KtorExperimentalLocationsAPI
import io.ktor.locations.Location import io.ktor.locations.Location
@KtorExperimentalLocationsAPI @KtorExperimentalLocationsAPI
object Paths { object Paths {
@Location("/articles") class ArticlesRequest @Location("/articles") class ArticlesRequest
@Location("/articles/{article}") class ArticleRequest(val article: Article)
@Location("/articles") class PostArticleRequest @Location("/articles") class PostArticleRequest
} }