schema.lua 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  1. local path = (...):gsub('%.[^%.]+$', '')
  2. local types = require(path .. '.types')
  3. local introspection = require(path .. '.introspection')
  4. local schema = {}
  5. schema.__index = schema
  6. function schema.create(config)
  7. assert(type(config.query) == 'table', 'must provide query object')
  8. assert(not config.mutation or type(config.mutation) == 'table', 'mutation must be a table if provided')
  9. local self = setmetatable({}, schema)
  10. for k, v in pairs(config) do
  11. self[k] = v
  12. end
  13. self.typeMap = {}
  14. self.interfaceMap = {}
  15. self.directiveMap = {}
  16. local function generateTypeMap(node)
  17. if not node or (self.typeMap[node.name] and self.typeMap[node.name] == node) then return end
  18. if node.__type == 'NonNull' or node.__type == 'List' then
  19. return generateTypeMap(node.ofType)
  20. end
  21. if self.typeMap[node.name] and self.typeMap[node.name] ~= node then
  22. error('Encountered multiple types named "' .. node.name .. '"')
  23. end
  24. if type(node.fields) == 'function' then node.fields = node.fields() end
  25. self.typeMap[node.name] = node
  26. if node.__type == 'Object' and node.interfaces then
  27. for _, interface in ipairs(node.interfaces) do
  28. generateTypeMap(interface)
  29. self.interfaceMap[interface.name] = self.interfaceMap[interface.name] or {}
  30. self.interfaceMap[interface.name][node] = node
  31. end
  32. end
  33. if node.__type == 'Object' or node.__type == 'Interface' or node.__type == 'InputObject' then
  34. for fieldName, field in pairs(node.fields) do
  35. if field.arguments then
  36. for k, argument in pairs(field.arguments) do
  37. if argument.__type
  38. then generateTypeMap(argument)
  39. else
  40. assert(type(argument.kind) == 'table', 'kind of argument "'.. k ..'" for "' .. fieldName .. '" must be supplied')
  41. generateTypeMap(argument.kind)
  42. end
  43. end
  44. end
  45. generateTypeMap(field.kind)
  46. end
  47. end
  48. end
  49. generateTypeMap(self.query)
  50. generateTypeMap(self.mutation)
  51. generateTypeMap(introspection.__Schema)
  52. self.directives = self.directives or {
  53. types.include,
  54. types.skip
  55. }
  56. if self.directives then
  57. for _, directive in ipairs(self.directives) do
  58. self.directiveMap[directive.name] = directive
  59. end
  60. end
  61. return self
  62. end
  63. function schema:getType(name)
  64. if not name then return end
  65. return self.typeMap[name]
  66. end
  67. function schema:getImplementors(interface)
  68. local kind = self:getType(interface)
  69. local isInterface = kind and kind.__type == 'Interface'
  70. return self.interfaceMap[interface] or (isInterface and {} or nil)
  71. end
  72. function schema:getDirective(name)
  73. if not name then return false end
  74. return self.directiveMap[name]
  75. end
  76. function schema:getQueryType()
  77. return self.query
  78. end
  79. function schema:getMutationType()
  80. return self.mutation
  81. end
  82. function schema:getTypeMap()
  83. return self.typeMap
  84. end
  85. function schema:getPossibleTypes(abstractType)
  86. if abstractType.__type == 'Union' then
  87. return abstractType.types
  88. end
  89. return self:getImplementors(abstractType)
  90. end
  91. function schema.getParentField(context, name, count)
  92. if name == '__schema' then
  93. return introspection.SchemaMetaFieldDef
  94. elseif name == '__type' then
  95. return introspection.TypeMetaFieldDef
  96. elseif name == '__typename' then
  97. return introspection.TypeNameMetaFieldDef
  98. end
  99. count = count or 1
  100. local parent = context.objects[#context.objects - count]
  101. -- Unwrap lists and non-null types
  102. while parent.ofType do
  103. parent = parent.ofType
  104. end
  105. return parent.fields[name]
  106. end
  107. return schema