diff --git a/src/main/kotlin/fr/shikkanime/entities/EpisodeMapping.kt b/src/main/kotlin/fr/shikkanime/entities/EpisodeMapping.kt index 677929df..9f5890a8 100644 --- a/src/main/kotlin/fr/shikkanime/entities/EpisodeMapping.kt +++ b/src/main/kotlin/fr/shikkanime/entities/EpisodeMapping.kt @@ -17,6 +17,10 @@ import java.util.* columnList = "anime_uuid, episode_type, season, number", unique = true ), + Index( + name = "idx_episode_mapping_anime_uuid", + columnList = "anime_uuid" + ), ] ) @Cacheable diff --git a/src/main/kotlin/fr/shikkanime/entities/EpisodeVariant.kt b/src/main/kotlin/fr/shikkanime/entities/EpisodeVariant.kt index 9e0c8c95..ec44a830 100644 --- a/src/main/kotlin/fr/shikkanime/entities/EpisodeVariant.kt +++ b/src/main/kotlin/fr/shikkanime/entities/EpisodeVariant.kt @@ -8,7 +8,19 @@ import java.time.ZonedDateTime import java.util.* @Entity -@Table(name = "episode_variant") +@Table( + name = "episode_variant", + indexes = [ + Index( + name = "idx_episode_variant_mapping_uuid", + columnList = "mapping_uuid" + ), + Index( + name = "idx_episode_variant_release_date_mapping_uuid", + columnList = "release_date_time, mapping_uuid" + ), + ] +) @Cacheable @Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE) class EpisodeVariant( diff --git a/src/main/kotlin/fr/shikkanime/repositories/AbstractRepository.kt b/src/main/kotlin/fr/shikkanime/repositories/AbstractRepository.kt index d4066a36..46f62b97 100644 --- a/src/main/kotlin/fr/shikkanime/repositories/AbstractRepository.kt +++ b/src/main/kotlin/fr/shikkanime/repositories/AbstractRepository.kt @@ -18,20 +18,20 @@ abstract class AbstractRepository { protected abstract fun getEntityClass(): Class - protected fun inTransaction(block: (EntityManager) -> T): T { - val entityManager = database.entityManager - val transaction = entityManager.transaction + protected fun inTransaction(block: () -> T): T { + val transaction = database.entityManager.transaction transaction.begin() val result: T try { - result = block(entityManager) + result = block() + database.entityManager.flush() transaction.commit() } catch (e: Exception) { transaction.rollback() throw e } finally { - entityManager.close() + database.entityManager.clear() } return result @@ -64,45 +64,41 @@ abstract class AbstractRepository { } open fun findAll(): List { - return inTransaction { - val cb = it.criteriaBuilder - val query = cb.createQuery(getEntityClass()) - query.from(getEntityClass()) + val cb = database.entityManager.criteriaBuilder + val query = cb.createQuery(getEntityClass()) + query.from(getEntityClass()) - createReadOnlyQuery(it, query) - .resultList - } + return createReadOnlyQuery(database.entityManager, query) + .resultList } open fun find(uuid: UUID): E? { - return inTransaction { - it.find(getEntityClass(), uuid) - } + return database.entityManager.find(getEntityClass(), uuid) } fun save(entity: E): E { return inTransaction { - it.persist(entity) + database.entityManager.persist(entity) entity } } fun update(entity: E): E { return inTransaction { - it.merge(entity) + database.entityManager.merge(entity) entity } } fun delete(entity: E) { inTransaction { - it.remove(entity) + database.entityManager.remove(entity) } } fun deleteAll() { inTransaction { - it.createQuery("DELETE FROM ${getEntityClass().simpleName}").executeUpdate() + database.entityManager.createQuery("DELETE FROM ${getEntityClass().simpleName}").executeUpdate() } } } \ No newline at end of file diff --git a/src/main/kotlin/fr/shikkanime/repositories/AnimeRepository.kt b/src/main/kotlin/fr/shikkanime/repositories/AnimeRepository.kt index 6994171a..26df08e2 100644 --- a/src/main/kotlin/fr/shikkanime/repositories/AnimeRepository.kt +++ b/src/main/kotlin/fr/shikkanime/repositories/AnimeRepository.kt @@ -15,23 +15,19 @@ class AnimeRepository : AbstractRepository() { override fun getEntityClass() = Anime::class.java fun preIndex() { - inTransaction { - val searchSession = Search.session(it) - val indexer = searchSession.massIndexer(getEntityClass()) - indexer.startAndWait() - } + val searchSession = Search.session(database.entityManager) + val indexer = searchSession.massIndexer(getEntityClass()) + indexer.startAndWait() } override fun findAll(): List { - return inTransaction { - val cb = it.criteriaBuilder - val query = cb.createQuery(getEntityClass()) - query.from(getEntityClass()) - - val list = it.createQuery(query).resultList - list.forEach { anime -> Hibernate.initialize(anime.mappings) } - list - } + val cb = database.entityManager.criteriaBuilder + val query = cb.createQuery(getEntityClass()) + query.from(getEntityClass()) + + val list = createReadOnlyQuery(database.entityManager, query).resultList + list.forEach { anime -> Hibernate.initialize(anime.mappings) } + return list } fun findAllBy( @@ -42,33 +38,31 @@ class AnimeRepository : AbstractRepository() { limit: Int, status: Status? = null ): Pageable { - return inTransaction { entityManager -> - val cb = entityManager.criteriaBuilder - val query = cb.createQuery(getEntityClass()) - val root = query.from(getEntityClass()) - - val predicates = mutableListOf() - simulcast?.let { predicates.add(cb.equal(root.join(Anime_.simulcasts), it)) } - countryCode?.let { predicates.add(cb.equal(root[Anime_.countryCode], it)) } - status?.let { predicates.add(cb.equal(root[Anime_.status], it)) } - query.where(*predicates.toTypedArray()) - - val orders = sort.mapNotNull { sortParameter -> - val order = if (sortParameter.order == SortParameter.Order.ASC) cb::asc else cb::desc - - val field = when (sortParameter.field) { - "name" -> root[Anime_.name] - "releaseDateTime" -> root[Anime_.releaseDateTime] - "lastReleaseDateTime" -> root[Anime_.lastReleaseDateTime] - else -> null - } - - field?.let { order(it) } + val cb = database.entityManager.criteriaBuilder + val query = cb.createQuery(getEntityClass()) + val root = query.from(getEntityClass()) + + val predicates = mutableListOf() + simulcast?.let { predicates.add(cb.equal(root.join(Anime_.simulcasts), it)) } + countryCode?.let { predicates.add(cb.equal(root[Anime_.countryCode], it)) } + status?.let { predicates.add(cb.equal(root[Anime_.status], it)) } + query.where(*predicates.toTypedArray()) + + val orders = sort.mapNotNull { sortParameter -> + val order = if (sortParameter.order == SortParameter.Order.ASC) cb::asc else cb::desc + + val field = when (sortParameter.field) { + "name" -> root[Anime_.name] + "releaseDateTime" -> root[Anime_.releaseDateTime] + "lastReleaseDateTime" -> root[Anime_.lastReleaseDateTime] + else -> null } - query.orderBy(orders) - buildPageableQuery(createReadOnlyQuery(entityManager, query), page, limit) + field?.let { order(it) } } + + query.orderBy(orders) + return buildPageableQuery(createReadOnlyQuery(database.entityManager, query), page, limit) } fun findAllByName(name: String, countryCode: CountryCode?, page: Int, limit: Int): Pageable { @@ -79,9 +73,7 @@ class AnimeRepository : AbstractRepository() { .where { w -> findWhere(w, name, countryCode) } .fetch((limit * page) - limit, limit) as SearchResult - return inTransaction { - Pageable(searchResult.hits(), page, limit, searchResult.total().hitCount()) - } + return Pageable(searchResult.hits(), page, limit, searchResult.total().hitCount()) } private fun findWhere( @@ -96,50 +88,45 @@ class AnimeRepository : AbstractRepository() { } fun findAllUuidImageAndBanner(): List { - return inTransaction { entityManager -> - val cb = entityManager.criteriaBuilder - val query = cb.createTupleQuery() - val root = query.from(getEntityClass()) - query.multiselect(root[Anime_.uuid], root[Anime_.image], root[Anime_.banner]) - entityManager.createQuery(query).resultList - } + val cb = database.entityManager.criteriaBuilder + val query = cb.createTupleQuery() + val root = query.from(getEntityClass()) + query.multiselect(root[Anime_.uuid], root[Anime_.image], root[Anime_.banner]) + return createReadOnlyQuery(database.entityManager, query) + .resultList } fun findBySlug(countryCode: CountryCode, slug: String): Anime? { - return inTransaction { entityManager -> - val cb = entityManager.criteriaBuilder - val query = cb.createQuery(getEntityClass()) - val root = query.from(getEntityClass()) - - query.where( - cb.and( - cb.equal(root[Anime_.countryCode], countryCode), - cb.equal(root[Anime_.slug], slug) - ) + val cb = database.entityManager.criteriaBuilder + val query = cb.createQuery(getEntityClass()) + val root = query.from(getEntityClass()) + + query.where( + cb.and( + cb.equal(root[Anime_.countryCode], countryCode), + cb.equal(root[Anime_.slug], slug) ) + ) - createReadOnlyQuery(entityManager, query) - .resultList - .firstOrNull() - } + return createReadOnlyQuery(database.entityManager, query) + .resultList + .firstOrNull() } fun findByName(countryCode: CountryCode, name: String?): Anime? { - return inTransaction { - val cb = it.criteriaBuilder - val query = cb.createQuery(getEntityClass()) - val root = query.from(getEntityClass()) - - query.where( - cb.and( - cb.equal(root[Anime_.countryCode], countryCode), - cb.equal(cb.lower(root[Anime_.name]), name?.lowercase()) - ) + val cb = database.entityManager.criteriaBuilder + val query = cb.createQuery(getEntityClass()) + val root = query.from(getEntityClass()) + + query.where( + cb.and( + cb.equal(root[Anime_.countryCode], countryCode), + cb.equal(cb.lower(root[Anime_.name]), name?.lowercase()) ) + ) - it.createQuery(query) - .resultList - .firstOrNull() - } + return database.entityManager.createQuery(query) + .resultList + .firstOrNull() } } \ No newline at end of file diff --git a/src/main/kotlin/fr/shikkanime/repositories/ConfigRepository.kt b/src/main/kotlin/fr/shikkanime/repositories/ConfigRepository.kt index 6a4059a7..99e3cade 100644 --- a/src/main/kotlin/fr/shikkanime/repositories/ConfigRepository.kt +++ b/src/main/kotlin/fr/shikkanime/repositories/ConfigRepository.kt @@ -7,27 +7,23 @@ class ConfigRepository : AbstractRepository() { override fun getEntityClass() = Config::class.java fun findAllByName(name: String): List { - return inTransaction { - val cb = it.criteriaBuilder - val query = cb.createQuery(getEntityClass()) - val root = query.from(getEntityClass()) - query.where(cb.like(cb.lower(root[Config_.propertyKey]), "%${name.lowercase()}%")) + val cb = database.entityManager.criteriaBuilder + val query = cb.createQuery(getEntityClass()) + val root = query.from(getEntityClass()) + query.where(cb.like(cb.lower(root[Config_.propertyKey]), "%${name.lowercase()}%")) - createReadOnlyQuery(it, query) - .resultList - } + return createReadOnlyQuery(database.entityManager, query) + .resultList } fun findByName(name: String): Config? { - return inTransaction { - val cb = it.criteriaBuilder - val query = cb.createQuery(getEntityClass()) - val root = query.from(getEntityClass()) - query.where(cb.equal(cb.lower(root[Config_.propertyKey]), name.lowercase())) + val cb = database.entityManager.criteriaBuilder + val query = cb.createQuery(getEntityClass()) + val root = query.from(getEntityClass()) + query.where(cb.equal(cb.lower(root[Config_.propertyKey]), name.lowercase())) - createReadOnlyQuery(it, query) - .resultList - .firstOrNull() - } + return createReadOnlyQuery(database.entityManager, query) + .resultList + .firstOrNull() } } \ No newline at end of file diff --git a/src/main/kotlin/fr/shikkanime/repositories/EpisodeMappingRepository.kt b/src/main/kotlin/fr/shikkanime/repositories/EpisodeMappingRepository.kt index 0d7a6df3..33fd0062 100644 --- a/src/main/kotlin/fr/shikkanime/repositories/EpisodeMappingRepository.kt +++ b/src/main/kotlin/fr/shikkanime/repositories/EpisodeMappingRepository.kt @@ -21,114 +21,104 @@ class EpisodeMappingRepository : AbstractRepository() { limit: Int, status: Status? = null ): Pageable { - return inTransaction { entityManager -> - val cb = entityManager.criteriaBuilder - val query = cb.createQuery(getEntityClass()) - val root = query.from(getEntityClass()) - - val predicates = mutableListOf() - anime?.let { predicates.add(cb.equal(root[EpisodeMapping_.anime], it)) } - season?.let { predicates.add(cb.equal(root[EpisodeMapping_.season], it)) } - countryCode?.let { predicates.add(cb.equal(root[EpisodeMapping_.anime][Anime_.countryCode], it)) } - status?.let { predicates.add(cb.equal(root[EpisodeMapping_.status], it)) } - query.where(*predicates.toTypedArray()) - - val orders = sort.mapNotNull { sortParameter -> - val order = if (sortParameter.order == SortParameter.Order.ASC) cb::asc else cb::desc - - val field = when (sortParameter.field) { - "episodeType" -> root[EpisodeMapping_.episodeType] - "releaseDateTime" -> root[EpisodeMapping_.releaseDateTime] - "lastReleaseDateTime" -> root[EpisodeMapping_.lastReleaseDateTime] - "season" -> root[EpisodeMapping_.season] - "number" -> root[EpisodeMapping_.number] - "animeName" -> root[EpisodeMapping_.anime][Anime_.name] - else -> null - } - - field?.let { order(it) } + val cb = database.entityManager.criteriaBuilder + val query = cb.createQuery(getEntityClass()) + val root = query.from(getEntityClass()) + + val predicates = mutableListOf() + anime?.let { predicates.add(cb.equal(root[EpisodeMapping_.anime], it)) } + season?.let { predicates.add(cb.equal(root[EpisodeMapping_.season], it)) } + countryCode?.let { predicates.add(cb.equal(root[EpisodeMapping_.anime][Anime_.countryCode], it)) } + status?.let { predicates.add(cb.equal(root[EpisodeMapping_.status], it)) } + query.where(*predicates.toTypedArray()) + + val orders = sort.mapNotNull { sortParameter -> + val order = if (sortParameter.order == SortParameter.Order.ASC) cb::asc else cb::desc + + val field = when (sortParameter.field) { + "episodeType" -> root[EpisodeMapping_.episodeType] + "releaseDateTime" -> root[EpisodeMapping_.releaseDateTime] + "lastReleaseDateTime" -> root[EpisodeMapping_.lastReleaseDateTime] + "season" -> root[EpisodeMapping_.season] + "number" -> root[EpisodeMapping_.number] + "animeName" -> root[EpisodeMapping_.anime][Anime_.name] + else -> null } - query.orderBy(orders) - buildPageableQuery(createReadOnlyQuery(entityManager, query), page, limit) + field?.let { order(it) } } + + query.orderBy(orders) + return buildPageableQuery(createReadOnlyQuery(database.entityManager, query), page, limit) } fun findAllUuidAndImage(): List { - return inTransaction { - val cb = it.criteriaBuilder - val query = cb.createTupleQuery() - val root = query.from(getEntityClass()) - query.multiselect(root[EpisodeMapping_.uuid], root[EpisodeMapping_.image]) - createReadOnlyQuery(it, query) - .resultList - } + val cb = database.entityManager.criteriaBuilder + val query = cb.createTupleQuery() + val root = query.from(getEntityClass()) + query.multiselect(root[EpisodeMapping_.uuid], root[EpisodeMapping_.image]) + return createReadOnlyQuery(database.entityManager, query) + .resultList } fun findAllByAnime(anime: Anime): List { - return inTransaction { - val cb = it.criteriaBuilder - val query = cb.createQuery(getEntityClass()) - val root = query.from(getEntityClass()) + val cb = database.entityManager.criteriaBuilder + val query = cb.createQuery(getEntityClass()) + val root = query.from(getEntityClass()) - query.where(cb.equal(root[EpisodeMapping_.anime], anime)) + query.where(cb.equal(root[EpisodeMapping_.anime], anime)) - createReadOnlyQuery(it, query) - .resultList - } + return createReadOnlyQuery(database.entityManager, query) + .resultList } fun findAllSeasonsByAnime(anime: Anime): List { - return inTransaction { - val cb = it.criteriaBuilder - val query = cb.createTupleQuery() - val root = query.from(getEntityClass()) - - query.multiselect(root[EpisodeMapping_.season], cb.greatest(root[EpisodeMapping_.lastReleaseDateTime])) - query.groupBy(root[EpisodeMapping_.season]) - query.where(cb.equal(root[EpisodeMapping_.anime], anime)) - query.orderBy(cb.asc(root[EpisodeMapping_.season])) - query.distinct(true) - - createReadOnlyQuery(it, query) - .resultList - } + val cb = database.entityManager.criteriaBuilder + val query = cb.createTupleQuery() + val root = query.from(getEntityClass()) + + query.multiselect(root[EpisodeMapping_.season], cb.greatest(root[EpisodeMapping_.lastReleaseDateTime])) + query.groupBy(root[EpisodeMapping_.season]) + query.where(cb.equal(root[EpisodeMapping_.anime], anime)) + query.orderBy(cb.asc(root[EpisodeMapping_.season])) + query.distinct(true) + + return createReadOnlyQuery(database.entityManager, query) + .resultList } fun findAllNeedUpdateByPlatform(platform: Platform, lastDateTime: ZonedDateTime): List { - return inTransaction { - val cb = it.criteriaBuilder - val query = cb.createQuery(getEntityClass()) - val root = query.from(getEntityClass()) - - // Platform is in the episode variant list - // Subquery to get the episode mapping with the platform - val subQuery = query.subquery(EpisodeMapping::class.java) - val subRoot = subQuery.from(EpisodeVariant::class.java) - subQuery.select(subRoot[EpisodeVariant_.mapping]) - - subQuery.where( - cb.and( - cb.equal(subRoot[EpisodeVariant_.platform], platform), - cb.equal(subRoot[EpisodeVariant_.mapping], root) - ) + val cb = database.entityManager.criteriaBuilder + val query = cb.createQuery(getEntityClass()) + val root = query.from(getEntityClass()) + + // Platform is in the episode variant list + // Subquery to get the episode mapping with the platform + val subQuery = query.subquery(EpisodeMapping::class.java) + val subRoot = subQuery.from(EpisodeVariant::class.java) + subQuery.select(subRoot[EpisodeVariant_.mapping]) + + subQuery.where( + cb.and( + cb.equal(subRoot[EpisodeVariant_.platform], platform), + cb.equal(subRoot[EpisodeVariant_.mapping], root) ) + ) - query.where( - cb.and( - cb.or( - cb.lessThanOrEqualTo(root[EpisodeMapping_.lastUpdateDateTime], lastDateTime), - cb.equal(root[EpisodeMapping_.status], Status.INVALID), - ), - cb.exists(subQuery) + query.where( + cb.and( + cb.or( + cb.lessThanOrEqualTo(root[EpisodeMapping_.lastUpdateDateTime], lastDateTime), + cb.equal(root[EpisodeMapping_.status], Status.INVALID), ), - ) + cb.exists(subQuery) + ), + ) - query.orderBy(cb.asc(root[EpisodeMapping_.lastUpdateDateTime])) + query.orderBy(cb.asc(root[EpisodeMapping_.lastUpdateDateTime])) - createReadOnlyQuery(it, query) - .resultList - } + return createReadOnlyQuery(database.entityManager, query) + .resultList } fun findByAnimeSeasonEpisodeTypeNumber( @@ -137,24 +127,22 @@ class EpisodeMappingRepository : AbstractRepository() { episodeType: EpisodeType, number: Int ): EpisodeMapping? { - return inTransaction { - val cb = it.criteriaBuilder - val query = cb.createQuery(getEntityClass()) - val root = query.from(getEntityClass()) - - query.where( - cb.and( - cb.equal(root[EpisodeMapping_.anime], anime), - cb.equal(root[EpisodeMapping_.episodeType], episodeType), - cb.equal(root[EpisodeMapping_.season], season), - cb.equal(root[EpisodeMapping_.number], number) - ) + val cb = database.entityManager.criteriaBuilder + val query = cb.createQuery(getEntityClass()) + val root = query.from(getEntityClass()) + + query.where( + cb.and( + cb.equal(root[EpisodeMapping_.anime], anime), + cb.equal(root[EpisodeMapping_.episodeType], episodeType), + cb.equal(root[EpisodeMapping_.season], season), + cb.equal(root[EpisodeMapping_.number], number) ) + ) - createReadOnlyQuery(it, query) - .resultList - .firstOrNull() - } + return createReadOnlyQuery(database.entityManager, query) + .resultList + .firstOrNull() } fun findLastNumber( @@ -164,28 +152,26 @@ class EpisodeMappingRepository : AbstractRepository() { platform: Platform, audioLocale: String ): Int { - return inTransaction { - val cb = it.criteriaBuilder - val query = cb.createQuery(Int::class.java) - val root = query.from(EpisodeVariant::class.java) - - query.select(root[EpisodeVariant_.mapping][EpisodeMapping_.number]) - - query.where( - cb.and( - cb.equal(root[EpisodeVariant_.mapping][EpisodeMapping_.anime], anime), - cb.equal(root[EpisodeVariant_.mapping][EpisodeMapping_.season], season), - cb.equal(root[EpisodeVariant_.platform], platform), - cb.equal(root[EpisodeVariant_.mapping][EpisodeMapping_.episodeType], episodeType), - cb.equal(root[EpisodeVariant_.audioLocale], audioLocale) - ) + val cb = database.entityManager.criteriaBuilder + val query = cb.createQuery(Int::class.java) + val root = query.from(EpisodeVariant::class.java) + + query.select(root[EpisodeVariant_.mapping][EpisodeMapping_.number]) + + query.where( + cb.and( + cb.equal(root[EpisodeVariant_.mapping][EpisodeMapping_.anime], anime), + cb.equal(root[EpisodeVariant_.mapping][EpisodeMapping_.season], season), + cb.equal(root[EpisodeVariant_.platform], platform), + cb.equal(root[EpisodeVariant_.mapping][EpisodeMapping_.episodeType], episodeType), + cb.equal(root[EpisodeVariant_.audioLocale], audioLocale) ) + ) - query.orderBy(cb.desc(root[EpisodeVariant_.mapping][EpisodeMapping_.number])) - createReadOnlyQuery(it, query) - .resultList - .firstOrNull() ?: 0 - } + query.orderBy(cb.desc(root[EpisodeVariant_.mapping][EpisodeMapping_.number])) + return createReadOnlyQuery(database.entityManager, query) + .resultList + .firstOrNull() ?: 0 } fun findPreviousEpisode( @@ -193,35 +179,33 @@ class EpisodeMappingRepository : AbstractRepository() { ): EpisodeMapping? { // Sort on release date time to get the previous episode // If the release date time is the same, sort on the number - return inTransaction { - val cb = it.criteriaBuilder - val query = cb.createQuery(getEntityClass()) - val root = query.from(getEntityClass()) - - query.where( - cb.and( - cb.equal(root[EpisodeMapping_.anime], episodeMapping.anime), - cb.equal(root[EpisodeMapping_.season], episodeMapping.season), - cb.or( - cb.lessThan(root[EpisodeMapping_.releaseDateTime], episodeMapping.releaseDateTime), - cb.and( - cb.equal(root[EpisodeMapping_.episodeType], episodeMapping.episodeType), - cb.lessThan(root[EpisodeMapping_.number], episodeMapping.number!!), - ) - ), - cb.notEqual(root[EpisodeMapping_.uuid], episodeMapping.uuid) - ) + val cb = database.entityManager.criteriaBuilder + val query = cb.createQuery(getEntityClass()) + val root = query.from(getEntityClass()) + + query.where( + cb.and( + cb.equal(root[EpisodeMapping_.anime], episodeMapping.anime), + cb.equal(root[EpisodeMapping_.season], episodeMapping.season), + cb.or( + cb.lessThan(root[EpisodeMapping_.releaseDateTime], episodeMapping.releaseDateTime), + cb.and( + cb.equal(root[EpisodeMapping_.episodeType], episodeMapping.episodeType), + cb.lessThan(root[EpisodeMapping_.number], episodeMapping.number!!), + ) + ), + cb.notEqual(root[EpisodeMapping_.uuid], episodeMapping.uuid) ) + ) - query.orderBy( - cb.desc(root[EpisodeMapping_.releaseDateTime]), - cb.desc(root[EpisodeMapping_.number]) - ) + query.orderBy( + cb.desc(root[EpisodeMapping_.releaseDateTime]), + cb.desc(root[EpisodeMapping_.number]) + ) - createReadOnlyQuery(it, query) - .resultList - .firstOrNull() - } + return createReadOnlyQuery(database.entityManager, query) + .resultList + .firstOrNull() } fun findNextEpisode( @@ -229,34 +213,32 @@ class EpisodeMappingRepository : AbstractRepository() { ): EpisodeMapping? { // Sort on release date time to get the next episode // If the release date time is the same, sort on the number - return inTransaction { - val cb = it.criteriaBuilder - val query = cb.createQuery(getEntityClass()) - val root = query.from(getEntityClass()) - - query.where( - cb.and( - cb.equal(root[EpisodeMapping_.anime], episodeMapping.anime), - cb.equal(root[EpisodeMapping_.season], episodeMapping.season), - cb.or( - cb.greaterThan(root[EpisodeMapping_.releaseDateTime], episodeMapping.releaseDateTime), - cb.and( - cb.equal(root[EpisodeMapping_.episodeType], episodeMapping.episodeType), - cb.greaterThan(root[EpisodeMapping_.number], episodeMapping.number!!), - ), + val cb = database.entityManager.criteriaBuilder + val query = cb.createQuery(getEntityClass()) + val root = query.from(getEntityClass()) + + query.where( + cb.and( + cb.equal(root[EpisodeMapping_.anime], episodeMapping.anime), + cb.equal(root[EpisodeMapping_.season], episodeMapping.season), + cb.or( + cb.greaterThan(root[EpisodeMapping_.releaseDateTime], episodeMapping.releaseDateTime), + cb.and( + cb.equal(root[EpisodeMapping_.episodeType], episodeMapping.episodeType), + cb.greaterThan(root[EpisodeMapping_.number], episodeMapping.number!!), ), - cb.notEqual(root[EpisodeMapping_.uuid], episodeMapping.uuid) - ) + ), + cb.notEqual(root[EpisodeMapping_.uuid], episodeMapping.uuid) ) + ) - query.orderBy( - cb.asc(root[EpisodeMapping_.releaseDateTime]), - cb.asc(root[EpisodeMapping_.number]) - ) + query.orderBy( + cb.asc(root[EpisodeMapping_.releaseDateTime]), + cb.asc(root[EpisodeMapping_.number]) + ) - createReadOnlyQuery(it, query) - .resultList - .firstOrNull() - } + return createReadOnlyQuery(database.entityManager, query) + .resultList + .firstOrNull() } } \ No newline at end of file diff --git a/src/main/kotlin/fr/shikkanime/repositories/EpisodeVariantRepository.kt b/src/main/kotlin/fr/shikkanime/repositories/EpisodeVariantRepository.kt index 2c61d7d6..c102f7e7 100644 --- a/src/main/kotlin/fr/shikkanime/repositories/EpisodeVariantRepository.kt +++ b/src/main/kotlin/fr/shikkanime/repositories/EpisodeVariantRepository.kt @@ -20,186 +20,166 @@ class EpisodeVariantRepository : AbstractRepository() { start: ZonedDateTime, end: ZonedDateTime, ): List { - return inTransaction { entityManager -> - val cb = entityManager.criteriaBuilder - val query = cb.createQuery(getEntityClass()) - val root = query.from(getEntityClass()) - - val countryPredicate = - cb.equal(root[EpisodeVariant_.mapping][EpisodeMapping_.anime][Anime_.countryCode], countryCode) - val datePredicate = cb.between(root[EpisodeVariant_.releaseDateTime], start, end) - val predicates = mutableListOf(countryPredicate, datePredicate) - - member?.let { - val animePredicate = root[EpisodeVariant_.mapping][EpisodeMapping_.anime][Anime_.uuid].`in`( - memberFollowAnimeService.findAllFollowedAnimesUUID(it) - ) - predicates.add(animePredicate) - } + val cb = database.entityManager.criteriaBuilder + val query = cb.createQuery(getEntityClass()) + val root = query.from(getEntityClass()) + + val countryPredicate = + cb.equal(root[EpisodeVariant_.mapping][EpisodeMapping_.anime][Anime_.countryCode], countryCode) + val datePredicate = cb.between(root[EpisodeVariant_.releaseDateTime], start, end) + val predicates = mutableListOf(countryPredicate, datePredicate) + + member?.let { + val animePredicate = root[EpisodeVariant_.mapping][EpisodeMapping_.anime][Anime_.uuid].`in`( + memberFollowAnimeService.findAllFollowedAnimesUUID(it) + ) + predicates.add(animePredicate) + } - query.where(cb.and(*predicates.toTypedArray())) + query.where(cb.and(*predicates.toTypedArray())) - createReadOnlyQuery(entityManager, query) - .resultList - } + return createReadOnlyQuery(database.entityManager, query) + .resultList } fun findAllTypeIdentifier(): List { - return inTransaction { entityManager -> - val cb = entityManager.criteriaBuilder - val query = cb.createTupleQuery() - val root = query.from(getEntityClass()) - - val episodeMappingPath = root[EpisodeVariant_.mapping] - val animePath = episodeMappingPath[EpisodeMapping_.anime] - - query.multiselect( - animePath[Anime_.countryCode], - animePath[Anime_.uuid], - root[EpisodeVariant_.platform], - episodeMappingPath[EpisodeMapping_.episodeType], - episodeMappingPath[EpisodeMapping_.season], - episodeMappingPath[EpisodeMapping_.number], - root[EpisodeVariant_.audioLocale], - root[EpisodeVariant_.identifier] - ) - - createReadOnlyQuery(entityManager, query) - .resultList - } + val cb = database.entityManager.criteriaBuilder + val query = cb.createTupleQuery() + val root = query.from(getEntityClass()) + + val episodeMappingPath = root[EpisodeVariant_.mapping] + val animePath = episodeMappingPath[EpisodeMapping_.anime] + + query.multiselect( + animePath[Anime_.countryCode], + animePath[Anime_.uuid], + root[EpisodeVariant_.platform], + episodeMappingPath[EpisodeMapping_.episodeType], + episodeMappingPath[EpisodeMapping_.season], + episodeMappingPath[EpisodeMapping_.number], + root[EpisodeVariant_.audioLocale], + root[EpisodeVariant_.identifier] + ) + + return createReadOnlyQuery(database.entityManager, query) + .resultList } fun findAllAudioLocalesByAnime(anime: Anime): List { - return inTransaction { entityManager -> - val cb = entityManager.criteriaBuilder - val query = cb.createQuery(String::class.java) - val root = query.from(getEntityClass()) + val cb = database.entityManager.criteriaBuilder + val query = cb.createQuery(String::class.java) + val root = query.from(getEntityClass()) - query.select(root[EpisodeVariant_.audioLocale]) - .where(cb.equal(root[EpisodeVariant_.mapping][EpisodeMapping_.anime], anime)) - .distinct(true) + query.select(root[EpisodeVariant_.audioLocale]) + .where(cb.equal(root[EpisodeVariant_.mapping][EpisodeMapping_.anime], anime)) + .distinct(true) - createReadOnlyQuery(entityManager, query) - .resultList - } + return createReadOnlyQuery(database.entityManager, query) + .resultList } fun findAllAudioLocalesByMapping(mapping: EpisodeMapping): List { - return inTransaction { entityManager -> - val cb = entityManager.criteriaBuilder - val query = cb.createQuery(String::class.java) - val root = query.from(getEntityClass()) + val cb = database.entityManager.criteriaBuilder + val query = cb.createQuery(String::class.java) + val root = query.from(getEntityClass()) - query.select(root[EpisodeVariant_.audioLocale]) - .where(cb.equal(root[EpisodeVariant_.mapping], mapping)) - .distinct(true) + query.select(root[EpisodeVariant_.audioLocale]) + .where(cb.equal(root[EpisodeVariant_.mapping], mapping)) + .distinct(true) - createReadOnlyQuery(entityManager, query) - .resultList - } + return createReadOnlyQuery(database.entityManager, query) + .resultList } fun findAllByAnime(anime: Anime): List { - return inTransaction { entityManager -> - val cb = entityManager.criteriaBuilder - val query = cb.createQuery(getEntityClass()) - val root = query.from(getEntityClass()) + val cb = database.entityManager.criteriaBuilder + val query = cb.createQuery(getEntityClass()) + val root = query.from(getEntityClass()) - query.where(cb.equal(root[EpisodeVariant_.mapping][EpisodeMapping_.anime], anime)) + query.where(cb.equal(root[EpisodeVariant_.mapping][EpisodeMapping_.anime], anime)) - createReadOnlyQuery(entityManager, query) - .resultList - } + return createReadOnlyQuery(database.entityManager, query) + .resultList } fun findAllByMapping(mapping: EpisodeMapping): List { - return inTransaction { entityManager -> - val cb = entityManager.criteriaBuilder - val query = cb.createQuery(getEntityClass()) - val root = query.from(getEntityClass()) + val cb = database.entityManager.criteriaBuilder + val query = cb.createQuery(getEntityClass()) + val root = query.from(getEntityClass()) - query.where(cb.equal(root[EpisodeVariant_.mapping], mapping)) + query.where(cb.equal(root[EpisodeVariant_.mapping], mapping)) - createReadOnlyQuery(entityManager, query) - .resultList - } + return createReadOnlyQuery(database.entityManager, query) + .resultList } fun findAllSimulcastedByAnime(anime: Anime): List { - return inTransaction { entityManager -> - val cb = entityManager.criteriaBuilder - val query = cb.createQuery(EpisodeMapping::class.java) - val root = query.from(getEntityClass()) - - query.distinct(true) - .select(root[EpisodeVariant_.mapping]) - .where( - cb.and( - cb.notEqual(root[EpisodeVariant_.audioLocale], anime.countryCode!!.locale), - cb.notEqual(root[EpisodeVariant_.mapping][EpisodeMapping_.episodeType], EpisodeType.FILM), - cb.notEqual(root[EpisodeVariant_.mapping][EpisodeMapping_.episodeType], EpisodeType.SUMMARY), - cb.equal(root[EpisodeVariant_.mapping][EpisodeMapping_.anime], anime) - ) - ) - .orderBy( - cb.asc(root[EpisodeVariant_.mapping][EpisodeMapping_.releaseDateTime]), - cb.asc(root[EpisodeVariant_.mapping][EpisodeMapping_.season]), - cb.asc(root[EpisodeVariant_.mapping][EpisodeMapping_.episodeType]), - cb.asc(root[EpisodeVariant_.mapping][EpisodeMapping_.number]), + val cb = database.entityManager.criteriaBuilder + val query = cb.createQuery(EpisodeMapping::class.java) + val root = query.from(getEntityClass()) + + query.distinct(true) + .select(root[EpisodeVariant_.mapping]) + .where( + cb.and( + cb.notEqual(root[EpisodeVariant_.audioLocale], anime.countryCode!!.locale), + cb.notEqual(root[EpisodeVariant_.mapping][EpisodeMapping_.episodeType], EpisodeType.FILM), + cb.notEqual(root[EpisodeVariant_.mapping][EpisodeMapping_.episodeType], EpisodeType.SUMMARY), + cb.equal(root[EpisodeVariant_.mapping][EpisodeMapping_.anime], anime) ) + ) + .orderBy( + cb.asc(root[EpisodeVariant_.mapping][EpisodeMapping_.releaseDateTime]), + cb.asc(root[EpisodeVariant_.mapping][EpisodeMapping_.season]), + cb.asc(root[EpisodeVariant_.mapping][EpisodeMapping_.episodeType]), + cb.asc(root[EpisodeVariant_.mapping][EpisodeMapping_.number]), + ) - createReadOnlyQuery(entityManager, query) - .resultList - } + return createReadOnlyQuery(database.entityManager, query) + .resultList } fun findByIdentifier(identifier: String): EpisodeVariant? { - return inTransaction { entityManager -> - val cb = entityManager.criteriaBuilder - val query = cb.createQuery(getEntityClass()) - val root = query.from(getEntityClass()) + val cb = database.entityManager.criteriaBuilder + val query = cb.createQuery(getEntityClass()) + val root = query.from(getEntityClass()) - query.where(cb.equal(root[EpisodeVariant_.identifier], identifier)) + query.where(cb.equal(root[EpisodeVariant_.identifier], identifier)) - createReadOnlyQuery(entityManager, query) - .resultList - .firstOrNull() - } + return createReadOnlyQuery(database.entityManager, query) + .resultList + .firstOrNull() } fun findMinAndMaxReleaseDateTimeByMapping(mapping: EpisodeMapping): Pair { - return inTransaction { entityManager -> - val cb = entityManager.criteriaBuilder - val query = cb.createQuery(Tuple::class.java) - val root = query.from(getEntityClass()) - - query.multiselect( - cb.least(root[EpisodeVariant_.releaseDateTime]), - cb.greatest(root[EpisodeVariant_.releaseDateTime]), - ) - .where(cb.equal(root[EpisodeVariant_.mapping], mapping)) - - createReadOnlyQuery(entityManager, query) - .singleResult - .let { Pair(it[0] as ZonedDateTime, it[1] as ZonedDateTime) } - } + val cb = database.entityManager.criteriaBuilder + val query = cb.createQuery(Tuple::class.java) + val root = query.from(getEntityClass()) + + query.multiselect( + cb.least(root[EpisodeVariant_.releaseDateTime]), + cb.greatest(root[EpisodeVariant_.releaseDateTime]), + ) + .where(cb.equal(root[EpisodeVariant_.mapping], mapping)) + + return createReadOnlyQuery(database.entityManager, query) + .singleResult + .let { it[0] as ZonedDateTime to it[1] as ZonedDateTime } } fun findMinAndMaxReleaseDateTimeByAnime(anime: Anime): Pair { - return inTransaction { entityManager -> - val cb = entityManager.criteriaBuilder - val query = cb.createQuery(Tuple::class.java) - val root = query.from(getEntityClass()) - - query.multiselect( - cb.least(root[EpisodeVariant_.releaseDateTime]), - cb.greatest(root[EpisodeVariant_.releaseDateTime]), - ) - .where(cb.equal(root[EpisodeVariant_.mapping][EpisodeMapping_.anime], anime)) - - createReadOnlyQuery(entityManager, query) - .singleResult - .let { Pair(it[0] as ZonedDateTime, it[1] as ZonedDateTime) } - } + val cb = database.entityManager.criteriaBuilder + val query = cb.createQuery(Tuple::class.java) + val root = query.from(getEntityClass()) + + query.multiselect( + cb.least(root[EpisodeVariant_.releaseDateTime]), + cb.greatest(root[EpisodeVariant_.releaseDateTime]), + ) + .where(cb.equal(root[EpisodeVariant_.mapping][EpisodeMapping_.anime], anime)) + + return createReadOnlyQuery(database.entityManager, query) + .singleResult + .let { it[0] as ZonedDateTime to it[1] as ZonedDateTime } } } \ No newline at end of file diff --git a/src/main/kotlin/fr/shikkanime/repositories/MemberActionRepository.kt b/src/main/kotlin/fr/shikkanime/repositories/MemberActionRepository.kt index 95f2a24c..297dc548 100644 --- a/src/main/kotlin/fr/shikkanime/repositories/MemberActionRepository.kt +++ b/src/main/kotlin/fr/shikkanime/repositories/MemberActionRepository.kt @@ -2,26 +2,24 @@ package fr.shikkanime.repositories import fr.shikkanime.entities.MemberAction import fr.shikkanime.entities.MemberAction_ -import java.util.UUID +import java.util.* class MemberActionRepository : AbstractRepository() { override fun getEntityClass() = MemberAction::class.java fun findByUuidAndCode(uuid: UUID, code: String): MemberAction? { - return inTransaction { - val cb = it.criteriaBuilder - val query = cb.createQuery(getEntityClass()) - val root = query.from(getEntityClass()) + val cb = database.entityManager.criteriaBuilder + val query = cb.createQuery(getEntityClass()) + val root = query.from(getEntityClass()) - query.where( - cb.equal(root[MemberAction_.uuid], uuid), - cb.equal(root[MemberAction_.code], code), - cb.isFalse(root[MemberAction_.validated]) - ) + query.where( + cb.equal(root[MemberAction_.uuid], uuid), + cb.equal(root[MemberAction_.code], code), + cb.isFalse(root[MemberAction_.validated]) + ) - createReadOnlyQuery(it, query) - .resultList - .firstOrNull() - } + return createReadOnlyQuery(database.entityManager, query) + .resultList + .firstOrNull() } } \ No newline at end of file diff --git a/src/main/kotlin/fr/shikkanime/repositories/MemberFollowAnimeRepository.kt b/src/main/kotlin/fr/shikkanime/repositories/MemberFollowAnimeRepository.kt index ce3480cf..7ac35018 100644 --- a/src/main/kotlin/fr/shikkanime/repositories/MemberFollowAnimeRepository.kt +++ b/src/main/kotlin/fr/shikkanime/repositories/MemberFollowAnimeRepository.kt @@ -10,19 +10,17 @@ class MemberFollowAnimeRepository : AbstractRepository() { override fun getEntityClass() = MemberFollowAnime::class.java fun findAllFollowedAnimesUUID(member: Member): List { - return inTransaction { - val cb = it.criteriaBuilder - val query = cb.createQuery(UUID::class.java) - val root = query.from(getEntityClass()) - query.select(root[MemberFollowAnime_.anime][Anime_.UUID]) + val cb = database.entityManager.criteriaBuilder + val query = cb.createQuery(UUID::class.java) + val root = query.from(getEntityClass()) + query.select(root[MemberFollowAnime_.anime][Anime_.UUID]) - query.where( - cb.equal(root[MemberFollowAnime_.member], member) - ) + query.where( + cb.equal(root[MemberFollowAnime_.member], member) + ) - createReadOnlyQuery(it, query) - .resultList - } + return createReadOnlyQuery(database.entityManager, query) + .resultList } fun findAllMissedAnimes( @@ -30,59 +28,53 @@ class MemberFollowAnimeRepository : AbstractRepository() { page: Int, limit: Int, ): Pageable { - return inTransaction { entityManager -> - val cb = entityManager.criteriaBuilder - val query = cb.createTupleQuery() - val root = query.from(getEntityClass()) - val anime = root.join(MemberFollowAnime_.anime) - val episodeMapping = anime.join(Anime_.mappings, JoinType.LEFT) - // And episode type is not SUMMARY - episodeMapping.on(cb.notEqual(episodeMapping[EpisodeMapping_.episodeType], EpisodeType.SUMMARY)) - val memberFollowEpisode = episodeMapping.join(EpisodeMapping_.memberFollowEpisodes, JoinType.LEFT) - memberFollowEpisode.on(cb.equal(memberFollowEpisode[MemberFollowEpisode_.member], member)) + val cb = database.entityManager.criteriaBuilder + val query = cb.createTupleQuery() + val root = query.from(getEntityClass()) + val anime = root.join(MemberFollowAnime_.anime) + val episodeMapping = anime.join(Anime_.mappings, JoinType.LEFT) + // And episode type is not SUMMARY + episodeMapping.on(cb.notEqual(episodeMapping[EpisodeMapping_.episodeType], EpisodeType.SUMMARY)) + val memberFollowEpisode = episodeMapping.join(EpisodeMapping_.memberFollowEpisodes, JoinType.LEFT) + memberFollowEpisode.on(cb.equal(memberFollowEpisode[MemberFollowEpisode_.member], member)) - val memberPredicate = cb.equal(root[MemberFollowAnime_.member], member) - val memberFollowEpisodePredicate = cb.and(cb.isNull(memberFollowEpisode[MemberFollowEpisode_.episode])) + val memberPredicate = cb.equal(root[MemberFollowAnime_.member], member) + val memberFollowEpisodePredicate = cb.and(cb.isNull(memberFollowEpisode[MemberFollowEpisode_.episode])) - query.multiselect(anime, cb.countDistinct(episodeMapping[EpisodeMapping_.uuid]).`as`(Long::class.java)) - query.where(memberPredicate, memberFollowEpisodePredicate) - query.groupBy(anime) - query.having(cb.greaterThan(cb.countDistinct(episodeMapping[EpisodeMapping_.uuid]), 0)) - query.orderBy(cb.desc(anime[Anime_.lastReleaseDateTime])) + query.multiselect(anime, cb.countDistinct(episodeMapping[EpisodeMapping_.uuid]).`as`(Long::class.java)) + query.where(memberPredicate, memberFollowEpisodePredicate) + query.groupBy(anime) + query.having(cb.greaterThan(cb.countDistinct(episodeMapping[EpisodeMapping_.uuid]), 0)) + query.orderBy(cb.desc(anime[Anime_.lastReleaseDateTime])) - buildPageableQuery(createReadOnlyQuery(entityManager, query), page, limit) - } + return buildPageableQuery(createReadOnlyQuery(database.entityManager, query), page, limit) } fun findAllByAnime(anime: Anime): List { - return inTransaction { - val cb = it.criteriaBuilder - val query = cb.createQuery(getEntityClass()) - val root = query.from(getEntityClass()) + val cb = database.entityManager.criteriaBuilder + val query = cb.createQuery(getEntityClass()) + val root = query.from(getEntityClass()) - query.where( - cb.equal(root[MemberFollowAnime_.anime], anime) - ) + query.where( + cb.equal(root[MemberFollowAnime_.anime], anime) + ) - createReadOnlyQuery(it, query) - .resultList - } + return createReadOnlyQuery(database.entityManager, query) + .resultList } fun findByMemberAndAnime(member: Member, anime: Anime): MemberFollowAnime? { - return inTransaction { - val cb = it.criteriaBuilder - val query = cb.createQuery(getEntityClass()) - val root = query.from(getEntityClass()) + val cb = database.entityManager.criteriaBuilder + val query = cb.createQuery(getEntityClass()) + val root = query.from(getEntityClass()) - query.where( - cb.equal(root[MemberFollowAnime_.member], member), - cb.equal(root[MemberFollowAnime_.anime], anime) - ) + query.where( + cb.equal(root[MemberFollowAnime_.member], member), + cb.equal(root[MemberFollowAnime_.anime], anime) + ) - createReadOnlyQuery(it, query) - .resultList - .firstOrNull() - } + return createReadOnlyQuery(database.entityManager, query) + .resultList + .firstOrNull() } } \ No newline at end of file diff --git a/src/main/kotlin/fr/shikkanime/repositories/MemberFollowEpisodeRepository.kt b/src/main/kotlin/fr/shikkanime/repositories/MemberFollowEpisodeRepository.kt index d9aba542..1cc2b704 100644 --- a/src/main/kotlin/fr/shikkanime/repositories/MemberFollowEpisodeRepository.kt +++ b/src/main/kotlin/fr/shikkanime/repositories/MemberFollowEpisodeRepository.kt @@ -7,67 +7,59 @@ class MemberFollowEpisodeRepository : AbstractRepository() override fun getEntityClass() = MemberFollowEpisode::class.java fun findAllFollowedEpisodesUUID(member: Member): List { - return inTransaction { - val cb = it.criteriaBuilder - val query = cb.createQuery(UUID::class.java) - val root = query.from(getEntityClass()) - query.select(root[MemberFollowEpisode_.episode][EpisodeMapping_.UUID]) + val cb = database.entityManager.criteriaBuilder + val query = cb.createQuery(UUID::class.java) + val root = query.from(getEntityClass()) + query.select(root[MemberFollowEpisode_.episode][EpisodeMapping_.UUID]) - query.where( - cb.equal(root[MemberFollowEpisode_.member], member) - ) + query.where( + cb.equal(root[MemberFollowEpisode_.member], member) + ) - createReadOnlyQuery(it, query) - .resultList - } + return createReadOnlyQuery(database.entityManager, query) + .resultList } fun findAllByEpisode(episode: EpisodeMapping): List { - return inTransaction { - val cb = it.criteriaBuilder - val query = cb.createQuery(getEntityClass()) - val root = query.from(getEntityClass()) + val cb = database.entityManager.criteriaBuilder + val query = cb.createQuery(getEntityClass()) + val root = query.from(getEntityClass()) - query.where( - cb.equal(root[MemberFollowEpisode_.episode], episode) - ) + query.where( + cb.equal(root[MemberFollowEpisode_.episode], episode) + ) - createReadOnlyQuery(it, query) - .resultList - } + return createReadOnlyQuery(database.entityManager, query) + .resultList } fun findByMemberAndEpisode(member: Member, episode: EpisodeMapping): MemberFollowEpisode? { - return inTransaction { - val cb = it.criteriaBuilder - val query = cb.createQuery(getEntityClass()) - val root = query.from(getEntityClass()) + val cb = database.entityManager.criteriaBuilder + val query = cb.createQuery(getEntityClass()) + val root = query.from(getEntityClass()) - query.where( - cb.equal(root[MemberFollowEpisode_.member], member), - cb.equal(root[MemberFollowEpisode_.episode], episode) - ) + query.where( + cb.equal(root[MemberFollowEpisode_.member], member), + cb.equal(root[MemberFollowEpisode_.episode], episode) + ) - createReadOnlyQuery(it, query) - .resultList - .firstOrNull() - } + return createReadOnlyQuery(database.entityManager, query) + .resultList + .firstOrNull() } fun getTotalDuration(member: Member): Long { - return inTransaction { - val cb = it.criteriaBuilder - val query = cb.createQuery(Long::class.java) - val root = query.from(getEntityClass()) - query.select(cb.sum(root[MemberFollowEpisode_.episode][EpisodeMapping_.duration])) + val cb = database.entityManager.criteriaBuilder + val query = cb.createQuery(Long::class.java) + val root = query.from(getEntityClass()) + query.select(cb.sum(root[MemberFollowEpisode_.episode][EpisodeMapping_.duration])) - query.where( - cb.equal(root[MemberFollowEpisode_.member], member) - ) + query.where( + cb.equal(root[MemberFollowEpisode_.member], member) + ) - createReadOnlyQuery(it, query) - .resultList - .firstOrNull() ?: 0L - } + return createReadOnlyQuery(database.entityManager, query) + .resultList + .firstOrNull() ?: 0L } } \ No newline at end of file diff --git a/src/main/kotlin/fr/shikkanime/repositories/MemberRepository.kt b/src/main/kotlin/fr/shikkanime/repositories/MemberRepository.kt index 5600a7a3..9afa91eb 100644 --- a/src/main/kotlin/fr/shikkanime/repositories/MemberRepository.kt +++ b/src/main/kotlin/fr/shikkanime/repositories/MemberRepository.kt @@ -8,72 +8,62 @@ class MemberRepository : AbstractRepository() { override fun getEntityClass() = Member::class.java fun findAllByRoles(roles: List): List { - return inTransaction { - val cb = it.criteriaBuilder - val query = cb.createQuery(getEntityClass()) - val root = query.from(getEntityClass()) - query.where(root.join(Member_.roles).`in`(roles)) + val cb = database.entityManager.criteriaBuilder + val query = cb.createQuery(getEntityClass()) + val root = query.from(getEntityClass()) + query.where(root.join(Member_.roles).`in`(roles)) - createReadOnlyQuery(it, query) - .resultList - } + return createReadOnlyQuery(database.entityManager, query) + .resultList } fun findAllByAnimeUUID(animeUuid: UUID): List { - return inTransaction { - val cb = it.criteriaBuilder - val query = cb.createQuery(getEntityClass()) - val root = query.from(MemberFollowAnime::class.java) + val cb = database.entityManager.criteriaBuilder + val query = cb.createQuery(getEntityClass()) + val root = query.from(MemberFollowAnime::class.java) - query.select(root[MemberFollowAnime_.member]) - query.distinct(true) - query.where(cb.equal(root[MemberFollowAnime_.anime][Anime_.uuid], animeUuid)) + query.select(root[MemberFollowAnime_.member]) + query.distinct(true) + query.where(cb.equal(root[MemberFollowAnime_.anime][Anime_.uuid], animeUuid)) - createReadOnlyQuery(it, query) - .resultList - } + return createReadOnlyQuery(database.entityManager, query) + .resultList } fun findByUsernameAndPassword(username: String, password: ByteArray): Member? { - return inTransaction { - val cb = it.criteriaBuilder - val query = cb.createQuery(getEntityClass()) - val root = query.from(getEntityClass()) + val cb = database.entityManager.criteriaBuilder + val query = cb.createQuery(getEntityClass()) + val root = query.from(getEntityClass()) - query.where( - cb.equal(root[Member_.username], username), - cb.equal(root[Member_.encryptedPassword], password) - ) + query.where( + cb.equal(root[Member_.username], username), + cb.equal(root[Member_.encryptedPassword], password) + ) - createReadOnlyQuery(it, query) - .resultList - .firstOrNull() - } + return createReadOnlyQuery(database.entityManager, query) + .resultList + .firstOrNull() } fun findByIdentifier(identifier: String): Member? { - return inTransaction { - val cb = it.criteriaBuilder - val query = cb.createQuery(getEntityClass()) - val root = query.from(getEntityClass()) - query.where(cb.equal(root[Member_.username], identifier)) + val cb = database.entityManager.criteriaBuilder + val query = cb.createQuery(getEntityClass()) + val root = query.from(getEntityClass()) + query.where(cb.equal(root[Member_.username], identifier)) - createReadOnlyQuery(it, query) - .resultList - .firstOrNull() - } + return createReadOnlyQuery(database.entityManager, query) + .resultList + .firstOrNull() } fun findByEmail(email: String): Member? { - return inTransaction { - val cb = it.criteriaBuilder - val query = cb.createQuery(getEntityClass()) - val root = query.from(getEntityClass()) - query.where(cb.equal(root[Member_.email], email)) + val cb = database.entityManager.criteriaBuilder + val query = cb.createQuery(getEntityClass()) + val root = query.from(getEntityClass()) + query.where(cb.equal(root[Member_.email], email)) - createReadOnlyQuery(it, query) - .resultList - .firstOrNull() - } + return createReadOnlyQuery(database.entityManager, query) + .resultList + .firstOrNull() } } \ No newline at end of file diff --git a/src/main/kotlin/fr/shikkanime/repositories/MetricRepository.kt b/src/main/kotlin/fr/shikkanime/repositories/MetricRepository.kt index b8e9a43b..4868fd52 100644 --- a/src/main/kotlin/fr/shikkanime/repositories/MetricRepository.kt +++ b/src/main/kotlin/fr/shikkanime/repositories/MetricRepository.kt @@ -8,21 +8,19 @@ class MetricRepository : AbstractRepository() { override fun getEntityClass() = Metric::class.java fun findAllAfter(date: ZonedDateTime): List { - return inTransaction { - val cb = it.criteriaBuilder - val query = cb.createQuery(getEntityClass()) - val root = query.from(getEntityClass()) - query.where(cb.greaterThan(root[Metric_.date], date)) - query.orderBy(cb.asc(root[Metric_.date])) + val cb = database.entityManager.criteriaBuilder + val query = cb.createQuery(getEntityClass()) + val root = query.from(getEntityClass()) + query.where(cb.greaterThan(root[Metric_.date], date)) + query.orderBy(cb.asc(root[Metric_.date])) - createReadOnlyQuery(it, query) - .resultList - } + return createReadOnlyQuery(database.entityManager, query) + .resultList } fun deleteAllBefore(date: ZonedDateTime) { inTransaction { - it.createQuery("DELETE FROM Metric WHERE date < :date") + database.entityManager.createQuery("DELETE FROM Metric WHERE date < :date") .setParameter("date", date) .executeUpdate() } diff --git a/src/main/kotlin/fr/shikkanime/repositories/SimulcastRepository.kt b/src/main/kotlin/fr/shikkanime/repositories/SimulcastRepository.kt index d10d70e3..5914b6da 100644 --- a/src/main/kotlin/fr/shikkanime/repositories/SimulcastRepository.kt +++ b/src/main/kotlin/fr/shikkanime/repositories/SimulcastRepository.kt @@ -7,33 +7,29 @@ class SimulcastRepository : AbstractRepository() { override fun getEntityClass() = Simulcast::class.java override fun findAll(): List { - return inTransaction { - val cb = it.criteriaBuilder - val query = cb.createQuery(getEntityClass()) - val root = query.from(getEntityClass()) + val cb = database.entityManager.criteriaBuilder + val query = cb.createQuery(getEntityClass()) + val root = query.from(getEntityClass()) - // Query where the animes are not empty - query.where(cb.isNotEmpty(root[Simulcast_.animes])) + // Query where the animes are not empty + query.where(cb.isNotEmpty(root[Simulcast_.animes])) - createReadOnlyQuery(it, query) - .resultList - } + return createReadOnlyQuery(database.entityManager, query) + .resultList } fun findBySeasonAndYear(season: String, year: Int): Simulcast? { - return inTransaction { - val cb = it.criteriaBuilder - val query = cb.createQuery(getEntityClass()) - val root = query.from(getEntityClass()) - - query.where( - cb.equal(root[Simulcast_.season], season), - cb.equal(root[Simulcast_.year], year) - ) - - createReadOnlyQuery(it, query) - .resultList - .firstOrNull() - } + val cb = database.entityManager.criteriaBuilder + val query = cb.createQuery(getEntityClass()) + val root = query.from(getEntityClass()) + + query.where( + cb.equal(root[Simulcast_.season], season), + cb.equal(root[Simulcast_.year], year) + ) + + return createReadOnlyQuery(database.entityManager, query) + .resultList + .firstOrNull() } } \ No newline at end of file diff --git a/src/main/kotlin/fr/shikkanime/utils/Database.kt b/src/main/kotlin/fr/shikkanime/utils/Database.kt index ce301dc7..355f0cf3 100644 --- a/src/main/kotlin/fr/shikkanime/utils/Database.kt +++ b/src/main/kotlin/fr/shikkanime/utils/Database.kt @@ -2,6 +2,7 @@ package fr.shikkanime.utils import fr.shikkanime.entities.ShikkEntity import jakarta.persistence.EntityManager +import jakarta.persistence.FlushModeType import liquibase.command.CommandScope import org.hibernate.SessionFactory import org.hibernate.cfg.Configuration @@ -12,6 +13,7 @@ import kotlin.system.exitProcess class Database { private val logger = LoggerFactory.getLogger(javaClass) private val sessionFactory: SessionFactory + var entityManager: EntityManager constructor(file: File) { if (!file.exists()) { @@ -64,6 +66,9 @@ class Database { logger.log(Level.SEVERE, "Error while validating database", e) exitProcess(1) } + + entityManager = sessionFactory.createEntityManager() + entityManager.flushMode = FlushModeType.COMMIT } constructor() : this( @@ -71,7 +76,4 @@ class Database { ClassLoader.getSystemClassLoader().getResource("hibernate.cfg.xml")?.file ?: "hibernate.cfg.xml" ) ) - - val entityManager: EntityManager - get() = sessionFactory.createEntityManager() } \ No newline at end of file diff --git a/src/main/resources/db/changelog/2024/06/02-changelog.xml b/src/main/resources/db/changelog/2024/06/02-changelog.xml new file mode 100644 index 00000000..8a95a243 --- /dev/null +++ b/src/main/resources/db/changelog/2024/06/02-changelog.xml @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/main/resources/db/changelog/db.changelog-master.xml b/src/main/resources/db/changelog/db.changelog-master.xml index cc6df9b7..29b96db5 100644 --- a/src/main/resources/db/changelog/db.changelog-master.xml +++ b/src/main/resources/db/changelog/db.changelog-master.xml @@ -54,4 +54,5 @@ + \ No newline at end of file diff --git a/src/main/resources/templates/site/episodeDetails.ftl b/src/main/resources/templates/site/episodeDetails.ftl index f3a22630..9fba8748 100644 --- a/src/main/resources/templates/site/episodeDetails.ftl +++ b/src/main/resources/templates/site/episodeDetails.ftl @@ -48,8 +48,8 @@ -

${episodeMapping.title}

- ${episodeMapping.description} +

${episodeMapping.title!">︿<"}

+ ${episodeMapping.description!"Aucune description pour le moment..."}
<#if previousEpisode??> diff --git a/src/main/resources/templates/site/seo/sitemap.ftl b/src/main/resources/templates/site/seo/sitemap.ftl index 2e782da5..c9ce77aa 100644 --- a/src/main/resources/templates/site/seo/sitemap.ftl +++ b/src/main/resources/templates/site/seo/sitemap.ftl @@ -34,8 +34,7 @@ <#list anime.episodes as episode> - ${baseUrl}/animes/${anime.slug}/season-${episode.season?c}/${episode.episodeType.slug} - -${episode.number?c} + ${baseUrl}/animes/${anime.slug}/season-${episode.season?c}/${episode.episodeType.slug}-${episode.number?c} ${episode.lastReleaseDateTime?replace("Z", "+00:00")}