Comment puis-je créer une liste imbriquée à l'aide d'un modèle de générateur?

Nov 30 2020

J'essaie de créer un générateur de requêtes pour la syntaxe GraphQL, en utilisant un modèle de générateur. Je l'ai déjà fait pour la partie filtrage:

Je veux programatically faire une façon de dire quelles sont les données que je veux revenir de la requête. (REMARQUE: avant que la titlepartie de la requête ne soit codée en dur dans le QueryBuilder.

Donc, pour cela, j'ai créé une classe appelée Entity qui a une liste d'elle-même comme attribut.

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(" ") + "}"
        }
    }
}

Et je l'ai fait fonctionner. Mais pour construire la structure. puis je dois ajouter à la liste et "visiter" la liste de l'entité pour visiter les entités de cette liste.

Par exemple, si je souhaite créer cette requête:

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

Ensuite, je dois descendre de 2 niveaux dans les couches de l'entité, et comme je le fais maintenant, mon code devient très large.

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)
}

Je pensais donc utiliser un modèle de constructeur. Ou quelque chose d'autre qui sera plus intelligent.

Merci d'avance pour votre aide et bonne journée.

BTW: J'utilise les énumérations suivantes:

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"),
}

Et le reste de mon code ressemble à ceci:

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"))
        }
    }

Réponses

1 Pelocho Dec 01 2020 at 10:48

Jetez un œil à la documentation de Kotlin Type-Safe Builders . Vous pouvez trouver un exemple sur la façon de le faire pour HTML