您现在的位置是:主页 > 币圈资讯 >

SubQuery开发者指南丨GraphQL 架构(GraphQL Schema)

2021-09-27 15:48币圈资讯 人已围观

简介 定义实体(Defining Entities)   schema.graphql 文件定义了各种 GraphQL 架构。 由于 GraphQL 查询语言的工作方式,模式文件...

定义实体(Defining Entities)

 

schema.graphql 文件定义了各种 GraphQL 架构。 由于 GraphQL 查询语言的工作方式,模式文件本质上决定了来自 SubQuery 的数据的形状。 要了解有关如何使用 GraphQL 架构语言编写的更多信息,我们建议查看架构和类型(https://graphql.org/learn/schema/#type-language)

 

重要提示:当您对架构文件(schema file)进行任何更改时,请确保使用 yarn codegen 代码来生成重新生成类型目录。

 

实体(Entities)

 

每个实体(entity)都必须定义它的必填字段id与ID的类型!它用作主键,并且在所有相同类型的实体中是唯一的。

 

实体(entity)中不可为空的字段由“ ! ”来表示。 请看下面的例子:

 

type Example @entity {   id: ID! # id field is always required and must look like this   name: String! # This is a required field   address: String # This is an optional field }

 

支持的标量和类型(Supported scalars and types)

 

我们目前支持流动标量类型:

• ID

• Int

• String

• BigInt

• Date

• Boolean

• <EntityName>   用于嵌套关系实体,您可以使用定义的实体名称作为字段之一。 请参阅实体关系(https://doc.subquery.network/create/graphql.html#entity-relationships)。

• JSON 也可以存储结构化数据,请参阅 JSON 类型(https://doc.subquery.network/create/graphql.html#json-type)。

 

按非主键字段进行索引(Indexing by non-primary-key field)

 

为了提高查询性能,只需在非主键字段上执行 @index 注释即可索引实体字段。

 

但是,我们不允许用户在任何 JSON 对象上添加 @index 注释。 默认情况下,索引会自动添加到外键和数据库中的 JSON 字段,但只是为了增强查询服务性能。

 

这有一个例子。

 

type User @entity {   id: ID!   name: String! @index(unique: true) # unique can be set to true or false   title: Title! # Indexes are automatically added to foreign key field  }

type Title @entity {   id: ID!     name: String! @index(unique:true) }

 

假设我们知道这个用户的名字,但我们不知道确切的 id 值,我们可以在名称字段后面添加@index,而不是提取所有用户然后按名称过滤。 这使得查询速度更快,我们还可以添加 unique: true 以确保唯一性。

 

如果字段不唯一,则最大结果集为 100

 

当代码生成运行时,这将自动在 User 模型下创建一个 getByName,然后外键字段 title 将创建一个 getByTitleId 方法,这两者都可以在映射函数中直接访问。

 

/* Prepare a record for title entity */ INSERT INTO titles (id, name) VALUES ('id_1', 'Captain')

 

// Handler in mapping function import {User} from "../types/models/User" import {Title} from "../types/models/Title"

const jack = await User.getByName('Jack Sparrow');

const captainTitle = await Title.getByName('Captain');

const pirateLords = await User.getByTitleId(captainTitle.id); // List of all Captains

 

实体关系(Entity Relationships)

 

一个实体(entity)通常与其他实体(entity)有嵌套关系。 默认情况下,将字段值设置为另一个实体(entity)名称将定义这两个实体(entity)之间的一对一关系。

 

可以使用以下示例配置不同的实体(entity)关系(一对一、一对多和多对多)。

 

  • 一对一关系(One-to-One Relationships)

  •  

    当只有一个实体映射到另一个实体时,一对一关系是默认的。

     

    例子:一本护照只属于一个人,一个人只有一本护照(在这个例子中):

     

    type Person @entity {   id: ID! }

    type Passport @entity {   id: ID!   owner: Person! }

     

    或者

     

    type Person @entity {   id: ID!   passport: Passport! }

    type Passport @entity {   id: ID!   owner: Person! }

     

  • 一对多关系(One-to-Many relationships)

  •  

    您可以使用方括号表示一个字段类型包括多个实体。

     

    示例:一个人可以拥有多个帐户。

     

    type Person @entity {   id: ID!   accounts: [Account]  }

    type Account @entity {   id: ID!   publicAddress: String! }

     

  • 多对多关系(Many-to-Many relationships)

  •  

    多对多关系可以通过实现一个映射实体(mapping entity)来连接其他两个实体(entity)来实现。

     

    示例:每个人都是多个组 (PersonGroup) 的一部分,并且组有多个不同的人 (PersonGroup)。

     

    type Person @entity {   id: ID!   name: String!   groups: [PersonGroup] }

    type PersonGroup @entity {   id: ID!   person: Person!   Group: Group! }

    type Group @entity {   id: ID!   name: String!   persons: [PersonGroup] }

     

    此外,可以在中间实体(entity)的多个字段中创建同一实体(entity)的连接。

     

    例如,一个账户可以实现多次转账,每次转账都有一个源账户和目的地账户。

     

    这将通过 Transfer 层在两个 Accounts(from 和 to)之间建立双向关系。

     

    type Account @entity {   id: ID!   publicAddress: String! }

    type Transfer @entity {   id: ID!   amount: BigInt   from: Account!   to: Account! }

     

    反向查找(Reverse Lookups)

     

    为了使一个实体(entity)能够反向查询到一个关系,请将 @derivedFrom 附加到该字段并指向另一个实体(entity)的反向查找字段。

     

    这会在可以查询的实体(entity)上创建一个虚拟字段。

     

    通过将 sentTransfer 或 receivedTransfer 设置为从相应的 from 或 to 字段得出的值,可以从帐户实体中访问“来自” 账户的转移。

     

    type Account @entity {   id: ID!   publicAddress: String!   sentTransfers: [Transfer] @derivedFrom(field: "from")   receivedTransfers: [Transfer] @derivedFrom(field: "to") }

    type Transfer @entity {   id: ID!   amount: BigInt   from: Account!   to: Account! }

     

    JSON 类型(JSON type)

     

    我们支持将数据保存为 JSON 类型(JSON type),这是一种存储结构化数据的快速方式。 我们将自动生成相应的 JSON 接口来查询这些数据,并节省您定义和管理实体(entities)的时间。

     

    我们建议用户在以下场景中使用 JSON 类型:

     

    • 在单个字段中存储结构化数据比创建多个单独的实体(entities)更易于管理。

     

    • 保存任意键/值用户首选项(其中值可以是布尔值、文本或数字,并且不用为不同的数据类型设置单独的列)

     

    • 架构是不稳定的并且经常变化

     

    定义 JSON 指令(Define JSON directive)

     

    通过在实体中添加 jsonField 注释,将该属性定义为 JSON 类型。 这将自动为您项目中 types/interfaces.ts 下的所有 JSON 对象生成接口,您也可以在映射函数中访问它们。

     

    与实体不同,jsonField 指令对象不需要任何 id 字段。 JSON 对象还可以与其他 JSON 对象嵌套。

     

    type AddressDetail @jsonField {   street: String!   district: String! }

    type ContactCard @jsonField {   phone: String!   address: AddressDetail # Nested JSON }

    type User @entity {   id: ID!    contact: [ContactCard] # Store a list of JSON objects }

     

    查询 JSON 字段(Querying JSON fields)

     

    使用 JSON 类型的缺点是过滤时对查询效率的影响很小,因为每次执行文本搜索时,都是针对整个实体来进行的。

     

    但是,在我们的查询服务中,影响仍然可以接受。 下面是一个示例,说明如何在 GraphQL 查询中对 JSON 字段使用 contains 运算符来查找拥有包含“0064”的电话号码的前 5 个用户。

     

    #To find the the first 5 users own phone numbers contains '0064'.

    query{   user(     first: 5,     filter: {       contactCard: {         contains: [{ phone: "0064" }]     } }){     nodes{       id       contactCard     }   } }

    Tags:

    标签云

    站点信息