<commit_before>import {
  InlineFragmentNode,
  FragmentDefinitionNode,
  SelectionSetNode,
  FieldNode,
} from "graphql";

import { KeyTrie } from 'optimism';
import { invariant, InvariantError } from 'ts-invariant';

import {
  FragmentMap,
  getFragmentFromSelection,
} from '../../utilities/graphql/fragments';
import {
  isField,
  getTypenameFromResult,
  storeKeyNameFromField,
  StoreValue,
  StoreObject,
  argumentsObjectFromField,
  Reference,
  isReference,
  getStoreKeyName,
} from '../../utilities/graphql/storeUtils';
import { canUseWeakMap } from '../../utilities/common/canUse';
import { IdGetter } from "./types";
import {
  hasOwn,
  fieldNameFromStoreName,
  FieldValueToBeMerged,
  isFieldValueToBeMerged,
  storeValueIsStoreObject,
} from './helpers';
import { FieldValueGetter } from './entityStore';
import { InMemoryCache } from './inMemoryCache';
import {
  SafeReadonly,
  FieldSpecifier,
  ToReferenceFunction,
  ReadFieldFunction,
  ReadFieldOptions,
} from '../core/types/common';

export type TypePolicies = {
  [__typename: string]: TypePolicy;
}

// TypeScript 3.7 will allow recursive type aliases, so this should work:
// type KeySpecifier = (string | KeySpecifier)[]
type KeySpecifier = (string | any[])[];

type KeyFieldsContext = {
  typename?: string;
  selectionSet?: SelectionSetNode;
  fragmentMap?: FragmentMap;
  // May be set by the KeyFieldsFunction to report fields that were involved
  // in computing the ID. Never passed in by the caller.
  keyObject?: Record<string, any>;
};

export type KeyFieldsFunction = (
  object: Readonly<StoreObject>,
  context: KeyFieldsContext,
) => KeySpecifier | ReturnType<IdGetter>;

export type TypePolicy = {
  // Allows defining the primary key fields for this type, either using an
  // array of field names or a function that returns an arbitrary string.
  keyFields?: KeySpecifier | KeyFieldsFunction | false;

  // In the rare event that your schema happens to use a different
  // __typename for the root Query, Mutation, and/or Schema types, you can
  // express your deviant preferences by enabling one of these options.
  queryType?: true,
  mutationType?: true,
  subscriptionType?: true,

  fields?: {
    [fieldName: string]:
      | FieldPolicy<any>
      | FieldReadFunction<any>;
  }
};

export type KeyArgsFunction = (
  args: Record<string, any> | null,
  context: {
    typename: string;
    fieldName: string;
    field: FieldNode | null;
  },
) => KeySpecifier | ReturnType<IdGetter>;

export type FieldPolicy<
  TExisting = any,
  TIncoming = TExisting,
  TReadResult = TExisting,
> = {
  keyArgs?: KeySpecifier | KeyArgsFunction | false;
  read?: FieldReadFunction<TExisting, TReadResult>;
  merge?: FieldMergeFunction<TExisting, TIncoming>;
};

type StorageType = Record<string, any>;

function argsFromFieldSpecifier(spec: FieldSpecifier) {
  return spec.args !== void 0 ? spec.args :
    spec.field ? argumentsObjectFromField(spec.field, spec.variables) : null;
}

export interface FieldFunctionOptions<
  TArgs = Record<string, any>,
  TVars = Record<string, any>,
> {
  args: TArgs | null;

  // The name of the field, equal to options.field.name.value when
  // options.field is available. Useful if you reuse the same function for
  // multiple fields, and you need to know which field you're currently
  // processing. Always a string, even when options.field is null.
  fieldName: string;

  // The full field key used internally, including serialized key arguments.
  storeFieldName: string;

  // The FieldNode object used to read this field. Useful if you need to
  // know about other attributes of the field, such as its directives. This
  // option will be null when a string was passed to options.readField.
  field: FieldNode | null;

  variables?: TVars;

  // Utilities for dealing with { __ref } objects.
  isReference: typeof isReference;
  toReference: ToReferenceFunction;

  // A handy place to put field-specific data that you want to survive
  // across multiple read function calls. Useful for field-level caching,
  // if your read function does any expensive work.
  storage: StorageType | null;

  cache: InMemoryCache;

  // Helper function for reading other fields within the current object.
  // If a foreign object or reference is provided, the field will be read
  // from that object instead of the current object, so this function can
  // be used (together with isReference) to examine the cache outside the
  // current object. If a FieldNode is passed instead of a string, and
  // that FieldNode has arguments, the same options.variables will be used
  // to compute the argument values. Note that this function will invoke
  // custom read functions for other fields, if defined. Always returns
  // immutable data (enforced with Object.freeze in development).
  readField: ReadFieldFunction;

  // Instead of just merging objects with { ...existing, ...incoming }, this
  // helper function can be used to merge objects in a way that respects any
  // custom merge functions defined for their fields.
  mergeObjects<T extends StoreObject | Reference>(
    existing: T,
    incoming: T,
  ): T | undefined;
}

