Query Functions
Query FunctionsIterasi dan Manipulasi Nilai Field

Iterasi dan Manipulasi Nilai Field

Included in the “Power Extensions” bundle

Penambahan meta-direktif ke skema GraphQL, untuk mengiterasi dan memanipulasi elemen nilai dari field bertipe array dan object:

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

@underArrayItem

@underArrayItem membuat direktif bersarang diterapkan pada item tertentu dari array.

Pada query di bawah, hanya item pertama dalam array berisi nama kategori yang diubah menjadi huruf kapital:

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

...menghasilkan:

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

@underJSONObjectProperty

@underJSONObjectProperty membuat direktif bersarang menerima entri dari objek JSON yang di-query.

Direktif ini sangat berguna untuk mengekstrak dan memanipulasi bagian data yang diinginkan setelah melakukan query ke API eksternal, yang kemungkinan besar memiliki tipe generik JSONObject (seperti saat menggunakan function field _sendJSONObjectItemHTTPRequest dari ekstensi HTTP Client).

Pada query di bawah, kita memperoleh objek JSON yang berasal dari WP REST API, dan menggunakan @underJSONObjectProperty untuk memanipulasi properti type dari respons, mengubahnya menjadi huruf kapital:

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
}

Ini akan menghasilkan:

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

Selain menerima "key" untuk menunjuk ke properti yang berada di level pertama objek JSON, direktif ini juga dapat menerima "path" untuk menavigasi struktur bagian dalam objek, menggunakan . sebagai pemisah antar level.

Pada query di bawah, endpoint WP REST API untuk sebuah post menyediakan properti "title.rendered". Kita dapat menavigasi ke subelemen tersebut, dan mengubahnya menjadi title case:

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
}

Ini akan menghasilkan:

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

@underEachArrayItem

@underEachArrayItem mengiterasi item-item array dari suatu field dalam entitas yang di-query, dan mengeksekusi direktif bersarang pada masing-masing item tersebut.

Sebagai contoh, field Post.categoryNames bertipe [String]. Dengan menggunakan @underEachArrayItem, kita dapat mengiterasi nama-nama kategori dan menerapkan direktif @strTranslate pada mereka.

Pada query ini, kategori-kategori post diterjemahkan dari bahasa Inggris ke bahasa Prancis:

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

...producing:

{
  "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 dapat meneruskan indeks maupun nilai elemen yang diiterasi sebagai variabel dinamis ke direktif bersarangnya, melalui argumen direktif passIndexOnwardsAs dan passValueOnwardsAs.

Query ini mendemonstrasikan penggunaan variabel dinamis $index dan $value:

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

Hasilnya adalah:

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

@underEachArrayItem juga dapat membatasi posisi-posisi array yang akan diiterasi, melalui param filter->by, yang dapat menerima entri include atau exclude.

Query ini:

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

...menghasilkan:

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

@underEachJSONObjectProperty

@underEachJSONObjectProperty serupa dengan @underEachArrayItem, namun beroperasi pada elemen JSONObject.

Pada query ini, kita mengiterasi semua entri dalam objek JSON dan mengganti setiap entri null dengan string kosong:

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

...menghasilkan:

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

@underEachJSONObjectProperty dapat meneruskan kunci dan nilai yang sedang diiterasinya sebagai variabel dinamis ke direktif bersarangnya, melalui argumen direktif passKeyOnwardsAs dan passValueOnwardsAs.

Query ini mendemonstrasikan penggunaan variabel dinamis $key dan $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
      )
}

Hasilnya adalah:

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

@underEachJSONObjectProperty juga dapat membatasi kunci-kunci dari objek JSON yang akan diiterasi, melalui param filter->by, yang dapat menerima entri includeKeys atau excludeKeys.

Query ini:

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

...menghasilkan:

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

@objectClone

Objek JSON dapat diakses secara referensi di dalam field resolver (dan bukan dengan menyalin/menduplikasi objek). Ketika hal tersebut terjadi, saat objek JSON dimodifikasi, modifikasi ini akan terlihat oleh semua field yang mengambil objek JSON tersebut.

Ini adalah kasus dengan field Block.attributes:

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

...yang menghasilkan:

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

Pada query di bawah, sementara originalAttributes hanya mengambil atribut, transformedAttributes juga akan menerjemahkan properti content ke bahasa Prancis:

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

Namun, karena entitas Block yang di-query mereferensikan objek JSON yang sama pada originalAttributes maupun transformedAttributes, transformasi yang dilakukan oleh field yang terakhir juga akan mempengaruhi field yang pertama (hal ini tidak bergantung pada urutan kemunculannya dalam query).

Akibatnya, kedua field diterjemahkan ke bahasa Prancis:

{
  "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
            }
          }
        ]
      }
    ]
  }
}

Kita dapat menghindari masalah ini dengan menambahkan direktif @objectClone pada field transformedAttributes, sehingga modifikasi dilakukan pada objek JSON yang sudah dikloning:

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

...menghasilkan:

{
  "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
            }
          }
        ]
      }
    ]
  }
}

Contoh lebih lanjut

Pada query ini, @underEachArrayItem membungkus @underJSONObjectProperty, yang pada gilirannya membungkus @strUpperCase, mengubah properti "title.rendered" menjadi huruf kapital, untuk beberapa entri post yang diperoleh melalui WP REST API:

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
}

...menghasilkan:

{
  "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"
        }
      }
    ]
  }
}