Graphql-ruby: How to display an array in an array?

Created on 22 Jul 2017  路  5Comments  路  Source: rmosolgo/graphql-ruby

Rails, GraphQL Ruby, and a field with the JSON type in the PostgreSQL table.

There are two types of records in this field:

  1. ["One","Two","Three"]
  2. [["One","Two","Three"]]

This is done specially. So it is necessary.

If Rails itself displays this data as it should, then gem GraphQL inside itself works correctly only with the first view.

The second view is displayed like this:

"json_field": [
    "[\"One\", \"Two\", \"Three\"]"
]

Responsible for displaying this code:

field :json_field, types[types.String]

I understand why the second option seems to grant that way, but I can not figure out how to fix it.

Help with this, please.

Most helpful comment

The two formats may be specified like this:

field :json_field, types[types.String]
# ["One", "Two", "Three"]
# OR: 
field :json_field, types[types[types.String]]
# [["One", "Two", "Three"]]

but there is no way to specify them _together_. Here are some options I can think of:

  • Make _two_ fields, one for each format

    field :shallow_strings, types[types.String] do 
    resolve ->(obj, args, ctx) {
      if obj.json_field.first.is_a?(String)
        obj.json_field 
      else 
        nil
      end
      }
    end  
    
    field :deep_strings, types[types[types.String]] do 
    resolve ->(obj, args, ctx) {
      if obj.json_field.first.is_a?(Array)
        obj.json_field 
      else 
        nil
      end
      }
    end  
    

    Then in graphql:

    my_object { 
    deep_strings
    shallow_strings
    }
    

    Then merge them in the view code

  • Use an intermediary object type + union

    ShallowStrings = GraphQL::ObjectType.new 
    name "ShallowStrings" 
    field :values, types[types.String]
    end 
    
    DeepStrings = GraphQL::ObjectType.define do 
    name "DeepStrings" 
    field :values, types[types[types.String]]
    end 
    
    StringList = GraphQL::UnionType.define do 
    name "StringList" 
    possible_types [DeepStrings, ShallowStrings]
    end 
    
    # ...
    
    field :json_field, StringList
    

    Then in GraphQL:

    json_field {
      ... on ShallowStrings { values }
      ... on DeepStrings { values } 
    }
    

    This way, the resulting "values" may be of either format.

    Unions can only be created of object types.

    How do those sound?

All 5 comments

The two formats may be specified like this:

field :json_field, types[types.String]
# ["One", "Two", "Three"]
# OR: 
field :json_field, types[types[types.String]]
# [["One", "Two", "Three"]]

but there is no way to specify them _together_. Here are some options I can think of:

  • Make _two_ fields, one for each format

    field :shallow_strings, types[types.String] do 
    resolve ->(obj, args, ctx) {
      if obj.json_field.first.is_a?(String)
        obj.json_field 
      else 
        nil
      end
      }
    end  
    
    field :deep_strings, types[types[types.String]] do 
    resolve ->(obj, args, ctx) {
      if obj.json_field.first.is_a?(Array)
        obj.json_field 
      else 
        nil
      end
      }
    end  
    

    Then in graphql:

    my_object { 
    deep_strings
    shallow_strings
    }
    

    Then merge them in the view code

  • Use an intermediary object type + union

    ShallowStrings = GraphQL::ObjectType.new 
    name "ShallowStrings" 
    field :values, types[types.String]
    end 
    
    DeepStrings = GraphQL::ObjectType.define do 
    name "DeepStrings" 
    field :values, types[types[types.String]]
    end 
    
    StringList = GraphQL::UnionType.define do 
    name "StringList" 
    possible_types [DeepStrings, ShallowStrings]
    end 
    
    # ...
    
    field :json_field, StringList
    

    Then in GraphQL:

    json_field {
      ... on ShallowStrings { values }
      ... on DeepStrings { values } 
    }
    

    This way, the resulting "values" may be of either format.

    Unions can only be created of object types.

    How do those sound?

@rmosolgo Your example from the first point helped me. Thank you.

The second point I did not understand. I copied your code, but in the end I get this error:

schema contains Interfaces or Unions, so you must define a 'resolve_type -> (obj, ctx) { ... }' function (NotImplementedError)

Because of this error the project falls.

Most likely the matter is that I incorrectly pass json_field in the query.

Sorry, that error popped up because you need to define resolve_type in your schema:

http://graphql-ruby.org/types/abstract_types.html#type-resolution

I hope that helped! Feel free to reopen with more details if you're still stuck.

thank you for being so helpful @rmosolgo !

Was this page helpful?
0 / 5 - 0 ratings

Related issues

pareeohnos picture pareeohnos  路  3Comments

rmosolgo picture rmosolgo  路  4Comments

KevinColemanInc picture KevinColemanInc  路  3Comments

theodorton picture theodorton  路  3Comments

jtippett picture jtippett  路  3Comments