overwrite fixes

This commit is contained in:
nishthaAhujaa
2025-10-16 00:25:37 +05:30
parent 163d25dfd9
commit 312bcb8e04
2 changed files with 112 additions and 102 deletions

View File

@@ -2,91 +2,86 @@ import { CircleFilled } from "@fluentui/react-icons";
import type { IIndexMetric } from "Explorer/Tabs/QueryTab/ResultsView"; import type { IIndexMetric } from "Explorer/Tabs/QueryTab/ResultsView";
import { useIndexAdvisorStyles } from "Explorer/Tabs/QueryTab/StylesAdvisor"; import { useIndexAdvisorStyles } from "Explorer/Tabs/QueryTab/StylesAdvisor";
import * as React from "react"; import * as React from "react";
interface IndexObject {
index: string; // SDK response format
impact: string; export interface IndexMetricsResponse {
section: "Included" | "Not Included" | "Header"; UtilizedIndexes?: {
composite?: { SingleIndexes?: Array<{ IndexSpec: string; IndexImpactScore?: string }>;
path: string; CompositeIndexes?: Array<{ IndexSpecs: string[]; IndexImpactScore?: string }>;
order: "ascending" | "descending"; };
}[]; PotentialIndexes?: {
path?: string; SingleIndexes?: Array<{ IndexSpec: string; IndexImpactScore?: string }>;
CompositeIndexes?: Array<{ IndexSpecs: string[]; IndexImpactScore?: string }>;
};
} }
export interface IndexMetricsJson { export function parseIndexMetrics(indexMetrics: IndexMetricsResponse): {
included?: IIndexMetric[];
notIncluded?: IIndexMetric[];
}
export function parseIndexMetrics(indexMetrics: string | IndexMetricsJson): {
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 in Current Policy)
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") {
included.push(indexObj);
} else if (currentSection === "notIncluded") {
notIncluded.push(indexObj);
}
}
} }
// Process PotentialIndexes (Not Included in Current Policy)
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 }; return { included, notIncluded };
} }

View File

@@ -27,8 +27,9 @@ import copy from "clipboard-copy";
import { HttpHeaders } from "Common/Constants"; 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 { QueryResults } from "Contracts/ViewModels";
import { EditorReact } from "Explorer/Controls/Editor/EditorReact"; import { EditorReact } from "Explorer/Controls/Editor/EditorReact";
import { parseIndexMetrics, renderImpactDots } from "Explorer/Tabs/QueryTab/IndexAdvisorUtils"; import { parseIndexMetrics, renderImpactDots, type IndexMetricsResponse } from "Explorer/Tabs/QueryTab/IndexAdvisorUtils";
import { IDocument, useQueryMetadataStore } from "Explorer/Tabs/QueryTab/QueryTabComponent"; import { IDocument, useQueryMetadataStore } 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";
@@ -394,9 +395,8 @@ const QueryStatsTab: React.FC<Pick<ResultsViewProps, "queryResults">> = ({ query
}, },
{ {
metric: "User defined function execution time", metric: "User defined function execution time",
value: `${ value: `${aggregatedQueryMetrics.runtimeExecutionTimes?.userDefinedFunctionExecutionTime?.toString() || 0
aggregatedQueryMetrics.runtimeExecutionTimes?.userDefinedFunctionExecutionTime?.toString() || 0 } ms`,
} ms`,
toolTip: "Total time spent executing user-defined functions", toolTip: "Total time spent executing user-defined functions",
}, },
{ {
@@ -544,11 +544,11 @@ export interface IIndexMetric {
path?: string; path?: string;
composite?: { path: string; order: string }[]; composite?: { path: string; order: string }[];
} }
export const IndexAdvisorTab: React.FC = () => { export const IndexAdvisorTab: React.FC<{ queryResults?: QueryResults }> = ({ queryResults }) => {
const style = useIndexAdvisorStyles(); const style = useIndexAdvisorStyles();
const { userQuery, databaseId, containerId } = useQueryMetadataStore(); const { userQuery, databaseId, containerId } = useQueryMetadataStore();
const [loading, setLoading] = useState(true); const [loading, setLoading] = useState(false);
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[]>([]);
@@ -560,32 +560,47 @@ export const IndexAdvisorTab: React.FC = () => {
const [justUpdatedPolicy, setJustUpdatedPolicy] = useState(false); const [justUpdatedPolicy, setJustUpdatedPolicy] = useState(false);
const indexingMetricsDocLink = "https://learn.microsoft.com/azure/cosmos-db/nosql/index-metrics"; const indexingMetricsDocLink = "https://learn.microsoft.com/azure/cosmos-db/nosql/index-metrics";
const fetchIndexMetrics = async () => {
if (!userQuery || !databaseId || !containerId) {
return;
}
setLoading(true);
const clearMessage = logConsoleProgress(`Querying items with IndexMetrics in container ${containerId}`);
try {
const containerRef = client().database(databaseId).container(containerId);
const { resource: containerDef } = await containerRef.read();
const querySpec = {
query: userQuery,
};
const sdkResponse = await client()
.database(databaseId)
.container(containerId)
.items.query(querySpec, {
populateIndexMetrics: true,
})
.fetchAll();
const parsedMetrics = typeof sdkResponse.indexMetrics === 'string'
? JSON.parse(sdkResponse.indexMetrics)
: sdkResponse.indexMetrics;
setIndexMetrics(parsedMetrics);
} catch (error) {
handleError(error, "queryItemsWithIndexMetrics", `Error querying items from ${containerId}`);
} finally {
clearMessage();
setLoading(false);
}
};
// Fetch index metrics when query results change (i.e., when Execute Query is clicked)
useEffect(() => { useEffect(() => {
const fetchIndexMetrics = async () => { if (userQuery && databaseId && containerId && queryResults) {
const clearMessage = logConsoleProgress(`Querying items with IndexMetrics in container ${containerId}`);
try {
const querySpec = {
query: userQuery,
};
const sdkResponse = await client()
.database(databaseId)
.container(containerId)
.items.query(querySpec, {
populateIndexMetrics: true,
})
.fetchAll();
setIndexMetrics(sdkResponse.indexMetrics);
} catch (error) {
handleError(error, "queryItemsWithIndexMetrics", `Error querying items from ${containerId}`);
} finally {
clearMessage();
setLoading(false);
}
};
if (userQuery && databaseId && containerId) {
fetchIndexMetrics(); fetchIndexMetrics();
} }
}, [userQuery, databaseId, containerId]); }, [queryResults]);
useEffect(() => { useEffect(() => {
if (!indexMetrics) { if (!indexMetrics) {
@@ -869,7 +884,7 @@ export const ResultsView: React.FC<ResultsViewProps> = ({ isMongoDB, queryResult
/> />
)} )}
{activeTab === ResultsTabs.QueryStats && <QueryStatsTab queryResults={queryResults} />} {activeTab === ResultsTabs.QueryStats && <QueryStatsTab queryResults={queryResults} />}
{activeTab === ResultsTabs.IndexAdvisor && <IndexAdvisorTab />} {activeTab === ResultsTabs.IndexAdvisor && <IndexAdvisorTab queryResults={queryResults} />}
</div> </div>
</div> </div>
); );