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;
|
path?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IndexMetricsJson {
|
// SDK response format
|
||||||
included?: IIndexMetric[];
|
export interface IndexMetricsResponse {
|
||||||
notIncluded?: IIndexMetric[];
|
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[];
|
included: IIndexMetric[];
|
||||||
notIncluded: 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 included: IIndexMetric[] = [];
|
||||||
const notIncluded: 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"> = {
|
// Composite indexes
|
||||||
included: "Included",
|
indexMetrics.UtilizedIndexes.CompositeIndexes?.forEach((index) => {
|
||||||
notIncluded: "Not Included",
|
const compositeSpec = index.IndexSpecs.join(", ");
|
||||||
};
|
included.push({
|
||||||
|
index: compositeSpec,
|
||||||
const indexObj: IndexObject = { index, impact, section: sectionMap[currentSection] ?? "Header" };
|
impact: index.IndexImpactScore || "Utilized",
|
||||||
if (isComposite) {
|
section: "Included",
|
||||||
indexObj.composite = index.split(",").map((part: string) => {
|
composite: index.IndexSpecs.map((spec) => {
|
||||||
const [path, order] = part.trim().split(/\s+/);
|
const [path, order] = spec.trim().split(/\s+/);
|
||||||
return {
|
return {
|
||||||
path: path.trim(),
|
path: path.trim(),
|
||||||
order: order?.toLowerCase() === "desc" ? "descending" : "ascending",
|
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") {
|
// Process PotentialIndexes (Not Included)
|
||||||
included.push(indexObj);
|
if (indexMetrics.PotentialIndexes) {
|
||||||
} else if (currentSection === "notIncluded") {
|
// Single indexes
|
||||||
notIncluded.push(indexObj);
|
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 };
|
return { included, notIncluded };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -28,7 +28,6 @@ import { HttpHeaders } from "Common/Constants";
|
|||||||
import MongoUtility from "Common/MongoUtility";
|
import MongoUtility from "Common/MongoUtility";
|
||||||
import { QueryMetrics } from "Contracts/DataModels";
|
import { QueryMetrics } from "Contracts/DataModels";
|
||||||
import { EditorReact } from "Explorer/Controls/Editor/EditorReact";
|
import { EditorReact } from "Explorer/Controls/Editor/EditorReact";
|
||||||
import { parseIndexMetrics, renderImpactDots } from "Explorer/Tabs/QueryTab/IndexAdvisorUtils";
|
|
||||||
import { IDocument } from "Explorer/Tabs/QueryTab/QueryTabComponent";
|
import { IDocument } from "Explorer/Tabs/QueryTab/QueryTabComponent";
|
||||||
import { useQueryTabStyles } from "Explorer/Tabs/QueryTab/Styles";
|
import { useQueryTabStyles } from "Explorer/Tabs/QueryTab/Styles";
|
||||||
import React, { useCallback, useEffect, useState } from "react";
|
import React, { useCallback, useEffect, useState } from "react";
|
||||||
@ -37,6 +36,7 @@ import { logConsoleProgress } from "Utils/NotificationConsoleUtils";
|
|||||||
import create from "zustand";
|
import create from "zustand";
|
||||||
import { client } from "../../../Common/CosmosClient";
|
import { client } from "../../../Common/CosmosClient";
|
||||||
import { handleError } from "../../../Common/ErrorHandlingUtils";
|
import { handleError } from "../../../Common/ErrorHandlingUtils";
|
||||||
|
import { parseIndexMetrics, renderImpactDots, type IndexMetricsResponse } from "./IndexAdvisorUtils";
|
||||||
import { ResultsViewProps } from "./QueryResultSection";
|
import { ResultsViewProps } from "./QueryResultSection";
|
||||||
import { useIndexAdvisorStyles } from "./StylesAdvisor";
|
import { useIndexAdvisorStyles } from "./StylesAdvisor";
|
||||||
enum ResultsTabs {
|
enum ResultsTabs {
|
||||||
@ -550,7 +550,7 @@ export const IndexAdvisorTab: React.FC<{
|
|||||||
}> = ({ queryText, databaseId, containerId }) => {
|
}> = ({ queryText, databaseId, containerId }) => {
|
||||||
const style = useIndexAdvisorStyles();
|
const style = useIndexAdvisorStyles();
|
||||||
const [loading, setLoading] = useState(true);
|
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 [showIncluded, setShowIncluded] = useState(true);
|
||||||
const [showNotIncluded, setShowNotIncluded] = useState(true);
|
const [showNotIncluded, setShowNotIncluded] = useState(true);
|
||||||
const [selectedIndexes, setSelectedIndexes] = useState<IIndexMetric[]>([]);
|
const [selectedIndexes, setSelectedIndexes] = useState<IIndexMetric[]>([]);
|
||||||
@ -592,7 +592,12 @@ export const IndexAdvisorTab: React.FC<{
|
|||||||
populateIndexMetrics: true,
|
populateIndexMetrics: true,
|
||||||
})
|
})
|
||||||
.fetchAll();
|
.fetchAll();
|
||||||
setIndexMetrics(sdkResponse.indexMetrics);
|
|
||||||
|
const parsedIndexMetrics = typeof sdkResponse.indexMetrics === 'string'
|
||||||
|
? JSON.parse(sdkResponse.indexMetrics)
|
||||||
|
: sdkResponse.indexMetrics;
|
||||||
|
|
||||||
|
setIndexMetrics(parsedIndexMetrics);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
handleError(error, "queryItemsWithIndexMetrics", `Error querying items from ${containerId}`);
|
handleError(error, "queryItemsWithIndexMetrics", `Error querying items from ${containerId}`);
|
||||||
} finally {
|
} finally {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user