Query Functions
Query FunctionsIteration und Manipulation von Feldwerten

Iteration und Manipulation von Feldwerten

Included in the “Power Extensions” bundle

Hinzufügen von Meta-Direktiven zum GraphQL-Schema, um die Wertelemente von Array- und Objektfeldern zu iterieren und zu manipulieren:

  1. @underArrayItem
  2. @underJSONObjectProperty
  3. @underEachArrayItem
  4. @underEachJSONObjectProperty
  5. @objectClone

@underArrayItem

@underArrayItem sorgt dafür, dass die verschachtelte Direktive auf ein bestimmtes Element des Arrays angewendet wird.

In der folgenden query wird nur das erste Element des Arrays mit den Kategorienamen in Großbuchstaben umgewandelt:

query {
  posts {
    categoryNames
      @underArrayItem(index: 0)
        @strUpperCase
  }
}

...was folgendes erzeugt:

{
  "data": {
    "posts": {
      "categoryNames": [
        "NEWS",
        "sports"
      ]
    }
  }
}

@underJSONObjectProperty

@underJSONObjectProperty sorgt dafür, dass die verschachtelte Direktive einen Eintrag aus dem abgefragten JSON-Objekt erhält.

Diese Direktive ist besonders nützlich, um nach der Abfrage einer externen API einen gewünschten Datensatz zu extrahieren und zu manipulieren, da diese API sehr wahrscheinlich einen generischen JSONObject-Typ hat (wie bei der Verwendung des Funktionsfeldes _sendJSONObjectItemHTTPRequest aus der HTTP Client-Erweiterung).

In der folgenden query erhalten wir ein JSON-Objekt von der WP REST API und verwenden @underJSONObjectProperty, um die type-Eigenschaft der Antwort zu manipulieren und in Großbuchstaben umzuwandeln:

query {
  postData: _sendJSONObjectItemHTTPRequest(input: {
    url: "https://newapi.getpop.org/wp-json/wp/v2/posts/1/?_fields=id,type,title,date"
  })
    @underJSONObjectProperty(by: { key: "type" })
      @strUpperCase
}

Dies wird folgendes erzeugen:

{
  "data": {
    "postData": {
      "id": 1,
      "date": "2019-08-02T07:53:57",
      "type": "POST",
      "title": {
        "rendered": "Hello world!"
      }
    }
  }
}

Neben dem Empfang eines "key", um auf eine Eigenschaft der ersten Ebene des JSON-Objekts zu zeigen, kann diese Direktive auch einen "path" erhalten, um innerhalb der inneren Struktur des Objekts zu navigieren, wobei . als Trennzeichen zwischen den Ebenen verwendet wird.

In der folgenden query liefert der WP REST API-Endpunkt für einen Beitrag die Eigenschaft "title.rendered". Wir können zu diesem tatsächlichen Unterelement navigieren und es in Title Case umwandeln:

query {
  postData: _sendJSONObjectItemHTTPRequest(input: {
    url: "https://newapi.getpop.org/wp-json/wp/v2/posts/1/?_fields=id,type,title,date"
  })
    @underJSONObjectProperty(by: { path: "title.rendered" })
      @strTitleCase
}

Dies wird folgendes erzeugen:

{
  "data": {
    "postData": {
      "id": 1,
      "date": "2019-08-02T07:53:57",
      "type": "post",
      "title": {
        "rendered": "HELLO WORLD!"
      }
    }
  }
}

@underEachArrayItem

@underEachArrayItem iteriert über die Array-Elemente eines bestimmten Feldes der abgefragten Entität und führt die verschachtelte(n) Direktive(n) auf jedem von ihnen aus.

Zum Beispiel ist das Feld Post.categoryNames vom Typ [String]. Mit @underEachArrayItem können wir die Kategorienamen iterieren und die Direktive @strTranslate auf sie anwenden.

In dieser query werden die Beitragskategorien vom Englischen ins Französische übersetzt:

query {
  posts {
    id
    title
    categoryNames
      @underEachArrayItem
        @strTranslate(
          from: "en",
          to: "fr"
        )
  }
}

...was folgendes erzeugt:

{
  "data": {
    "posts": [
      {
        "id": 662,
        "title": "Explaining the privacy policy",
        "categoryNames": [
          "Non classé"
        ]
      },
      {
        "id": 28,
        "title": "HTTP caching improves performance",
        "categoryNames": [
          "Avancé"
        ]
      },
      {
        "id": 25,
        "title": "Public or Private API mode, for extra security",
        "categoryNames": [
          "Ressource",
          "Blog",
          "Avancé"
        ]
      }
    ]
  }
}

