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

io.github.graphglue.model.property.BaseNodePropertyDelegate.kt Maven / Gradle / Ivy

Go to download

A library to develop annotation-based code-first GraphQL servers using GraphQL Kotlin, Spring Boot and Neo4j - excluding Spring GraphQL server dependencies

There is a newer version: 7.0.5
Show newest version
package io.github.graphglue.model.property

import io.github.graphglue.data.execution.NodeQueryResult
import io.github.graphglue.data.repositories.RelationshipDiff
import io.github.graphglue.definition.*
import io.github.graphglue.model.Node
import kotlin.reflect.KProperty
import kotlin.reflect.KProperty1

/**
 * Base class for many and one node property delegates
 * Provides cache based GraphQL functionality, and abstract methods with allow persistence
 *
 * @param parent the node which hosts this property
 * @param property the property on the class
 * @param T the type of the value [Node] (s)
 * @param R the type of property
 */
abstract class BaseNodePropertyDelegate(
    parent: Node,
    property: KProperty1<*, *>
) : PropertyDelegate>(parent, property) {

    /**
     * NodeCache used to load this property
     * might be set after initial loading, but must not be changed
     */
    protected var nodeCache: NodeCache? = null

    /**
     * Dynamic type of [parent] and name of [property], can be used for error messages without leaking information
     */
    protected val propertyName = "${parent::class.qualifiedName}.${property.name}"

    /**
     * Delegate for lazy-loading the property
     */
    private val lazyLoadingDelegate = object : LazyLoadingDelegate {
        override suspend fun invoke(cache: NodeCache?, loader: (LazyLoadingSubqueryGenerator.() -> Unit)?): R {
            if (nodeCache != null && cache != null && nodeCache != cache) {
                throw IllegalStateException("This property was already loaded with another cache")
            }
            return getLoadedProperty(cache, loader)
        }
    }

    /**
     * Gets the diff of added and removed relationships to persist in the database
     *
     * @return the diff which describes how to add and remove relationships
     */
    internal abstract fun getRelationshipDiff(): RelationshipDiff

    /**
     * Gets [Node]s which should be persisted when this [Node] is persisted
     *
     * @return other nodes to save
     */
    internal abstract fun getRelatedNodesToSave(): Collection

    /**
     * Gets related nodes defined by this property, but only those already loaded (therefore no lazy loading)
     * The relationships do not have to be persisted yet
     *
     * @return the already loaded related nodes
     */
    internal abstract fun getLoadedRelatedNodes(): Collection

    /**
     * Gets the loaded property which is returned by the lazy loading delegate
     *
     * @param cache used to load nodes from, if provided, not loading deleted nodes
     * @param loader if provided used to define nested nodes to load
     * @return the loaded property
     */
    internal abstract suspend fun getLoadedProperty(cache: NodeCache?, loader: (LazyLoadingSubqueryGenerator.() -> Unit)?): R

    /**
     * Gets the lazy loading delegate which is used to get the value of the property
     *
     * @param thisRef the [Node] containing the delegated property
     * @param property the delegated property
     * @return the lazy loading delegate which can be used to get the property
     */
    operator fun getValue(thisRef: Node, property: KProperty<*>): LazyLoadingDelegate {
        return lazyLoadingDelegate
    }

    /**
     * Called to validate the property
     * Should throw an exception if the property is invalid, with an appropriate reason
     *
     * @param savingNodes the nodes which are currently saved
     * @param relationshipDefinition definition of the relationship
     * @param nodeDefinitionCollection used to obtain the inverse of [relationshipDefinition]
     */
    abstract fun validate(
        savingNodes: Set,
        relationshipDefinition: RelationshipDefinition,
        nodeDefinitionCollection: NodeDefinitionCollection
    )

    override fun registerQueryResult(
        fieldDefinition: FieldDefinition,
        queryResult: NodeQueryResult
    ) {
        val relationshipDefinition = (fieldDefinition as RelationshipFieldDefinition<*>).relationshipDefinition
        val setter = relationshipDefinition.remotePropertySetter
        if (setter != null) {
            val nodes = queryResult.nodes
            for (node in nodes) {
                setter(node, parent)
            }
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy