Şema genişletme
Şema genişletme'oneOf' Giriş Nesnesi

'oneOf' Giriş Nesnesi

oneOf giriş nesnesi, özel bir giriş nesnesi türüdür; giriş alanlarından tam olarak biri giriş olarak sağlanmalıdır, aksi takdirde sunucu bir doğrulama hatası döndürür. Bu davranış, GraphQL'de giriş değerleri için polimorfizm sunar ve daha temiz şemalar tasarlamamıza olanak tanır.

Örneğin, uygulamamızda bir kullanıcıyı farklı özellikler aracılığıyla almak mümkün olabilir; kullanıcı kimliği veya e-posta gibi. Bunu yapmak için normalde her özellik için ayrı bir alan oluşturmamız gerekir:

type Query {
  userByID(id: ID!): User
  userByEmail(email: String!): User
}

oneOf giriş nesnesi sayesinde, özelliklerden yalnızca birinin (ya kimlik ya da e-posta) sağlanabileceğini ve sağlanması gerektiğini bilerek, tüm özellikleri bir UserByInput oneOf giriş nesnesi aracılığıyla kabul eden tek bir user alanına sahip olabiliriz:

type Query {
  user(by: UserByInput!): User
}
 
input UserByInput @oneOf {
  id: ID
  email: String
}

(Yukarıdaki @oneOf sözdiziminin yalnızca Gato GraphQL bağlamında belgeleme amacıyla kullanıldığını lütfen unutmayın; şemayı oluşturmak için SDL —Şema Tanım Dili— kullanmamız gerekmez; eklenti, Şema Yapılandırmasındaki girdileri kullanarak şemayı PHP kodu aracılığıyla zaten oluşturur.)

Sorguda, özelliklerden tam olarak biri için giriş değerini sağlarız:

{
  tom: user(by: {
    id: 1
  }) {
    name
  }
 
  jerry: user(by: {
    email: "jerry@warnerbros.com"
  }) {
    name
  }
}

Girişe iki (veya daha fazla) değer sağlarsak:

{
  user(by: {
    id: 1
    email: "jerry@warnerbros.com"
  }) {
    name
  }
}

... sunucu bir hata döndürür:

{
  "errors": [
    {
      "message": "The oneOf input object 'UserByInput' must be provided exactly one value, but 2 have been provided",
      "extensions": {
        "type": "Query",
        "field": "user(by:{id:1,email:\"jerry@warnerbros.com\"})",
        "argument": "by"
      }
    }
  ],
  "data": {
    "user": null
  }
}

Gato GraphQL'in oneOf giriş nesnelerini nasıl kullandigi

Eklentinin bu özelliği kullandigi birkaç duruma bakalim; bunlari GraphQL şemalarimizi genisletmek için de kullanabiliriz.

Farklı özelliklerle tek bir varlık seçme

Bu, user alanındaki UserByInput girdisini kapsayan yukarıda gösterilen sorgunun genel durumudur.

Birden fazla özellikle (kimlik veya e-posta, kimlik veya slug gibi) benzersiz biçimde tanımlanabilen tek bir varlık (User, Post, PostTag vb.) almamız gerektiğinde, tüm farklı özellikleri bir oneOf giriş nesnesinde tanımlayabilir ve o varlığı almak için farklı alanların tümünü tek bir alanda toplayabiliriz.

Mutation'larda farklı veri kümelerini kabul etme

Bir mutation yaparken, giriş olarak farklı veri kümeleri kabul edebiliriz. Her farklı veri kümesi için ayrı mutation alanları sunmak yerine, bir oneOf giriş nesnesi kullanarak tek bir mutation alanı tüm olasılıkları ele alabilir.

Örneğin, loginUser mutation'u kullanıcıların bir dizi farklı yöntemle giriş yapmasını destekleyebilir: kullanıcı adı/parola, JWT token, uygulama parolaları veya diğerleri. Bu nedenle bu mutation, şu anda standart WordPress kullanıcı adı/parola doğrulamasını kabul eden ancak diğer yöntemlere de genişletilebilen LoginUserByInput oneOf Giriş Nesnesini alır:

type Mutation {
  loginUser(by: LoginUserByInput!): RootLoginUserMutationPayload!
}
 
input LoginUserByInput @oneOf {
  credentials: LoginCredentialsInput
}
 
input LoginCredentialsInput {
  usernameOrEmail: String!
  password: String!
}

Meta değerlerini sorgulama

WordPress'te meta değerlerini sorgulamak, belgelerinde açıklandığı üzere birbiriyle çakışabilecek giriş kombinasyonlarıyla karmaşık olabilir:

The following arguments can be passed in a key=>value paired array.

  • meta_query (array) – Contains one or more arrays with the following keys:
    • key (string) – Custom field key.
    • value (string|array) – Custom field value. It can be an array only when compare is 'IN', 'NOT IN', 'BETWEEN', or 'NOT BETWEEN'. You don't have to specify a value when using the 'EXISTS' or 'NOT EXISTS' comparisons in WordPress 3.9 and up. (Note: Due to bug #23268, value was required for NOT EXISTS comparisons to work correctly prior to 3.9. You had to supply some string for the value parameter. An empty string or NULL will NOT work. However, any other string will do the trick and will NOT show up in your SQL when using NOT EXISTS. Need inspiration? How about 'bug #23268'.)
    • compare (string) – Operator to test. Possible values are '=', '!=', '>', '>=', '<', '<=', 'LIKE', 'NOT LIKE', 'IN', 'NOT IN', 'BETWEEN', 'NOT BETWEEN', 'EXISTS' (only in WP >= 3.5), and 'NOT EXISTS' (also only in WP >= 3.5). Values 'REGEXP', 'NOT REGEXP' and 'RLIKE' were added in WordPress 3.7. Default value is '='.

