This commit is contained in:
Vladimir Voronin
2025-01-07 13:15:08 +03:00
parent 2506e6081f
commit 8b440ad9e8
45 changed files with 51 additions and 1048 deletions

View File

@@ -1,9 +1,6 @@
package space.luminic.budgerapp.services
import com.mongodb.client.model.Aggregates.addFields
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.async
import kotlinx.coroutines.runBlocking
import org.bson.Document
import org.bson.types.ObjectId
import org.slf4j.LoggerFactory
@@ -12,74 +9,44 @@ import org.springframework.cache.annotation.Cacheable
import org.springframework.context.ApplicationEventPublisher
import org.springframework.data.domain.Sort
import org.springframework.data.domain.Sort.Direction
import org.springframework.data.mongodb.MongoExpression
import org.springframework.data.mongodb.core.aggregation.Aggregation.newAggregation
import org.springframework.data.mongodb.core.MongoTemplate
import org.springframework.data.mongodb.core.ReactiveMongoTemplate
import org.springframework.data.mongodb.core.aggregation.AddFieldsOperation
import org.springframework.data.mongodb.core.aggregation.Aggregation
import org.springframework.data.mongodb.core.aggregation.Aggregation.ROOT
import org.springframework.data.mongodb.core.aggregation.Aggregation.group
import org.springframework.data.mongodb.core.aggregation.Aggregation.limit
import org.springframework.data.mongodb.core.aggregation.Aggregation.lookup
import org.springframework.data.mongodb.core.aggregation.Aggregation.match
import org.springframework.data.mongodb.core.aggregation.Aggregation.newAggregation
import org.springframework.data.mongodb.core.aggregation.Aggregation.project
import org.springframework.data.mongodb.core.aggregation.Aggregation.skip
import org.springframework.data.mongodb.core.aggregation.Aggregation.sort
import org.springframework.data.mongodb.core.aggregation.Aggregation.unwind
import org.springframework.data.mongodb.core.aggregation.Aggregation.addFields
import org.springframework.data.mongodb.core.aggregation.Aggregation.limit
import org.springframework.data.mongodb.core.aggregation.Aggregation.skip
import org.springframework.data.mongodb.core.aggregation.AggregationExpression
import org.springframework.data.mongodb.core.aggregation.AggregationResults
import org.springframework.data.mongodb.core.aggregation.ArrayOperators
import org.springframework.data.mongodb.core.aggregation.ArrayOperators.Filter.filter
import org.springframework.data.mongodb.core.aggregation.ConditionalOperators
import org.springframework.data.mongodb.core.aggregation.ConditionalOperators.IfNull.ifNull
import org.springframework.data.mongodb.core.aggregation.DateOperators
import org.springframework.data.mongodb.core.aggregation.DateOperators.DateToString
import org.springframework.data.mongodb.core.aggregation.LookupOperation
import org.springframework.data.mongodb.core.aggregation.MatchOperation
import org.springframework.data.mongodb.core.query.Criteria
import org.springframework.data.mongodb.core.query.Query
import org.springframework.data.mongodb.core.query.update
import org.springframework.security.core.context.ReactiveSecurityContextHolder
import org.springframework.stereotype.Service
import reactor.core.publisher.Flux
import reactor.core.publisher.Mono
import space.luminic.budgerapp.models.Budget
import space.luminic.budgerapp.models.Category
import space.luminic.budgerapp.models.CategoryType
import space.luminic.budgerapp.models.SortSetting
import space.luminic.budgerapp.models.SortTypes
import space.luminic.budgerapp.models.Transaction
import space.luminic.budgerapp.models.TransactionEvent
import space.luminic.budgerapp.models.TransactionEventType
import space.luminic.budgerapp.models.TransactionType
import space.luminic.budgerapp.models.User
import space.luminic.budgerapp.repos.TransactionRepo
import java.math.BigDecimal
import java.time.LocalDate
import java.time.LocalDateTime
import java.time.LocalTime
import java.time.ZoneId
import java.time.ZoneOffset
import java.time.ZonedDateTime
import java.time.format.DateTimeFormatter
import java.time.temporal.TemporalAdjusters
import java.util.ArrayList
import java.util.Arrays
import java.util.Date
import kotlin.jvm.optionals.getOrNull
@Service
class TransactionService(
private val mongoTemplate: MongoTemplate,
private val reactiveMongoTemplate: ReactiveMongoTemplate,
val transactionsRepo: TransactionRepo,
val userService: UserService,
@@ -608,13 +575,6 @@ class TransactionService(
}
fun getCategoriesExplainReactive(pipeline: List<Document>): Mono<Document> {
val command = Document("aggregate", "transactions")
.append("pipeline", pipeline)
.append("explain", true)
return reactiveMongoTemplate.executeCommand(command)
}
private fun extractTransactions(aggregationResult: Document, key: String): Mono<List<Transaction>> {
val resultTransactions = aggregationResult[key] as? List<Document> ?: emptyList()
@@ -658,7 +618,7 @@ class TransactionService(
transactionType["code"] as String,
transactionType["name"] as String
),
user = user!!,
user = user,
category = category,
comment = document["comment"] as String,
date = (document["date"] as Date).toInstant().atZone(ZoneId.systemDefault()).toLocalDate(),
@@ -669,116 +629,4 @@ class TransactionService(
)
}
// fun getPlannedForBudget(budget: Budget, transactionType: String? = null): List<Map<String, Any>> {
// // 1) $lookup: "categories"
// val lookupCategories = Aggregation.lookup(
// "categories",
// "category.\$id",
// "_id",
// "categoryDetailed"
// )
//
// // 2) $lookup: "budgets" (pipeline + let)
// val matchBudgetsDoc = Document(
// "\$expr", Document(
// "\$and", listOf(
// Document("\$gte", listOf("\$\$transactionDate", "\$dateFrom")),
// Document("\$lt", listOf("\$\$transactionDate", "\$dateTo"))
// )
// )
// )
// val matchBudgetsOp = MatchOperation(matchBudgetsDoc)
//
// val lookupBudgets = LookupOperation.newLookup()
// .from("budgets")
// .letValueOf("transactionDate").bindTo("date")
// .pipeline(matchBudgetsOp)
// .`as`("budgetDetails")
//
// // 3) $unwind
// val unwindCategory = Aggregation.unwind("categoryDetailed")
// val unwindBudget = Aggregation.unwind("budgetDetails")
//
// // 4) $match: диапазон дат
// val matchDates = Aggregation.match(
// Criteria("date")
// .gte(budget.dateFrom)
// .lt(budget.dateTo)
// )
//
// // 5) $facet (разные ветки: plannedExpenses, plannedExpensesSum, ...)
// // plannedExpenses
// val plannedExpensesMatch = Aggregation.match(
// Criteria().andOperator(
// Criteria("type.code").`is`("PLANNED"),
// Criteria("categoryDetailed.type.code").`is`("EXPENSE")
// )
// )
// val plannedExpensesPipeline = listOf(plannedExpensesMatch)
//
// // plannedExpensesSum
// val plannedExpensesSumPipeline = listOf(
// plannedExpensesMatch,
// group(null).`as`("_id").sum("amount").`as`("sum"),
// project("sum").andExclude("_id")
// )
//
// // plannedIncome
// val plannedIncomeMatch = Aggregation.match(
// Criteria().andOperator(
// Criteria("type.code").`is`("PLANNED"),
// Criteria("categoryDetailed.type.code").`is`("INCOME")
// )
// )
// val plannedIncomePipeline = listOf(plannedIncomeMatch)
//
// // plannedIncomeSum
// val plannedIncomeSumPipeline = listOf(
// plannedIncomeMatch,
// group().`as`("_id").sum("amount").`as`("sum"),
// project("sum").andExclude("_id")
// )
//
// // instantTransactions
// val instantTransactionsMatch = Aggregation.match(
// Criteria("type.code").`is`("INSTANT")
// )
// val instantTransactionsProject = Aggregation.project(
// "_id", "type", "comment", "user", "amount", "date",
// "category", "isDone", "createdAt", "parentId"
// )
// val instantTransactionsPipeline = listOf(instantTransactionsMatch, instantTransactionsProject)
//
// val facetStage = Aggregation.facet(*plannedExpensesPipeline.toTypedArray()).`as`("plannedExpenses")
// .and(*plannedExpensesSumPipeline.toTypedArray()).`as`("plannedExpensesSum")
// .and(*plannedIncomePipeline.toTypedArray()).`as`("plannedIncome")
// .and(*plannedIncomeSumPipeline.toTypedArray()).`as`("plannedIncomeSum")
// .and(*instantTransactionsPipeline.toTypedArray()).`as`("instantTransactions")
//
// // 6) $set: вытаскиваем суммы из массивов
// val setStage = AddFieldsOperation.builder()
// .addField("plannedExpensesSum").withValue(
// ArrayOperators.ArrayElemAt.arrayOf("\$plannedExpensesSum.sum").elementAt(0)
// )
// .addField("plannedIncomeSum").withValue(
// ArrayOperators.ArrayElemAt.arrayOf("\$plannedIncomeSum.sum").elementAt(0)
// )
// .build()
//
// // Собираем все стадии
// val aggregation = Aggregation.newAggregation(
// lookupCategories,
// lookupBudgets,
// unwindCategory,
// unwindBudget,
// matchDates,
// facetStage,
// setStage
// )
//
// val results = mongoTemplate.aggregate(aggregation, "transactions", Map::class.java)
// return results.mappedResults
// }
}