/**
 * THIS IS AN AUTO-GENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
 */
/* eslint-disable no-console,no-underscore-dangle */
import type { ReactText } from 'react';
import type { SortOrder } from 'antd/lib/table/interface';
import type { DataIndex } from '../utils';
import { isObject, isString, capitalize } from '../utils';
import { relationMap, isPureFieldItem, isNameKeyItem, isRelateFieldItem } from './items';
import type { PureFieldItem, RelateFieldItem } from './items';
import deepEqual from 'fast-deep-equal';
import moment from 'moment';
import request from './request';

export function getRelationMap(table: string) {
  const result = relationMap[capitalize(table)];
  if (!result) {
    console.warn(table, 'table not found');
  }
  return result;
}

export function getFields(table: string): string[] {
  return getRelationMap(table)
    .filter(isPureFieldItem)
    .map((item) => item.key);
}

export function getNameKey(table: string): string {
  return getRelationMap(table).find(isNameKeyItem)?.nameKey || 'id';
}

export function getField(table: string, key: string): PureFieldItem | RelateFieldItem {
  return getRelationMap(table).find((item) => (item as PureFieldItem).key === key) as
    | PureFieldItem
    | RelateFieldItem;
}

export function getFieldType(table: string, fieldName: string): string | undefined {
  const [name, ...restName] = fieldName.split('.');

  const field = getField(table, name);
  if (!field) return undefined;
  if (isRelateFieldItem(field)) {
    if (restName.length > 0) {
      return getFieldType(field.relation, restName.join('.'));
    }
    return undefined;
  }
  return field.type;
}

export function getKeyFields(table: string) {
  return [...new Set([getNameKey(table), 'id'])];
}

export function appendRelateIds(item: any) {
  const relateIds = {};
  Object.entries(item).forEach(([key, value]) => {
    if (Array.isArray(value)) {
      relateIds['@set'] = relateIds['@set'] ?? {};
      relateIds['@set'][key] = value.map((n: any) => n.id).filter(Boolean);
      const newValue = value.map((n) => appendRelateIds(n));
      Object.assign(item, { [key]: newValue });
    } else if (isObject(value)) {
      relateIds['@connect'] = relateIds['@connect'] ?? {};
      relateIds['@connect'][key] = (value as any).id;
      const newValue = appendRelateIds(value);
      Object.assign(item, { [key]: newValue });
    }
  });
  return {
    ...item,
    ...relateIds,
  };
}

export function batchAppendRelateIds(arr: any[]) {
  return arr.map((item) => appendRelateIds(item));
}

/**
 * GQL拼接工具
 */
export function getAggAttr(table: string) {
  return `aggregate${capitalize(table)}`;
}

export function getCountGql(table: string) {
  const aggAttr = getAggAttr(table);
  return `${aggAttr}(where: $where) {
    _count {
      _all
    }
  }`;
}

export function dataIndexToField(dataIndex?: DataIndex): string {
  if (!dataIndex) {
    return '';
  }
  // 兼容['@connect', 'user']格式
  if (Array.isArray(dataIndex)) {
    return String(dataIndex[dataIndex.length - 1]);
  }
  // 兼容@connect.user格式
  const indexes = String(dataIndex).split('.');
  return indexes[indexes.length - 1];
}

/**
 * 表单columns转graphql查询字段
 * @param columns
 * @param parent 父级对象名
 */
export function formColumnsToFields(table: string, columns: any[], parent = ''): string[] {
  const items = getRelationMap(table);
  return columns.reduce((acc, column) => {
    if (Array.isArray(column)) {
      const fields = formColumnsToFields(table, column, parent);
      return acc.concat(fields);
    }

    if (column.hideInForm) return acc;

    const subField = dataIndexToField(column.dataIndex || column._models);
    const field = [parent, subField].filter(Boolean).join('.');
    const item = items.filter(isRelateFieldItem).find((n) => n.key === subField);

    const subColumns = column._columns || column.columns;
    const subTable = item?.relation || table;
    if (subColumns) {
      const fields = formColumnsToFields(subTable, subColumns, field);
      return acc.concat(fields);
    }

    // 关联选择，未指定字段，返回nameKey
    if (item?.relation) {
      const fields = getKeyFields(item.relation).map((n: string) => `${field}.${n}`);
      return acc.concat(fields);
    }

    acc.push(field);
    return acc;
  }, []);
}

