<commit_before>/* @flow */

import type { ComposeFieldConfigMap } from 'graphql-compose';
import {
  EnumTypeComposer,
  graphql,
  schemaComposer,
  SchemaComposer,
  TypeComposer,
} from 'graphql-compose';
import type { GraphQLFieldConfigMap } from 'graphql-compose/lib/graphql';
import type {
  ComposePartialFieldConfigAsObject,
  RelationOpts,
} from 'graphql-compose/lib/TypeComposer';
import { Model } from 'mongoose';
import type { TypeConverterOpts } from './composeWithMongoose';
import { composeWithMongoose } from './composeWithMongoose';
import { composeChildTC } from './discriminators';
import { mergeCustomizationOptions } from './discriminators/merge-customization-options';
import { prepareBaseResolvers } from './discriminators/prepare-resolvers/prepareBaseResolvers';
import { reorderFields } from './discriminators/utils';

const { GraphQLInterfaceType } = graphql;

export type Options = {
  test_disTypes?: boolean,
  reorderFields?: boolean | string[], // true order: _id, DKey, DInterfaceFields, DiscriminatorFields
  customizationOptions?: TypeConverterOpts,
};

type Discriminators = {
  [DName: string]: any,
};

// sets the values on DKey enum TC
function setDKeyETCValues(discriminators: Discriminators): any {
  const values: { [propName: string]: { value: string } } = {};

  for (const DName in discriminators) {
    if (discriminators.hasOwnProperty(DName)) {
      values[DName] = {
        value: DName,
      };
    }
  }

  return values;
}

// creates an enum from discriminator names
// then sets this enum type as the discriminator key field type
function createAndSetDKeyETC(dTC: DiscriminatorTypeComposer, discriminators: Discriminators) {
  const DKeyETC = EnumTypeComposer.create({
    name: `EnumDKey${dTC.getDBaseName()}${dTC.getDKey()[0].toUpperCase() +
      dTC.getDKey().substr(1)}`,
    values: setDKeyETCValues(discriminators),
  });

  // set on Output
  dTC.extendField(dTC.getDKey(), {
    type: () => DKeyETC,
  });

  // set on Input
  dTC.getInputTypeComposer().extendField(dTC.getDKey(), {
    type: () => DKeyETC,
  });

  return DKeyETC;
}

function getBaseTCFieldsWithTypes(baseTC: TypeComposer) {
  const baseFields = baseTC.getFieldNames();
  const baseFieldsWithTypes: GraphQLFieldConfigMap<any, any> = {};

  for (const field of baseFields) {
    baseFieldsWithTypes[field] = baseTC.getFieldConfig(field);
  }

  return baseFieldsWithTypes;
}

function createDInterface(baseModelTC: DiscriminatorTypeComposer): GraphQLInterfaceType {
  return new GraphQLInterfaceType({
    name: `${baseModelTC.getDBaseName()}Interface`,

    resolveType: (value: any) => {
      const childDName = value[baseModelTC.getDKey()];
      const sComposer = baseModelTC.getGQC(); // get schemaComposer

      if (childDName) {
        return sComposer.getTC(childDName).getType();
      }

      // as fallback return BaseModelTC
      return sComposer.getTC(baseModelTC.getTypeName()).getType();
    },
    // hoisting issue solved, get at time :)
    fields: () => getBaseTCFieldsWithTypes(baseModelTC),
  });
}

export class DiscriminatorTypeComposer extends TypeComposer {
  modelName: string;

  discriminatorKey: string;

  DKeyETC: EnumTypeComposer;

  GQC: SchemaComposer<any>;

  opts: Options;

  DInterface: GraphQLInterfaceType;

  discriminators: Discriminators;

  childTCs: TypeComposer[];

