remove shop provider, shop controller and non-database models

This commit is contained in:
Denis Savosin
2024-10-16 15:54:52 +07:00
parent 08d3445ac4
commit 52cadf74d7
15 changed files with 80 additions and 295 deletions

View File

@@ -5,7 +5,9 @@ import com.fasterxml.jackson.databind.SerializationFeature
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule
import com.github.dannecron.demo.config.properties.KafkaProperties
import com.github.dannecron.demo.config.properties.ValidationProperties
import com.github.dannecron.demo.providers.*
import com.github.dannecron.demo.providers.CityRepository
import com.github.dannecron.demo.providers.CustomerRepository
import com.github.dannecron.demo.providers.ProductRepository
import com.github.dannecron.demo.services.database.city.CityService
import com.github.dannecron.demo.services.database.city.CityServiceImpl
import com.github.dannecron.demo.services.database.customer.CustomerService
@@ -35,9 +37,6 @@ class AppConfig(
configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false)
}
@Bean
fun shopProvider(): ShopProvider = MockedShopProvider()
@Bean
fun productService(
@Autowired productRepository: ProductRepository,

View File

@@ -1,32 +0,0 @@
package com.github.dannecron.demo.http.controllers
import com.github.dannecron.demo.http.exceptions.NotFoundException
import com.github.dannecron.demo.providers.ShopProvider
import jakarta.servlet.http.HttpServletResponse
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.encodeToJsonElement
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.ResponseBody
import org.springframework.web.bind.annotation.RestController
@RestController
class ShopController (
@field:Autowired private val shopProvider: ShopProvider,
) {
@GetMapping(value = ["/shop/common-info"], produces = ["application/json"])
@ResponseBody
@Throws(NotFoundException::class)
fun commonInfo(response: HttpServletResponse): String {
val shop = shopProvider.getRandomShop() ?: throw NotFoundException()
return Json.encodeToJsonElement(value = mapOf(
"customers" to mapOf(
"withMoreUndeliveredOrdersThanDelivered" to shop.getCustomersWithMoreUndeliveredOrdersThanDelivered().map { cus -> cus.name }
),
"products" to mapOf(
"orderedByAllCustomers" to shop.getSetOfProductsOrderedByEveryCustomer().map { pr -> pr.name },
)
)).toString()
}
}

View File

@@ -1,16 +0,0 @@
package com.github.dannecron.demo.models
data class CustomerLocal(val name: String, val city: City, val orders: List<OrderLocal>) {
/**
* Return the most expensive product among all delivered products
*/
fun getMostExpensiveDeliveredProduct(): Product? = orders.filter { ord -> ord.isDelivered }
.flatMap { ord -> ord.products }
.maxByOrNull { pr -> pr.price }
fun getMostExpensiveOrderedProduct(): Product? = orders.flatMap { ord -> ord.products }.maxByOrNull { pr -> pr.price }
fun getOrderedProducts(): Set<Product> = orders.flatMap { order -> order.products }.toSet()
fun getTotalOrderPrice(): Double = orders.flatMap { ord -> ord.products }.sumOf { pr -> pr.getPriceDouble()}
}

View File

@@ -1,3 +0,0 @@
package com.github.dannecron.demo.models
data class OrderLocal(val products: List<Product>, val isDelivered: Boolean)

View File

@@ -1,48 +0,0 @@
package com.github.dannecron.demo.models
data class Shop(val name: String, val customers: List<CustomerLocal>) {
fun checkAllCustomersAreFrom(city: City): Boolean = customers.count { cus -> cus.city == city } == customers.count()
fun countCustomersFrom(city: City): Int = customers.count { cus -> cus.city == city }
fun getCitiesCustomersAreFrom(): Set<City> = customers.map { cus -> cus.city }.toSet()
fun findAnyCustomerFrom(city: City): CustomerLocal? = customers.firstOrNull { cus -> cus.city == city }
fun getAllOrderedProducts(): Set<Product> = customers.flatMap { cus -> cus.getOrderedProducts() }.toSet()
fun getCustomersFrom(city: City): List<CustomerLocal> = customers.filter { cus -> cus.city == city }
fun getCustomersSortedByNumberOfOrders(): List<CustomerLocal> = customers.sortedBy { cus -> cus.orders.count() }
fun getCustomerWithMaximumNumberOfOrders(): CustomerLocal? = customers.maxByOrNull { cus -> cus.orders.count() }
/**
* Return customers who have more undelivered orders than delivered
*/
fun getCustomersWithMoreUndeliveredOrdersThanDelivered(): Set<CustomerLocal> = customers.partition(predicate = fun (cus): Boolean {
val (del, undel) = cus.orders.partition { ord -> ord.isDelivered }
return del.count() < undel.count()
}).first.toSet()
fun getNumberOfTimesProductWasOrdered(product: Product): Int = customers
.flatMap { cus -> cus.orders.flatMap { ord -> ord.products } }
.count { pr -> pr.name == product.name }
/**
* Return the set of products that were ordered by every customer.
* Note: a customer may order the same product for several times.
*/
fun getSetOfProductsOrderedByEveryCustomer(): Set<Product> {
val products = customers.flatMap { cus -> cus.orders.flatMap { ord -> ord.products } }.toSet()
return customers.fold(products) { orderedProducts, cus ->
orderedProducts.intersect(cus.orders.flatMap { ord -> ord.products }.toSet())
}.toSet()
}
fun groupCustomersByCity(): Map<City, List<CustomerLocal>> = customers.groupBy { cus -> cus.city }
fun hasCustomerFrom(city: City): Boolean = customers.any { cus -> cus.city == city }
}

View File

@@ -1,4 +1,4 @@
package com.github.dannecron.demo.models
package com.github.dannecron.demo.models.order
import com.github.dannecron.demo.services.serializables.OffsetDateTimeSerialization
import com.github.dannecron.demo.services.serializables.UuidSerialization

View File

@@ -1,4 +1,4 @@
package com.github.dannecron.demo.models
package com.github.dannecron.demo.models.order
import com.github.dannecron.demo.services.serializables.OffsetDateTimeSerialization
import com.github.dannecron.demo.services.serializables.UuidSerialization

View File

@@ -0,0 +1,12 @@
package com.github.dannecron.demo.models.order
import com.github.dannecron.demo.models.Product
data class OrderWithProducts(
val order: Order,
val products: List<Product>,
) {
fun getMostExpensiveOrderedProduct(): Product? = products.maxByOrNull { pr -> pr.price }
fun getTotalOrderPrice(): Double = products.sumOf { pr -> pr.getPriceDouble() }
}

View File

@@ -1,54 +0,0 @@
package com.github.dannecron.demo.providers
import com.github.dannecron.demo.models.*
import java.time.OffsetDateTime
import java.util.*
class MockedShopProvider: com.github.dannecron.demo.providers.ShopProvider {
override fun getRandomShop(): Shop? {
val productOne = makeProduct(id = 1, name = "one", price = 11.2)
val productTwo = makeProduct(id = 2, name = "two", price = 13.2)
val productThree = makeProduct(id = 3, name = "three", price = 15.2)
val productFour = makeProduct(id = 4, name = "four", price = 14.2)
return Shop(name="shop", customers= listOf(
CustomerLocal(
name = "Foo-1",
city = makeCity(id = 1, name = "Foo"),
orders = listOf(
OrderLocal(products = listOf(productOne, productTwo), isDelivered = true),
OrderLocal(products = listOf(productThree), isDelivered = false),
)
),
CustomerLocal(
name = "Foo-2",
city = makeCity(id = 2, name = "Bar"),
orders = listOf(
OrderLocal(products = listOf(productOne), isDelivered = false),
OrderLocal(products = listOf(productTwo), isDelivered = true),
OrderLocal(products = listOf(productFour), isDelivered = true),
)
),
))
}
private fun makeProduct(id: Long, name: String, price: Double): Product = Product(
id = id,
guid = UUID.randomUUID(),
name = name,
description = null,
price = (price * 100).toLong(),
createdAt = OffsetDateTime.now(),
updatedAt = null,
deletedAt = null,
)
private fun makeCity(id: Long, name: String): City = City(
id = id,
guid = UUID.randomUUID(),
name = name,
createdAt = OffsetDateTime.now(),
updatedAt = null,
deletedAt = null,
)
}

View File

@@ -1,7 +1,9 @@
package com.github.dannecron.demo.providers
import com.github.dannecron.demo.models.OrderProduct
import com.github.dannecron.demo.models.order.OrderProduct
import org.springframework.data.repository.CrudRepository
import java.util.*
interface OrderProductRepository: CrudRepository<OrderProduct, UUID>
interface OrderProductRepository: CrudRepository<OrderProduct, UUID> {
fun findByOrderId(orderId: Long): List<OrderProduct>
}

View File

@@ -1,8 +1,10 @@
package com.github.dannecron.demo.providers
import com.github.dannecron.demo.models.Order
import com.github.dannecron.demo.models.order.Order
import org.springframework.data.repository.CrudRepository
import org.springframework.stereotype.Repository
@Repository
interface OrderRepository: CrudRepository<Order, Long>
interface OrderRepository: CrudRepository<Order, Long> {
fun findByCustomerId(customerId: Long): List<Order>
}

View File

@@ -1,7 +0,0 @@
package com.github.dannecron.demo.providers
import com.github.dannecron.demo.models.Shop
interface ShopProvider {
fun getRandomShop(): Shop?
}

View File

@@ -1,11 +1,13 @@
package com.github.dannecron.demo.services.database.order
import com.github.dannecron.demo.models.Customer
import com.github.dannecron.demo.models.Order
import com.github.dannecron.demo.models.OrderProduct
import com.github.dannecron.demo.models.Product
import com.github.dannecron.demo.models.order.Order
import com.github.dannecron.demo.models.order.OrderProduct
import com.github.dannecron.demo.models.order.OrderWithProducts
import com.github.dannecron.demo.providers.OrderProductRepository
import com.github.dannecron.demo.providers.OrderRepository
import com.github.dannecron.demo.providers.ProductRepository
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.stereotype.Service
import org.springframework.transaction.annotation.Transactional
@@ -14,9 +16,18 @@ import java.util.*
@Service
class OrderServiceImpl(
@Autowired val orderRepository: OrderRepository,
@Autowired val orderProductRepository: OrderProductRepository,
@Autowired private val orderRepository: OrderRepository,
@Autowired private val orderProductRepository: OrderProductRepository,
@Autowired private val productRepository: ProductRepository,
) {
fun getByCustomerId(customerId: Long): List<OrderWithProducts> = orderRepository.findByCustomerId(customerId)
.let { orders -> orders.map { order -> OrderWithProducts(
order = order,
products = orderProductRepository.findByOrderId(orderId = order.id!!)
.map { orderProduct -> orderProduct.productId }
.let { productIds -> productRepository.findAllById(productIds).toList() }
) } }
@Transactional
fun createOrder(customer: Customer, products: Set<Product>): Order {
val order = Order(
@@ -27,16 +38,18 @@ class OrderServiceImpl(
createdAt = OffsetDateTime.now(),
updatedAt = null,
)
return orderRepository.save(order).also {
savedOrder -> products.toList().forEach {
product -> orderProductRepository.save(OrderProduct(
guid = UUID.randomUUID(),
orderId = savedOrder.id!!,
productId = product.id!!,
createdAt = OffsetDateTime.now(),
updatedAt = null
))
return orderRepository.save(order)
.also {
savedOrder -> products.toList()
.map { product -> OrderProduct(
guid = UUID.randomUUID(),
orderId = savedOrder.id!!,
productId = product.id!!,
createdAt = OffsetDateTime.now(),
updatedAt = null
) }
.also { orderProductRepository.saveAll(it) }
}
}
}
}