expand.js 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  1. const { buildSchema, GraphQLObjectType, GraphQLString, GraphQLInt, GraphQLList, GraphQLSchema } = require('graphql');
  2. const ObjectID = require("mongodb").ObjectID;
  3. function mmExpandSchema(gqlSchema){
  4. const types = {}
  5. const _typeMap = gqlSchema.getTypeMap()
  6. const buildInTypes = ['Query', 'Mutation', 'ID', 'Float', "String", 'Int', 'Boolean',
  7. 'Query!', 'Mutation!', 'ID!', 'Float!', "String!", 'Int!', 'Boolean!' ]
  8. async function argToSavables(arg, outputTypeName, Savable){
  9. console.log('argToSavables', arg)
  10. const entity = arg._id ? await Savable.m[outputTypeName].findOne({_id: ObjectID(arg._id)}) :
  11. new Savable.classes[outputTypeName]({})
  12. const {_id, ...data} = arg;
  13. const type = _typeMap[outputTypeName + 'Input']
  14. const fields = type.getFields()
  15. for(let [fieldName, value] of Object.entries(data)){
  16. let typeName = fields[fieldName].type.toString()
  17. if (!buildInTypes.includes(typeName)){
  18. console.log('recursive', arg[fieldName], typeName)
  19. if (typeName[0] === '['){
  20. const nestedTypeName = typeName.slice(1,-6)
  21. console.log('array',nestedTypeName)
  22. entity[fieldName] = []
  23. for (let nestedArg of value){
  24. const nestedEntity = await argToSavables(nestedArg, nestedTypeName, Savable)
  25. entity[fieldName].push(nestedEntity)
  26. }
  27. }
  28. else {
  29. const nestedTypeName = typeName.slice(0,-5)
  30. console.log('one', nestedTypeName)
  31. entity[fieldName] = await argToSavables(value, nestedTypeName, Savable)
  32. }
  33. }
  34. else {
  35. entity[fieldName] = value
  36. }
  37. }
  38. return await entity.save()
  39. }
  40. let queryFields = _typeMap.Query ? _typeMap.Query.getFields() : {}
  41. let mutationFields = _typeMap.Mutation ? _typeMap.Mutation.getFields() : {}
  42. for (let [typeName, type] of Object.entries(_typeMap))
  43. if (!buildInTypes.includes(typeName) &&
  44. !typeName.startsWith('__')){
  45. if (typeName.endsWith('Input')){
  46. let outputTypeName = typeName.substr(0, typeName.length - 'Input'.length)
  47. if (outputTypeName in _typeMap){
  48. types[outputTypeName] = type
  49. const find = {
  50. type: GraphQLList(_typeMap[outputTypeName]),
  51. args: {query: {type: GraphQLString}},
  52. async resolve(root, args, context, info){
  53. //console.log(root, args, context, info)
  54. const Savable = context.models.SlicedSavable || context.models.Savable
  55. args = JSON.parse(args.query)
  56. let results = []
  57. for (let result of Savable.m[outputTypeName].find(...args)){
  58. try {result = await result} catch (e) { break }
  59. results.push(result)
  60. }
  61. return results;
  62. }
  63. }
  64. queryFields[`${outputTypeName}Find`] = find
  65. const count = {
  66. type: GraphQLInt,
  67. args: {query: {type: GraphQLString}},
  68. async resolve(root, args, context, info){
  69. console.log(root, args, context, info)
  70. q = JSON.parse(args.query)
  71. q[1] = q[1] || {}
  72. q[1].count = []
  73. args.query = JSON.stringify(q)
  74. return find.resolve(root, args, context, info)
  75. }
  76. }
  77. queryFields[`${outputTypeName}Count`] = count
  78. const findOne = {
  79. type: _typeMap[outputTypeName],
  80. args: {query: {type: GraphQLString}},
  81. async resolve(root, args, context, info){
  82. //console.log(root, args, context, info)
  83. const Savable = context.models.SlicedSavable || context.models.Savable
  84. args = JSON.parse(args.query)
  85. let [query] = args
  86. if (query._id && typeof query._id === 'string'){
  87. query._id = ObjectID(query._id)
  88. }
  89. let record = Savable.m[outputTypeName].findOne(query, ...args.slice(1))
  90. return record;
  91. }
  92. }
  93. queryFields[`${outputTypeName}FindOne`] = findOne
  94. const lowerCaseName = outputTypeName[0].toLowerCase() + outputTypeName.slice(1)
  95. const del = {
  96. type: _typeMap[outputTypeName],
  97. args: {[lowerCaseName]: {type: _typeMap[typeName]}},
  98. async resolve(root, args, context, info){
  99. //console.log(root, args, context, info)
  100. const Savable = context.models.SlicedSavable || context.models.Savable
  101. const arg = args[lowerCaseName]
  102. if (! ('_id' in arg)){
  103. return null;
  104. }
  105. let entity = await Savable.m[outputTypeName].findOne({_id: ObjectID(arg._id)})
  106. if (entity){
  107. let copy = {...record}
  108. await entity.delete()
  109. return copy;
  110. }
  111. return entity;
  112. }
  113. }
  114. mutationFields[`${outputTypeName}Delete`] = del
  115. const upsert = {
  116. type: _typeMap[outputTypeName],
  117. args: {[lowerCaseName]: {type: _typeMap[typeName]}},
  118. async resolve(root, args, context, info){
  119. //console.log(root, args, context, info)
  120. const Savable = context.models.SlicedSavable || context.models.Savable
  121. const arg = args[lowerCaseName]
  122. const entity = argToSavables(args[lowerCaseName], outputTypeName, Savable)
  123. return entity;
  124. }
  125. }
  126. mutationFields[`${outputTypeName}Upsert`] = upsert
  127. }
  128. }
  129. }
  130. let newQuery = new GraphQLObjectType({name: 'Query', fields: queryFields})
  131. let newMutation = new GraphQLObjectType({name: 'Mutation', fields: mutationFields})
  132. let newSchema = new GraphQLSchema({query: newQuery, mutation: newMutation})
  133. return newSchema;
  134. }
  135. module.exports = mmExpandSchema