Przeglądaj źródła

Start on types and schema;

bjorn 9 lat temu
rodzic
commit
7629d50681
2 zmienionych plików z 191 dodań i 0 usunięć
  1. 10 0
      schema.lua
  2. 181 0
      types.lua

+ 10 - 0
schema.lua

@@ -0,0 +1,10 @@
+local schema = {}
+schema.__index = schema
+
+function schema.create(config)
+  assert(type(config.query) == 'table', 'must provide query object')
+
+  return config
+end
+
+return schema

+ 181 - 0
types.lua

@@ -0,0 +1,181 @@
+local types = {}
+
+function types.nonNull(kind)
+  assert(kind, 'Must provide a type')
+
+  return {
+    __type = 'NonNull',
+    ofType = kind
+  }
+end
+
+function types.scalar(config)
+  assert(type(config.name) == 'string', 'type name must be provided as a string')
+  assert(type(config.serialize) == 'function', 'serialize must be a function')
+  if config.parseValue or config.parseLiteral then
+    assert(
+      type(config.parseValue) == 'function' and type(config.parseLiteral) == 'function',
+      'must provide both parseValue and parseLiteral to scalar type'
+    )
+  end
+
+  local instance = {
+    __type = 'Scalar',
+    name = config.name,
+    description = config.description,
+    serialize = config.serialize,
+    parseValue = config.parseValue,
+    parseLiteral = config.parseLiteral
+  }
+
+  instance.nonNull = types.nonNull(instance)
+
+  return instance
+end
+
+function types.object(config)
+  assert(type(config.name) == 'string', 'type name must be provided as a string')
+  if config.isTypeOf then
+    assert(type(config.isTypeOf) == 'function', 'must provide isTypeOf as a function')
+  end
+  assert(type(config.fields) == 'table', 'fields table must be provided')
+
+  local fields = {}
+  for fieldName, field in pairs(config.fields) do
+    field = field.__type and { kind = field } or field
+    fields[fieldName] = {
+      name = fieldName,
+      kind = field.kind,
+      args = field.args or {}
+    }
+  end
+
+  local instance = {
+    __type = 'Object',
+    name = config.name,
+    isTypeOf = config.isTypeOf,
+    fields = fields
+  }
+
+  instance.nonNull = types.nonNull(instance)
+
+  return instance
+end
+
+function types.interface(config)
+  assert(type(config.name) == 'string', 'type name must be provided as a string')
+  assert(type(config.fields) == 'table', 'fields table must be provided')
+  if config.resolveType then
+    assert(type(config.resolveType) == 'function', 'must provide resolveType as a function')
+  end
+
+  local instance = {
+    __type = 'Interface',
+    name = config.name,
+    description = config.description,
+    fields = config.fields,
+    resolveType = config.resolveType
+  }
+
+  instance.nonNull = types.nonNull(instance)
+
+  return instance
+end
+
+function types.enum(config)
+  assert(type(config.name) == 'string', 'type name must be provided as a string')
+  assert(type(config.values) == 'table', 'values table must be provided')
+
+  local instance = {
+    __type = 'Enum',
+    name = config.name,
+    description = config.description,
+    values = config.values
+  }
+
+  instance.nonNull = types.nonNull(instance)
+
+  return instance
+end
+
+function types.union(config)
+  assert(type(config.name) == 'string', 'type name must be provided as a string')
+  assert(type(config.types) == 'table', 'types table must be provided')
+
+  local instance = {
+    __type = 'Union',
+    name = config.name,
+    types = config.types
+  }
+
+  instance.nonNull = types.nonNull(instance)
+
+  return instance
+end
+
+local coerceInt = function(value)
+  value = tonumber(value)
+
+  if not value then return end
+
+  if value == value and value < 2 ^ 32 and value >= -2 ^ 32 then
+    return value < 0 and math.ceil(value) or math.floor(value)
+  end
+end
+
+types.int = types.scalar({
+  name = 'Int',
+  serialize = coerceInt,
+  parseValue = coerceInt,
+  parseLiteral = function(node)
+    if node.kind == 'int' then
+      return coerceInt(node.value)
+    end
+  end
+})
+
+types.float = types.scalar({
+  name = 'Float',
+  serialize = tonumber,
+  parseValue = tonumber,
+  parseLiteral = function(node)
+    if node.kind == 'float' or node.kind == 'int' then
+      return tonumber(node.value)
+    end
+  end
+})
+
+types.string = types.scalar({
+  name = 'String',
+  serialize = tostring,
+  parseValue = tostring,
+  parseLiteral = function(node)
+    if node.kind == 'string' then
+      return node.value
+    end
+  end
+})
+
+local function toboolean(x)
+  return x and true or false
+end
+
+types.boolean = types.scalar({
+  name = 'Boolean',
+  serialize = toboolean,
+  parseValue = toboolean,
+  parseLiteral = function(node)
+    return node.kind == 'boolean' and node.value or nil
+  end
+})
+
+types.id = types.scalar({
+  name = 'ID',
+  serialize = tostring,
+  parseValue = tostring,
+  parseLiteral = function(node)
+    return node.kind == 'string' or node.kind == 'int' and node.value or nil
+  end
+})
+
+return types