All Downloads are FREE. Search and download functionalities are using the official Maven repository.

jvmMain.zakadabar.lib.content.backend.ContentPa.kt Maven / Gradle / Ivy

/*
 * Copyright © 2020-2021, Simplexion, Hungary and contributors. Use of this source code is governed by the Apache 2.0 license.
 */
package zakadabar.lib.content.backend

import org.jetbrains.exposed.dao.id.EntityID
import org.jetbrains.exposed.sql.*
import org.jetbrains.exposed.sql.statements.UpdateBuilder
import zakadabar.core.data.EntityId
import zakadabar.core.persistence.exposed.ExposedPaBase
import zakadabar.core.persistence.exposed.Sql
import zakadabar.core.persistence.exposed.entityId
import zakadabar.lib.content.data.*
import zakadabar.lib.i18n.data.LocaleBo
import zakadabar.lib.i18n.persistence.LocaleExposedTableGen

open class ContentPa : ExposedPaBase(
    table = ContentTable
) {

    private val textTable = TextBlockTable

    override fun onModuleLoad() {
        super.onModuleLoad()
        Sql.tables += textTable
    }

    override fun create(bo: ContentBo): ContentBo {
        val created = super.create(bo)

        bo.textBlocks.forEach { textBo ->
            textTable.insert {
                it[content] = bo.id.toLong()
                it[stereotype] = textBo.stereotype
                it[value] = textBo.value
            }
        }

        return created
    }

    override fun read(entityId: EntityId): ContentBo {
        val bo = super.read(entityId)

        bo.textBlocks = textTable
            .select { textTable.content eq bo.id.toLong() }
            .map {
                TextBlockBo(
                    it[textTable.stereotype],
                    it[textTable.value]
                )
            }

        return bo
    }

    fun readLocalized(master: EntityId, locale: EntityId) =
        readLocalizedOrNull(master, locale) ?: throw NoSuchElementException("masterId=$master localeId=$locale")

    fun readLocalizedOrNull(master: EntityId, locale: EntityId): ContentBo? {
        val bo = table
            .select { (table.master eq master.toLong()) and (table.locale eq locale.toLong()) }
            .firstOrNull()
            ?.toBo()
            ?: return null

        readTextBlocks(bo)

        return bo
    }

    fun listLocalized(master: EntityId): List =
        table
            .select { table.master eq master.toLong() }
            .map { it.toBo() }

    private fun readTextBlocks(bo: ContentBo) {
        bo.textBlocks = textTable
            .select { textTable.content eq bo.id.toLong() }
            .map {
                TextBlockBo(
                    it[textTable.stereotype],
                    it[textTable.value]
                )
            }
    }

    override fun update(bo: ContentBo): ContentBo {
        super.update(bo)

        textTable.deleteWhere { textTable.content eq bo.id.toLong() }

        bo.textBlocks.forEach { textBo ->
            textTable.insert {
                it[content] = bo.id.toLong()
                it[stereotype] = textBo.stereotype
                it[value] = textBo.value
            }
        }

        return bo
    }

    override fun delete(entityId: EntityId) {
        super.delete(entityId)
        textTable.deleteWhere { textTable.content eq entityId.toLong() }
    }

    fun bySeoTitle(locale: EntityId, parent: EntityId?, seoTitle: String): ContentBo? {
        val jt = table.alias("jt")
        val bo = table
            .innerJoin(jt, { table.master }, { jt[table.id] })
            .select { table.seoTitle eq seoTitle }
            .andWhere { jt[table.parent] eq parent?.toLong() }
            .andWhere { table.locale eq locale.toLong() }
            .firstOrNull()
            ?.toBo()
            ?: return null

        readTextBlocks(bo)

        return bo
    }

    fun mastersQuery(): List =
        table
            .slice(table.id, table.title)
            .select { table.master.isNull() }
            .map {
                MastersEntry(
                    it[table.id].entityId(),
                    it[table.title]
                )
            }

    fun folderQuery(): List =
        table
            .slice(table.id, table.title)
            .select { table.master.isNull() and (table.folder eq true) }
            .map {
                FolderEntry(
                    it[table.id].entityId(),
                    it[table.title]
                )
            }

    fun navQuery(localeId: EntityId, parentMasterId: EntityId?, parentSeoPath: String): List =
        localizedChildrenNav(localeId, parentMasterId, parentSeoPath).onEach { entry ->
            if (entry.folder) {
                entry.children = navQuery(localeId, entry.masterId, entry.seoPath)
            }
        }

    private fun localizedChildrenNav(locale: EntityId, parentMasterId: EntityId?, parentSeoPath: String): List {
        val jt = table.alias("jt")
        return table
            .innerJoin(jt, { table.master }, { jt[table.id] })
            .slice(table.id, table.title, table.seoTitle, jt[table.id], jt[table.folder])
            .select { jt[table.parent] eq parentMasterId?.toLong() }
            .andWhere { table.locale eq locale.toLong() }
            .map {
                NavEntry(
                    it[jt[table.id]].entityId(),
                    it[table.id].entityId(),
                    it[table.title],
                    "${parentSeoPath}/${it[table.seoTitle]}",
                    it[jt[table.folder]],
                    emptyList()
                )
            }
    }

    fun thumbnailQuery(localeId: EntityId, parentMasterId: EntityId?, parentSeoPath: String): List {
        val jt = table.alias("jt")

        return table
            .innerJoin(jt, { table.master }, { jt[table.id] })
            .slice(table.id, table.title, table.seoTitle, jt[table.id])
            .select { jt[table.parent] eq parentMasterId?.toLong() }
            .andWhere { table.locale eq localeId.toLong() }
            .map {
                ThumbnailEntry(
                    it[jt[table.id]].entityId(),
                    it[table.id].entityId(),
                    it[table.title],
                    "${parentSeoPath}/${it[table.seoTitle]}",
                    "" // this will be filled later
                )
            }
    }

    override fun ResultRow.toBo() = ContentBo(
        id = this[table.id].entityId(),
        status = this[table.status].entityId(),
        folder = this[table.folder],
        parent = this[table.parent]?.entityId(),
        master = this[table.master]?.entityId(),
        position = this[table.position],
        locale = this[table.locale]?.entityId(),
        title = this[table.title],
        seoTitle = this[table.seoTitle],
        textBlocks = emptyList(),
        attachments = emptyList()
    )

    override fun UpdateBuilder<*>.fromBo(bo: ContentBo) {
        this[table.status] = bo.status.toLong()
        this[table.folder] = bo.folder
        this[table.parent] = bo.parent?.let { EntityID(it.toLong(), table) }
        this[table.master] = bo.master?.let { EntityID(it.toLong(), table) }
        this[table.position] = bo.position
        this[table.locale] = bo.locale?.let { EntityID(it.toLong(), LocaleExposedTableGen) }
        this[table.title] = bo.title
        this[table.seoTitle] = bo.seoTitle
    }

}





© 2015 - 2025 Weber Informatics LLC | Privacy Policy