Upcoming U19 Elite and Esiliiga Matches: Estonia's Football Spotlight
Tomorrow promises to be an exhilarating day for football enthusiasts in Estonia, with a series of U19 Elite and Esiliiga matches set to take place. As the anticipation builds, we delve into the details of these fixtures, offering expert betting predictions and insights into what to expect from each game. Whether you're a seasoned bettor or a passionate supporter, this comprehensive guide will keep you informed and ready to place your bets.
Match Highlights and Predictions
The U19 Elite league is renowned for showcasing some of the brightest young talents in Estonian football. Tomorrow's fixtures are no exception, with several teams vying for supremacy. Here’s a breakdown of the key matches and our expert predictions:
Tallinna JK Legion vs. Flora U19
This clash between Tallinna JK Legion and Flora U19 is one of the most anticipated matches of the day. Known for their tactical prowess, Flora U19 has been in excellent form this season, making them favorites to win. However, Tallinna JK Legion has shown resilience and determination, often proving to be a tough opponent.
- Key Players: Keep an eye on Flora's striker, who has been in top form, scoring multiple goals in recent matches.
- Betting Tip: Consider placing a bet on Flora U19 to win with a handicap of -1.5 goals.
Narva Trans vs. Levadia U19
Narva Trans and Levadia U19 have had a competitive history, with both teams exchanging victories over the past seasons. Narva Trans is known for their solid defense, while Levadia U19 boasts a dynamic attacking lineup.
- Key Players: Narva Trans' goalkeeper has been instrumental in keeping clean sheets, while Levadia's midfield maestro orchestrates their play.
- Betting Tip: A draw could be a safe bet given the evenly matched nature of these teams.
FinnPa vs. FC Kuressaare U19
FinnPa has been steadily climbing the ranks this season, thanks to their disciplined approach and strategic gameplay. FC Kuressaare U19, on the other hand, is known for their high-energy performances and ability to surprise opponents.
- Key Players: FinnPa's captain leads from the front with his leadership and skillful play.
- Betting Tip: Betting on over 2.5 goals might be lucrative given FC Kuressaare's attacking style.
Esiliiga Insights: Estonia's Second Tier Showdowns
The Esiliiga matches add another layer of excitement to tomorrow's football calendar. These games are crucial for teams looking to climb up to the elite league or avoid relegation. Here are some key matchups to watch:
Kohtla-Järve JK Järve vs. Pärnu Jalgpalliklubi
Kohtla-Järve JK Järve has been struggling with consistency this season but has shown flashes of brilliance that make them dangerous opponents. Pärnu Jalgpalliklubi, meanwhile, is determined to secure their position in the league with strong defensive tactics.
- Key Players: Kohtla-Järve's winger is known for his speed and ability to create scoring opportunities.
- Betting Tip: A low-scoring game could be expected due to Pärnu's defensive focus.
Lelle SK vs. Vaprus Pärnu
Lelle SK has been impressive with their attacking play, often outscoring their opponents by significant margins. Vaprus Pärnu, however, has shown resilience and tactical discipline in recent games.
- Key Players: Lelle SK's forward line is formidable, with several players capable of turning the game on its head.
- Betting Tip: Betting on Lelle SK to win outright could be a wise choice.
Tactical Analysis: What to Watch For
Each match tomorrow offers unique tactical battles that will captivate fans and analysts alike. From defensive solidity to attacking flair, here’s what to watch for:
Defensive Strategies
Teams like Narva Trans and Pärnu Jalgpalliklubi will rely heavily on their defensive organization. Look for compact formations and disciplined marking as they aim to neutralize their opponents' attacks.
Attacking Play
GordianKnot/raffle<|file_sep|>/src/test/kotlin/raffle/api/HttpIntegrationSpec.kt
package raffle.api
import io.ktor.application.*
import io.ktor.http.*
import io.ktor.server.testing.*
import org.junit.jupiter.api.Test
import kotlin.test.assertEquals
class HttpIntegrationSpec {
@Test
fun `GET /healthcheck should return status code OK`() {
withTestApplication(Application::main) {
handleRequest(HttpMethod.Get,"/healthcheck").apply {
assertEquals(HttpStatusCode.OK,status())
}
}
}
}
<|repo_name|>GordianKnot/raffle<|file_sep|>/src/main/kotlin/raffle/model/Ticket.kt
package raffle.model
data class Ticket(val id: Int)
<|repo_name|>GordianKnot/raffle<|file_sep|>/src/main/kotlin/raffle/model/Prize.kt
package raffle.model
data class Prize(val id: Int)
<|repo_name|>GordianKnot/raffle<|file_sep|>/src/main/kotlin/raffle/api/RaffleApi.kt
package raffle.api
import io.ktor.application.*
import io.ktor.features.ContentNegotiation
import io.ktor.http.HttpStatusCode
import io.ktor.response.respond
import io.ktor.response.respondText
import io.ktor.routing.*
import io.ktor.serialization.jackson.jackson
import kotlinx.serialization.Serializable
import raffle.controller.RaffleController
fun Route.raffleApi(controller: RaffleController) {
route("/api") {
get("healthcheck") {
call.respond(HttpStatusCode.OK)
}
route("/raffles") {
get {
val raffles = controller.getAllRaffles()
call.respond(raffles)
}
post {
val raffle = call.receive()
val newRaffle = controller.addRaffle(raffle)
call.respond(HttpStatusCode.Created,newRaffle)
}
}
route("/raffles/{id}") {
get {
val id = call.parameters["id"]?.toIntOrNull()
if (id == null) {
call.respondText("Invalid id",status = HttpStatusCode.BadRequest)
return@get
}
val raffle = controller.getRaffle(id)
if (raffle == null) {
call.respondText("Raffle not found",status = HttpStatusCode.NotFound)
return@get
}
call.respond(raffle)
}
put {
val id = call.parameters["id"]?.toIntOrNull()
if (id == null) {
call.respondText("Invalid id",status = HttpStatusCode.BadRequest)
return@put
}
val raffle = call.receive()
val updatedRaffle = controller.updateRaffle(id,raffle)
if (updatedRaffle == null) {
call.respondText("Raffle not found",status = HttpStatusCode.NotFound)
return@put
}
call.respond(HttpStatusCode.OK,updatedRaffle)
}
delete {
val id = call.parameters["id"]?.toIntOrNull()
if (id == null) {
call.respondText("Invalid id",status = HttpStatusCode.BadRequest)
return@delete
}
val deletedRaffel = controller.deleteRaffel(id)
if (deletedRaffel == null) {
call.respondText("Raffel not found",status = HttpStatusCode.NotFound)
return@delete
}
call.respond(HttpStatusCode.OK,"Deleted ${deletedRaffel.id}")
}
post("/tickets") {
val id = call.parameters["id"]?.toIntOrNull()
if (id == null) {
call.respondText("Invalid id",status = HttpStatusCode.BadRequest)
return@post
}
val ticketId = controller.addTicket(id)
if (ticketId != null) {
call.respond(HttpStatusCode.Created,ticketId)
return@post
} else {
call.respond(HttpStatusCode.NotFound,"Ticket not found")
return@post
}
}
post("/prizes") {
}
}
route("/raffles/{id}/prizes/{prizeId}") {
}
route("/prizes") {
}
}
}
@Serializable data class Raffle(val name: String,val startAt: Long,val endAt: Long)<|file_sep|>package raffle.controller
import org.junit.jupiter.api.TestInstance.Lifecycle.PER_CLASS
open class BaseTest : TestBase() {
}<|repo_name|>GordianKnot/raffle<|file_sep|>/src/main/kotlin/raffle/controller/RaffleController.kt
package raffle.controller
import raffle.model.Prize
import raffle.model.RaffelStatusEnum.*
import raffle.model.RaffelStatusEnum.Companion.STARTED_STATUS_ENUM_MAPPER
import raffle.model.RaffelStatusEnum.Companion.STATUS_ENUM_MAPPER
import raffle.model.Ticket
import java.time.Instant
class RaffleController(private val repository: RaffelRepository): BaseController() {
fun getAllRaffles(): List? =
repository.getAllRaffles()?.map { rafl -> rafl.toResponseModel() }?.filter { rafl ->
Instant.now().toEpochMilli() >= rafl.startAt && Instant.now().toEpochMilli() <= rafl.endAt ||
rafl.status == RaffelStatusEnum.CLOSED.value || rafl.status == RaffelStatusEnum.FINISHED.value ||
rafl.status == RaffelStatusEnum.CANCELLED.value || rafl.status == RaffelStatusEnum.WONNER_DECLARED.value}
fun getRaffle(id: Int): RaffelResponseModel? =
repository.getRaffel(id)?.toResponseModel()
fun addRaffle(raffle: RaffelRequestModel): RaffelResponseModel? =
repository.add(raffle).let { it.toResponseModel() }
fun updateRaffle(id: Int?, rafl: RaffelRequestModel): RaffelResponseModel? =
repository.update(id ?: -1, rafl).let { it.toResponseModel() }
fun deleteRaffel(id: Int?): Int? =
repository.delete(id ?: -1)
fun addTicket(raffleId: Int): Int? =
repository.addTicket(raffleId)
fun getTicket(ticketId: Int): Ticket? =
repository.getTicket(ticketId)
}<|repo_name|>GordianKnot/raffle<|file_sep|>/src/test/kotlin/raffle/controller/BaseTest.kt
package raffle.controller
abstract class TestBase : BaseTest()<|repo_name|>GordianKnot/raffle<|file_sep|>/src/main/kotlin/raffle/controller/BaseController.kt
package raffle.controller
open class BaseController() {
}<|repo_name|>GordianKnot/raffle<|file_sep|>/src/test/kotlin/raffle/controller/RaffleControllerTest.kt
package raffle.controller
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.TestInstance.Lifecycle.PER_CLASS
import org.junit.jupiter.params.ParameterizedTest
import org.junit.jupiter.params.provider.ArgumentsSource
import org.mockito.Mockito.*
import org.mockito.stubbing.Answer
class RaffleControllerTest : TestBase() {
}<|file_sep|># ktor-ktor-jpa-junit5-kotlin-kotest-spring-boot-properties-file-kotlin-serialization-mockito-koin-kotlintest-kotest-testcontainers-postgresql-groovy-cucumber-picocontainer-spring-boot-gradlew-springboot-groovy-test-containers-mockito-groovy-test-junit5-h2-mockito-kotest-kotlinx-coroutines-junit5-kotlintest-kotlinx-coroutines-junit4-spring-boot-test-webclient-testcontainers-gradlew-gradlew-tests-gradlew-runTests-gradlew-integrationTests-kotest-assertions-kotlintest-matchers-kotlintest-runner-junit5-mockito-kotlintest-spring-integrationTests-all-integrationTests-run integrationTests-all run integrationTests
# Installation
bash
./gradlew clean build
# Run tests
bash
./gradlew test
# Run app
bash
./gradlew run
# Run app with docker compose
bash
docker-compose up -d
# Swagger UI
http://localhost:8080/swagger-ui/index.html?url=/swagger/openapi.json#/
# OpenAPI
http://localhost:8080/swagger/openapi.json
## Generate openAPI documentation from KTOR application
* https://ktor.io/docs/openapi.html
* https://ktor.io/docs/openapi.html#creating-openapi-documentation-for-your-application
* https://github.com/jmfayard/buildSrcVersions/tree/master/examples/buildSrc/src/main/kotlin/com/jmfayard/buildSrcVersions/examples/vcs/OpenApiDocsExample
## References
* https://ktor.io/docs/openapi.html
* https://ktor.io/docs/openapi.html#creating-openapi-documentation-for-your-application
* https://ktor.io/docs/testing.html
* https://ktor.io/docs/testing.html#testing-with-ktor-server-testing
* https://github.com/JetBrains/kotlin-examples/tree/master/testing/src/test/kotlin/io/github/kostaj/examples/testing/server_testing
* https://github.com/JetBrains/kotlin-examples/blob/master/testing/src/test/kotlin/io/github/kostaj/examples/testing/server_testing/SimpleIntegrationTestWithMockServerApplicationEngine.kt
* https://github.com/JetBrains/kotlin-examples/blob/master/testing/src/test/kotlin/io/github/kostaj/examples/testing/server_testing/SimpleIntegrationTestWithMockApplicationEngine.kt
* https://ktor.io/docs/features.html#content-negotiation
* https://ktor.io/docs/features.html#content-negotiation-jackson
* https://ktor.io/docs/features.html#serialization-and-content-negotiation-with-json-and-yaml-serialization-libraries
* https://github.com/JetBrains/kotlin-examples/blob/master/application_features/src/main/resources/application.properties.example
* https://ktor.io/docs/application-properties.html#reading-application-properties-from-a-resource-file-in-the-classpath
* https://github.com/JetBrains/kotlin-examples/blob/master/application_features/src/main/resources/application.properties.example
## Swagger / OpenAPI Generator
### Client
bash
java -jar swagger-codegen-cli.jar generate
-i http://localhost:8080/swagger/openapi.json
-l kotlin
-o /tmp/client
--group-id com.github.gordianknot.raffle
--artifact-id client
--artifact-version v0.1
--git-repo-id gordianknot/client
--git-repo-url https://github.com/GordianKnot/client.git
--git-user-id gordianknot
--git-email [email protected]
--git-name Gordian Knot
### Server
bash
java -jar swagger-codegen-cli.jar generate
-i http://localhost:8080/swagger/openapi.json
-l kotlin-server
-o /tmp/server
--group-id com.github.gordianknot.raffle
--artifact-id server
--artifact-version v0.1
--git-repo-id gordianknot/server
--git-repo-url https://github.com/GordianKnot/server.git
--git-user-id gordianknot
--git-email [email protected]
--git-name Gordian Knot
<|repo_name|>GordianKnot/raffle<|file_sep|>/src/main/resources/db/migration/V1__init.sql
CREATE TABLE IF NOT EXISTS raffles (
id SERIAL PRIMARY KEY,
name VARCHAR(255) NOT NULL,
start_at BIGINT NOT NULL,
end_at BIGINT NOT NULL,
status SMALLINT NOT NULL,
create_date TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
update_date TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
version INT NOT NULL DEFAULT '1'
);
CREATE TABLE IF NOT EXISTS tickets (
id SERIAL PRIMARY KEY,
name VARCHAR(255) NOT NULL,
create_date TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
update_date TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
version INT NOT NULL DEFAULT '1',
buyer_id INT NOT NULL,
prize_id INT NOT NULL,
status SMALLINT NOT NULL,
status_change_date TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
seller_id INT NOT NULL,
purchase_date TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
rattle_id INT NOT NULL REFERENCES raffles(id),
seller_contact VARCHAR(255),
buyer_contact VARCHAR(255),
buyer_ip VARCHAR(255),
buyer_location VARCHAR(255),
seller_location VARCHAR(255),
cost DECIMAL(10 ,2 ) NOT NULL,
is_donation BOOLEAN DEFAULT false NOT NULL,
is_taxable BOOLEAN DEFAULT true NOT NULL