mirror of
https://github.com/Azure/cosmos-explorer.git
synced 2025-10-13 15:28:05 +01:00
fixed sdk response
This commit is contained in:
parent
2cf18ff055
commit
15c6bd6d0e
@ -13,80 +13,85 @@ interface IndexObject {
|
||||
path?: string;
|
||||
}
|
||||
|
||||
export interface IndexMetricsJson {
|
||||
included?: IIndexMetric[];
|
||||
notIncluded?: IIndexMetric[];
|
||||
// SDK response format
|
||||
export interface IndexMetricsResponse {
|
||||
UtilizedIndexes?: {
|
||||
SingleIndexes?: Array<{ IndexSpec: string; IndexImpactScore?: string }>;
|
||||
CompositeIndexes?: Array<{ IndexSpecs: string[]; IndexImpactScore?: string }>;
|
||||
};
|
||||
PotentialIndexes?: {
|
||||
SingleIndexes?: Array<{ IndexSpec: string; IndexImpactScore?: string }>;
|
||||
CompositeIndexes?: Array<{ IndexSpecs: string[]; IndexImpactScore?: string }>;
|
||||
};
|
||||
}
|
||||
export function parseIndexMetrics(indexMetrics: string | IndexMetricsJson): {
|
||||
|
||||
export function parseIndexMetrics(indexMetrics: IndexMetricsResponse): {
|
||||
included: IIndexMetric[];
|
||||
notIncluded: IIndexMetric[];
|
||||
} {
|
||||
// If already JSON, just extract arrays
|
||||
if (typeof indexMetrics === "object" && indexMetrics !== null) {
|
||||
return {
|
||||
included: Array.isArray(indexMetrics.included) ? indexMetrics.included : [],
|
||||
notIncluded: Array.isArray(indexMetrics.notIncluded) ? indexMetrics.notIncluded : [],
|
||||
};
|
||||
}
|
||||
|
||||
// Otherwise, parse as string (current SDK)
|
||||
const included: IIndexMetric[] = [];
|
||||
const notIncluded: IIndexMetric[] = [];
|
||||
const lines = (indexMetrics as string)
|
||||
.split("\n")
|
||||
.map((line) => line.trim())
|
||||
.filter(Boolean);
|
||||
let currentSection = "";
|
||||
for (let i = 0; i < lines.length; i++) {
|
||||
const line = lines[i];
|
||||
if (line.startsWith("Utilized Single Indexes") || line.startsWith("Utilized Composite Indexes")) {
|
||||
currentSection = "included";
|
||||
} else if (line.startsWith("Potential Single Indexes") || line.startsWith("Potential Composite Indexes")) {
|
||||
currentSection = "notIncluded";
|
||||
} else if (line.startsWith("Index Spec:")) {
|
||||
const index = line.replace("Index Spec:", "").trim();
|
||||
const impactLine = lines[i + 1];
|
||||
const impact = impactLine?.includes("Index Impact Score:") ? impactLine.split(":")[1].trim() : "Unknown";
|
||||
|
||||
const isComposite = index.includes(",");
|
||||
// Process UtilizedIndexes (Included)
|
||||
if (indexMetrics.UtilizedIndexes) {
|
||||
// Single indexes
|
||||
indexMetrics.UtilizedIndexes.SingleIndexes?.forEach((index) => {
|
||||
included.push({
|
||||
index: index.IndexSpec,
|
||||
impact: index.IndexImpactScore || "Utilized",
|
||||
section: "Included",
|
||||
path: index.IndexSpec,
|
||||
});
|
||||
});
|
||||
|
||||
const sectionMap: Record<string, "Included" | "Not Included"> = {
|
||||
included: "Included",
|
||||
notIncluded: "Not Included",
|
||||
};
|
||||
|
||||
const indexObj: IndexObject = { index, impact, section: sectionMap[currentSection] ?? "Header" };
|
||||
if (isComposite) {
|
||||
indexObj.composite = index.split(",").map((part: string) => {
|
||||
const [path, order] = part.trim().split(/\s+/);
|
||||
// Composite indexes
|
||||
indexMetrics.UtilizedIndexes.CompositeIndexes?.forEach((index) => {
|
||||
const compositeSpec = index.IndexSpecs.join(", ");
|
||||
included.push({
|
||||
index: compositeSpec,
|
||||
impact: index.IndexImpactScore || "Utilized",
|
||||
section: "Included",
|
||||
composite: index.IndexSpecs.map((spec) => {
|
||||
const [path, order] = spec.trim().split(/\s+/);
|
||||
return {
|
||||
path: path.trim(),
|
||||
order: order?.toLowerCase() === "desc" ? "descending" : "ascending",
|
||||
};
|
||||
}),
|
||||
});
|
||||
});
|
||||
} else {
|
||||
let path = "/unknown/*";
|
||||
const pathRegex = /\/[^/\s*?]+(?:\/[^/\s*?]+)*(\/\*|\?)/;
|
||||
const match = index.match(pathRegex);
|
||||
if (match) {
|
||||
path = match[0];
|
||||
} else {
|
||||
const simplePathRegex = /\/[^/\s]+/;
|
||||
const simpleMatch = index.match(simplePathRegex);
|
||||
if (simpleMatch) {
|
||||
path = simpleMatch[0] + "/*";
|
||||
}
|
||||
}
|
||||
indexObj.path = path;
|
||||
}
|
||||
|
||||
if (currentSection === "included") {
|
||||
included.push(indexObj);
|
||||
} else if (currentSection === "notIncluded") {
|
||||
notIncluded.push(indexObj);
|
||||
}
|
||||
}
|
||||
// Process PotentialIndexes (Not Included)
|
||||
if (indexMetrics.PotentialIndexes) {
|
||||
// Single indexes
|
||||
indexMetrics.PotentialIndexes.SingleIndexes?.forEach((index) => {
|
||||
notIncluded.push({
|
||||
index: index.IndexSpec,
|
||||
impact: index.IndexImpactScore || "Unknown",
|
||||
section: "Not Included",
|
||||
path: index.IndexSpec,
|
||||
});
|
||||
});
|
||||
|
||||
// Composite indexes
|
||||
indexMetrics.PotentialIndexes.CompositeIndexes?.forEach((index) => {
|
||||
const compositeSpec = index.IndexSpecs.join(", ");
|
||||
notIncluded.push({
|
||||
index: compositeSpec,
|
||||
impact: index.IndexImpactScore || "Unknown",
|
||||
section: "Not Included",
|
||||
composite: index.IndexSpecs.map((spec) => {
|
||||
const [path, order] = spec.trim().split(/\s+/);
|
||||
return {
|
||||
path: path.trim(),
|
||||
order: order?.toLowerCase() === "desc" ? "descending" : "ascending",
|
||||
};
|
||||
}),
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
return { included, notIncluded };
|
||||
}
|
||||
|
||||
|
@ -28,7 +28,6 @@ import { HttpHeaders } from "Common/Constants";
|
||||
import MongoUtility from "Common/MongoUtility";
|
||||
import { QueryMetrics } from "Contracts/DataModels";
|
||||
import { EditorReact } from "Explorer/Controls/Editor/EditorReact";
|
||||
import { parseIndexMetrics, renderImpactDots } from "Explorer/Tabs/QueryTab/IndexAdvisorUtils";
|
||||
import { IDocument } from "Explorer/Tabs/QueryTab/QueryTabComponent";
|
||||
import { useQueryTabStyles } from "Explorer/Tabs/QueryTab/Styles";
|
||||
import React, { useCallback, useEffect, useState } from "react";
|
||||
@ -37,6 +36,7 @@ import { logConsoleProgress } from "Utils/NotificationConsoleUtils";
|
||||
import create from "zustand";
|
||||
import { client } from "../../../Common/CosmosClient";
|
||||
import { handleError } from "../../../Common/ErrorHandlingUtils";
|
||||
import { parseIndexMetrics, renderImpactDots, type IndexMetricsResponse } from "./IndexAdvisorUtils";
|
||||
import { ResultsViewProps } from "./QueryResultSection";
|
||||
import { useIndexAdvisorStyles } from "./StylesAdvisor";
|
||||
enum ResultsTabs {
|
||||
@ -550,7 +550,7 @@ export const IndexAdvisorTab: React.FC<{
|
||||
}> = ({ queryText, databaseId, containerId }) => {
|
||||
const style = useIndexAdvisorStyles();
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [indexMetrics, setIndexMetrics] = useState<string | null>(null);
|
||||
const [indexMetrics, setIndexMetrics] = useState<IndexMetricsResponse | null>(null);
|
||||
const [showIncluded, setShowIncluded] = useState(true);
|
||||
const [showNotIncluded, setShowNotIncluded] = useState(true);
|
||||
const [selectedIndexes, setSelectedIndexes] = useState<IIndexMetric[]>([]);
|
||||
@ -592,7 +592,12 @@ export const IndexAdvisorTab: React.FC<{
|
||||
populateIndexMetrics: true,
|
||||
})
|
||||
.fetchAll();
|
||||
setIndexMetrics(sdkResponse.indexMetrics);
|
||||
|
||||
const parsedIndexMetrics = typeof sdkResponse.indexMetrics === 'string'
|
||||
? JSON.parse(sdkResponse.indexMetrics)
|
||||
: sdkResponse.indexMetrics;
|
||||
|
||||
setIndexMetrics(parsedIndexMetrics);
|
||||
} catch (error) {
|
||||
handleError(error, "queryItemsWithIndexMetrics", `Error querying items from ${containerId}`);
|
||||
} finally {
|
||||
|
Loading…
x
Reference in New Issue
Block a user