Belgeler, value değerinin bir dize veya dizi olabileceğini ve bu değere bağlı olarak compare öğesinin bir değerler kümesini ya da başkasını kabul edebileceğini açıklar (örneğin IN yalnızca diziler için, LIKE yalnızca dizeler için). Ayrıca value zorunludur; ancak compare, EXISTS değerini alırsa bu durumda value hiç gerekli değildir.

Farklı giriş kümelerini analiz ettiğimizde, anahtara veya değere uygulanan karşılaştırmaya ve değer türüne bağlı olarak 4 olası kombinasyon olduğunu keşfedeceğiz:

  • key
  • numericValue
  • stringValue
  • arrayValue

MetaQueryCompareByInput oneOf giriş nesnesi, her giriş için olası operatörleri tanımlayan farklı Enum'larla desteklenerek bu 4 girişi ele alır. Böylece numericValue ile filtrelediğimizde GREATER_THAN operatörünü, arrayValue ile IN operatörünü ve key ile EXISTS operatörünü kullanabiliriz (ve value sağlamaya gerek yoktur).

Elde edilen GraphQL şeması (SDL kullanılarak) şu şekildedir:

type Query {
  posts(filter: PostsFilterInput): [Post!]!
}
 
input PostsFilterInput {
  metaQuery: [PostMetaQueryInput!] 
}
 
input PostMetaQueryInput {
  compareBy: MetaQueryCompareByInput!
  key: String!
}
 
type MetaQueryCompareByInput @oneOf {
  """
  Compare against the meta key
  """
  key: MetaQueryCompareByKeyInput
 
  """
  Compare against an array meta value
  """
  array: ValueMetaQueryCompareByArrayValueInput
 
  """
  Compare against a numeric meta value
  """
  numeric: ValueMetaQueryCompareByNumericValueInput
 
  """
  Compare against a string meta value
  """
  string: ValueMetaQueryCompareByStringValueInput
}
 
input MetaQueryCompareByKeyInput {
  operator: MetaQueryCompareByKeyOperatorEnum!
}
 
enum MetaQueryCompareByKeyOperatorEnum {
  EXISTS
  NOT_EXISTS
}
 
input ValueMetaQueryCompareByArrayValueInput {
  operator: MetaQueryCompareByArrayValueOperatorEnum!
  value: [AnyBuiltInScalar!]!
}
 
# AnyBuiltInScalar: Int, Float, String or Bool
scalar AnyBuiltInScalar
 
enum MetaQueryCompareByArrayValueOperatorEnum {
  BETWEEN
  IN
  NOT_BETWEEN
  NOT_IN
}
 
input ValueMetaQueryCompareByNumericValueInput {
  operator: MetaQueryCompareByNumericValueOperatorEnum!
  value: Numeric!
}
 
enum MetaQueryCompareByNumericValueOperatorEnum {
  EQUALS
  GREATER_THAN
  GREATER_THAN_OR_EQUAL
  LESS_THAN
  LESS_THAN_OR_EQUAL
  NOT_EQUALS
}
 
# Numeric: Float or Int
scalar Numeric
 
input ValueMetaQueryCompareByStringValueInput {
  operator: MetaQueryCompareByStringValueOperatorEnum!
  value: String!
}
 
enum MetaQueryCompareByStringValueOperatorEnum {
  EQUALS
  LIKE
  NOT_EQUALS
  NOT_LIKE
  NOT_REGEXP
  REGEXP
  RLIKE
}

Bu şekilde, compareBy altında hangi girişin kullanılacağını seçerek genel giriş veri kümesinin doğruluğu GraphQL tarafından doğrulanacaktır. Artık bazı meta anahtarının var olduğu gönderileri filtrelerken value sağlayamayız:

{
  posts(filter: {
    metaQuery: {
      key: "_thumbnail_id",
      compareBy:{
        key: {
          operator: EXISTS
        }
      }
    }
  }) {
    id
    title
    metaValue(key: "_thumbnail_id")
  }
}

Bir kullanıcının "beğendiği" gönderileri filtrelemek için arrayValue girdisini kullanır ve IN operatörünü seçeriz:

query FilterPostsLikedByUser($userID: ID!) {
  posts(filter: {
    metaQuery: {
      key: "liked_by_users",
      compareBy:{
        arrayValue: {
          value: $userID
          operator: IN
        }
      }
    }
  }) {
    id
    title
  }
}

İç gözlem: bir türün "oneOf" Giriş Nesnesi olup olmadığını öğrenme

isOneOf iç gözlem alanı aracılığıyla bir türün "oneOf" Giriş Nesnesi olup olmadığını öğrenebiliriz:

query IsOneOfInputObject {
  __schema {
    types {
      name
      isOneOf
    }
  }
}