module CanvasApi::GraphQLHelpers

Constants

CONFLICTING_NAMES

list of names that conflict with built in methods, Instead of generating a regular field for these ones, generate a resolver method

Public Instance Methods

argument_format(name, type, description="") click to toggle source
# File lib/canvas_api/rb_graphql_helpers.rb, line 163
def argument_format(name, type, description="")
  "argument :#{name.underscore}, #{type}, \"#{description}\", required: false\n"
end
canvas_name(type, input_type = false) click to toggle source
# File lib/canvas_api/rb_graphql_helpers.rb, line 76
def canvas_name(type, input_type = false)
  # Remove chars and fix spelling errors
  name = type.split('|').first.strip.gsub(" ", "_").singularize.gsub("MediaTrackk", "MediaTrack")
  "LMSGraphQL::Types::Canvas::Canvas#{name}#{input_type ? 'Input' : ''}"
end
enum_class_name(model, field_name) click to toggle source
# File lib/canvas_api/rb_graphql_helpers.rb, line 109
def enum_class_name(model, field_name)
  "#{model['id'].classify}#{field_name.classify}Enum"
end
field_format(name, type, description="") click to toggle source
# File lib/canvas_api/rb_graphql_helpers.rb, line 167
def field_format(name, type, description="")
  "field :#{name.underscore}, #{type}, \"#{description}\", null: true\n"
end
field_resolver_format(name, type, description) click to toggle source
# File lib/canvas_api/rb_graphql_helpers.rb, line 171
    def field_resolver_format(name, type, description)
      <<-CODE
