ui/src/app/services/conversion/conversion.service.ts (658 lines of code) (raw):
import { Injectable } from '@angular/core'
import ISchemaObjectNode from 'src/app/model/schema-object-node'
import IConv, {
ICreateIndex,
IIndexKey,
IIndex,
IForeignKey,
ISrcIndexKey,
IColumnDef,
} from '../../model/conv'
import IColumnTabData, { IIndexData, ISequenceData } from '../../model/edit-table'
import IFkTabData from 'src/app/model/fk-tab-data'
import { ColLength, Dialect, ObjectExplorerNodeType, StorageKeys, autoGenSupportedDbs } from 'src/app/app.constants'
import { BehaviorSubject } from 'rxjs'
import { FetchService } from '../fetch/fetch.service'
import { extractSourceDbName } from 'src/app/utils/utils'
import ICcTabData from 'src/app/model/cc-tab-data'
@Injectable({
providedIn: 'root',
})
export class ConversionService {
constructor(private fetch: FetchService,) { }
private standardTypeToPGSQLTypeMapSub = new BehaviorSubject(new Map<string, string>())
private pgSQLToStandardTypeTypeMapSub = new BehaviorSubject(new Map<string, string>())
standardTypeToPGSQLTypeMap = this.standardTypeToPGSQLTypeMapSub.asObservable()
pgSQLToStandardTypeTypeMap = this.pgSQLToStandardTypeTypeMapSub.asObservable()
srcDbName: string = localStorage.getItem(StorageKeys.SourceDbName) as string
getStandardTypeToPGSQLTypemap() {
return this.fetch.getStandardTypeToPGSQLTypemap().subscribe({
next: (standardTypeToPGSQLTypeMap: any) => {
this.standardTypeToPGSQLTypeMapSub.next(new Map<string, string>(Object.entries(standardTypeToPGSQLTypeMap)))
},
})
}
getPGSQLToStandardTypeTypemap() {
return this.fetch.getPGSQLToStandardTypeTypemap().subscribe({
next: (pgSQLToStandardTypeTypeMap: any) => {
this.pgSQLToStandardTypeTypeMapSub.next(new Map<string, string>(Object.entries(pgSQLToStandardTypeTypeMap)))
},
})
}
createTreeNode(
conv: IConv,
conversionRates: Record<string, string>,
searchText: string = '',
sortOrder: string = ''
): ISchemaObjectNode[] {
if (conv.DatabaseType) {
this.srcDbName = extractSourceDbName(conv.DatabaseType)
}
let spannerTableIds = Object.keys(conv.SpSchema).filter((tableId: string) =>
conv.SpSchema[tableId].Name.toLocaleLowerCase().includes(searchText.toLocaleLowerCase())
)
let spannerSequenceIds = Object.keys(conv.SpSequences).filter((seqId: string) =>
conv.SpSequences[seqId].Name.toLocaleLowerCase().includes(searchText.toLocaleLowerCase())
)
let deletedTableIds = Object.keys(conv.SrcSchema).filter((tableId: string) => {
return (
spannerTableIds.indexOf(tableId) == -1 &&
conv.SrcSchema[tableId].Name.replace(/[^A-Za-z0-9_]/g, '_').includes(
searchText.toLocaleLowerCase()
)
)
})
let deletedIndexes = this.getDeletedIndexes(conv)
let parentNode: ISchemaObjectNode = {
name: `Tables (${spannerTableIds.length})`,
type: ObjectExplorerNodeType.Tables,
parent: '',
pos: -1,
isSpannerNode: true,
id: '',
parentId: '',
children: spannerTableIds.map((tableId: string) => {
let spannerTable = conv.SpSchema[tableId]
return {
name: spannerTable.Name,
status: conversionRates[tableId],
type: ObjectExplorerNodeType.Table,
parent: spannerTable.ParentTable.Id != '' ? conv.SpSchema[spannerTable.ParentTable.Id]?.Name : '',
pos: -1,
isSpannerNode: true,
id: tableId,
parentId: spannerTable.ParentTable.Id,
children: [
{
name: `Indexes (${spannerTable.Indexes ? spannerTable.Indexes.length : 0})`,
status: '',
type: ObjectExplorerNodeType.Indexes,
parent: conv.SpSchema[tableId].Name,
pos: -1,
isSpannerNode: true,
id: '',
parentId: tableId,
children: spannerTable.Indexes
? spannerTable.Indexes.map((index: ICreateIndex, i: number) => {
return {
name: index.Name,
type: ObjectExplorerNodeType.Index,
parent: conv.SpSchema[tableId].Name,
pos: i,
isSpannerNode: true,
id: index.Id,
parentId: tableId,
}
})
: [],
},
],
}
}),
}
deletedTableIds.forEach((tableId: string) => {
parentNode.children?.push({
name: conv.SrcSchema[tableId].Name.replace(/[^A-Za-z0-9_]/g, '_'),
status: 'DARK',
type: ObjectExplorerNodeType.Table,
pos: -1,
isSpannerNode: true,
children: [],
isDeleted: true,
id: tableId,
parent: '',
parentId: '',
})
})
// add deleted indexes
parentNode.children?.forEach((tableNode: ISchemaObjectNode, i: number) => {
if (deletedIndexes[tableNode.id]) {
deletedIndexes[tableNode.id].forEach((index: IIndex) => {
parentNode.children![i].children![0].children?.push({
name: index.Name.replace(/[^A-Za-z0-9_]/g, '_'),
type: ObjectExplorerNodeType.Index,
parent: conv.SpSchema[tableNode.name]?.Name,
pos: i,
isSpannerNode: true,
isDeleted: true,
id: index.Id,
parentId: tableNode.id,
})
})
}
})
let sequenceNode: ISchemaObjectNode = {
name: `Sequences (${spannerSequenceIds.length})`,
type: ObjectExplorerNodeType.Sequences,
parent: '',
pos: -1,
isSpannerNode: true,
id: '',
parentId: '',
children: spannerSequenceIds.map((seqId: string) => {
let spannerSequence = conv.SpSequences[seqId]
return {
name: spannerSequence.Name,
status: '',
type: ObjectExplorerNodeType.Sequence,
parent: '',
pos: -1,
isSpannerNode: true,
id: seqId,
parentId: '',
children: [],
}
}),
}
this.sortNodeChildren(parentNode, sortOrder)
this.sortNodeChildren(sequenceNode, sortOrder)
let mainNodeChildren :ISchemaObjectNode[] = [parentNode]
if (autoGenSupportedDbs.includes(this.srcDbName)) {
mainNodeChildren.push(sequenceNode)
}
return [
{
name: conv.DatabaseName,
children: mainNodeChildren,
type: ObjectExplorerNodeType.DbName,
parent: '',
pos: -1,
isSpannerNode: true,
id: '',
parentId: '',
},
]
}
sortNodeChildren(node: ISchemaObjectNode, sortOrder: string) {
if (sortOrder === 'asc' || sortOrder === '') {
node.children?.sort((a, b) => (a.name > b.name ? 1 : b.name > a.name ? -1 : 0))
} else if (sortOrder === 'desc') {
node.children?.sort((a, b) => (b.name > a.name ? 1 : a.name > b.name ? -1 : 0))
}
}
createTreeNodeForSource(
conv: IConv,
conversionRates: Record<string, string>,
searchText: string = '',
sortOrder: string = ''
): ISchemaObjectNode[] {
let srcTableIds = Object.keys(conv.SrcSchema).filter((tableId: string) =>
conv.SrcSchema[tableId].Name.toLocaleLowerCase().includes(searchText.toLocaleLowerCase())
)
let parentNode: ISchemaObjectNode = {
name: `Tables (${srcTableIds.length})`,
type: ObjectExplorerNodeType.Tables,
pos: -1,
isSpannerNode: false,
id: '',
parent: '',
parentId: '',
children: srcTableIds.map((tableId: string) => {
let srcTable = conv.SrcSchema[tableId]
return {
name: srcTable.Name,
status: conversionRates[tableId] ? conversionRates[tableId] : 'NONE',
type: ObjectExplorerNodeType.Table,
parent: '',
pos: -1,
isSpannerNode: false,
id: tableId,
parentId: '',
parentOnDelete: '',
children: [
{
name: `Indexes (${srcTable.Indexes?.length || '0'})`,
status: '',
type: ObjectExplorerNodeType.Indexes,
parent: '',
pos: -1,
isSpannerNode: false,
id: '',
parentId: '',
parentOnDelete: '',
children: srcTable.Indexes
? srcTable.Indexes.map((index: IIndex, i: number) => {
return {
name: index.Name,
type: ObjectExplorerNodeType.Index,
parent: conv.SrcSchema[tableId].Name,
isSpannerNode: false,
pos: i,
id: index.Id,
parentId: tableId,
}
})
: [],
},
],
}
}),
}
if (sortOrder === 'asc' || sortOrder === '') {
parentNode.children?.sort((a, b) => (a.name > b.name ? 1 : b.name > a.name ? -1 : 0))
} else if (sortOrder === 'desc') {
parentNode.children?.sort((a, b) => (b.name > a.name ? 1 : a.name > b.name ? -1 : 0))
}
return [
{
name: conv.DatabaseName,
children: [parentNode],
type: ObjectExplorerNodeType.DbName,
isSpannerNode: false,
parent: '',
pos: -1,
id: '',
parentId: '',
},
]
}
getCheckConstraints(tableId: string, data: IConv): ICcTabData[] {
let srcArr = data.SrcSchema[tableId].CheckConstraints || []
let spArr = data.SpSchema[tableId].CheckConstraints || []
let res: ICcTabData[] = []
if (srcArr.length > spArr.length) {
for (let i = 0; i < srcArr.length; i++) {
res.push({
srcSno: `${i + 1}`,
srcConstraintName: srcArr[i].Name,
srcCondition: srcArr[i].Expr,
spSno: spArr[i] ? `${i + 1}` : '',
spConstraintName: spArr[i] ? spArr[i].Name : '',
spConstraintCondition: spArr[i] ? spArr[i].Expr : '',
spExprId:srcArr[i] ? srcArr[i].ExprId : '',
deleteIndex: `cc${i + 1}`,
})
}
} else {
for (let i = 0; i < spArr.length; i++) {
res.push({
srcSno: srcArr[i] ? `${i + 1}` : '',
srcConstraintName: srcArr[i] ? srcArr[i].Name : '',
srcCondition: srcArr[i] ? srcArr[i].Expr : '',
spSno: `${i + 1}`,
spConstraintName: spArr[i].Name,
spConstraintCondition: spArr[i].Expr,
spExprId: spArr[i].ExprId,
deleteIndex: `cc${i + 1}`,
})
}
}
return res
}
getColumnMapping(tableId: string, data: IConv): IColumnTabData[] {
let spTableName = this.getSpannerTableNameFromId(tableId, data)
let srcColIds = data.SrcSchema[tableId].ColIds
let spColIds = data.SpSchema[tableId] ? data.SpSchema[tableId].ColIds : null
let srcPks = data.SrcSchema[tableId].PrimaryKeys
let spPks = spColIds ? data.SpSchema[tableId].PrimaryKeys : null
let standardTypeToPGSQLTypeMap: Map<String, String>
this.standardTypeToPGSQLTypeMap.subscribe((typemap) => {
standardTypeToPGSQLTypeMap = typemap
})
const spColMax = ColLength.StorageMaxLength
const res: IColumnTabData[] = data.SrcSchema[tableId].ColIds.map((colId: string, i: number) => {
let spPkOrder
if (spTableName) {
data.SpSchema[tableId].PrimaryKeys.forEach((pk: IIndexKey) => {
if (pk.ColId == colId) {
spPkOrder = pk.Order
}
})
}
let spannerColDef = spTableName ? data.SpSchema[tableId]?.ColDefs[colId] : null
let pgSQLDatatype = spannerColDef ? standardTypeToPGSQLTypeMap.get(spannerColDef.T.Name) : ''
return {
spOrder: spannerColDef ? i + 1 : '',
srcOrder: i + 1,
spColName: spannerColDef ? spannerColDef.Name : '',
spDataType: spannerColDef ? (data.SpDialect === Dialect.PostgreSQLDialect ? (pgSQLDatatype === undefined ? spannerColDef.T.Name : pgSQLDatatype) : spannerColDef.T.Name) : '',
srcColName: data.SrcSchema[tableId].ColDefs[colId].Name,
srcDataType: data.SrcSchema[tableId].ColDefs[colId].Type.Name,
spIsPk:
spannerColDef && spTableName
? data.SpSchema[tableId].PrimaryKeys?.map((pk) => pk.ColId).indexOf(colId) !== -1
: false,
srcIsPk: srcPks ? srcPks.map((pk) => pk.ColId).indexOf(colId) !== -1 : false,
spIsNotNull: spannerColDef && spTableName ? spannerColDef.NotNull : false,
srcIsNotNull: data.SrcSchema[tableId].ColDefs[colId].NotNull,
srcId: colId,
srcDefaultValue: data.SrcSchema[tableId].ColDefs[colId].DefaultValue.Value.Statement,
spId: spannerColDef ? colId : '',
spColMaxLength: spannerColDef?.T.Len != 0 ? (spannerColDef?.T.Len != spColMax ? spannerColDef?.T.Len: 'MAX') : '',
srcColMaxLength: data.SrcSchema[tableId].ColDefs[colId].Type.Mods != null ? data.SrcSchema[tableId].ColDefs[colId].Type.Mods[0] : '',
spAutoGen: spannerColDef?.AutoGen != null ? spannerColDef?.AutoGen : {
Name: '',
GenerationType: ''
},
srcAutoGen: data.SrcSchema[tableId].ColDefs[colId].AutoGen ? data.SrcSchema[tableId].ColDefs[colId].AutoGen : {
Name: '',
GenerationType: ''
},
spDefaultValue: spannerColDef?.DefaultValue != null ? spannerColDef?.DefaultValue : {
IsPresent: false,
Value: {
ExpressionId: '',
Statement: ''
}
},
}
})
if (spColIds) {
spColIds.forEach((colId: string, i: number) => {
if (srcColIds.indexOf(colId) < 0) {
let spColumn = data.SpSchema[tableId].ColDefs[colId]
let spannerColDef = spTableName ? data.SpSchema[tableId]?.ColDefs[colId] : null
let pgSQLDatatype = spannerColDef ? standardTypeToPGSQLTypeMap.get(spannerColDef.T.Name) : ''
res.push({
spOrder: i + 1,
srcOrder: '',
spColName: spColumn.Name,
spDataType: spannerColDef ? (data.SpDialect === Dialect.PostgreSQLDialect ? (pgSQLDatatype === undefined ? spannerColDef.T.Name : pgSQLDatatype) : spannerColDef.T.Name) : '',
srcColName: '',
srcDataType: '',
spIsPk: spPks ? spPks.map((p) => p.ColId).indexOf(colId) !== -1 : false,
srcIsPk: false,
spIsNotNull: spColumn.NotNull,
srcIsNotNull: false,
srcId: '',
srcDefaultValue: '',
spId: colId,
srcColMaxLength: '',
spColMaxLength: spannerColDef?.T.Len,
spAutoGen: spColumn.AutoGen,
srcAutoGen: {
Name: '',
GenerationType: ''
},
spDefaultValue: spannerColDef?.DefaultValue != null ? spannerColDef?.DefaultValue : {
IsPresent: false,
Value: {
ExpressionId: '',
Statement: ''
}
},
})
}
})
}
return res
}
getPkMapping(tableData: IColumnTabData[]): IColumnTabData[] {
let pkColumns = tableData.filter((column: IColumnTabData) => {
return column.spIsPk || column.srcIsPk
})
return JSON.parse(JSON.stringify(pkColumns))
}
getFkMapping(id: string, data: IConv): IFkTabData[] {
let srcFks = data.SrcSchema[id]?.ForeignKeys
if (!srcFks) {
return []
}
return srcFks.map((srcFk: IForeignKey) => {
let spFk = this.getSpannerFkFromId(data, id, srcFk.Id)
let spColumns = spFk
? spFk.ColIds.map((columnId: string) => {
return data.SpSchema[id].ColDefs[columnId].Name
})
: []
let spColIds = spFk ? spFk.ColIds : []
let srcColumns = srcFk.ColIds.map((columnId: string) => {
return data.SrcSchema[id].ColDefs[columnId].Name
})
let spReferColumns = spFk
? spFk.ReferColumnIds.map((referColId: string) => {
return data.SpSchema[srcFk.ReferTableId].ColDefs[referColId].Name
})
: []
let spReferColumnIds = spFk ? spFk.ReferColumnIds : []
let srcReferColumns = srcFk.ReferColumnIds.map((referColId: string) => {
return data.SrcSchema[srcFk.ReferTableId].ColDefs[referColId].Name
})
return {
srcFkId: srcFk.Id,
spFkId: spFk?.Id,
spName: spFk ? spFk.Name : '',
srcName: srcFk.Name,
spColumns: spColumns,
srcColumns: srcColumns,
spReferTable: spFk ? data.SpSchema[spFk.ReferTableId].Name : '',
srcReferTable: data.SrcSchema[srcFk.ReferTableId].Name,
spReferColumns: spReferColumns,
srcReferColumns: srcReferColumns,
spColIds: spColIds,
spReferColumnIds: spReferColumnIds,
spReferTableId: spFk ? spFk.ReferTableId : '',
srcOnDelete: srcFk.OnDelete,
spOnDelete: spFk ? spFk.OnDelete : '',
srcOnUpdate: srcFk.OnUpdate,
spOnUpdate: spFk? spFk.OnUpdate : '',
}
})
}
getIndexMapping(tableId: string, data: IConv, indexId: string): IIndexData[] {
let srcIndex = this.getSourceIndexFromId(data, tableId, indexId)
let spIndex = this.getSpannerIndexFromId(data, tableId, indexId)
let srcIndexKeyColIds: string[] = srcIndex
? srcIndex.Keys.map((indexKey: ISrcIndexKey) => indexKey.ColId)
: []
let spIndexKeyColIds: string[] = spIndex
? spIndex.Keys.map((indexKey: IIndexKey) => indexKey.ColId)
: []
let indexData: Array<IIndexData> = srcIndex
? srcIndex.Keys.map((srcIndexKey: ISrcIndexKey) => {
let spIndexKey: IIndexKey | null = this.getSpannerIndexKeyFromColId(
data,
tableId,
indexId,
srcIndexKey.ColId
)
return {
srcColId: srcIndexKey.ColId,
spColId: spIndexKey ? spIndexKey.ColId : undefined,
srcColName: data.SrcSchema[tableId].ColDefs[srcIndexKey.ColId].Name,
srcOrder: srcIndexKey.Order,
srcDesc: srcIndexKey.Desc,
spColName: spIndexKey ? data.SpSchema[tableId].ColDefs[spIndexKey.ColId].Name : '',
spOrder: spIndexKey ? spIndexKey.Order : undefined,
spDesc: spIndexKey ? spIndexKey.Desc : undefined,
}
})
: []
spIndexKeyColIds.forEach((spColId: string) => {
if (srcIndexKeyColIds.indexOf(spColId) == -1) {
let spIndexKey = this.getSpannerIndexKeyFromColId(data, tableId, indexId, spColId)
indexData.push({
srcColName: '',
srcOrder: '',
srcColId: undefined,
srcDesc: undefined,
spColName: data.SpSchema[tableId].ColDefs[spColId].Name,
spOrder: spIndexKey ? spIndexKey.Order : undefined,
spDesc: spIndexKey ? spIndexKey.Desc : undefined,
spColId: spIndexKey ? spIndexKey.ColId : undefined,
})
}
})
return indexData
}
getSequenceMapping(seqId: string, data: IConv): ISequenceData {
let srcSequence = null
let spSequenceName = this.getSpannerSequenceNameFromId(seqId, data)
let sequence: ISequenceData = {}
if (spSequenceName != null) {
let spSequence = data.SpSequences[seqId]
sequence.spSeqName = spSequence.Name
sequence.spSequenceKind = spSequence.SequenceKind
sequence.spSkipRangeMax = spSequence.SkipRangeMax
sequence.spSkipRangeMin = spSequence.SkipRangeMin
sequence.spStartWithCounter = spSequence.StartWithCounter
}
return sequence
}
getSpannerFkFromId(conv: IConv, tableId: string, srcFkId: string | undefined): IForeignKey | null {
let spFk: IForeignKey | null = null
conv.SpSchema[tableId]?.ForeignKeys?.forEach((fk: IForeignKey) => {
if (fk.Id == srcFkId) {
spFk = fk
}
})
return spFk
}
getSourceIndexFromId(conv: IConv, tableId: string, indexId: string): IIndex | null {
let srcIndex: IIndex | null = null
conv.SrcSchema[tableId]?.Indexes?.forEach((index: IIndex) => {
if (index.Id == indexId) {
srcIndex = index
}
})
return srcIndex
}
getSpannerIndexFromId(conv: IConv, tableId: string, indexId: string): ICreateIndex | null {
let spIndex: ICreateIndex | null = null
conv.SpSchema[tableId]?.Indexes?.forEach((index: ICreateIndex) => {
if (index.Id == indexId) {
spIndex = index
}
})
return spIndex
}
getSpannerSequenceNameFromId(id: string, conv: IConv): string | null {
let spSeqName: string | null = null
Object.keys(conv.SpSequences).forEach((key: string) => {
if (conv.SpSequences[key].Id === id) {
spSeqName = conv.SpSequences[key].Name
}
})
return spSeqName
}
getSpannerIndexKeyFromColId(
conv: IConv,
tableId: string,
indexId: string,
colId: string
): IIndexKey | null {
let indexKey: IIndexKey | null = null
let indexes = conv.SpSchema[tableId]?.Indexes
? conv.SpSchema[tableId].Indexes.filter((index: IIndex) => {
return index.Id == indexId
})
: null
if (indexes && indexes.length > 0) {
let indexKeys = indexes[0].Keys.filter((key: IIndexKey) => {
return key.ColId == colId
})
indexKey = indexKeys.length > 0 ? indexKeys[0] : null
}
return indexKey
}
getSourceIndexKeyFromColId(
conv: IConv,
tableId: string,
indexId: string,
colId: string
): ISrcIndexKey | null {
let indexKey: ISrcIndexKey | null = null
let indexes = conv.SrcSchema[tableId]?.Indexes
? conv.SrcSchema[tableId].Indexes.filter((index: IIndex) => {
return index.Id == indexId
})
: null
if (indexes && indexes.length > 0) {
let indexKeys = indexes[0].Keys.filter((key: IIndexKey) => {
return key.ColId == colId
})
indexKey = indexKeys.length > 0 ? indexKeys[0] : null
}
return indexKey
}
getSpannerColDefFromId(tableName: string, id: string, data: IConv): IColumnDef | null {
let res: IColumnDef | null = null
Object.keys(data.SpSchema[tableName].ColDefs).forEach((colName) => {
if (data.SpSchema[tableName].ColDefs[colName].Id == id) {
res = data.SpSchema[tableName].ColDefs[colName]
}
})
return res
}
getSourceTableNameFromId(id: string, conv: IConv): string {
let srcName: string = ''
Object.keys(conv.SrcSchema).forEach((key: string) => {
if (conv.SrcSchema[key].Id === id) {
srcName = conv.SrcSchema[key].Name
}
})
return srcName
}
getSpannerTableNameFromId(id: string, conv: IConv): string | null {
let spName: string | null = null
Object.keys(conv.SpSchema).forEach((key: string) => {
if (conv.SpSchema[key].Id === id) {
spName = conv.SpSchema[key].Name
}
})
return spName
}
getTableIdFromSpName(name: string, conv: IConv): string {
let tableId: string = ''
Object.keys(conv.SpSchema).forEach((key: string) => {
if (conv.SpSchema[key].Name === name) {
tableId = conv.SpSchema[key].Id
}
})
return tableId
}
getColIdFromSpannerColName(name: string, tableId: string, conv: IConv): string {
let colId: string = ''
Object.keys(conv.SpSchema[tableId].ColDefs).forEach((key: string) => {
if (conv.SpSchema[tableId].ColDefs[key].Name === name) {
colId = conv.SpSchema[tableId].ColDefs[key].Id
}
})
return colId
}
getDeletedIndexes(conv: IConv): Record<string, IIndex[]> {
let deletedIndexes: Record<string, IIndex[]> = {}
Object.keys(conv.SpSchema).forEach((tableId: string) => {
let spTable = conv.SpSchema[tableId]
let srcTable = conv.SrcSchema[tableId]
let spIndexIds: string[] =
spTable && spTable.Indexes
? spTable.Indexes.map((index: ICreateIndex) => {
return index.Id
})
: []
let tableDeletedIndexes =
srcTable && srcTable.Indexes
? srcTable.Indexes?.filter((index: IIndex) => {
if (!spIndexIds.includes(index.Id)) {
return true
}
return false
})
: null
if (spTable && srcTable && tableDeletedIndexes && tableDeletedIndexes.length > 0) {
deletedIndexes[tableId] = tableDeletedIndexes
}
})
return deletedIndexes
}
}