@underEachArrayItem kann sowohl den Index als auch den Wert des iterierten Elements als dynamische Variable an seine verschachtelte(n) Direktive(n) weitergeben, über die Direktiv-Args passIndexOnwardsAs und passValueOnwardsAs.

Diese query demonstriert die Verwendung der dynamischen Variablen $index und $value:

{
  _echo(value: ["first", "second", "third"])
    @underEachArrayItem(
      passIndexOnwardsAs: "index"
      passValueOnwardsAs: "value"
    )
      @applyField(
        name: "_echo"
        arguments: {
          value: {
            index: $index,
            value: $value
          }
        },
        setResultInResponse: true
      )
}

Das Ergebnis ist:

{
  "data": {
    "_echo": [
      {
        "index": 0,
        "value": "first"
      },
      {
        "index": 1,
        "value": "second"
      },
      {
        "index": 2,
        "value": "third"
      }
    ]
  }
}

@underEachArrayItem kann auch die Positionen des Arrays einschränken, über die iteriert werden soll, über den Param filter->by, der entweder den Eintrag include oder exclude akzeptieren kann.

Diese query:

{
  including: _echo([
    "first",
    "second",
    "third"
  ])
    @underEachArrayItem(
      filter: {
        by: {
          include: [0, 2]
        }
      }
    )
      @strUpperCase
 
  excluding: _echo([
    "first",
    "second",
    "third"
  ])
    @underEachArrayItem(
      filter: {
        by: {
          exclude: [0, 2]
        }
      }
    )
      @strUpperCase
}

...erzeugt:

{
  "data": {
    "including": [
      "FIRST",
      "second",
      "THIRD"
    ],
    "excluding": [
      "first",
      "SECOND",
      "third"
    ]
  }
}

@underEachJSONObjectProperty

@underEachJSONObjectProperty ist ähnlich wie @underEachArrayItem, arbeitet jedoch auf JSONObject-Elementen.

In dieser query iterieren wir alle Einträge im JSON-Objekt und ersetzen jeden null-Eintrag durch einen leeren String:

{
  _echo(
    value: {
      first: "hello",
      second: "world",
      third: null
    }
  )
    @underEachJSONObjectProperty
      @default(value: "")
}

...was folgendes erzeugt:

{
  "data": {
    "_echo": {
      "first": "hello",
      "second": "world",
      "third": ""
    }
  }
}

@underEachJSONObjectProperty kann den Schlüssel und den Wert, über den es iteriert, als dynamische Variable an seine verschachtelte(n) Direktive(n) weitergeben, über die Direktiv-Args passKeyOnwardsAs und passValueOnwardsAs.

Diese query demonstriert die Verwendung der dynamischen Variablen $key und $value:

{
  _echo(value: {
    uno: "first",
    dos: "second",
    tres: "third"
  })
    @underEachJSONObjectProperty(
      passKeyOnwardsAs: "key"
      passValueOnwardsAs: "value"
    )
      @applyField(
        name: "_echo"
        arguments: {
          value: {
            key: $key,
            value: $value
          }
        },
        setResultInResponse: true
      )
}

Das Ergebnis ist:

{
  "data": {
    "_echo": {
      "uno": {
        "key": "uno",
        "value": "first"
      },
      "dos": {
        "key": "dos",
        "value": "second"
      },
      "tres": {
        "key": "tres",
        "value": "third"
      }
    }
  }
}

@underEachJSONObjectProperty kann auch die Schlüssel des JSON-Objekts einschränken, über die iteriert werden soll, über den Param filter->by, der entweder den Eintrag includeKeys oder excludeKeys akzeptieren kann.

Diese query:

{
  includingKeys: _echo(value: {
    uno: "first",
    dos: "second",
    tres: "third"
  })
    @underEachJSONObjectProperty(
      filter: {
        by: {
          includeKeys: ["uno", "tres"]
        }
      }
    )
      @strUpperCase
 
  excludingKeys: _echo(value: {
    uno: "first",
    dos: "second",
    tres: "third"
  })
    @underEachJSONObjectProperty(
      filter: {
        by: {
          excludeKeys: ["uno", "tres"]
        }
      }
    )
      @strUpperCase
}

...erzeugt:

{
  "data": {
    "includingKeys": {
      "uno": "FIRST",
      "dos": "second",
      "tres": "THIRD"
    },
    "excludingKeys": {
      "uno": "first",
      "dos": "SECOND",
      "tres": "third"
    }
  }
}