field :#{name.underscore}, #{type}, "#{description}", resolver_method: :resolve_#{name.underscore}, null: true
        def resolve_#{name.underscore}
          object[:#{name.underscore}]
        end
      CODE
    end
graphql_field_enums(model) click to toggle source
# File lib/canvas_api/rb_graphql_helpers.rb, line 113
    def graphql_field_enums(model)
      return unless model["properties"]
      enums = model["properties"].map do |name, property|
        if property["allowableValues"]
          values = property["allowableValues"]["values"].map do |value|
            "value \"#{value}\""
          end.join("\n          ")
          <<-CODE
        class #{enum_class_name(model, name)} < ::GraphQL::Schema::Enum
          #{values}
        end
          CODE
        end
      end.compact
      if enums.length > 0
        enums.join("\n        ")
      else
        ""
      end
    end
graphql_fields(model, resource_name) click to toggle source
# File lib/canvas_api/js_graphql_helpers.rb, line 67
def graphql_fields(model, resource_name)
  model["properties"].map do |name, property|
    # HACK. This property doesn't have any metadata. Throw in a couple lines of code
    # specific to this field.
    if name == "created_source" && property == "manual|sis|api"
      "#{name}: new GraphQLEnumType({ name: '#{name}', values: { manual: { value: 'manual' }, sis: { value: 'sis' }, api: { value: 'api' } } })"
    else

      description = ""
      if property["description"].present? && property["example"].present?
        description << "#{safe_js(property['description'])}. Example: #{safe_js(property['example'])}".gsub("..", "").gsub("\n", " ")
      end

      if type = graphql_type(name, property)
        resolve = graphql_resolve(name, property)
        resolve = "#{resolve}, " if resolve.present?
        "#{name}: { type: #{type}, #{resolve}description: \"#{description}\" }"
      end

    end
  end.compact
end
graphql_primitive(type, format) click to toggle source
# File lib/canvas_api/js_graphql_helpers.rb, line 35
def graphql_primitive(type, format)
  case type
  when "integer"
    "GraphQLInt"
  when "number"
    if format == "float64"
      "GraphQLFloat"
    else
      # TODO many of the LMS types with 'number' don't indicate a type so we have to guess
      # Hopefully that changes. For now we go with float
      "GraphQLFloat"
    end
  when "string"
    "GraphQLString"
  when "boolean"
    "GraphQLBoolean"
  when "datetime"
    "GraphQLDateTime"
  else
    raise "Unable to match requested primitive '#{type}' to GraphQL Type."
  end
end
graphql_resolve(name, property) click to toggle source
# File lib/canvas_api/js_graphql_helpers.rb, line 58
def graphql_resolve(name, property)
  if property["$ref"]
    "resolve(model){ return model.#{name}; }"
  elsif property["type"] == "array" && property["items"] && property["items"]["$ref"]
    "resolve(model){ return model.#{name}; }"
  end
  "resolve(model){ return model.#{name}; }"
end
graphql_type(name, property) click to toggle source
# File lib/canvas_api/js_graphql_helpers.rb, line 5
def graphql_type(name, property)
  if property["$ref"]
    "#{property['$ref']}, resolve: function(model){ return model.#{name}; }"
  else
    type = property["type"]
    case type
    when "integer", "string", "boolean", "datetime", "number"
      graphql_primitive(type, property["format"])
    when "array"
      begin
        type = if property["items"]["$ref"]
                 property["items"]["$ref"]
               else
                 graphql_primitive(property["items"]["type"], property["items"]["format"])
               end
      rescue
        puts "Unable to discover list type for '#{name}' ('#{property}'). Defaulting to GraphQLString"
        type = "GraphQLString"
      end
      "new GraphQLList(#{type})"
    when "object"
      puts "Using string type for '#{name}' ('#{property}') of type object."
      "GraphQLString"
    else
      puts "Unable to match '#{name}' requested property '#{property}' to GraphQL Type."
      "GraphQLString"
    end
  end
end
is_basic_type(type) click to toggle source
# File lib/canvas_api/rb_graphql_helpers.rb, line 194
def is_basic_type(type)
  ["Int", "String", "Boolean", "LMSGraphQL::Types::DateTimeType", "Float", "ID"].include?(type)
end
make_file_name(str) click to toggle source
# File lib/canvas_api/rb_graphql_helpers.rb, line 202
def make_file_name(str)
  str.underscore.split("/").last.split("|").first.gsub("canvas_", "").gsub(" ", "_").strip.singularize
end
name_from_operation(operation) click to toggle source
# File lib/canvas_api/rb_graphql_helpers.rb, line 185
def name_from_operation(operation)
  type = no_brackets_period(type_from_operation(@operation))
  if !is_basic_type(type)
    make_file_name(type)
  else
    "return_value"
  end
end
nested_arg(str) click to toggle source
# File lib/canvas_api/rb_graphql_helpers.rb, line 235
def nested_arg(str)
  # TODO/HACK we are replacing values from the string here to get things to work for now.
  # However, removing these symbols means that the methods that use the arguments
  # generated herein will have bugs and be unusable.
  str.gsub("[", "_").
    gsub("]", "").
    gsub("*", "star").
    gsub("<", "_").
    gsub(">", "_").
    gsub("`", "").
    gsub("https://canvas.instructure.com/lti/", "").
    gsub("https://www.instructure.com/", "").
    gsub("https://purl.imsglobal.org/spec/lti/claim/", "").
    gsub(".", "")
end
no_brackets_period(str) click to toggle source
# File lib/canvas_api/rb_graphql_helpers.rb, line 198
def no_brackets_period(str)
  str.gsub("[", "").gsub("]", "").gsub(".", "")
end
params_as_string(parameters, paramTypes) click to toggle source
# File lib/canvas_api/rb_graphql_helpers.rb, line 251
def params_as_string(parameters, paramTypes)
  filtered = parameters.select{ |p| paramTypes.include?(p["paramType"]) }
  if filtered && !filtered.empty?
    s = filtered.
      map{ |p| "              \"#{p['name']}\": #{nested_arg(p['name'])}" }.
      join(",\n")
    "            {\n#{s}\n            }"
  else
    "            {}"
  end
end
require_from_operation(operation) click to toggle source
# File lib/canvas_api/rb_graphql_helpers.rb, line 206
def require_from_operation(operation)
  type = no_brackets_period(type_from_operation(@operation))
  if !is_basic_type(type)
    "require_relative \"../../types/canvas/#{make_file_name(type)}\""
  end
end
require_from_properties(model) click to toggle source
# File lib/canvas_api/rb_graphql_helpers.rb, line 213
def require_from_properties(model)
  return unless model["properties"]
  requires = model["properties"].map do |name, property|
    type = no_brackets_period(graphql_type(name, property, true, model))
    if !is_basic_type(type) && !property["allowableValues"]
      "require_relative \"#{make_file_name(type)}\""
    end
  end.compact
  if requires.length > 0
    requires.join("\n")
  else
    ""
  end
end
safe_js(str) click to toggle source
# File lib/canvas_api/js_graphql_helpers.rb, line 90
def safe_js(str)
  str = str.join(", ") if str.is_a?(Array)
  str = str.map { |_k, v| v }.join(", ") if str.is_a?(Hash)
  return str unless str.is_a?(String)
  str.gsub('"', "'")
end
safe_rb(str) click to toggle source
# File lib/canvas_api/rb_graphql_helpers.rb, line 228
def safe_rb(str)
  str = str.join(", ") if str.is_a?(Array)
  str = str.map { |_k, v| v }.join(", ") if str.is_a?(Hash)
  return str unless str.is_a?(String)
  str.gsub('"', "'")
end
type_from_operation(operation) click to toggle source
# File lib/canvas_api/rb_graphql_helpers.rb, line 181
def type_from_operation(operation)
  type = graphql_type("operation", operation, true)
end