Translate type system almost done with some TODO.

Signed-off-by: Peter Rong <PeterRong96@gmail.com>
This commit is contained in:
Peter Rong 2020-05-09 10:53:41 -07:00
parent 08539d8151
commit b5c8e80151
9 changed files with 240 additions and 0 deletions

View File

@ -1 +1,21 @@
# Context
The main goal of `Context` is to acquire global data attached to Schema. **Note that if the return value of your Resulve boored data in `Context`, you need to explictly state the lifetime of the argument.**
The following example shows how to borrow data in `Context`.
```rust
use async_graphql::*;
struct Query;
#[Object]
impl Query {
async fn borrow_from_context_data<'ctx'>(
&self,
ctx: &'ctx Context<'_>
) -> &'ctx String {
ctx.data::<String>
}
}
```

View File

@ -1 +1,34 @@
# Object
Different from `SimpleObject`, `Object` must have Resolve defined for each field in `impl`.
**A Resolve function has to be asynchronous. The first argument has to be `&self`, second being optional `Context` and followed by field arguments.**
Resolve is used to get the value of the field. You can query a database and return the result. **The return type of the function is the type of the field.** You can also return a `async_graphql::FieldResult` so to return an error if it occrs and error message will be send to query result.
<!--TODO: 全局类型的数据?-->
When querying a database, you may need a global data base connection pool, you can use `Schema::data` to attach a global data when creating Schema, the following `value_from_db` function showed how to retrive a database connection from `Context`.
```rust
use async_graphql::*;
struct MyObject {
value: i32,
}
#[Object]
impl MyObject {
async fn value(&self) -> String {
self.value.to_string()
}
async fn value_from_db(
&self,
ctx: &Context<'_'>,
#[arg(desc = "Id of object")] id: i64
) -> FieldResult<String> {
let conn = ctx.data::<DbPool>().take();
Ok(conn.query_something(id)?.name)
}
}
```

View File

@ -1 +1,22 @@
# Enum
It's easy to define an `Enum`, here we have an example:
**Async-graphql can automatically change the name of each item to GraphQL's convsion (all capitals and underscores), you can also use `name` to rename.**
```rust
use async_graphql::*;
#[Enum(desc = "One of the films in the Star Wars Trilogy")]
pub enum Episode {
#[item(desc = "Released in 1977.")]
NewHope,
#[item(desc = "Released in 1980.")]
Empire,
// rename to `AAA`
#[item(name="AAA", desc = "Released in 1983.")]
Jedi,
}
```

View File

@ -1 +1,31 @@
# InputObject
<!--Input Object and SimpleObject inconsistant space.-->
You can define an `Object` as argument, GraphQL calls it `InputObject`.
The definition of `InputObject` is similar to [SimpleObject](define_simple_object.md).
However, `InputObject` can only be used for output and `SimpleObject` can only be used as input.
`InputObject` don't need a `#[field]` for each field, every field is `InputValue`.
But you can add optional `#[field]` to add description or rename the field.
```rust
use async_graphql::*;
#[InputObject]
struct Coordinate {
latitude: f64,
#[field(desc = "...")]
longitude: f64
}
struct Mutation;
#[Object]
impl Mutation {
async fn users_at_location(&self, coordinate: Coordinate, radius: f64) -> Vec<User> {
// Writes coordination to database.
// ...
}
}
```

View File

@ -1 +1,48 @@
# Interface
`Interface` is used to abstract `Object`s with common fields.
`Async-graphql` implemented it as a wrapper.
The wrapper will forward Resolve to the `Object` that implemented this `Interface`.
Therefore, the `Object`'s fields' type, arguments must match with the `Interface`'s.
`Async-graphql` implemented auto conversion from `Object` to `Interface`, you only need to call `Into::into`.
```rust
use async_graphql::*;
struct Circle {
radius: f32,
}
#[Object]
impl Circle {
async fn area(&self) -> f32 {
std::f32::consts::PI * self.radius * self.radius
}
async fn scale(&self, s: f32) -> Shape {
Circle { radius: self.radius * s }.into()
}
}
struct Square {
width: f32,
}
#[Object]
impl Square {
async fn area(&self) -> f32 {
self.width * self.width
}
async fn scale(&self, s: f32) -> Shape {
Square { width: self.width * s }.into()
}
}
#[Interface(
field(name = "area", type = "f32"),
field(name = "scale", type = "Shape", arg(name = "s", type = "f32"))
)]
struct Shape(Circle, Square);
```

View File

@ -1 +1,18 @@
# SimpleObject
`SimpleObject` directly map all field of a struct to GraphQL object, you cannot define a Resolve function on it.
The example below defined an object `MyObject`, including field `a` and `b`. `c` will be not mapped to GraphQL as it is labelled as `#[field(skip)]`
```rust
use async_graphql::*;
#[SimpleObject]
struct MyObject {
a: i32,
b: i32,
#[field(skip)]
c: i32,
}
```

View File

@ -1 +1,44 @@
# Union
The definition of `Union` is similar to `Interface`'s, **but no field allowed.**.
The implemention is quite similar for `Async-graphql`.
From `Async-graphql`'s perspective, `Union` is a subset of `Interface`.
The following example modified the definition of `Interface` a little bit and removed fields.
```rust
use async_graphql::*;
struct Circle {
radius: f32,
}
#[Object]
impl Circle {
async fn area(&self) -> f32 {
std::f32::consts::PI * self.radius * self.radius
}
async fn scale(&self, s: f32) -> Shape {
Circle { radius: self.radius * s }.into()
}
}
struct Square {
width: f32,
}
#[Object]
impl Square {
async fn area(&self) -> f32 {
self.width * self.width
}
async fn scale(&self, s: f32) -> Shape {
Square { width: self.width * s }.into()
}
}
#[Union]
struct Shape(Circle, Square);
```

View File

@ -1 +1,28 @@
# Error handling
Resolve can return a `FieldResult`, following is the definition:
```rust
type FieldResult<T> = std::result::Result<T, FieldError>;
```
<!--TODO: 扩展标准的错误输出? -->
Any `Error` can be converted to `FieldError` and you can extend error message.
Following example shows how to parse an input string to integer. When parsing failed, it would return error and attach error message.
```rust
use async_graphql::*;
struct Query;
#[Object]
impl Query {
#[field]
async fn parse_with_extensions(&self, input: String) -> FieldResult<i32> {
Ok("234a"
.parse()
.map_err(|err| err.extend_with(|_| json!({"code": 400})))?)
}
}
```

View File

@ -1 +1,3 @@
# Type System
`Async-graphql` implemented conversion from GraphQL Object to Rust struct, and it's easy to use.