/**
 * fields字段数组转object
 * @param fields ['id','title','post.id','post.name']
 * @return {id:true,title:true,post:{id:true,name:true}}
 */
export function fieldsToRecord(fields: string[]) {
  return fields.reduce((acc, field) => {
    const fieldKeys = field.split('.');
    const fieldKeysLen = fieldKeys.length;
    fieldKeys.reduce((fieldAcc, key, index) => {
      if (index === fieldKeysLen - 1) {
        // the last item
        Object.assign(fieldAcc, { [key]: true });
        // auto append id field
        if (fieldKeys[index - 1] !== '_count') {
          // _count统计没有id
          Object.assign(fieldAcc, { id: true });
        }
      } else if (!fieldAcc[key]) {
        // has't define previous
        Object.assign(fieldAcc, { [key]: {} });
      }
      return fieldAcc[key];
    }, acc);
    return acc;
  }, {});
}

export function fieldRecordToGql(fields: Record<string, any>, paddingStart = ''): string {
  return Object.entries(fields)
    .map(([key, value]) => {
      if (isObject(value)) {
        const subFields = fieldRecordToGql(value, `${paddingStart}  `);
        return `${paddingStart}${key} {\n${subFields}\n${paddingStart}}`;
      }
      return `${paddingStart}${key}`;
    })
    .join('\n');
}

export type FieldsType = string[] | Record<string, any> | string;
export function fieldsToGql(fields: FieldsType) {
  if (Array.isArray(fields)) {
    return fieldRecordToGql(fieldsToRecord(fields));
  }
  if (typeof fields === 'string') {
    return fields;
  }
  return fieldRecordToGql(fields);
}

export function fragmentsRecordToGql(items: Record<string, unknown[]>) {
  return Object.entries(items)
    .map(([model, fields]) => {
      const coreFields = fields.filter(isString).join('\n');
      return `fragment ${model}Fragment on ${model}{\n${coreFields}}\n`;
    })
    .join('\n');
}
export type FragmentsType = string[] | Record<string, unknown[]> | string;
export function fragmentsToGql(fragments?: FragmentsType) {
  if (typeof fragments === 'string' || !fragments) {
    return fragments;
  }
  if (Array.isArray(fragments)) {
    const fragmentsRecord = fragments.reduce((acc, table) => {
      acc[capitalize(table)] = getFields(table);
      return acc;
    }, {});
    return fragmentsRecordToGql(fragmentsRecord);
  }
  return fragmentsRecordToGql(fragments);
}

// aggregate fields type
export type AggregateType = 'count' | 'avg' | 'sum' | 'min' | 'max';
export type AggregateFieldsType = Partial<Record<AggregateType, Record<string, true>>> | string;
export function aggregateFieldsToGql(fields: AggregateFieldsType) {
  if (typeof fields === 'string') {
    return fields;
  }
  return aggregateFieldRecordToGql(fields);
}
export function aggregateFieldRecordToGql(fields: AggregateFieldsType, paddingStart = ''): string {
  return Object.entries(fields)
    .map(([key, value]) => {
      const subFields = fieldRecordToGql(value, `${paddingStart}  `);
      return `${paddingStart}_${key} {\n${subFields}\n${paddingStart}}`;
    })
    .join('\n');
}

export function getFindManyGql(table: string, fieldsGql: string, fragmentsGql?: string) {
  const capTable = capitalize(table);
  const headGql = `${
    fragmentsGql ? `${fragmentsGql}\n` : ''
  }query Get${capTable}s($where: ${capTable}WhereInput, $orderBy:[${capTable}OrderByWithRelationInput!], $take:Int, $skip:Int) {`;
  const countGql = getCountGql(table);
  const funcGql = `findMany${capTable}(
    where: $where
    orderBy: $orderBy
    take: $take
    skip: $skip
  ) {
    ${fieldsGql}
  }`;
  return `${headGql}\n${countGql}\n${funcGql}\n}`;
}

export function getFindUniqueGql(table: string, fieldsGql: string, fragmentsGql?: string) {
  const capTable = capitalize(table);
  const headGql = `${
    fragmentsGql ? `${fragmentsGql}\n` : ''
  }query Get${capTable}($where: ${capTable}WhereUniqueInput!) {`;
  const funcGql = `findUnique${capTable}(
    where: $where
  ) {
    ${fieldsGql}
  }`;
  return `${headGql}\n${funcGql}\n}`;
}

