fix(mongodb): route find result sorting through shell sort clauses
Use find().sort() for MongoDB query grid sorting instead of SQL ORDER BY, and normalize document browser sort input the same way as filters. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
06231d512f
commit
e7ec2ecaf2
|
|
@ -16,7 +16,18 @@ import * as api from "@/lib/api";
|
|||
import { useConnectionStore } from "@/stores/connectionStore";
|
||||
import { clampSearchSplitWidth } from "@/lib/dataGridSearchSplit";
|
||||
import { documentViewerFontStyle } from "@/lib/documentViewerFontStyle";
|
||||
import { buildDocumentFilterCondition, combineDocumentFilterConditions, currentDocumentFilterJson, defaultDocumentFilterRule, documentFilterModeNeedsValue, documentFilterModeOptions, documentStoreProviderFor, type DocumentFilterMode, type DocumentFilterRule } from "@/lib/documentStoreProvider";
|
||||
import {
|
||||
buildDocumentFilterCondition,
|
||||
combineDocumentFilterConditions,
|
||||
currentDocumentFilterJson,
|
||||
currentDocumentSortJson,
|
||||
defaultDocumentFilterRule,
|
||||
documentFilterModeNeedsValue,
|
||||
documentFilterModeOptions,
|
||||
documentStoreProviderFor,
|
||||
type DocumentFilterMode,
|
||||
type DocumentFilterRule,
|
||||
} from "@/lib/documentStoreProvider";
|
||||
import { buildMongoInsertDocument, buildMongoUpdateDocument, formatMongoShellLiteral, parseMongoDocumentInputValue, type MongoInputValue } from "@/lib/mongoDocumentValues";
|
||||
import { normalizeResultPageSize } from "@/lib/paginationPageSize";
|
||||
import { useSettingsStore } from "@/stores/settingsStore";
|
||||
|
|
@ -433,7 +444,7 @@ async function load() {
|
|||
const previousSelectedId = previousSelectedIdx === null ? null : documentIdentity(documents.value[previousSelectedIdx]);
|
||||
try {
|
||||
const filter = currentDocumentFilter();
|
||||
const sort = sortInput.value.trim() || undefined;
|
||||
const sort = currentDocumentSortJson(sortInput.value);
|
||||
const result = await api.documentFindDocuments(props.connectionId, props.database, props.collection, page.value * pageSize.value, pageSize.value, filter, undefined, sort, executionId);
|
||||
if (documentLoadExecutionId.value !== executionId) return;
|
||||
const nextDocuments = result.documents.map(asRecord);
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ import * as api from "@/lib/api";
|
|||
import type { QueryTab } from "@/types/database";
|
||||
import { useToast } from "@/composables/useToast";
|
||||
import { effectiveDatabaseTypeForConnection, metadataSchemaForConnection } from "@/lib/jdbcDialect";
|
||||
import { applyMongoFindSort } from "@/lib/mongoShellCommand";
|
||||
import { uuid } from "@/lib/utils";
|
||||
import type { DataGridSortMode } from "@/lib/dataGridSort";
|
||||
|
||||
|
|
@ -235,6 +236,22 @@ export function useDataGridActions(activeTab: ComputedRef<QueryTab | undefined>)
|
|||
}
|
||||
|
||||
const config = connectionStore.getConfig(tab.connectionId);
|
||||
if (effectiveDatabaseTypeForConnection(config) === "mongodb") {
|
||||
const sortedSql = applyMongoFindSort(baseSql, column, direction);
|
||||
if (!sortedSql) {
|
||||
toast(t("grid.sortUnsupported"), 5000);
|
||||
return;
|
||||
}
|
||||
queryStore.updateSql(tab.id, sortedSql);
|
||||
await queryStore.executeTabSql(tab.id, sortedSql, {
|
||||
resultBaseSql: baseSql,
|
||||
resultSortedSql: sortedSql,
|
||||
preserveResultDuringExecution: true,
|
||||
preserveTotalRowCountDuringExecution: true,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
const built = await api.buildSortedQuerySql({
|
||||
originalSql: baseSql,
|
||||
databaseType: effectiveDatabaseTypeForConnection(config),
|
||||
|
|
|
|||
|
|
@ -151,6 +151,11 @@ export function currentDocumentFilterJson(input: string, structured: Record<stri
|
|||
return Object.keys(filter).length ? JSON.stringify(filter) : undefined;
|
||||
}
|
||||
|
||||
export function currentDocumentSortJson(input: string): string | undefined {
|
||||
const sort = parseDocumentFilterInput(input);
|
||||
return Object.keys(sort).length ? JSON.stringify(sort) : undefined;
|
||||
}
|
||||
|
||||
function parseDocumentFilterValue(raw: string): unknown {
|
||||
const trimmed = raw.trim();
|
||||
if (!trimmed) return "";
|
||||
|
|
|
|||
|
|
@ -112,6 +112,27 @@ export function parseMongoFindCommand(input: string): MongoFindCommand | null {
|
|||
};
|
||||
}
|
||||
|
||||
export function applyMongoFindSort(input: string, column: string, direction: "asc" | "desc"): string | null {
|
||||
const source = input.trim().replace(/;$/, "").trim();
|
||||
const parsed = parseMongoFindCommand(source);
|
||||
if (!parsed) return null;
|
||||
|
||||
const target = parseFindTarget(source);
|
||||
if (!target) return null;
|
||||
|
||||
const findOpenIndex = source.indexOf("(", target.findCallIndex);
|
||||
const findCloseIndex = findMatchingParen(source, findOpenIndex);
|
||||
if (findCloseIndex < 0) return null;
|
||||
|
||||
const prefix = source.slice(0, findCloseIndex + 1);
|
||||
const chainSource = source.slice(findCloseIndex + 1).trim();
|
||||
if (chainSource && !chainSource.startsWith(".")) return null;
|
||||
|
||||
const chain = removeChainedMethodCall(chainSource, "sort");
|
||||
const sortCall = `.sort(${JSON.stringify({ [column]: direction === "asc" ? 1 : -1 })})`;
|
||||
return `${prefix}${sortCall}${chain}`;
|
||||
}
|
||||
|
||||
export function parseMongoCountDocumentsCommand(input: string): MongoCountDocumentsCommand | null {
|
||||
const source = input.trim().replace(/;$/, "").trim();
|
||||
// Accept deprecated Mongo shell count helpers for old server workflows, but
|
||||
|
|
@ -934,6 +955,21 @@ function readChainedIntegerArgument(source: string, name: string, fallback: numb
|
|||
return value;
|
||||
}
|
||||
|
||||
function removeChainedMethodCall(chain: string, name: string): string {
|
||||
if (!chain.trim()) return "";
|
||||
let result = chain.trim();
|
||||
const pattern = chainedMethodCallPattern(name);
|
||||
let match: RegExpExecArray | null;
|
||||
while ((match = pattern.exec(result)) !== null) {
|
||||
const openIndex = result.indexOf("(", match.index);
|
||||
const closeIndex = findMatchingParen(result, openIndex);
|
||||
if (closeIndex < 0) break;
|
||||
result = `${result.slice(0, match.index)}${result.slice(closeIndex + 1)}`.trim();
|
||||
pattern.lastIndex = 0;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
function readChainedCallArgument(source: string, name: string): string | undefined {
|
||||
const pattern = chainedMethodCallPattern(name);
|
||||
let match = pattern.exec(source);
|
||||
|
|
|
|||
Loading…
Reference in New Issue