  constructor(baseModel: Model, opts?: any) {
    if (!baseModel || !(baseModel: any).discriminators) {
      throw Error('Discriminator Key not Set, Use composeWithMongoose for Normal Collections');
    }

    opts = {  // eslint-disable-line
      reorderFields: true,
      customizationOptions: {
        schemaComposer,
      },
      ...opts,
    };

    super(composeWithMongoose(baseModel, opts.customizationOptions).gqType);

    // !ORDER MATTERS
    this.opts = opts;
    this.modelName = (baseModel: any).modelName;
    this.discriminatorKey = (baseModel: any).schema.get('discriminatorKey') || '__t';

    // discriminants and object containing all discriminants with key
    // key being their DNames
    this.discriminators = (baseModel: any).discriminators;

    this.childTCs = [];
    this.GQC =
      opts.customizationOptions && opts.customizationOptions.schemaComposer
        ? opts.customizationOptions.schemaComposer
        : schemaComposer;
    this.setTypeName(this.modelName);
    this.DKeyETC = createAndSetDKeyETC(this, this.discriminators);

    reorderFields(this, (this.opts: any).reorderFields, this.discriminatorKey);

    this.DInterface = createDInterface(this);
    this.setInterfaces([this.DInterface]);

    // Hoist on _disTypes
    if (opts.test_disTypes) {
      if (!this.GQC.rootQuery().hasField('_disTypes')) {
        this.GQC.rootQuery().addFields({
          _disTypes: TypeComposer.create({
            name: '_disTypes',
            description: 'Hoisting for Discriminator Types',
          }),
        });
      }

      this.GQC.rootQuery()
        .getFieldTC('_disTypes')
        .addFields({
          [this.getTypeName()]: this,
        });
    }

    // prepare Base Resolvers
    prepareBaseResolvers(this);
  }

  getGQC(): SchemaComposer<any> {
    return this.GQC;
  }

  getDKey(): string {
    return this.discriminatorKey;
  }

  getDKeyETC(): EnumTypeComposer {
    return this.DKeyETC;
  }

  getDBaseName(): string {
    return this.modelName;
  }

  getDInterface(): GraphQLInterfaceType {
    return this.DInterface;
  }

  hasChildTC(DName: string): boolean {
    return !!this.childTCs.find(ch => ch.getTypeName() === DName);
  }<commit_msg>fix: remove YAGNI method getGQC(), rename GQC to schemaComposer<commit_after>/* @flow */

import type { ComposeFieldConfigMap } from 'graphql-compose';
import {
  EnumTypeComposer,
  graphql,
  schemaComposer,
  SchemaComposer,
  TypeComposer,
} from 'graphql-compose';
import type { GraphQLFieldConfigMap } from 'graphql-compose/lib/graphql';
import type {
  ComposePartialFieldConfigAsObject,
  RelationOpts,
} from 'graphql-compose/lib/TypeComposer';
import { Model } from 'mongoose';
import type { TypeConverterOpts } from './composeWithMongoose';
import { composeWithMongoose } from './composeWithMongoose';
import { composeChildTC } from './discriminators';
import { mergeCustomizationOptions } from './discriminators/merge-customization-options';
import { prepareBaseResolvers } from './discriminators/prepare-resolvers/prepareBaseResolvers';
import { reorderFields } from './discriminators/utils';

const { GraphQLInterfaceType } = graphql;

export type Options = {
  test_disTypes?: boolean,
  reorderFields?: boolean | string[], // true order: _id, DKey, DInterfaceFields, DiscriminatorFields
  customizationOptions?: TypeConverterOpts,
};

type Discriminators = {
  [DName: string]: any,
};

// sets the values on DKey enum TC
function setDKeyETCValues(discriminators: Discriminators): any {
  const values: { [propName: string]: { value: string } } = {};

  for (const DName in discriminators) {
    if (discriminators.hasOwnProperty(DName)) {
      values[DName] = {
        value: DName,
      };
    }
  }

  return values;
}

// creates an enum from discriminator names
// then sets this enum type as the discriminator key field type
function createAndSetDKeyETC(dTC: DiscriminatorTypeComposer, discriminators: Discriminators) {
  const DKeyETC = EnumTypeComposer.create({
    name: `EnumDKey${dTC.getDBaseName()}${dTC.getDKey()[0].toUpperCase() +
      dTC.getDKey().substr(1)}`,
    values: setDKeyETCValues(discriminators),
  });

  // set on Output
  dTC.extendField(dTC.getDKey(), {
    type: () => DKeyETC,
  });

  // set on Input
  dTC.getInputTypeComposer().extendField(dTC.getDKey(), {
    type: () => DKeyETC,
  });

  return DKeyETC;
}

function getBaseTCFieldsWithTypes(baseTC: TypeComposer) {
  const baseFields = baseTC.getFieldNames();
  const baseFieldsWithTypes: GraphQLFieldConfigMap<any, any> = {};

  for (const field of baseFields) {
    baseFieldsWithTypes[field] = baseTC.getFieldConfig(field);
  }

  return baseFieldsWithTypes;
}

function createDInterface(baseModelTC: DiscriminatorTypeComposer): GraphQLInterfaceType {
  return new GraphQLInterfaceType({
    name: `${baseModelTC.getDBaseName()}Interface`,

    resolveType: (value: any) => {
      const childDName = value[baseModelTC.getDKey()];

      if (childDName) {
        return baseModelTC.schemaComposer.getTC(childDName).getType();
      }

      // as fallback return BaseModelTC
      return baseModelTC.schemaComposer.getTC(baseModelTC.getTypeName()).getType();
    },
    // hoisting issue solved, get at time :)
    fields: () => getBaseTCFieldsWithTypes(baseModelTC),
  });
}

export class DiscriminatorTypeComposer extends TypeComposer {
  modelName: string;

