Comments (44)
I added the Any::parse_value
method in version 1.10.11
.
from async-graphql.
that looks good, similar to the containers used in Actix for json and data. Thanks!
from async-graphql.
Thank you. I am writing a new parser and will help you later. 😁
from async-graphql.
I'm not at a computer right now but will update to the latest version on monday and check things.
from async-graphql.
@sunli829 it worked! thanks
from async-graphql.
yea
from async-graphql.
I have figured it out: #[InputObject]
from async-graphql.
Yep, no luck with this so far. Any help would be appreciated and for sure will be useful for anyone else trying to implement a similar thing.
from async-graphql.
I'm going to go for Scalar implementation for this one as it seems like the only way forward at the moment. My guess is that #[InputObject]
does not like complex types and expects a set of primitives.
from async-graphql.
Maybe you can use Any
type.
from async-graphql.
Because the GraphQL's type system doesn't have a Map
type.
from async-graphql.
I'm going to go for Scalar implementation for this one as it seems like the only way forward at the moment. My guess is that
#[InputObject]
does not like complex types and expects a set of primitives.
Yes, if you want the input value to be a Map
, that's the only way, and Any
scalar is to handle that.
from async-graphql.
Well, I basically want to receive a json there and then have it converted to the Criteria object, but without extra steps like calling a method. Any idea how that could be done?
from async-graphql.
Actually, nevermind.
Here's my solution to this:
pub type JsonMap = serde_json::Map<String, serde_json::Value>;
#[derive(Clone)]
pub struct Map {
pub data: JsonMap,
}
#[Scalar]
impl ScalarType for Map {
fn type_name() -> &'static str {
"Map"
}
fn parse(value: &Value) -> Option<Self> {
match value {
Value::String(s) => match serde_json::from_str(s) {
Ok(map) => Some(Map { data: map }),
_ => None,
},
_ => None,
}
}
fn to_json(&self) -> Result<serde_json::Value> {
Ok(self.data.clone().into())
}
}
And I'm going to use a similar one to define criteria scalars
from async-graphql.
You can call ScalarType::to_json
on Any
and parse the result into Criteria
using serde_json::from_value
, I will provide a convenient way to do this later.
from async-graphql.
Actually, nevermind.
Here's my solution to this:
pub type JsonMap = serde_json::Map<String, serde_json::Value>; #[derive(Clone)] pub struct Map { pub data: JsonMap, } #[Scalar] impl ScalarType for Map { fn type_name() -> &'static str { "Map" } fn parse(value: &Value) -> Option<Self> { match value { Value::String(s) => match serde_json::from_str(s) { Ok(map) => Some(Map { data: map }), _ => None, }, _ => None, } } fn to_json(&self) -> Result<serde_json::Value> { Ok(self.data.clone().into()) } }
And I'm going to use a similar one to define criteria scalars
Yes, that's the way to do it.😁
from async-graphql.
If you wait for me for 5 minutes, I will add a method to Any, which will make it easier for you. I don't think it is necessary to add a Map type.
from async-graphql.
@sunli829 sure, but then the method definition is going to turn from async fn records(&self, criteria: Criteria, start: i64, skip: i64, order: SortCriteria)
to
async fn records(&self, criteria: Any, start: i64, skip: i64, order: Any)
Correct? And that would mean I'd need to manually convert those each time to whatever type I need.
from async-graphql.
Yes, you have to do it manually every time, because GraphQL doesn't have a Map
type. Unless I extend the GraphQL, which leads to other compatibility problems, I don't think it's worth the trouble.😁
from async-graphql.
@sunli829 great, I'll look into it! I'm curious why fn gql_value_to_json_value(value: &Value) -> serde_json::Value {
is not exposed, that would make implementing types like Criteria
via Scalar a matter of simple derive macro possibly.
from async-graphql.
You can call Any::to_json directly, so there's no need to expose it.
from async-graphql.
@sunli829 yeah, but that only works with an instance of Any as it's not a static method, so I'd have to reimplement this for any other type should the need arise. But I think I have a good idea how to use 'Any' to my advantage now. Thanks!
from async-graphql.
I guess I can implement a CriteriaInput object, that would contain 'Any' and have it convert using a From
/ Into
to whatever I need.
from async-graphql.
@sunli829 is there any way currently to support something like that
#[serde(transparent)]
pub struct CriteriaInput {
pub data: Any
}
So that I could have a custom input object, but it would actually resolve to Any
for graphql instead of {"data": Any...}
.
Because then I can implement my helper From/Into conversions for CriteriaInput and then my whole use-case would be more eloquent than doing something like:
let criteria: Criteria = any_val.parse_value
which is going to be quite repetitive.
I guess you know what "transparent" does, it just basically deserilizes things into data
directly.
from async-graphql.
You've given me some inspiration, and I'm going to add a Json
scalar type.😁
from async-graphql.
@ruseinov Look at this Json scalar, I think it's a little easier to use.
from async-graphql.
looking into it
from async-graphql.
@sunli829 One think that'd be nice to have is Clone
.
#[derive(Clone)]
pub struct RecordTypeInput {
pub name: String,
pub schema: Json<JsonMap>,
}
is not possible now
from async-graphql.
It does not block me, however might be a nice to have. I leave it up to you to see if it makes sense.
from async-graphql.
I have found another curious issue, however:
This works fine
async fn create_record_type(
&self,
ctx: &Context<'_>,
record_type: crate::model::RecordTypeInput,
)
With that input:
mutation createRecordType ($recordType: RecordTypeInput) {
createRecordType (recordType: $recordType) {
...
}
}
where variables are:
{
"recordType": {
"name": "test",
"schema": {
"$schema": "http://json-schema.org/draft-07/schema",
"$id": "http://example.com/example.json",
"type": "object",
"title": "The Root Schema",
"description": "The root schema comprises the entire JSON document.",
"default": {},
"additionalProperties": true,
"required": [
"id"
],
"properties": {
"id": {
"$id": "#/properties/id",
"type": "integer",
"title": "The Id Schema",
"description": "An explanation about the purpose of this instance.",
"default": "",
"examples": [
1
]
}
}
}
}
}
So the schema is plain JSON.
However, when I'm trying to use a JSON type directly like this:
async fn records(
&self,
criteria: Json<Criteria>,
start: i64,
skip: i64,
order: Json<SortCriteria>,
) -> FieldResult<Vec<Record>> {
info!("{:?}", criteria.0);
info!("{:?}", order.0);
Ok(Vec::new())
}
query records ($criteria: JSON, $start: Int, $skip: Int, $order: JSON) {
records (criteria: $criteria, start: $start, skip: $skip, order: $order) {
id
data
createdAt
updatedAt
}
}
with
{
"criteria": {
"name": {"=": 1}
},
"start": 0,
"skip": 0,
"order": {}
}
yields
{
"errors": [
{
"message": "Expected type \"JSON!\", found {name: {=: 1}}.",
"locations": [
{
"line": 2,
"column": 5
}
]
}
]
}
However it works if I pass an empty object to criteria :/
from async-graphql.
@ruseinov Can you provide a minimum test case that can be run?😁
from async-graphql.
I'll do that, but basically if you try using the Json scalar to wrap a struct and use that as a parameter in, say, a query endpoint - that only works with an empty object passed to that parameter. Otherwise there is an issue. I'll try to reproduce it as an isolated test case
from async-graphql.
Because I tried, but I couldn't reproduce the problem. 😣
from async-graphql.
I can give you what I have now, but I'll def dig into it more and get you a test:
#[Object]
impl QueryRoot {
async fn records(
&self,
criteria: Json<Criteria>,
start: i64,
skip: i64,
order: Json<SortCriteria>,
) -> FieldResult<Vec<Record>> {
info!("{:?}", criteria.0);
info!("{:?}", order.0);
Ok(Vec::new())
}
}
// you can use String, String map for simplicity, it does not seem to matter
pub struct Criteria {
pub value: HashMap<String, Vec<Criterion>>,
}
and the test code:
curl --location --request POST 'localhost:8089/graphql' \
--header 'Content-Type: application/json' \
--data-raw '{"query":"query records ($criteria: JSON, $start: Int, $skip: Int, $order: JSON) {\n records (criteria: $criteria, start: $start, skip: $skip, order: $order) {\n id\n data\n createdAt\n updatedAt\n }\n}","variables":{"criteria":{"name":{"=":1}},"start":0,"skip":0,"order":{}}}'
from async-graphql.
@ruseinov How is Criterion defined?
from async-graphql.
#[derive(Serialize, Deserialize, Debug)]
pub struct Criterion {
pub value: Value,
pub operator: Operator,
}
#[derive(Deserialize, Debug)]
pub enum Operator {
Equal,
NotEqual,
LessThan,
GreaterThan,
Like,
IncorrectValue,
}
impl From<&str> for Operator {
fn from(str: &str) -> Self {
match str {
">" => GreaterThan,
"<" => LessThan,
"=" => Equal,
"!=" => NotEqual,
"like" => Like,
_ => IncorrectValue,
}
}
}
impl<'de> Visitor<'de> for Operator {
type Value = Operator;
fn expecting(&self, formatter: &mut Formatter) -> fmt::Result {
formatter.write_str("An operator, e.g. '>', '<', '=', '!=', 'like'")
}
fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
where
E: de::Error,
{
let op = Operator::from(v);
match op {
IncorrectValue => Err(de::Error::invalid_value(Unexpected::Str(v), &self)),
_ => Ok(op),
}
}
fn visit_borrowed_str<E>(self, v: &'de str) -> Result<Self::Value, E>
where
E: de::Error,
{
self.visit_str(v)
}
fn visit_string<E>(self, v: String) -> Result<Self::Value, E>
where
E: de::Error,
{
self.visit_str(v.as_str())
}
}
from async-graphql.
Where Value is serde_json::Value
from async-graphql.
Your input Json
is incorrect, I am going to change the return value of ScalarType::parse
to Result
, so you can see the correct error message.
from async-graphql.
I created a new issue to track this. #70
from async-graphql.
@ruseinov Please upgrade to version 1.11.1 to see the real error message. 😁
from async-graphql.
You can call Any::to_json directly, so there's no need to expose it.
Once the parser and the Any type is under our control we can add conversion to and from serde_json::Value
.
from async-graphql.
@nicolaiunrein Did you also use the Any
type? Now it can be replaced with Json
, which is more convenient.
from async-graphql.
@nicolaiunrein Then help to see if this code is still needed?😁
impl Any {
/// Parse this `Any` value to T by `serde_json`.
pub fn parse_value<T: DeserializeOwned>(&self) -> std::result::Result<T, serde_json::Error> {
serde_json::from_value(self.to_json().unwrap())
}
}
impl<T> From<T> for Any
where
T: Into<Value>,
{
fn from(value: T) -> Any {
Any(value.into())
}
}
from async-graphql.
@ruseinov Is the input json format incorrect?
from async-graphql.
Related Issues (20)
- Has anyone does any benchmarks because im getting extremely poor results and I do not know why? HOT 8
- Get mutable referenece to the global data defined in the `Context` or `Schema` HOT 1
- Confusing `unused_mut` warning in `#[Object]` HOT 8
- How to handle both directions of one-to-many relation in federated graph
- Question: How to get server to send ping messages on subscriptions? HOT 2
- Parsing multiple operations in a file HOT 1
- Non nullable variables should allow default values HOT 3
- Object with single skipped field but with ComplexObject HOT 2
- As using proxy type
- Using flatten inside an impl with no other fields causes a compile error
- Subscription with MPSC receiver in context data
- Reduce clippy noise from #[Object] macro HOT 2
- Guard trait lifetime HOT 1
- Using generics with both SimpleObject and InputObject as field in output type fails HOT 1
- Subscription Authentication
- Stack overflow after upgrade to 7.0.2 HOT 5
- Does async-graphql validate responses?
- Error reading data from ExtensionContext after upgrade to 7.0.3 HOT 1
- Create a general error formateer
- Allow flatten on arguments
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from async-graphql.