class WCC::Contentful::Graphql::Builder

Attributes

root_types[R]
schema_types[R]

Public Class Methods

new(types, store) click to toggle source
# File lib/wcc/contentful/graphql/builder.rb, line 15
def initialize(types, store)
  @types = types if types.is_a? WCC::Contentful::IndexedRepresentation
  @types ||=
    if types.is_a?(String) && File.exist?(types)
      WCC::Contentful::ContentTypeIndexer.load(types).types
    end

  unless @types
    raise ArgumentError, 'Cannot parse types - not an IndexedRepresentation ' \
      "nor a schema file on disk: #{types}"
  end

  @store = store

  @schema_types = build_schema_types
  @root_types = @schema_types.dup
end

Public Instance Methods

build_schema() click to toggle source
# File lib/wcc/contentful/graphql/builder.rb, line 38
def build_schema
  root_query_type = build_root_query(root_types)

  builder = self
  GraphQL::Schema.define do
    query root_query_type

    resolve_type ->(_type, obj, _ctx) {
      content_type = WCC::Contentful::Helpers.content_type_from_raw(obj)
      builder.schema_types[content_type]
    }
  end
end
configure(&block) click to toggle source
# File lib/wcc/contentful/graphql/builder.rb, line 33
def configure(&block)
  instance_exec(&block)
  self
end

Private Instance Methods

build_root_query(schema_types) click to toggle source
# File lib/wcc/contentful/graphql/builder.rb, line 54
def build_root_query(schema_types)
  store = @store

  GraphQL::ObjectType.define do
    name 'Query'
    description 'The query root of this schema'

    schema_types.each do |content_type, schema_type|
      field schema_type.name.to_sym do
        type schema_type
        argument :id, types.ID
        description "Find a #{schema_type.name}"

        schema_type.fields.each do |(name, field)|
          next unless input_type = Types::QueryOperatorInput.call(field.type)

          argument name, input_type
        end

        resolve ->(_obj, args, _ctx) {
          if args['id'].nil?
            store.find_by(content_type: content_type, filter: args.to_h)
          else
            store.find(args['id'])
          end
        }
      end

      field "all#{schema_type.name}".to_sym do
        type schema_type.to_list_type
        argument :filter, Types::FilterInputType.call(schema_type)

        resolve ->(_obj, args, ctx) {
          relation = store.find_all(content_type: content_type)
          relation = relation.apply(args[:filter].to_h, ctx) if args[:filter]
          relation.to_enum
        }
      end
    end
  end
end
build_schema_type(typedef) click to toggle source
# File lib/wcc/contentful/graphql/builder.rb, line 102
def build_schema_type(typedef)
  store = @store
  builder = self
  content_type = typedef.content_type

  GraphQL::ObjectType.define do
    name(typedef.name)

    description("Generated from content type #{content_type}")

    field :id, !types.ID do
      resolve ->(obj, _args, _ctx) {
        obj.dig('sys', 'id')
      }
    end

    field :_content_type, !types.String do
      resolve ->(_, _, _) {
        content_type
      }
    end

    # Make a field for each column:
    typedef.fields.each_value do |f|
      case f.type
      when :Asset
        field(f.name.to_sym, -> {
          type = builder.schema_types['Asset']
          type = type.to_list_type if f.array
          type
        }) do
          resolve contentful_link_resolver(f.name, store: store)
        end
      when :Link
        field(f.name.to_sym, -> {
          type =
            if f.link_types.nil? || f.link_types.empty?
              builder.schema_types['AnyContentful'] ||=
                Types::BuildUnionType.call(builder.schema_types, 'AnyContentful')
            elsif f.link_types.length == 1
              builder.schema_types[f.link_types.first]
            else
              from_types = builder.schema_types.select { |key| f.link_types.include?(key) }
              name = "#{typedef.name}_#{f.name}"
              builder.schema_types[name] ||= Types::BuildUnionType.call(from_types, name)
            end
          type = type.to_list_type if f.array
          type
        }) do
          resolve contentful_link_resolver(f.name, store: store)
        end
      else
        contentful_field(f.name, f.type, array: f.array)
      end
    end
  end
end
build_schema_types() click to toggle source
# File lib/wcc/contentful/graphql/builder.rb, line 96
def build_schema_types
  @types.each_with_object({}) do |(k, v), h|
    h[k] = build_schema_type(v)
  end
end