¿Cómo puedo crear una lista anidada usando un patrón de construcción?

Nov 30 2020

Estoy tratando de crear un generador de consultas para la sintaxis GraphQL, utilizando un patrón de generador. Ya lo hice por la parte de filtrado:

Quiero hacer una forma programática de decir qué datos quiero recuperar de la consulta. (NOTA: antes de que la titleparte de la consulta fuera codificada en QueryBuilder.

Así que para eso hice una clase llamada Entity que tiene una lista de sí misma como atributo.

class Entity(
        private val entity: EntityType,
        private val entities: MutableList<Entity> = mutableListOf()
) {
    override fun toString(): String {
        return if (this.entities.isEmpty()) {
            entity.str
        } else {
            this.entity.str + "{" + this.entities.onEach {
                it.toString()
            }.joinToString(" ") + "}"
        }
    }
}

Y lo hice funcionar. Pero para construir la estructura. luego tengo que agregar a la lista y "visitar" la lista de la entidad para visitar las entidades en esa lista.

Por ejemplo, si quiero crear esta consulta:

{
  events(place:"Somewhere", area:"The place"){
    title
    location{
      coordinates{
        longitude
        latitude
      }
    }
  }
}

Entonces necesito bajar 2 niveles en las capas de la Entidad, y la forma en que lo estoy haciendo ahora, entonces mi código se está volviendo muy amplio.

fun main() {
    val e1 = listOf<Entity>(
            Entity(EntityType.TITLE),
            Entity(EntityType.LOCATION,
                    mutableListOf(
                            Entity(EntityType.COORDINATES,
                                    mutableListOf(
                                            Entity(EntityType.LONGITUDE),
                                            Entity(EntityType.LATITUDE)
                                    )
                            )
                    )
            )
    )

    val q1 = Query.Builder()
            .filter(FilterType.PLACE, "Somewhere")
            .filter(FilterType.AREA,"The place")
            .add(e1)
            .build()
    println(q1.query)
}

Entonces estaba pensando en usar el patrón de construcción. O algo más que sea más inteligente.

Gracias de antemano por su ayuda y que tenga un buen día.

Por cierto: estoy usando las siguientes enumeraciones:

enum class EntityType(val str: String) {
    EVENTS("events"),
    TITLE("title"),
    LOCATION("location"),
    COORDINATES("coordinates"),
    LONGITUDE("longitude"),
    LATITUDE("latitude"),
}

enum class Filter(val str: String) {
    PLACE("place"),
    AREA("area"),
}

Y el resto de mi código se ve así:

class Filter {
    var filters = mutableMapOf<FilterType, Any>()
    override fun toString(): String {
        return if (filters.isNotEmpty()) {
            "(" + filters.map {
                if (it.value is Int || it.value is Long) {
                    it.key.str + ":" + it.value + ","
                } else {
                    it.key.str + ":\"" + it.value + "\","
                }
            }.joinToString(" ").dropLast(1) + ")"
        } else {
            ""
        }
    }
}

class Query private constructor(val query: String) {
    class Builder {
        private lateinit var entities: List<Entity>
        private var filter = Filter()

        fun filter(key: FilterType, value: Any) = apply {
            this.filter.filters[key] = value
        }

        fun add(entities: List<Entity>) = apply {
            this.entities = entities
        }

        private fun collect(root:String):String {
            return "{$root$filter{${entities.joinToString(" ")}}}"
        }

        fun build(): Query {
            return Query(collect("events"))
        }
    }

Respuestas

1 Pelocho Dec 01 2020 at 10:48

Eche un vistazo a la documentación de Kotlin Type-Safe Builders . Puede encontrar un ejemplo sobre cómo hacerlo para HTML