fix(mongodb): support legacy count helpers

This commit is contained in:
t8y2 committed 2026-07-03 13:25:36 +08:00
1 parent c702149931
commit cabe89a19b
5 files changed
+146 -31

No files matched your search

+45 -5
View File
@@ -88,6 +88,7 @@ export function parseMongoFindCommand(input: string): MongoFindCommand | null {
const chain = source.slice(findCloseIndex + 1).trim();
if (chain && !chain.startsWith(".")) return null;
if (findChainedMethodCallIndex(chain, "count") >= 0) return null;
const sortArg = readChainedCallArgument(chain, "sort");
let sort: string | undefined;
@@ -113,7 +114,13 @@ export function parseMongoFindCommand(input: string): MongoFindCommand | null {
export function parseMongoCountDocumentsCommand(input: string): MongoCountDocumentsCommand | null {
const source = input.trim().replace(/;$/, "").trim();
const target = parseCollectionMethodTarget(source, "countDocuments");
// Accept deprecated Mongo shell count helpers for old server workflows, but
// keep DBX's internal execution mapped to the countDocuments result shape.
return parseCollectionCountCommand(source, "countDocuments") ?? parseCollectionCountCommand(source, "count") ?? parseFindCountCommand(source);
}
function parseCollectionCountCommand(source: string, method: "countDocuments" | "count"): MongoCountDocumentsCommand | null {
const target = parseCollectionMethodTarget(source, method);
if (!target) return null;
const openIndex = source.indexOf("(", target.methodCallIndex);
@@ -131,6 +138,28 @@ export function parseMongoCountDocumentsCommand(input: string): MongoCountDocume
};
}
function parseFindCountCommand(source: string): MongoCountDocumentsCommand | 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 chain = source.slice(findCloseIndex + 1).trim();
if (!hasSingleEmptyChainedCall(chain, "count")) return null;
const findArgs = splitTopLevel(source.slice(findOpenIndex + 1, findCloseIndex));
if (findArgs.length > 2 && findArgs.slice(2).some((arg) => arg.trim())) return null;
const filter = normalizeJsonArgument(findArgs[0] || "{}");
if (!filter) return null;
return {
collection: target.collection,
filter,
};
}
export function parseMongoAggregateCommand(input: string): MongoAggregateCommand | null {
const source = input.trim().replace(/;$/, "").trim();
const target = parseCollectionMethodTarget(source, "aggregate");
@@ -268,18 +297,20 @@ export function parseMongoCommand(input: string): ParsedMongoCommand | null {
// Keep the more specific readers ahead of generic write parsing so the
// returned kind matches the result renderer we want to use downstream.
const parsers: Array<(source: string) => MongoCommand | null> = [
(source) => {
const find = parseMongoFindCommand(source);
return find ? { kind: "find", ...find } : null;
},
(source) => {
const version = parseMongoVersionCommand(source);
return version ?? null;
},
(source) => {
// Legacy Mongo shell uses count()/find().count(); keep accepting it
// while mapping to DBX's countDocuments-compatible result path.
const count = parseMongoCountDocumentsCommand(source);
return count ? { kind: "countDocuments", ...count } : null;
},
(source) => {
const find = parseMongoFindCommand(source);
return find ? { kind: "find", ...find } : null;
},
(source) => {
const aggregate = parseMongoAggregateCommand(source);
return aggregate ? { kind: "aggregate", ...aggregate } : null;
@@ -915,6 +946,15 @@ function readChainedCallArgument(source: string, name: string): string | undefin
return undefined;
}
function hasSingleEmptyChainedCall(source: string, name: string): boolean {
const trimmed = source.trim();
const match = chainedMethodCallPattern(name).exec(trimmed);
if (!match || match.index !== 0) return false;
const openIndex = trimmed.indexOf("(", match.index);
const closeIndex = findMatchingParen(trimmed, openIndex);
return closeIndex >= 0 && !trimmed.slice(openIndex + 1, closeIndex).trim() && !trimmed.slice(closeIndex + 1).trim();
}
function findChainedMethodCallIndex(source: string, name: string): number {
return chainedMethodCallPattern(name).exec(source)?.index ?? -1;
}