types.lua 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264
  1. local types = {}
  2. function types.nonNull(kind)
  3. assert(kind, 'Must provide a type')
  4. return {
  5. __type = 'NonNull',
  6. ofType = kind
  7. }
  8. end
  9. function types.list(kind)
  10. assert(kind, 'Must provide a type')
  11. return {
  12. __type = 'List',
  13. ofType = kind
  14. }
  15. end
  16. function types.scalar(config)
  17. assert(type(config.name) == 'string', 'type name must be provided as a string')
  18. assert(type(config.serialize) == 'function', 'serialize must be a function')
  19. if config.parseValue or config.parseLiteral then
  20. assert(
  21. type(config.parseValue) == 'function' and type(config.parseLiteral) == 'function',
  22. 'must provide both parseValue and parseLiteral to scalar type'
  23. )
  24. end
  25. local instance = {
  26. __type = 'Scalar',
  27. name = config.name,
  28. description = config.description,
  29. serialize = config.serialize,
  30. parseValue = config.parseValue,
  31. parseLiteral = config.parseLiteral
  32. }
  33. instance.nonNull = types.nonNull(instance)
  34. return instance
  35. end
  36. function types.object(config)
  37. assert(type(config.name) == 'string', 'type name must be provided as a string')
  38. if config.isTypeOf then
  39. assert(type(config.isTypeOf) == 'function', 'must provide isTypeOf as a function')
  40. end
  41. assert(type(config.fields) == 'table', 'fields table must be provided')
  42. local fields = {}
  43. for fieldName, field in pairs(config.fields) do
  44. field = field.__type and { kind = field } or field
  45. fields[fieldName] = {
  46. name = fieldName,
  47. kind = field.kind,
  48. arguments = field.arguments or {},
  49. resolve = field.resolve
  50. }
  51. end
  52. local instance = {
  53. __type = 'Object',
  54. name = config.name,
  55. isTypeOf = config.isTypeOf,
  56. fields = fields,
  57. interfaces = config.interfaces
  58. }
  59. instance.nonNull = types.nonNull(instance)
  60. return instance
  61. end
  62. function types.interface(config)
  63. assert(type(config.name) == 'string', 'type name must be provided as a string')
  64. assert(type(config.fields) == 'table', 'fields table must be provided')
  65. if config.resolveType then
  66. assert(type(config.resolveType) == 'function', 'must provide resolveType as a function')
  67. end
  68. local fields = {}
  69. for fieldName, field in pairs(config.fields) do
  70. field = field.__type and { kind = field } or field
  71. fields[fieldName] = {
  72. name = fieldName,
  73. kind = field.kind,
  74. arguments = field.arguments or {}
  75. }
  76. end
  77. local instance = {
  78. __type = 'Interface',
  79. name = config.name,
  80. description = config.description,
  81. fields = fields,
  82. resolveType = config.resolveType
  83. }
  84. instance.nonNull = types.nonNull(instance)
  85. return instance
  86. end
  87. function types.enum(config)
  88. assert(type(config.name) == 'string', 'type name must be provided as a string')
  89. assert(type(config.values) == 'table', 'values table must be provided')
  90. local instance = {
  91. __type = 'Enum',
  92. name = config.name,
  93. description = config.description,
  94. values = config.values
  95. }
  96. instance.nonNull = types.nonNull(instance)
  97. return instance
  98. end
  99. function types.union(config)
  100. assert(type(config.name) == 'string', 'type name must be provided as a string')
  101. assert(type(config.types) == 'table', 'types table must be provided')
  102. local instance = {
  103. __type = 'Union',
  104. name = config.name,
  105. types = config.types
  106. }
  107. instance.nonNull = types.nonNull(instance)
  108. return instance
  109. end
  110. function types.inputObject(config)
  111. assert(type(config.name) == 'string', 'type name must be provided as a string')
  112. local fields = {}
  113. for fieldName, field in pairs(config.fields) do
  114. field = field.__type and { kind = field } or field
  115. fields[fieldName] = {
  116. name = fieldName,
  117. kind = field.kind
  118. }
  119. end
  120. local instance = {
  121. __type = 'InputObject',
  122. name = config.name,
  123. description = config.description,
  124. fields = fields
  125. }
  126. return instance
  127. end
  128. local coerceInt = function(value)
  129. value = tonumber(value)
  130. if not value then return end
  131. if value == value and value < 2 ^ 32 and value >= -2 ^ 32 then
  132. return value < 0 and math.ceil(value) or math.floor(value)
  133. end
  134. end
  135. types.int = types.scalar({
  136. name = 'Int',
  137. serialize = coerceInt,
  138. parseValue = coerceInt,
  139. parseLiteral = function(node)
  140. if node.kind == 'int' then
  141. return coerceInt(node.value)
  142. end
  143. end
  144. })
  145. types.float = types.scalar({
  146. name = 'Float',
  147. serialize = tonumber,
  148. parseValue = tonumber,
  149. parseLiteral = function(node)
  150. if node.kind == 'float' or node.kind == 'int' then
  151. return tonumber(node.value)
  152. end
  153. end
  154. })
  155. types.string = types.scalar({
  156. name = 'String',
  157. serialize = tostring,
  158. parseValue = tostring,
  159. parseLiteral = function(node)
  160. if node.kind == 'string' then
  161. return node.value
  162. end
  163. end
  164. })
  165. local function toboolean(x)
  166. return (x and x ~= 'false') and true or false
  167. end
  168. types.boolean = types.scalar({
  169. name = 'Boolean',
  170. serialize = toboolean,
  171. parseValue = toboolean,
  172. parseLiteral = function(node)
  173. if node.kind == 'boolean' then
  174. return toboolean(node.value)
  175. else
  176. return nil
  177. end
  178. end
  179. })
  180. types.id = types.scalar({
  181. name = 'ID',
  182. serialize = tostring,
  183. parseValue = tostring,
  184. parseLiteral = function(node)
  185. return node.kind == 'string' or node.kind == 'int' and node.value or nil
  186. end
  187. })
  188. function types.directive(config)
  189. assert(type(config.name) == 'string', 'type name must be provided as a string')
  190. local instance = {
  191. __type = 'Directive',
  192. name = config.name,
  193. description = config.description,
  194. arguments = config.arguments,
  195. onOperation = config.onOperation or false,
  196. onFragment = config.onOperation or false,
  197. onField = config.onField or false
  198. }
  199. return instance
  200. end
  201. types.include = types.directive({
  202. name = 'include',
  203. arguments = {
  204. ['if'] = types.boolean.nonNull
  205. },
  206. onOperation = false,
  207. onFragment = true,
  208. onField = true
  209. })
  210. types.skip = types.directive({
  211. name = 'skip',
  212. arguments = {
  213. ['if'] = types.boolean.nonNull
  214. },
  215. onOperation = false,
  216. onFragment = true,
  217. onField = true
  218. })
  219. return types