@objectClone

JSON-Objekte können in den Field-Resolvern per Referenz (und nicht per Kopie/Duplikat des Objekts) aufgerufen werden. In diesem Fall ist die Änderung, wenn das JSON-Objekt geändert wird, für alle Felder sichtbar, die dieses JSON-Objekt abrufen.

Dies ist der Fall beim Feld Block.attributes:

{
  posts {
    blocks(filterBy: { include: "core/heading" } ) {
      attributes
    }
  }
}

...das folgendes erzeugt:

{
  "data": {
    "posts": [
      {
        "blocks": [
          {
            "attributes": {
              "content": "Image Block (Full width)",
              "level": 2
            }
          },
          {
            "attributes": {
              "content": "Gallery Block",
              "level": 2
            }
          }
        ]
      }
    ]
  }
}

In der folgenden query ruft originalAttributes lediglich die Attribute ab, während transformedAttributes zusätzlich die content-Eigenschaft ins Französische übersetzt:

{
  posts {
    blocks(filterBy: { include: "core/heading" } ) {
      originalAttributes: attributes
      transformedAttributes: attributes
        @underJSONObjectProperty(by: { key: "content" })
          @strTranslate(to: "fr")
    }
  }
}

Da die abgefragte Block-Entität jedoch in beiden Feldern originalAttributes und transformedAttributes auf dasselbe JSON-Objekt verweist, wirken sich die von letzterem Feld vorgenommenen Transformationen auch auf ersteres aus (dies ist unabhängig von der Reihenfolge, in der sie in der query erscheinen).

Dadurch werden beide Felder ins Französische übersetzt:

{
  "data": {
    "posts": [
      {
        "blocks": [
          {
            "originalAttributes": {
              "content": "Bloc d'image (pleine largeur)",
              "level": 2
            },
            "transformedAttributes": {
              "content": "Bloc d'image (pleine largeur)",
              "level": 2
            }
          },
          {
            "originalAttributes": {
              "content": "Bloc Galerie",
              "level": 2
            },
            "transformedAttributes": {
              "content": "Bloc Galerie",
              "level": 2
            }
          }
        ]
      }
    ]
  }
}

Wir können dieses Problem vermeiden, indem wir die Direktive @objectClone zum Feld transformedAttributes hinzufügen, sodass die Änderungen an einem geklonten JSON-Objekt vorgenommen werden:

{
  posts {
    blocks(filterBy: { include: "core/heading" } ) {
      originalAttributes: attributes
      transformedAttributes: attributes
        @objectClone
        @underJSONObjectProperty(by: { key: "content" })
          @strTranslate(to: "fr")
    }
  }
}

...was folgendes erzeugt:

{
  "data": {
    "posts": [
      {
        "blocks": [
          {
            "originalAttributes": {
              "content": "Image Block (Full width)",
              "level": 2
            },
            "transformedAttributes": {
              "content": "Bloc d'image (pleine largeur)",
              "level": 2
            }
          },
          {
            "originalAttributes": {
              "content": "Gallery Block",
              "level": 2
            },
            "transformedAttributes": {
              "content": "Bloc Galerie",
              "level": 2
            }
          }
        ]
      }
    ]
  }
}

Weitere Beispiele

In dieser query umschließt @underEachArrayItem die @underJSONObjectProperty, die ihrerseits @strUpperCase umschließt und die Eigenschaft "title.rendered" für die mehreren Beitragseinträge, die über die WP REST API abgerufen wurden, in Großbuchstaben umwandelt:

query {
  postListData: _sendJSONObjectCollectionHTTPRequest(
    url: "https://newapi.getpop.org/wp-json/wp/v2/posts/?per_page=3&_fields=id,type,title,date"
  )
    @underEachArrayItem
      @underJSONObjectProperty(by: { path: "title.rendered" })
        @strUpperCase
}

...was folgendes erzeugt:

{
  "data": {
    "postListData": [
      {
        "id": 1692,
        "date": "2022-04-26T10:10:08",
        "type": "post",
        "title": {
          "rendered": "MY BLOGROLL"
        }
      },
      {
        "id": 1657,
        "date": "2020-12-21T08:24:18",
        "type": "post",
        "title": {
          "rendered": "A TALE OF TWO CITIES – TEASER"
        }
      },
      {
        "id": 1499,
        "date": "2019-08-08T02:49:36",
        "type": "post",
        "title": {
          "rendered": "COPE WITH WORDPRESS: POST DEMO CONTAINING PLENTY OF BLOCKS"
        }
      }
    ]
  }
}