export function getCreateGql(table: string, fieldsGql = 'id', fragmentsGql?: string) {
  const capTable = capitalize(table);
  const headGql = `${
    fragmentsGql ? `${fragmentsGql}\n` : ''
  }mutation Create${capTable}($data: ${capTable}CreateInput!) {`;
  const funcGql = `create${capTable}(
    data: $data
  ) {
    ${fieldsGql}
  }`;
  return `${headGql}\n${funcGql}\n}`;
}

export function getUpdateGql(table: string, fieldsGql = 'id', fragmentsGql?: string) {
  const capTable = capitalize(table);
  const headGql = `${
    fragmentsGql ? `${fragmentsGql}\n` : ''
  }mutation Update${capTable}($data: ${capTable}UpdateInput!, $where: ${capTable}WhereUniqueInput!) {`;
  const funcGql = `update${capTable}(
    data: $data
    where: $where
  ) {
    ${fieldsGql}
  }`;
  return `${headGql}\n${funcGql}\n}`;
}

export function getDeleteGql(table: string) {
  const capTable = capitalize(table);
  return `mutation Delete${capTable}($where: ${capTable}WhereUniqueInput!) {
    delete${capTable}(
      where: $where
    ) {
      id
    }
  }`;
}

export function getManyCreateGql(table: string) {
  const capTable = capitalize(table);
  return `mutation CreateMany${capTable}($data: [${capTable}CreateManyInput!]!, $skipDuplicates: Boolean) {
    createMany${capTable}(
      data: $data
      skipDuplicates: $skipDuplicates
    ) {
      count
    }
  }`;
}

export function getManyUpdateGql(table: string) {
  const capTable = capitalize(table);
  return `mutation UpdateMany${capTable}($data: ${capTable}UpdateManyMutationInput!, $where: ${capTable}WhereInput) {
    updateMany${capTable}(
      data: $data
      where: $where
    ) {
      count
    }
  }`;
}

export function getManyDeleteGql(table: string) {
  const capTable = capitalize(table);
  return `mutation DeleteMany${capTable}($where: ${capTable}WhereInput) {
    deleteMany${capTable}(
      where: $where
    ) {
      count
    }
  }`;
}

export function getAggregateGql(table: string, fieldsGql: string) {
  const capTable = capitalize(table);
  return `query Aggregate${capTable}($where: ${capTable}WhereInput) {
    aggregate${capTable}(
      where: $where
    ) {
      ${fieldsGql}
    }
  }`;
}

/**
 * 请求参数转换工具
 */
const sorterMap = {
  null: null,
  ascend: 'asc',
  descend: 'desc',
};
export function transSorter(sorter?: Record<string, SortOrder>) {
  if (sorter === undefined) return undefined;
  return Object.entries(sorter)
    .map(([key, value]) => {
      const sorterValue = sorterMap[String(value)];
      if (sorterValue) {
        return dotKeyToObject(key, sorterValue);
      }
      return undefined;
    })
    .filter(Boolean);
}

export function dotKeyToArray(key: string) {
  const arr = key.split(/,|\./);
  if (arr[0] === '_count') {
    // _count关联数量字段在table和order的顺序是反转的
    return arr.reverse();
  }
  return arr;
}

export function dotKeyToObject(key: string, value: unknown) {
  const result = {};
  dotKeyToArray(key).reduce((acc, k, index, arr) => {
    if (index === arr.length - 1) {
      acc[k] = value;
      return acc;
    }
    acc[k] = {};
    return acc[k];
  }, result);
  return result;
}

export function appendDefaultSorter(table: string, sorter?: Record<string, SortOrder>) {
  const idType = getFieldType(table, 'id');
  if (idType !== 'number') {
    return sorter;
  }
  const resultSorter = sorter || {};
  if (!resultSorter.hasOwnProperty('id')) {
    resultSorter.id = 'descend';
  }
  return resultSorter;
}

// 表单中的时间字段，统一转换成ISO格式，以兼容不同时区
export function traverseToISODate(params: any): any {
  if (Array.isArray(params)) {
    return params.map((item) => traverseToISODate(item));
  }
  if (isObject(params)) {
    Object.keys(params).forEach((key) => {
      Object.assign(params, { [key]: traverseToISODate(params[key]) });
    });
    return params;
  }
  if (isString(params) && /^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}$/.test(params)) {
    return moment(params).toISOString();
  }
  return params;
}

