Skip to content

Commit

Permalink
feat: #98 Generate the non-standard dictionaries exporters dynamicall…
Browse files Browse the repository at this point in the history
…y, based on config. Pass the `PlayerVocabularyStatsRepository` from `StatisticsGenerator`.
  • Loading branch information
dmitry-weirdo committed Nov 28, 2024
1 parent 951ede1 commit c51517a
Show file tree
Hide file tree
Showing 7 changed files with 99 additions and 66 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -90,15 +90,15 @@ default String topByHaulExcelSheetName() { // Excel sheet name, may be shorter a
return "DEFAULT_TOP_BY_HAUL_EXCEL_SHEET_NAME";
}

default List<PlayerVocabularyStatsEntity> getPlayersByBestSpeed() {
default List<PlayerVocabularyStatsEntity> getPlayersByBestSpeed(ExportContext context) {
return Collections.emptyList();
}

default List<PlayerVocabularyStatsEntity> getPlayersByRacesCount() {
default List<PlayerVocabularyStatsEntity> getPlayersByRacesCount(ExportContext context) {
return Collections.emptyList();
}

default List<PlayerVocabularyStatsEntity> getPlayersByHaul() {
default List<PlayerVocabularyStatsEntity> getPlayersByHaul(ExportContext context) {
return Collections.emptyList();
}

Expand Down Expand Up @@ -171,7 +171,7 @@ private void validate() { // fail fast, not in ExcelExporter
}

private void exportTopByBestSpeed(final ExportContext context, final PlayerVocabularyDtoMapper mapper) {
List<PlayerVocabularyStatsEntity> players = getPlayersByBestSpeed();
List<PlayerVocabularyStatsEntity> players = getPlayersByBestSpeed(context);
List<PlayerVocabularyDto> dtos = mapper.entitiesToDtos(players, PlayerVocabularyDto::getBestSpeed);

int totalPlayers = players.size();
Expand Down Expand Up @@ -223,7 +223,7 @@ private void exportTopByBestSpeed(final ExportContext context, final PlayerVocab
}

private void exportTopByRacesCount(final ExportContext context, final PlayerVocabularyDtoMapper mapper) {
List<PlayerVocabularyStatsEntity> players = getPlayersByRacesCount();
List<PlayerVocabularyStatsEntity> players = getPlayersByRacesCount(context);
List<PlayerVocabularyDto> dtos = mapper.entitiesToDtos(players, PlayerVocabularyDto::getRacesCount);

int totalPlayers = players.size();
Expand Down Expand Up @@ -275,7 +275,7 @@ private void exportTopByRacesCount(final ExportContext context, final PlayerVoca
}

private void exportTopByHaul(final ExportContext context, final PlayerVocabularyDtoMapper mapper) {
List<PlayerVocabularyStatsEntity> players = getPlayersByHaul();
List<PlayerVocabularyStatsEntity> players = getPlayersByHaul(context);
List<PlayerVocabularyDto> dtos = mapper.entitiesToDtos(players, PlayerVocabularyDto::getHaulInteger);

int totalPlayers = players.size();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import org.springframework.stereotype.Component;
import ru.klavogonki.statistics.entity.PlayerEntity;
import ru.klavogonki.statistics.entity.PlayerVocabularyStatsEntity;
import ru.klavogonki.statistics.export.ExportContext;
import ru.klavogonki.statistics.export.LoggerWrapper;
import ru.klavogonki.statistics.export.vocabulary.non_standard.NonStandardVocabularyTopExporter;
import ru.klavogonki.statistics.repository.PlayerVocabularyStatsRepository;
Expand Down Expand Up @@ -38,26 +39,38 @@ private LoggerWrapper getLoggerWrapper() {
}

@Override
public List<PlayerVocabularyStatsEntity> getPlayersByBestSpeed() {
List<PlayerVocabularyStatsEntity> players = repository.findByVocabularyCodeEqualsAndRacesCountGreaterThanEqualAndPlayerBlockedEqualsOrderByBestSpeedDesc(vocabularyCode(), minRacesCount(), PlayerEntity.NOT_BLOCKED);
public List<PlayerVocabularyStatsEntity> getPlayersByBestSpeed(ExportContext context) {
PlayerVocabularyStatsRepository repo = getRepositorySafe(context);

List<PlayerVocabularyStatsEntity> players = repo.findByVocabularyCodeEqualsAndRacesCountGreaterThanEqualAndPlayerBlockedEqualsOrderByBestSpeedDesc(vocabularyCode(), minRacesCount(), PlayerEntity.NOT_BLOCKED);
logger().debug("Total players by best speed, min total races = {}: {}", minRacesCount(), players.size());

return players;
}

@Override
public List<PlayerVocabularyStatsEntity> getPlayersByRacesCount() {
List<PlayerVocabularyStatsEntity> players = repository.findByVocabularyCodeEqualsAndRacesCountGreaterThanEqualAndPlayerBlockedEqualsOrderByRacesCountDesc(vocabularyCode(), minRacesCount(), PlayerEntity.NOT_BLOCKED);
public List<PlayerVocabularyStatsEntity> getPlayersByRacesCount(ExportContext context) {
PlayerVocabularyStatsRepository repo = getRepositorySafe(context);

List<PlayerVocabularyStatsEntity> players = repo.findByVocabularyCodeEqualsAndRacesCountGreaterThanEqualAndPlayerBlockedEqualsOrderByRacesCountDesc(vocabularyCode(), minRacesCount(), PlayerEntity.NOT_BLOCKED);
logger().debug("Total players by races count, min total races = {}: {}", minRacesCount(), players.size());

return players;
}

@Override
public List<PlayerVocabularyStatsEntity> getPlayersByHaul() {
List<PlayerVocabularyStatsEntity> players = repository.findByVocabularyCodeEqualsAndRacesCountGreaterThanEqualAndPlayerBlockedEqualsOrderByHaulDesc(vocabularyCode(), minRacesCount(), PlayerEntity.NOT_BLOCKED);
public List<PlayerVocabularyStatsEntity> getPlayersByHaul(ExportContext context) {
PlayerVocabularyStatsRepository repo = getRepositorySafe(context);

List<PlayerVocabularyStatsEntity> players = repo.findByVocabularyCodeEqualsAndRacesCountGreaterThanEqualAndPlayerBlockedEqualsOrderByHaulDesc(vocabularyCode(), minRacesCount(), PlayerEntity.NOT_BLOCKED);
logger().debug("Total players by haul, min total races = {}: {}", minRacesCount(), players.size());

return players;
}

private PlayerVocabularyStatsRepository getRepositorySafe(ExportContext context) {
return (this.repository != null)
? this.repository // this.repository is not inherited by the dynamicaally created subclasses
: context.repository;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import org.springframework.stereotype.Component;
import ru.klavogonki.statistics.entity.PlayerEntity;
import ru.klavogonki.statistics.entity.PlayerVocabularyStatsEntity;
import ru.klavogonki.statistics.export.ExportContext;
import ru.klavogonki.statistics.export.LoggerWrapper;
import ru.klavogonki.statistics.repository.PlayerVocabularyStatsRepository;
import ru.klavogonki.statistics.springboot.Profiles;
Expand Down Expand Up @@ -36,23 +37,23 @@ private LoggerWrapper getLoggerWrapper() {
}

@Override
public List<PlayerVocabularyStatsEntity> getPlayersByBestSpeed() {
public List<PlayerVocabularyStatsEntity> getPlayersByBestSpeed(ExportContext context) {
List<PlayerVocabularyStatsEntity> players = repository.findByVocabularyCodeEqualsAndRacesCountGreaterThanEqualAndPlayerBlockedEqualsOrderByBestSpeedDesc(vocabularyCode(), minRacesCount(), PlayerEntity.NOT_BLOCKED);
logger().debug("Total players by best speed, min total races = {}: {}", minRacesCount(), players.size());

return players;
}

@Override
public List<PlayerVocabularyStatsEntity> getPlayersByRacesCount() {
public List<PlayerVocabularyStatsEntity> getPlayersByRacesCount(ExportContext context) {
List<PlayerVocabularyStatsEntity> players = repository.findByVocabularyCodeEqualsAndRacesCountGreaterThanEqualAndPlayerBlockedEqualsOrderByRacesCountDesc(vocabularyCode(), minRacesCount(), PlayerEntity.NOT_BLOCKED);
logger().debug("Total players by races count, min total races = {}: {}", minRacesCount(), players.size());

return players;
}

@Override
public List<PlayerVocabularyStatsEntity> getPlayersByHaul() {
public List<PlayerVocabularyStatsEntity> getPlayersByHaul(ExportContext context) {
List<PlayerVocabularyStatsEntity> players = repository.findByVocabularyCodeEqualsAndRacesCountGreaterThanEqualAndPlayerBlockedEqualsOrderByHaulDesc(vocabularyCode(), minRacesCount(), PlayerEntity.NOT_BLOCKED);
logger().debug("Total players by haul, min total races = {}: {}", minRacesCount(), players.size());

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package ru.klavogonki.statistics.export

import ru.klavogonki.statistics.Config
import ru.klavogonki.statistics.repository.PlayerVocabularyStatsRepository
import ru.klavogonki.statistics.util.DateUtils
import java.time.LocalDateTime

Expand All @@ -11,9 +12,10 @@ data class ExportContext(
@JvmField val minPlayerId: Int,
@JvmField val maxPlayerId: Int,
@JvmField val dataDownloadStartDate: LocalDateTime,
@JvmField val dataDownloadEndDate: LocalDateTime
@JvmField val dataDownloadEndDate: LocalDateTime,
@JvmField val repository: PlayerVocabularyStatsRepository
) {
constructor(config: Config): this(
constructor(config: Config, repository: PlayerVocabularyStatsRepository): this(
// we can use property-access from a Java class when there is an explicit geter
// but the lombok-generated getters do NOT work

Expand All @@ -27,6 +29,8 @@ data class ExportContext(

// todo: think about UTC timeZone
// todo: also change to OffsetDateTime
dataDownloadEndDate = DateUtils.convertToUtcLocalDateTime(config.dataDownloadEndDate)
dataDownloadEndDate = DateUtils.convertToUtcLocalDateTime(config.dataDownloadEndDate),

repository = repository
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,8 @@ import org.springframework.context.annotation.Profile
import org.springframework.stereotype.Component
import ru.klavogonki.common.NonStandardDictionary
import ru.klavogonki.statistics.Config
import ru.klavogonki.statistics.export.vocabulary.non_standard.DigitsOneHundredTopExporter
import ru.klavogonki.statistics.export.vocabulary.non_standard.FrequencyVocabularyTopExporter
import ru.klavogonki.statistics.export.vocabulary.non_standard.MiniMarathonTopExporter
import ru.klavogonki.statistics.export.vocabulary.non_standard.NormalInEnglishTopExporter
import ru.klavogonki.statistics.export.vocabulary.non_standard.OneHundredRussianTopExporter
import ru.klavogonki.statistics.export.vocabulary.non_standard.PinkiesPlusTopExporter
import ru.klavogonki.statistics.export.vocabulary.non_standard.RingFingersTopExporter
import ru.klavogonki.statistics.export.vocabulary.non_standard.ShortTextsTopExporter
import ru.klavogonki.statistics.export.vocabulary.non_standard.TrainingIndexFingersTopExporter
import ru.klavogonki.statistics.export.vocabulary.NonStandardVocabularyTopExporterGenerator
import ru.klavogonki.statistics.export.vocabulary.non_standard.NonStandardVocabularyTopExporter
import ru.klavogonki.statistics.export.vocabulary.standard.AbraTopExporter
import ru.klavogonki.statistics.export.vocabulary.standard.CharsTopExporter
import ru.klavogonki.statistics.export.vocabulary.standard.DigitsTopExporter
Expand All @@ -24,6 +17,7 @@ import ru.klavogonki.statistics.export.vocabulary.standard.NoErrorTopExporter
import ru.klavogonki.statistics.export.vocabulary.standard.NormalTopExporter
import ru.klavogonki.statistics.export.vocabulary.standard.ReferatsTopExporter
import ru.klavogonki.statistics.export.vocabulary.standard.SprintTopExporter
import ru.klavogonki.statistics.repository.PlayerVocabularyStatsRepository
import ru.klavogonki.statistics.springboot.Profiles

@Component
Expand Down Expand Up @@ -68,36 +62,15 @@ class StatisticsGenerator : Logging {
@Autowired
private val sprintTopExporter: SprintTopExporter? = null

// non-standard vocabularies
@Autowired
private val normalInEnglishTopExporter: NormalInEnglishTopExporter? = null

@Autowired
private val miniMarathonTopExporter: MiniMarathonTopExporter? = null

@Autowired
private val shortTextsTopExporter: ShortTextsTopExporter? = null

@Autowired
private val frequencyVocabularyTopExporter: FrequencyVocabularyTopExporter? = null

@Autowired
private val oneHundredRussianTopExporter: OneHundredRussianTopExporter? = null

@Autowired
private val digitsOneHundredTopExporter: DigitsOneHundredTopExporter? = null

@Autowired
private val trainingIndexFingersTopExporter: TrainingIndexFingersTopExporter? = null

@Autowired
private val ringFingersTopExporter: RingFingersTopExporter? = null

@Autowired
private val pinkiesPlusTopExporter: PinkiesPlusTopExporter? = null
private val repository: PlayerVocabularyStatsRepository? = null

fun generateStatistics(config: Config, generatorConfig: StatisticsGeneratorConfig) {
val context = ExportContext(config)
checkNotNull(repository) {
"PlayerVocabularyStatsRepository is null. Check your Spring profiles."
}

val context = ExportContext(config, repository)

/*
context.webRootDir = "C:/java/kgparser/kgstats/src/main/webapp/";
Expand Down Expand Up @@ -137,15 +110,15 @@ class StatisticsGenerator : Logging {
export(context, generatorConfig.exportSprintTop, sprintTopExporter)

// non-standard vocabularies exporters
export(context, generatorConfig, NonStandardDictionary.NORMAL_IN_ENGLISH, normalInEnglishTopExporter)
export(context, generatorConfig, NonStandardDictionary.MINI_MARATHON, miniMarathonTopExporter)
export(context, generatorConfig, NonStandardDictionary.SHORT_TEXTS, shortTextsTopExporter)
export(context, generatorConfig, NonStandardDictionary.FREQUENCY_VOCABULARY, frequencyVocabularyTopExporter)
export(context, generatorConfig, NonStandardDictionary.ONE_HUNDRED_RUSSIAN, oneHundredRussianTopExporter)
export(context, generatorConfig, NonStandardDictionary.DIGITS_ONE_HUNDRED, digitsOneHundredTopExporter)
export(context, generatorConfig, NonStandardDictionary.TRAINING_INDEX_FINGERS, trainingIndexFingersTopExporter)
export(context, generatorConfig, NonStandardDictionary.RING_FINGERS, ringFingersTopExporter)
export(context, generatorConfig, NonStandardDictionary.PINKIES_PLUS, pinkiesPlusTopExporter)
val nonStandardDictionariesGeneratorContext =
NonStandardVocabularyTopExporterGenerator.generateContext(generatorConfig.nonStandardDictionariesCodes)

generatorConfig.nonStandardDictionariesCodes.forEach {
val exporter = nonStandardDictionariesGeneratorContext.getExporter(it)

// export flag is true since we're only iterating the dictionaries set in the config
export(context, true, exporter)
}
}

// todo: think about moving StatisticsGeneratorConfig field determination to Exporter interface
Expand Down Expand Up @@ -187,20 +160,34 @@ class StatisticsGenerator : Logging {

logger.info("===============================================")

val exporterName = getExporterName(exporter)

if (!export) {
logger.info(
"${StatisticsGeneratorConfig::class.java.simpleName} flag" +
" for ${exporter.javaClass.simpleName} is ${false}. Do not execute the export.",
" for $exporterName is ${false}. Do not execute the export.",
)

return
}

logger.info(
"${StatisticsGeneratorConfig::class.java.simpleName} flag" +
" for ${exporter.javaClass.simpleName} is ${true}. Execute the export.",
" for $exporterName is ${true}. Execute the export.",
)

exporter.export(context)
}
}

private fun getExporterName(exporter: DataExporter): String {
// todo: we may just return exporter name from DataExporter interface

if (exporter is NonStandardVocabularyTopExporter) {
return exporter.vocabularyTopData().loggerName
}

// other exporters now have
// todo: if we switch completely to generated exporters -> user
return exporter.javaClass.simpleName
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package ru.klavogonki.statistics.export.vocabulary

import ru.klavogonki.statistics.export.vocabulary.non_standard.NonStandardVocabularyTopExporter

data class NonStandardVocabularyGeneratorContext(
@JvmField val dictionaryIdToExporter: Map<Int, NonStandardVocabularyTopExporter>
) {
fun getExporter(dictionaryId: Int): NonStandardVocabularyTopExporter =
dictionaryIdToExporter[dictionaryId]
?: error(
"No non-standard dictionary generator for dictionaryId = $dictionaryId." +
" Please check you generator config."
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,20 @@ object NonStandardVocabularyTopExporterGenerator : Logging {
}
}

fun generateContext(dictionaryIds: List<Int>) : NonStandardVocabularyGeneratorContext {
val distinctDictionaryIds = dictionaryIds.distinct()

val dictionaryIdToExporter = mutableMapOf<Int, NonStandardVocabularyTopExporter>()

distinctDictionaryIds.forEach {
val exporter = generate(it)

dictionaryIdToExporter[it] = exporter
}

return NonStandardVocabularyGeneratorContext(dictionaryIdToExporter)
}

@JvmStatic
fun main(args: Array<String>) {
val normalInEnglishTopExporter = generate(NonStandardDictionary.NORMAL_IN_ENGLISH.code)
Expand Down

0 comments on commit c51517a

Please sign in to comment.