{"version":3,"file":"indexes.mjs","names":[],"sources":["../../src/sql/indexes.ts"],"sourcesContent":["import type { FullSchemaIndex } from \"../schema.js\";\n\ntype IndexTypeHint = { indexType: string };\ntype IndexDropHint = { isPrimary: boolean; isUnique: boolean };\n\nexport function isIndexSupported(index: IndexTypeHint) {\n  return index.indexType === \"btree\" || index.indexType === \"gin\";\n}\n\n/**\n * Doesn't necessarily decide whether the index can be dropped but can be\n * used to not even try dropping indexes that _definitely_ cannot be dropped\n */\nexport function isIndexProbablyDroppable(index: IndexDropHint) {\n  /* TODO: until we have a better solution, this is the best we have */\n  /* The is_unique check is problematic only if the column is declared as unique */\n  return !index.isPrimary && !index.isUnique;\n}\n\nexport type DuplicateIndexGroup =\n  | { kind: \"exact\"; indexes: FullSchemaIndex[] }\n  | {\n      kind: \"prefix\";\n      indexes: FullSchemaIndex[];\n      sharedPrefix: FullSchemaIndex[\"keyColumns\"];\n    };\n\nfunction columnsEqual(\n  a: FullSchemaIndex[\"keyColumns\"],\n  b: FullSchemaIndex[\"keyColumns\"],\n): boolean {\n  if (a.length !== b.length) return false;\n  for (let i = 0; i < a.length; i++) {\n    if (\n      a[i].name.toString() !== b[i].name.toString() ||\n      (a[i].order ?? null) !== (b[i].order ?? null) ||\n      (a[i].opclass ?? null) !== (b[i].opclass ?? null)\n    ) {\n      return false;\n    }\n  }\n  return true;\n}\n\nfunction indexesAreEqual(a: FullSchemaIndex, b: FullSchemaIndex): boolean {\n  return (\n    a.schemaName.toString() === b.schemaName.toString() &&\n    a.tableName.toString() === b.tableName.toString() &&\n    a.indexType === b.indexType &&\n    (a.wherePredicate ?? null) === (b.wherePredicate ?? null) &&\n    columnsEqual(a.keyColumns, b.keyColumns)\n  );\n}\n\nfunction sharedPrefixColumns(\n  shorter: FullSchemaIndex,\n  longer: FullSchemaIndex,\n): FullSchemaIndex[\"keyColumns\"] | null {\n  if (\n    shorter.schemaName.toString() !== longer.schemaName.toString() ||\n    shorter.tableName.toString() !== longer.tableName.toString() ||\n    shorter.indexType !== longer.indexType ||\n    shorter.indexType !== \"btree\" ||\n    shorter.wherePredicate !== undefined ||\n    longer.wherePredicate !== undefined ||\n    shorter.keyColumns.length >= longer.keyColumns.length\n  ) {\n    return null;\n  }\n  for (let i = 0; i < shorter.keyColumns.length; i++) {\n    const s = shorter.keyColumns[i];\n    const l = longer.keyColumns[i];\n    if (\n      s.name.toString() !== l.name.toString() ||\n      (s.order ?? null) !== (l.order ?? null) ||\n      (s.opclass ?? null) !== (l.opclass ?? null)\n    ) {\n      return null;\n    }\n  }\n  return shorter.keyColumns;\n}\n\nexport function groupDuplicateIndexes(\n  indexes: FullSchemaIndex[],\n): DuplicateIndexGroup[] {\n  const groups: DuplicateIndexGroup[] = [];\n\n  for (const index of indexes) {\n    const existing = groups.find(\n      (g) => g.kind === \"exact\" && indexesAreEqual(g.indexes[0], index),\n    );\n    if (existing) {\n      existing.indexes.push(index);\n    } else {\n      groups.push({ kind: \"exact\", indexes: [index] });\n    }\n  }\n\n  const exactGroups = groups.filter((g) => g.indexes.length > 1);\n\n  const representatives = groups\n    .filter((g) => g.indexes.length === 1)\n    .map((g) => g.indexes[0]);\n\n  const prefixGroups: Extract<DuplicateIndexGroup, { kind: \"prefix\" }>[] = [];\n\n  for (const shorter of representatives) {\n    const existing = prefixGroups.find((g) =>\n      g.indexes.some(\n        (idx) =>\n          sharedPrefixColumns(shorter, idx) !== null ||\n          sharedPrefixColumns(idx, shorter) !== null,\n      ),\n    );\n    if (existing) {\n      if (!existing.indexes.includes(shorter)) {\n        existing.indexes.push(shorter);\n      }\n    } else {\n      const longer = representatives.find(\n        (idx) => idx !== shorter && sharedPrefixColumns(shorter, idx) !== null,\n      );\n      if (longer) {\n        const sharedPrefix = sharedPrefixColumns(shorter, longer)!;\n        prefixGroups.push({\n          kind: \"prefix\",\n          indexes: [longer, shorter],\n          sharedPrefix,\n        });\n      }\n    }\n  }\n\n  return [...exactGroups, ...prefixGroups];\n}\n"],"mappings":";;AAKA,SAAgB,iBAAiB,OAAsB;AACrD,QAAO,MAAM,cAAc,WAAW,MAAM,cAAc;;;;;;AAO5D,SAAgB,yBAAyB,OAAsB;AAG7D,QAAO,CAAC,MAAM,aAAa,CAAC,MAAM;;AAWpC,SAAS,aACP,GACA,GACS;AACT,KAAI,EAAE,WAAW,EAAE,OAAQ,QAAO;AAClC,MAAK,IAAI,IAAI,GAAG,IAAI,EAAE,QAAQ,IAC5B,KACE,EAAE,GAAG,KAAK,UAAU,KAAK,EAAE,GAAG,KAAK,UAAU,KAC5C,EAAE,GAAG,SAAS,WAAW,EAAE,GAAG,SAAS,UACvC,EAAE,GAAG,WAAW,WAAW,EAAE,GAAG,WAAW,MAE5C,QAAO;AAGX,QAAO;;AAGT,SAAS,gBAAgB,GAAoB,GAA6B;AACxE,QACE,EAAE,WAAW,UAAU,KAAK,EAAE,WAAW,UAAU,IACnD,EAAE,UAAU,UAAU,KAAK,EAAE,UAAU,UAAU,IACjD,EAAE,cAAc,EAAE,cACjB,EAAE,kBAAkB,WAAW,EAAE,kBAAkB,SACpD,aAAa,EAAE,YAAY,EAAE,WAAW;;AAI5C,SAAS,oBACP,SACA,QACsC;AACtC,KACE,QAAQ,WAAW,UAAU,KAAK,OAAO,WAAW,UAAU,IAC9D,QAAQ,UAAU,UAAU,KAAK,OAAO,UAAU,UAAU,IAC5D,QAAQ,cAAc,OAAO,aAC7B,QAAQ,cAAc,WACtB,QAAQ,mBAAmB,KAAA,KAC3B,OAAO,mBAAmB,KAAA,KAC1B,QAAQ,WAAW,UAAU,OAAO,WAAW,OAE/C,QAAO;AAET,MAAK,IAAI,IAAI,GAAG,IAAI,QAAQ,WAAW,QAAQ,KAAK;EAClD,MAAM,IAAI,QAAQ,WAAW;EAC7B,MAAM,IAAI,OAAO,WAAW;AAC5B,MACE,EAAE,KAAK,UAAU,KAAK,EAAE,KAAK,UAAU,KACtC,EAAE,SAAS,WAAW,EAAE,SAAS,UACjC,EAAE,WAAW,WAAW,EAAE,WAAW,MAEtC,QAAO;;AAGX,QAAO,QAAQ;;AAGjB,SAAgB,sBACd,SACuB;CACvB,MAAM,SAAgC,EAAE;AAExC,MAAK,MAAM,SAAS,SAAS;EAC3B,MAAM,WAAW,OAAO,MACrB,MAAM,EAAE,SAAS,WAAW,gBAAgB,EAAE,QAAQ,IAAI,MAAM,CAClE;AACD,MAAI,SACF,UAAS,QAAQ,KAAK,MAAM;MAE5B,QAAO,KAAK;GAAE,MAAM;GAAS,SAAS,CAAC,MAAM;GAAE,CAAC;;CAIpD,MAAM,cAAc,OAAO,QAAQ,MAAM,EAAE,QAAQ,SAAS,EAAE;CAE9D,MAAM,kBAAkB,OACrB,QAAQ,MAAM,EAAE,QAAQ,WAAW,EAAE,CACrC,KAAK,MAAM,EAAE,QAAQ,GAAG;CAE3B,MAAM,eAAmE,EAAE;AAE3E,MAAK,MAAM,WAAW,iBAAiB;EACrC,MAAM,WAAW,aAAa,MAAM,MAClC,EAAE,QAAQ,MACP,QACC,oBAAoB,SAAS,IAAI,KAAK,QACtC,oBAAoB,KAAK,QAAQ,KAAK,KACzC,CACF;AACD,MAAI;OACE,CAAC,SAAS,QAAQ,SAAS,QAAQ,CACrC,UAAS,QAAQ,KAAK,QAAQ;SAE3B;GACL,MAAM,SAAS,gBAAgB,MAC5B,QAAQ,QAAQ,WAAW,oBAAoB,SAAS,IAAI,KAAK,KACnE;AACD,OAAI,QAAQ;IACV,MAAM,eAAe,oBAAoB,SAAS,OAAO;AACzD,iBAAa,KAAK;KAChB,MAAM;KACN,SAAS,CAAC,QAAQ,QAAQ;KAC1B;KACD,CAAC;;;;AAKR,QAAO,CAAC,GAAG,aAAa,GAAG,aAAa"}