export function transRelateIds(type: 'connect' | 'set', relates: any, originRelates?: any) {
  return Object.entries(relates || {}).reduce((acc, [relateKey, ids]) => {
    if (deepEqual(ids, originRelates?.[relateKey])) return acc;
    if (ids === undefined && type === 'connect' && originRelates?.[relateKey]) {
      // 取消关联
      acc[relateKey] = { disconnect: true };
    } else if (Array.isArray(ids)) {
      const value = ids.map((id) => ({ id }));
      acc[relateKey] = { [type]: value };
    } else if (isObject(ids)) {
      acc[relateKey] = { [type]: ids };
    } else {
      acc[relateKey] = { [type]: { id: ids } };
    }
    return acc;
  }, {});
}

export function parseRelateParams(params: Record<string, any>) {
  const { '@set': sets = {}, '@connect': connects = {}, ...restParams } = params;
  const rests = {};
  Object.entries(restParams).forEach(([key, value]) => {
    if (key.startsWith('@set.')) {
      sets[key.split('@set.')[1]] = value;
    } else if (key.startsWith('@connect.')) {
      connects[key.split('@connect.')[1]] = value;
    } else {
      rests[key] = value;
    }
  });
  return { sets, connects, rests };
}

export function transCreateParams(params?: Record<string, any>) {
  if (params === undefined) return undefined;
  const formattedParams = traverseToISODate(params);
  const { sets, connects, rests } = parseRelateParams(formattedParams);
  const connectAndSets = { ...connects, ...sets }; // 新建时使用connect关联替代set更新
  const relateIds = transRelateIds('connect', connectAndSets);
  return Object.entries(rests).reduce((acc, [key, value]) => {
    if (Array.isArray(value)) {
      return { ...acc, [key]: { create: value } };
    }
    if (isObject(value)) {
      return { ...acc, [key]: { create: value } };
    }
    if (value === null || value === undefined) {
      return acc;
    }
    return { ...acc, [key]: value };
  }, relateIds);
}

export function transUpdateParams(
  params?: Record<string, any>,
  originValue?: any,
  ignoreObject = false,
): any {
  if (params === undefined) return undefined;
  const formattedParams = traverseToISODate(params);
  const { sets, connects, rests } = parseRelateParams(formattedParams);
  const {
    sets: originSets,
    connects: originConnects,
    rests: originRests,
  } = parseRelateParams(originValue || {});
  const relateIds = {
    ...transRelateIds('set', sets, originSets),
    ...transRelateIds('connect', connects, originConnects),
  };
  return Object.entries(rests).reduce((acc, [key, value]) => {
    if (deepEqual(value, originRests?.[key])) return acc;
    if (Array.isArray(value)) {
      if (ignoreObject) return acc;
      const createRelations = value
        .filter((item) => !item.id)
        .map((item) => transCreateParams(item));
      const updateRelations = value
        .filter((item) => !!item.id)
        .map((item) => {
          const { id, createdAt, updatedAt, ...restItem } = item;
          return { where: { id }, data: transUpdateParams(restItem, undefined, true) };
        });
      const updateRelationIds = updateRelations.map((item) => item.where.id);
      const originIds = (originValue?.[key] || []).map((item) => item.id);
      const disconnectIds = originIds.filter((id) => !updateRelationIds.includes(id));
      return {
        ...acc,
        [key]: {
          disconnect: disconnectIds.map((id) => ({ id })),
          create: createRelations,
          update: updateRelations,
        },
      };
    }
    if (isObject(value)) {
      if (ignoreObject) return acc;
      // @前缀表示原始格式不做转换
      if (key.startsWith('@')) {
        return { ...acc, [key.slice(1)]: value };
      }
      if (value.id) {
        return { ...acc, [key]: { update: transSetParams(value) } };
      }
      return { ...acc, [key]: { create: transCreateParams(value) } };
    }
    if (value === null || value === undefined) {
      return acc;
    }
    return { ...acc, [key]: { set: value } };
  }, relateIds);
}

export function transSetParams(params: Record<string, any>) {
  return Object.entries(params).reduce((acc, [key, value]) => {
    return { ...acc, [key]: { set: value } };
  }, {});
}

