query JobQuery {
objects {
getJob(objectId: "sqvJTrN9no") {
title
company {
name
}
countries
}
}
}
{
"data": {
"objects": {
"getJob": {
"title": "Sales Assistant",
"company": {
"name": "Gulfstream Distribution"
},
"countries": [
{
"__type": "Pointer",
"className": "Country",
"objectId": "lZ15JnGq7h"
}
]
}
}
}
}
query JobQuery {
objects {
getJob(objectId: "sqvJTrN9no") {
title
company {
name
}
countries
}
findCountry(where: { objectId: { _in: ["lZ15JnGq7h"]} }) {
results {
name
}
}
}
}
{
"data": {
"objects": {
"getJob": {
"title": "Sales Assistant",
"company": {
"name": "Gulfstream Distribution"
},
"countries": [
{
"__type": "Pointer",
"className": "Country",
"objectId": "lZ15JnGq7h"
}
]
},
"findCountry": {
"results": [
{
"name": "Azerbaijan"
}
]
}
}
}
}
It works pretty much like you expect if you have a field that is a Pointer or a Relation. Since it is an Array, and an Array can have any kind of item, the Parse GraphQL Server does not know beforehand what kind of object you have there and can't make its fields automatically available. We can think about some solutions for this. Maybe allow the developer to specify the type of the array? @Moumouls @omairvaiyani @douglasmuraoka
One option is to introduce this into the Parse GraphQL Config:
{
...
classConfigs: [
{
className: "Country",
type: {
pointerArrays: [ { field: "cities", className: "City" }, { field: "states", className: "State" } ]
}
}
]
...
}
Longer-term would be to introduce this knowledge directly into the database schema, although I've not assessed the drawbacks yet.
@omairvaiyani I like this idea. I am only wondering if this information could be also useful for Parse Server overall. So maybe having this information in the parse server schema would be better?
@davimacedo it certainly would be. I understand that the Parse Server _Schema class stores the field type as "array", regardless of whether the array stores regular POJOS, or Parse pointers. The source code also freely allows pointers to be changed from one class to another. If we did introduce a specific type, it would result in stricter behaviour, possibly classified as a breaking change.
A way around this would be to allow the current type "array" to continue behaving exactly as it does today, whilst allowing those who wish to upgrade to store the type as e.g. "array$_User", where the $ would signal a bifurcation in the SchemaController.
This migration could be sped up using a simple code snippet that runs through an active database (at runtime), and updates the _Schema class with extracted array pointer classes where available.
We could also leave the Array data type as it is now (to avoid the breaking change or any migration) and just add a metadata specifying it is a pointer Array (like we did in the required fields). What do you think? Is this something that you would be willed to tackle?
We could also have a huge problem with multi pointers in an Array (ex: [User, Role, Product]).
I think the solution is to implement an InlineFragment strategy: GraphQL InlineFragment
Tasks:
Union Type: ArrayResult, add all Classes to the UnionType and a ScalarObjectType: Implement Union TypeInlineFragment strategyInlineFragment on Array ResolversExample:
query JobQuery {
objects {
getJob(objectId: "sqvJTrN9no") {
title
company {
name
}
countries {
... on Country {
name
}
}
}
}
Multi Pointer example:
query JobQuery {
objects {
getJob(objectId: "sqvJTrN9no") {
title
company {
name
}
relatedTo {
... on Country {
name
objectId
}
... on ProfessionalCode {
readableName
code
objectId
}
}
}
}
@Moumouls thanks for the suggestion. I think it is really the best way to solve this issue! I will take a look in your PR and revert my feedback.
@murshudov on the master branch you can test the new powerful InlineFragment feature, example here:
{
objects {
getCountry(objectId: "8dDDVCHN2q") {
objectId
name
companies {
... on CompanyClass {
objectId
name
employees {
... on EmployeeClass {
objectId
name
}
}
teams {
... on TeamClass {
objectId
name
employees {
... on EmployeeClass {
objectId
name
country {
objectId
name
}
}
}
}
}
}
}
}
}
}
{
"data": {
"objects": {
"getCountry": {
"objectId": "8dDDVCHN2q",
"name": "imACountry",
"companies": [
{
"objectId": "jk2pZjsDsv",
"name": "imACompany",
"employees": [
{
"objectId": "7KBQ8bOpZA",
"name": "imAnEmployee"
}
],
"teams": [
{
"objectId": "dRiSUajdpq",
"name": "imATeam",
"employees": [
{
"objectId": "7KBQ8bOpZA",
"name": "imAnEmployee",
"country": {
"objectId": "8dDDVCHN2q",
"name": "imACountry"
}
}
]
}
]
}
]
}
}
}
}
Don't be afraid of performance when diving into objects, this example was executed in 17ms (macbook pro i7 15" 2016), with only one call REST Parse Server.
@Moumouls and others, thank you very much for the great effort and awesome work 馃憤
Most helpful comment
@Moumouls and others, thank you very much for the great effort and awesome work 馃憤