schema.lua 3.8 KB

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