text: "use strict";
  var __extends = (this && this.__extends) || (function () {
      var extendStatics = function (d, b) {
          extendStatics = Object.setPrototypeOf ||
              ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
              function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
          return extendStatics(d, b);
      };
      return function (d, b) {
          extendStatics(d, b);
          function __() { this.constructor = d; }
          d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
      };
  })();
  Object.defineProperty(exports, "__esModule", { value: true });
  var type_1 = require("graphql/type");
  var prisma_datamodel_1 = require("prisma-datamodel");
  // tslint:disable:max-classes-per-file
  /**
   * Type cache for object types.
   */
  var TypeRegistry = /** @class */ (function () {
      function TypeRegistry() {
      }
      return TypeRegistry;
  }());
  exports.TypeRegistry = TypeRegistry;
  /**
   * Base class of all generators,
   * has a reference to the set of generators we need
   * and a type registry.
   */
  var Generator = /** @class */ (function () {
      function Generator(knownTypes, generators) {
          this.knownTypes = knownTypes;
          this.generators = generators;
      }
      return Generator;
  }());
  exports.Generator = Generator;
  /**
   * Base class for all generators that create types.
   * This class implements caching via the given TypeRegistry.
   */
  var TypeGenerator = /** @class */ (function (_super) {
      __extends(TypeGenerator, _super);
      function TypeGenerator() {
          return _super !== null && _super.apply(this, arguments) || this;
      }
      TypeGenerator.prototype.generate = function (input, args) {
          var name = this.getTypeName(input, args);
          if (this.knownTypes.hasOwnProperty(name)) {
              // Force cast should be safe because of the name lookup.
              return this.knownTypes[name];
          }
          else {
              var type = this.generateInternal(input, args);
              this.knownTypes[name] = type;
              return type;
          }
      };
      return TypeGenerator;
  }(Generator));
  exports.TypeGenerator = TypeGenerator;
  /**
   * Base class for all generators which map
   * a type from the datamodel to some object type.
   *
   * This class adds provides methods that assemble
   * a GraphQLObject type, for code re-use.
   *
   * Ideally a deriving class would override the
   * generateScalarFieldType or generateRelationFieldType methods.
   */
  var TypeFromModelGenerator = /** @class */ (function (_super) {
      __extends(TypeFromModelGenerator, _super);
      function TypeFromModelGenerator() {
          return _super !== null && _super.apply(this, arguments) || this;
      }
      /**
       * Checks if the given list of fields has
       * a unique field.
       * @param fields
       */
      TypeFromModelGenerator.prototype.hasUniqueField = function (fields) {
          return fields.filter(function (field) { return field.isUnique; }).length > 0;
      };
      /**
       * Checks if the given list of fields has
       * other fields than the fields given in the second
       * parameter.
       * @param fields
       * @param fieldNames
       */
      TypeFromModelGenerator.prototype.hasFieldsExcept = function (fields) {
          var fieldNames = [];
          for (var _i = 1; _i < arguments.length; _i++) {
              fieldNames[_i - 1] = arguments[_i];
          }
          return fields.filter(function (field) { return !fieldNames.includes(field.name); }).length > 0;
      };
      /**
       * Returns all fields needed for the create input in the given field list.
       * @param fields
       */
      TypeFromModelGenerator.prototype.getCreateInputFields = function (fields) {
          return fields.filter(function (field) {
              return !field.isReadOnly ||
                  field.idStrategy === prisma_datamodel_1.IdStrategy.Auto ||
                  field.idStrategy === prisma_datamodel_1.IdStrategy.None;
          });
      };
      /**
       * Checks if the given field list contains at least one field that is used in the created input
       * @param fields
       */
      TypeFromModelGenerator.prototype.hasCreateInputFields = function (fields) {
          return this.getCreateInputFields(fields).length > 0;
      };
      /**
       * Returns all writeable fields in the given field list.
       * @param fields
       */
      TypeFromModelGenerator.prototype.getWriteableFields = function (fields) {
          return fields.filter(function (field) { return !field.isReadOnly; });
      };
      /**
       * Checks if the given field list contains at least one writeable field.
       */
      TypeFromModelGenerator.prototype.hasWriteableFields = function (fields) {
          return this.getWriteableFields(fields).length > 0;
      };
      /**
       * Checks if the given list of fields contains at least one scalar field.
       * @param fields
       */
      TypeFromModelGenerator.prototype.hasScalarFields = function (fields) {
          return this.getScalarFields(fields).length > 0;
      };
      /**
       * Returns all scalar fields from the given field list.
       * @param fields
       */
      TypeFromModelGenerator.prototype.getScalarFields = function (fields) {
          var _this = this;
          return fields.filter(function (field) {
              return _this.generators.scalarTypeGenerator.isScalarField(field);
          });
      };
      /**
       * Returns all scalar fields from the given field list.
       * @param fields
       */
      TypeFromModelGenerator.prototype.getRelationFields = function (fields) {
          var _this = this;
          return fields.filter(function (field) { return !_this.generators.scalarTypeGenerator.isScalarField(field); });
      };
      /**
       * Indicates if the resulting type would be empty.
       * @param model
       * @param args
       */
      TypeFromModelGenerator.prototype.wouldBeEmpty = function (model, args) {
          return false;
      };
      /**
       * Generates all fields of this type.
       * @param model
       * @param args
       */
      TypeFromModelGenerator.prototype.generateFields = function (model, args) {
          var fields = {};
          for (var _i = 0, _a = model.fields; _i < _a.length; _i++) {
              var field = _a[_i];
              var fieldSchema = this.generators.scalarTypeGenerator.isScalarField(field)
                  ? this.generateScalarField(model, args, field)
                  : this.generateRelationField(model, args, field);
              if (fieldSchema !== null) {
                  fields[field.name] = fieldSchema;
              }
          }
          return fields;
      };
      /**
       * Calls generateFields and wraps the result into a function.
       * Then calls instantiateObjectType to create the actual AST node.
       * @param model
       * @param args
       */
      TypeFromModelGenerator.prototype.generateInternal = function (model, args) {
          var _this = this;
          var fieldFunction = function () { return _this.generateFields(model, args); };
          return this.instantiateObjectType(this.getTypeName(model, args), fieldFunction);
      };
      TypeFromModelGenerator.prototype.generateScalarField = function (model, args, field) {
          var type = this.generateScalarFieldType(model, args, field);
          if (type === null) {
              return null;
          }
          else {
              // We need a force-cast with any here, since we would need a type constraint for a type that depends on
              // FieldConfig, which is something that TS cannot do.
              return { type: type };
          }
      };
      TypeFromModelGenerator.prototype.generateRelationField = function (model, args, field) {
          var type = this.generateRelationFieldType(model, args, field);
          if (type === null) {
              return null;
          }
          else {
              // We need a force-cast with any here, since we would need a type constraint for a type that depends on
              // FieldConfig, which is something that TS cannot do.
              return { type: type };
          }
      };
      TypeFromModelGenerator.prototype.generateScalarFieldType = function (model, args, field) {
          return this.generators.scalarTypeGenerator.mapToScalarFieldType(field);
      };
      TypeFromModelGenerator.prototype.generateRelationFieldType = function (model, args, field) {
          throw new Error('Method not implemented.');
      };
      return TypeFromModelGenerator;
  }(TypeGenerator));
  exports.TypeFromModelGenerator = TypeFromModelGenerator;
  /**
   * Base class for all generators that generate GraphQLEnums.
   */
  var ModelEnumTypeGeneratorBase = /** @class */ (function (_super) {
      __extends(ModelEnumTypeGeneratorBase, _super);
      function ModelEnumTypeGeneratorBase() {
          return _super !== null && _super.apply(this, arguments) || this;
      }
      ModelEnumTypeGeneratorBase.prototype.instantiateObjectType = function (name, values) {
          return new type_1.GraphQLEnumType({
              name: name,
              values: values(),
          });
      };
      return ModelEnumTypeGeneratorBase;
  }(TypeFromModelGenerator));
  exports.ModelEnumTypeGeneratorBase = ModelEnumTypeGeneratorBase;
  /**
   * Base class for all generators that generate GraphQLObjectTypes.
   */
  var ModelObjectTypeGeneratorBase = /** @class */ (function (_super) {
      __extends(ModelObjectTypeGeneratorBase, _super);
      function ModelObjectTypeGeneratorBase() {
          return _super !== null && _super.apply(this, arguments) || this;
      }
      ModelObjectTypeGeneratorBase.prototype.instantiateObjectType = function (name, fields) {
          return new type_1.GraphQLObjectType({
              name: name,
              fields: fields,
          });
      };
      return ModelObjectTypeGeneratorBase;
  }(TypeFromModelGenerator));
  exports.ModelObjectTypeGeneratorBase = ModelObjectTypeGeneratorBase;
  var ModelObjectTypeGenerator = /** @class */ (function (_super) {
      __extends(ModelObjectTypeGenerator, _super);
      function ModelObjectTypeGenerator() {
          return _super !== null && _super.apply(this, arguments) || this;
      }
      return ModelObjectTypeGenerator;
  }(ModelObjectTypeGeneratorBase));
  exports.ModelObjectTypeGenerator = ModelObjectTypeGenerator;
  /**
   * Base class for all generators that generate GraphQLInputObjectTypes.
   */
  var ModelInputObjectTypeGeneratorBase = /** @class */ (function (_super) {
      __extends(ModelInputObjectTypeGeneratorBase, _super);
      function ModelInputObjectTypeGeneratorBase() {
          return _super !== null && _super.apply(this, arguments) || this;
      }
      ModelInputObjectTypeGeneratorBase.prototype.instantiateObjectType = function (name, fields) {
          return new type_1.GraphQLInputObjectType({
              name: name,
              fields: fields,
          });
      };
      return ModelInputObjectTypeGeneratorBase;
  }(TypeFromModelGenerator));
  exports.ModelInputObjectTypeGeneratorBase = ModelInputObjectTypeGeneratorBase;
  var ModelInputObjectTypeGenerator = /** @class */ (function (_super) {
      __extends(ModelInputObjectTypeGenerator, _super);
      function ModelInputObjectTypeGenerator() {
          return _super !== null && _super.apply(this, arguments) || this;
      }
      return ModelInputObjectTypeGenerator;
  }(ModelInputObjectTypeGeneratorBase));
  exports.ModelInputObjectTypeGenerator = ModelInputObjectTypeGenerator;
  /**
   * Special base class for the scalar field generator.
   */
  var ScalarTypeGeneratorBase = /** @class */ (function (_super) {
      __extends(ScalarTypeGeneratorBase, _super);
      function ScalarTypeGeneratorBase() {
          return _super !== null && _super.apply(this, arguments) || this;
      }
      return ScalarTypeGeneratorBase;
  }(TypeGenerator));
  exports.ScalarTypeGeneratorBase = ScalarTypeGeneratorBase;
  /**
   * Abstract base class for all generators that generate scalar input fields.
   */
  var ScalarInputGenerator = /** @class */ (function (_super) {
      __extends(ScalarInputGenerator, _super);
      function ScalarInputGenerator() {
          return _super !== null && _super.apply(this, arguments) || this;
      }
      return ScalarInputGenerator;
  }(TypeGenerator));
  exports.ScalarInputGenerator = ScalarInputGenerator;
  /**
   * Base class for generators that generate argument lists.
   */
  var ArgumentsGenerator = /** @class */ (function (_super) {
      __extends(ArgumentsGenerator, _super);
      function ArgumentsGenerator() {
          return _super !== null && _super.apply(this, arguments) || this;
      }
      ArgumentsGenerator.prototype.wouldBeEmpty = function (model, args) {
          return false;
      };
      return ArgumentsGenerator;
  }(Generator));
  exports.ArgumentsGenerator = ArgumentsGenerator;
  /**
   * Arguments passed to generators that need to take a related field into account.
   */
  var RelatedGeneratorArgs = /** @class */ (function () {
      function RelatedGeneratorArgs() {
      }
      return RelatedGeneratorArgs;
  }());
  exports.RelatedGeneratorArgs = RelatedGeneratorArgs;
  /**
   * Base class for generators that generate GraphQLObject types which take a related field into account.
   */
  var RelatedModelInputObjectTypeGenerator = /** @class */ (function (_super) {
      __extends(RelatedModelInputObjectTypeGenerator, _super);
      function RelatedModelInputObjectTypeGenerator() {
          return _super !== null && _super.apply(this, arguments) || this;
      }
      return RelatedModelInputObjectTypeGenerator;
  }(ModelInputObjectTypeGeneratorBase));
  exports.RelatedModelInputObjectTypeGenerator = RelatedModelInputObjectTypeGenerator;
  /**
   * Base class for generators that generate a GraphQLObjectType without taking any input.
   */
  var AuxillaryObjectTypeGenerator = /** @class */ (function (_super) {
      __extends(AuxillaryObjectTypeGenerator, _super);
      function AuxillaryObjectTypeGenerator() {
          return _super !== null && _super.apply(this, arguments) || this;
      }
      return AuxillaryObjectTypeGenerator;
  }(TypeGenerator));
  exports.AuxillaryObjectTypeGenerator = AuxillaryObjectTypeGenerator;
  /**
   * Base class for generators that generate a GraphQLInterfaceType without taking any input.
   */
  var AuxillaryInterfaceGenerator = /** @class */ (function (_super) {
      __extends(AuxillaryInterfaceGenerator, _super);
      function AuxillaryInterfaceGenerator() {
          return _super !== null && _super.apply(this, arguments) || this;
      }
      return AuxillaryInterfaceGenerator;
  }(TypeGenerator));
  exports.AuxillaryInterfaceGenerator = AuxillaryInterfaceGenerator;
  /**
   * Base class for generators that generate a GraphQLInputObjectType without taking any input.
   */
  var AuxillaryInputObjectTypeGenerator = /** @class */ (function (_super) {
      __extends(AuxillaryInputObjectTypeGenerator, _super);
      function AuxillaryInputObjectTypeGenerator() {
          return _super !== null && _super.apply(this, arguments) || this;
      }
      return AuxillaryInputObjectTypeGenerator;
  }(TypeGenerator));
  exports.AuxillaryInputObjectTypeGenerator = AuxillaryInputObjectTypeGenerator;
  /**
   * Base class for generators that generate a GraphQLEnumType without taking any input.
   */
  var AuxillaryEnumGenerator = /** @class */ (function (_super) {
      __extends(AuxillaryEnumGenerator, _super);
      function AuxillaryEnumGenerator() {
          return _super !== null && _super.apply(this, arguments) || this;
      }
      return AuxillaryEnumGenerator;
  }(TypeGenerator));
  exports.AuxillaryEnumGenerator = AuxillaryEnumGenerator;
  /**
   * Base class for generators that generate a query, mutation or subscription object from
   * a list of datamodel types.
   */
  var RootGenerator = /** @class */ (function (_super) {
      __extends(RootGenerator, _super);
      function RootGenerator() {
          return _super !== null && _super.apply(this, arguments) || this;
      }
      return RootGenerator;
  }(TypeGenerator));
  exports.RootGenerator = RootGenerator;
  /**
   * Base class for generators that generate a schema from a list of datamodel types.
   */
  var SchemaGeneratorBase = /** @class */ (function (_super) {
      __extends(SchemaGeneratorBase, _super);
      function SchemaGeneratorBase() {
          return _super !== null && _super.apply(this, arguments) || this;
      }
      return SchemaGeneratorBase;
  }(Generator));
  exports.SchemaGeneratorBase = SchemaGeneratorBase;
  /**
   * Utility class that merges field configration.
   */
  var FieldConfigUtils = /** @class */ (function () {
      function FieldConfigUtils() {
      }
      /**
       * Merges all given field config maps.
       * @param fieldMaps The field config maps to merge.
       */
      FieldConfigUtils.merge = function () {
          var fieldMaps = [];
          for (var _i = 0; _i < arguments.length; _i++) {
              fieldMaps[_i] = arguments[_i];
          }
          var newMap = {};
          var _loop_1 = function (fieldMap) {
              if (fieldMap === null) {
                  return "continue";
              }
              Object.keys(fieldMap).forEach(function (name) {
                  var field = fieldMap[name];
                  if (name in newMap) {
                      throw new Error('Field configuration to merge has duplicate field names.');
                  }
                  newMap[name] = field;
              });
          };
          for (var _a = 0, fieldMaps_1 = fieldMaps; _a < fieldMaps_1.length; _a++) {
              var fieldMap = fieldMaps_1[_a];
              _loop_1(fieldMap);
          }
          return newMap;
      };
      return FieldConfigUtils;
  }());
  exports.FieldConfigUtils = FieldConfigUtils;
  //# sourceMappingURL=generator.js.map