export function transQueryField(
  table: string,
  key: string,
  value: unknown,
  preferSearch = false,
): Record<string, any> | null {
  // 优先根据字段key判断类型，次选根据value判断类型
  const fieldType = getFieldType(table, key) || typeof value;
  if (value === '@null@') {
    return { [key]: null };
  }
  if (isObject(value)) {
    return { [key]: value };
  }
  if (fieldType === 'boolean') {
    if (typeof value !== 'boolean') {
      console.warn(`[${table}.${key}]boolean field could not search`);
      return null;
    }
    return { [key]: { equals: value } };
  }
  if (fieldType === 'number') {
    const num = Number(value);
    if (Number.isNaN(num)) {
      // ignore invalid number search
      return null;
    }
    return { [key]: { equals: num } };
  }
  if (preferSearch) {
    return { [key]: { contains: value } };
  }
  return { [key]: { equals: value } };
}

export function transRelateFilter(
  table: string,
  relFields: string[],
  relKey: string,
  value: unknown,
  preferSearch = false,
) {
  const [relField, ...restRelFields] = relFields;
  const fieldItem = getField(table, relField);
  if (!fieldItem || !isRelateFieldItem(fieldItem)) {
    console.error(`[${relField}.${relKey}]search field not found.`);
    return false;
  }
  const hasSubRel = restRelFields.length > 0;
  const queryValue: any = hasSubRel
    ? transRelateFilter(fieldItem.relation, restRelFields, relKey, value, preferSearch)
    : transQueryField(fieldItem.relation, relKey, value, preferSearch);
  if (fieldItem.multi) {
    return {
      [relField]: { some: queryValue },
    };
  }
  return { [relField]: { is: queryValue } };
}

export function transFilter(
  table: string,
  where: Record<string, any>,
  filter?: Record<string, any>,
) {
  const formattedWhere = traverseToISODate(where) as Record<string, any>;
  const conditions = Object.entries(formattedWhere).reduce((acc, [key, value]) => {
    // 忽略空值
    if (value === '' || value === undefined || value === null) {
      return acc;
    }

    // 多字段搜索
    // '@search':{
    //   keyword:'xxx',
    //   fields:['name','title','user.name'],
    // }
    if (key === '@search') {
      acc.push({
        OR: value.fields
          .map((field: string) => {
            // 关联搜索
            const relFields = field.split('.');
            if (relFields.length > 1) {
              return transRelateFilter(
                table,
                relFields.slice(0, -1),
                relFields.slice(-1)[0],
                value.keyword,
                true,
              );
            }
            // 单表搜索
            return transQueryField(table, field, value.keyword, true);
          })
          .filter(Boolean),
      });
      return acc;
    }

    // 忽略dependence注入的表单关联字段（该字段只用于表单，不能用于查询）
    if (['@connect', '@set'].includes(key)) {
      return acc;
    }

    // 关联查询
    const relFields = key.split('.');
    if (relFields.length > 1) {
      const relFilter = transRelateFilter(
        table,
        relFields.slice(0, -1),
        relFields.slice(-1)[0],
        value,
      );
      if (relFilter) {
        acc.push(relFilter);
      }
      return acc;
    }

    if (Array.isArray(value) && !isObject(value[0])) {
      // 事件范围
      acc.push({ [key]: { gte: value[0] } });
      acc.push({ [key]: { lte: value[1] } });
    } else {
      const cond = transQueryField(table, key, value);
      if (cond) acc.push(cond);
    }

    return acc;
  }, [] as any);

  if (filter) {
    Object.entries(filter).forEach(([key, value]) => {
      if (Array.isArray(value)) {
        if (key.startsWith('!')) {
          conditions.push({ [key.slice(1)]: { notIn: value } });
        } else {
          conditions.push({ [key]: { in: value } });
        }
      }
    });
  }

  return { AND: conditions };
}

/**
 * 请求工具
 */
export async function requestList(
  table: string,
  fieldsGql: string,
  params: any,
  sorter?: Record<string, SortOrder>,
  filter?: Record<string, ReactText[] | null>,
  fragmentsGql?: string,
) {
  console.debug('requestList', { table, params, sorter, filter });
  const capTable = capitalize(table);
  const { current = 1, pageSize = 20, ...where } = params;
  const gql = getFindManyGql(table, fieldsGql, fragmentsGql);
  const response = await request({
    query: gql,
    variables: {
      where: transFilter(table, where, filter),
      orderBy: transSorter(appendDefaultSorter(table, sorter)),
      skip: (current - 1) * pageSize,
      take: pageSize,
    },
  });
  return {
    success: true,
    data: batchAppendRelateIds(response[`findMany${capTable}`]),
    current,
    pageSize,
    // eslint-disable-next-line no-underscore-dangle
    total: response[`${getAggAttr(table)}`]._count._all,
  };
}