export type FieldReadFunction<TExisting = any, TReadResult = TExisting> = (
  // When reading a field, one often needs to know about any existing
  // value stored for that field. If the field is read before any value
  // has been written to the cache, this existing parameter will be
  // undefined, which makes it easy to use a default parameter expression
  // to supply the initial value. This parameter is positional (rather
  // than one of the named options) because that makes it possible for the
  // developer to annotate it with a type, without also having to provide
  // a whole new type for the options object.
  existing: SafeReadonly<TExisting> | undefined,
  options: FieldFunctionOptions,
) => TReadResult | undefined;

export type FieldMergeFunction<TExisting = any, TIncoming = TExisting> = (
  existing: SafeReadonly<TExisting> | undefined,
  // The incoming parameter needs to be positional as well, for the same
  // reasons discussed in FieldReadFunction above.
  incoming: SafeReadonly<TIncoming>,
  options: FieldFunctionOptions,
) => TExisting;

export const defaultDataIdFromObject: KeyFieldsFunction = (
  { __typename, id, _id },
  context,
) => {
  if (typeof __typename === "string") {
    if (context) {
      context.keyObject =
         id !== void 0 ? {  id } :
        _id !== void 0 ? { _id } :
        void 0;
    }
    const idValue = id || _id;
    if (idValue !== void 0) {
      return `${__typename}:${(
        typeof idValue === "number" ||
        typeof idValue === "string"<commit_msg>Improve defaultDataIdFromObject type declaration (#6382)<commit_after>import {
  InlineFragmentNode,
  FragmentDefinitionNode,
  SelectionSetNode,
  FieldNode,
} from "graphql";

import { KeyTrie } from 'optimism';
import { invariant, InvariantError } from 'ts-invariant';

import {
  FragmentMap,
  getFragmentFromSelection,
} from '../../utilities/graphql/fragments';
import {
  isField,
  getTypenameFromResult,
  storeKeyNameFromField,
  StoreValue,
  StoreObject,
  argumentsObjectFromField,
  Reference,
  isReference,
  getStoreKeyName,
} from '../../utilities/graphql/storeUtils';
import { canUseWeakMap } from '../../utilities/common/canUse';
import { IdGetter } from "./types";
import {
  hasOwn,
  fieldNameFromStoreName,
  FieldValueToBeMerged,
  isFieldValueToBeMerged,
  storeValueIsStoreObject,
} from './helpers';
import { FieldValueGetter } from './entityStore';
import { InMemoryCache } from './inMemoryCache';
import {
  SafeReadonly,
  FieldSpecifier,
  ToReferenceFunction,
  ReadFieldFunction,
  ReadFieldOptions,
} from '../core/types/common';

export type TypePolicies = {
  [__typename: string]: TypePolicy;
}

// TypeScript 3.7 will allow recursive type aliases, so this should work:
// type KeySpecifier = (string | KeySpecifier)[]
type KeySpecifier = (string | any[])[];

type KeyFieldsContext = {
  typename?: string;
  selectionSet?: SelectionSetNode;
  fragmentMap?: FragmentMap;
  // May be set by the KeyFieldsFunction to report fields that were involved
  // in computing the ID. Never passed in by the caller.
  keyObject?: Record<string, any>;
};

export type KeyFieldsFunction = (
  object: Readonly<StoreObject>,
  context: KeyFieldsContext,
) => KeySpecifier | ReturnType<IdGetter>;

export type TypePolicy = {
  // Allows defining the primary key fields for this type, either using an
  // array of field names or a function that returns an arbitrary string.
  keyFields?: KeySpecifier | KeyFieldsFunction | false;

  // In the rare event that your schema happens to use a different
  // __typename for the root Query, Mutation, and/or Schema types, you can
  // express your deviant preferences by enabling one of these options.
  queryType?: true,
  mutationType?: true,
  subscriptionType?: true,

  fields?: {
    [fieldName: string]:
      | FieldPolicy<any>
      | FieldReadFunction<any>;
  }
};

export type KeyArgsFunction = (
  args: Record<string, any> | null,
  context: {
    typename: string;
    fieldName: string;
    field: FieldNode | null;
  },
) => KeySpecifier | ReturnType<IdGetter>;

export type FieldPolicy<
  TExisting = any,
  TIncoming = TExisting,
  TReadResult = TExisting,
> = {
  keyArgs?: KeySpecifier | KeyArgsFunction | false;
  read?: FieldReadFunction<TExisting, TReadResult>;
  merge?: FieldMergeFunction<TExisting, TIncoming>;
};

type StorageType = Record<string, any>;

function argsFromFieldSpecifier(spec: FieldSpecifier) {
  return spec.args !== void 0 ? spec.args :
    spec.field ? argumentsObjectFromField(spec.field, spec.variables) : null;
}

export interface FieldFunctionOptions<
  TArgs = Record<string, any>,
  TVars = Record<string, any>,
> {
  args: TArgs | null;

  // The name of the field, equal to options.field.name.value when
  // options.field is available. Useful if you reuse the same function for
  // multiple fields, and you need to know which field you're currently
  // processing. Always a string, even when options.field is null.
  fieldName: string;

  // The full field key used internally, including serialized key arguments.
  storeFieldName: string;

  // The FieldNode object used to read this field. Useful if you need to
  // know about other attributes of the field, such as its directives. This
  // option will be null when a string was passed to options.readField.
  field: FieldNode | null;

  variables?: TVars;

  // Utilities for dealing with { __ref } objects.
  isReference: typeof isReference;
  toReference: ToReferenceFunction;

  // A handy place to put field-specific data that you want to survive
  // across multiple read function calls. Useful for field-level caching,
  // if your read function does any expensive work.
  storage: StorageType | null;

  cache: InMemoryCache;

  // Helper function for reading other fields within the current object.
  // If a foreign object or reference is provided, the field will be read
  // from that object instead of the current object, so this function can
  // be used (together with isReference) to examine the cache outside the
  // current object. If a FieldNode is passed instead of a string, and
  // that FieldNode has arguments, the same options.variables will be used
  // to compute the argument values. Note that this function will invoke
  // custom read functions for other fields, if defined. Always returns
  // immutable data (enforced with Object.freeze in development).
  readField: ReadFieldFunction;

  // Instead of just merging objects with { ...existing, ...incoming }, this
  // helper function can be used to merge objects in a way that respects any
  // custom merge functions defined for their fields.
  mergeObjects<T extends StoreObject | Reference>(
    existing: T,
    incoming: T,
  ): T | undefined;
}

export type FieldReadFunction<TExisting = any, TReadResult = TExisting> = (
  // When reading a field, one often needs to know about any existing
  // value stored for that field. If the field is read before any value
  // has been written to the cache, this existing parameter will be
  // undefined, which makes it easy to use a default parameter expression
  // to supply the initial value. This parameter is positional (rather
  // than one of the named options) because that makes it possible for the
  // developer to annotate it with a type, without also having to provide
  // a whole new type for the options object.
  existing: SafeReadonly<TExisting> | undefined,
  options: FieldFunctionOptions,
) => TReadResult | undefined;

export type FieldMergeFunction<TExisting = any, TIncoming = TExisting> = (
  existing: SafeReadonly<TExisting> | undefined,
  // The incoming parameter needs to be positional as well, for the same
  // reasons discussed in FieldReadFunction above.
  incoming: SafeReadonly<TIncoming>,
  options: FieldFunctionOptions,
) => TExisting;

export const defaultDataIdFromObject = (
  { __typename, id, _id }: Readonly<StoreObject>,
  context?: KeyFieldsContext,
) => {
  if (typeof __typename === "string") {
    if (context) {
      context.keyObject =
         id !== void 0 ? {  id } :
        _id !== void 0 ? { _id } :
        void 0;
    }
    const idValue = id || _id;
    if (idValue !== void 0) {
      return `${__typename}:${(
        typeof idValue === "number" ||
        typeof idValue === "string"
{'fraction_non_alphanumeric': 0.09252378121284185, 'fraction_numerical': 0.00133769322235434, 'mean_word_length': 3.705244755244755, 'pattern_counts': {'":': 0, '<': 44, '<?xml version=': 0, '>': 54, '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': '1531236', 'n_tokens_mistral': 3778, 'n_tokens_neox': 3728, 'n_words': 1452}