  discriminatorKey: string;

  DKeyETC: EnumTypeComposer;

  schemaComposer: SchemaComposer<any>;

  opts: Options;

  DInterface: GraphQLInterfaceType;

  discriminators: Discriminators;

  childTCs: TypeComposer[];

  constructor(baseModel: Model, opts?: any) {
    if (!baseModel || !(baseModel: any).discriminators) {
      throw Error('Discriminator Key not Set, Use composeWithMongoose for Normal Collections');
    }

    opts = {  // eslint-disable-line
      reorderFields: true,
      customizationOptions: {
        schemaComposer,
      },
      ...opts,
    };

    super(composeWithMongoose(baseModel, opts.customizationOptions).gqType);

    // !ORDER MATTERS
    this.opts = opts;
    this.modelName = (baseModel: any).modelName;
    this.discriminatorKey = (baseModel: any).schema.get('discriminatorKey') || '__t';

    // discriminants and object containing all discriminants with key
    // key being their DNames
    this.discriminators = (baseModel: any).discriminators;

    this.childTCs = [];
    this.schemaComposer =
      opts.customizationOptions && opts.customizationOptions.schemaComposer
        ? opts.customizationOptions.schemaComposer
        : schemaComposer;
    this.setTypeName(this.modelName);
    this.DKeyETC = createAndSetDKeyETC(this, this.discriminators);

    reorderFields(this, (this.opts: any).reorderFields, this.discriminatorKey);

    this.DInterface = createDInterface(this);
    this.setInterfaces([this.DInterface]);

    // Hoist on _disTypes
    if (opts.test_disTypes) {
      if (!this.GQC.rootQuery().hasField('_disTypes')) {
        this.GQC.rootQuery().addFields({
          _disTypes: TypeComposer.create({
            name: '_disTypes',
            description: 'Hoisting for Discriminator Types',
          }),
        });
      }

      this.GQC.rootQuery()
        .getFieldTC('_disTypes')
        .addFields({
          [this.getTypeName()]: this,
        });
    }

    // prepare Base Resolvers
    prepareBaseResolvers(this);
  }

  getDKey(): string {
    return this.discriminatorKey;
  }

  getDKeyETC(): EnumTypeComposer {
    return this.DKeyETC;
  }

  getDBaseName(): string {
    return this.modelName;
  }

  getDInterface(): GraphQLInterfaceType {
    return this.DInterface;
  }

  hasChildTC(DName: string): boolean {
    return !!this.childTCs.find(ch => ch.getTypeName() === DName);
  }
{'fraction_non_alphanumeric': 0.1198919891989199, 'fraction_numerical': 0.00036003600360036, 'mean_word_length': 3.714043275350021, 'pattern_counts': {'":': 0, '<': 8, '<?xml version=': 0, '>': 18, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2752946', 'n_tokens_mistral': 3571, 'n_tokens_neox': 3470, 'n_words': 705}