export async function requestInfo(
  table: string,
  id: string | number,
  fieldsGql: string,
  fragmentsGql?: string,
) {
  console.debug('requestInfo', { table, id });
  const capTable = capitalize(table);
  const gql = getFindUniqueGql(table, fieldsGql, fragmentsGql);
  const response = await request({
    query: gql,
    variables: {
      where: { id },
    },
  });
  return {
    success: true,
    data: appendRelateIds(response[`findUnique${capTable}`]),
  };
}

export async function requestCreate(
  table: string,
  params: any,
  fieldsGql: string,
  fragmentsGql?: string,
) {
  console.log('requestCreate', { table, params });
  const capTable = capitalize(table);
  const gql = getCreateGql(table, fieldsGql, fragmentsGql);
  const response = await request({
    query: gql,
    variables: {
      data: transCreateParams(params),
    },
  });
  return {
    success: true,
    data: response[`create${capTable}`],
  };
}

export async function requestUpdate(
  table: string,
  params: any,
  originValue?: any,
  fieldsGql?: string,
  fragmentsGql?: string,
) {
  console.log('requestUpdate', { table, params });
  const { id, ...restParams } = params;
  if (!id) {
    throw new Error('need param id to update');
  }
  const capTable = capitalize(table);
  const gql = getUpdateGql(table, fieldsGql, fragmentsGql);
  const response = await request({
    query: gql,
    variables: {
      data: transUpdateParams(restParams, originValue),
      where: { id },
    },
  });
  return {
    success: true,
    data: response[`update${capTable}`],
  };
}

export async function requestDelete(table: string, params: any) {
  console.log('requestDelete', { table, params });
  const { id } = params;
  if (!id) {
    throw new Error('need param id to update');
  }
  const capTable = capitalize(table);
  const gql = getDeleteGql(table);
  const response = await request({
    query: gql,
    variables: {
      where: { id },
    },
  });
  return {
    success: true,
    data: response[`delete${capTable}`],
  };
}

export async function requestManyCreate(table: string, params: any[], skipDuplicates = false) {
  console.log('requestManyCreate', { table, params });
  const capTable = capitalize(table);
  const gql = getManyCreateGql(table);
  const response = await request({
    query: gql,
    variables: {
      data: traverseToISODate(params),
      skipDuplicates,
    },
  });
  return {
    success: true,
    data: response[`createMany${capTable}`],
  };
}

export async function requestManyUpdate(table: string, ids: number[] | string[], params: any) {
  console.log('requestManyUpdate', { table, ids, params });
  if (!ids || !ids.length) {
    throw new Error('need param ids to update');
  }
  const capTable = capitalize(table);
  const gql = getManyUpdateGql(table);
  const response = await request({
    query: gql,
    variables: {
      data: transUpdateParams(params),
      where: { id: { in: ids } },
    },
  });
  return {
    success: true,
    data: response[`updateMany${capTable}`],
  };
}

export async function requestManyDelete(table: string, ids: number[] | string[]) {
  console.log('requestManyDelete', { table, ids });
  if (!ids || !ids.length) {
    throw new Error('need param ids to delete');
  }
  const capTable = capitalize(table);
  const gql = getManyDeleteGql(table);
  const response = await request({
    query: gql,
    variables: {
      where: { id: { in: ids } },
    },
  });
  return {
    success: true,
    data: response[`deleteMany${capTable}`],
  };
}

export async function requestAggregate(table: string, fieldsGql: string, params: any) {
  console.debug('requestAggregate', { table, params, fieldsGql });
  const capTable = capitalize(table);
  const gql = getAggregateGql(table, fieldsGql);
  const response = await request({
    query: gql,
    variables: {
      where: transFilter(table, params),
    },
  });
  return {
    success: true,
    data: response[`aggregate${capTable}`],
  };
}

/**
 * 响应结果转换工具
 */
export function removeEmptyChildren(data: Record<string, any>[], childrenName = 'children') {
  data.forEach((item) => {
    if (Array.isArray(item[childrenName])) {
      if (item[childrenName].length > 0) {
        removeEmptyChildren(item[childrenName], childrenName);
      } else {
        // eslint-disable-next-line no-param-reassign
        delete item[childrenName];
      }
    }
  });
}

export function removeEmptyResponseChildren(
  response: Record<string, any>,
  childrenName = 'children',
) {
  if (response.data) {
    removeEmptyChildren(response.data, childrenName);
  }
  return response;
}
