Graphql-ruby: Access Posgres' JSONB columns

Created on 5 Jan 2017  路  10Comments  路  Source: rmosolgo/graphql-ruby

Hi! How can I include JSONB attributes (using PostgreSQL) in my GraphQL Schema?

In my Rails app I usually access those column using store_accessor:

store_accessor :jsonb_column, :prop_a, :prop_b

Disclaimer: I'm new to GraphQL 馃檲

Thanks!

Most helpful comment

Oh right, the other difference is:

# Access a key named `:measurements` (symbol) 
field :measurements, types[MeasurementsType], hash_key: :measurements
# Access a key named `"measurements"` (string)
field :measurements, types[MeasurementsType], hash_key: "measurements"

Does it work for you if you specify a string as the key (hash_key: "measurements")?

Judging by the docs, ActiveRecord::Store accepts _either_ strings or symbols, but I imagine that after the first key, it's up to you to choose the right kind of key. And if the storage is JSON, the keys are probably strings!

Any luck?

All 10 comments

Does store_accessor make a method with the same name? If so, then you don't need anything special, just add a field, eg

field :prop_a, types.String # or types.Int, whatever type is in that field

@rmosolgo mmm good point, I should have omitted the store_accesor stuff, since what I'm looking for is to keep it as a nested record. For example:

# person_type.rb
module Graph
  PersonType = GraphQL::ObjectType.define do
    name 'Person'
    description 'A person'

    field :id, types.ID
    field :medical_records do # this is the JSONB column
      type MedicalRecordsType
      resolve lambda { |obj, _args, _ctw|
        obj.medical_records
      }
    end
  end
end
# medical_records_type.rb
module Graph
  MedicalRecordsType = GraphQL::ObjectType.define do
    name 'MedicalRecords'
    description 'A medical records'

    field :diabetes, types.String
    # ... other regular fields
  end
end

If I try to run the following query:

query: {
  person(id: 1) {
    medical_records { 
      diabetes 
    }
  }
}

I get the following Exception:

NoMethodError in Api::V1::GraphController#index

undefined method `diabetes' for #<Hash:0x007fe143e36878>

Oh I see!

By default, fields perform a method call. To resolve a field with [...], You can specify a key with hash_key:, eg,

field :diabetes, types.String, hash_key: :diabetes 
# will find a value by doing `medical_records[:diabetes]`

A few more examples here: http://www.rubydoc.info/gems/graphql/GraphQL/Field

Does that work for you? Please reopen this if not!

@rmosolgo awesome! It worked like a charm for 1-level nested fields, but it stops working for deeply nested fields:

# medical_records_type.rb
module Graph
  MedicalRecordsType = GraphQL::ObjectType.define do
    name 'MedicalRecords'
    description 'A medical records'

    field :diabetes, types.String

    # Option A
    field :measurements, types[MeasurementsType], hash_key: :measurements

    # Option B
    field :measurements do
      type MeasurementsType
      resolve lambda { |obj, _args, _ctw|
        obj['measurements']
      }
    end
  end
end
# measurements_type.rb
module Graph
  MeasurementsType = GraphQL::ObjectType.define do
    name 'Measurements'
    description 'A measurements'

    field :weight, types.Integer
    field :height, types.Integer
  end
end

Can you help me understand what "stops working" means here? Is there runtime error?

@rmosolgo sorry, I sent the comment before finishing it (freaking CMD + Enter). I updated the code above 鈽濓笍

Basically the issue is with the resulting repsonse:

Option A will return: measurements: null

Option B will return: measurements: {weight: null, height: null}

...while the actual value in the JSONB record being: measurements: {weight: 100, height: 70}

Option A has

field :measurements, types[MeasurementsType]

which means that measurements returns a _list_ of MeasurementsType objects. Should it be

field :measurements, MeasurementsType

which means it returns an object of type MeasurementsType? (This would match Option B.)

@rmosolgo good catch, this was indeed a newbie mistake. Although neither results changed at all for some reason

Option A will return: measurements: null

Option B will return: measurements: {weight: null, height: null}

Oh right, the other difference is:

# Access a key named `:measurements` (symbol) 
field :measurements, types[MeasurementsType], hash_key: :measurements
# Access a key named `"measurements"` (string)
field :measurements, types[MeasurementsType], hash_key: "measurements"

Does it work for you if you specify a string as the key (hash_key: "measurements")?

Judging by the docs, ActiveRecord::Store accepts _either_ strings or symbols, but I imagine that after the first key, it's up to you to choose the right kind of key. And if the storage is JSON, the keys are probably strings!

Any luck?

@rmosolgo yeah that did the trick!

thanks a lot for the help 馃樃 u're awesome!

Was this page helpful?
0 / 5 - 0 ratings

Related issues

pareeohnos picture pareeohnos  路  3Comments

ecomuere picture ecomuere  路  3Comments

amozoss picture amozoss  路  3Comments

sayduck-daniel picture sayduck-daniel  路  3Comments

Plummat picture Plummat  路  4Comments