feat(mongodb): support replaceOne
This commit is contained in:
1 parent
72be4ad9eb
commit
9eafac706e
24 files changed
+496
-16
No files matched your search
@@ -815,6 +815,7 @@ export const mongoInsertDocuments = forward("mongoInsertDocuments");
|
||||
export const documentUpdateDocument = forward("documentUpdateDocument");
|
||||
export const mongoUpdateDocument = forward("mongoUpdateDocument");
|
||||
export const mongoUpdateDocuments = forward("mongoUpdateDocuments");
|
||||
export const mongoReplaceDocument = forward("mongoReplaceDocument");
|
||||
export const documentDeleteDocument = forward("documentDeleteDocument");
|
||||
export const documentSaveMeilisearchBatch = forward("documentSaveMeilisearchBatch");
|
||||
export const meilisearchSearchDocuments = forward("meilisearchSearchDocuments");
|
||||
|
||||
@@ -4530,6 +4530,17 @@ export async function documentUpdateDocument(connectionId: string, database: str
|
||||
});
|
||||
}
|
||||
|
||||
export async function mongoReplaceDocument(connectionId: string, database: string, collection: string, filterJson: string, replacementJson: string, optionsJson?: string): Promise<{ affected_rows: number }> {
|
||||
return post("/api/mongo/replace-document", {
|
||||
connectionId,
|
||||
database,
|
||||
collection,
|
||||
filterJson,
|
||||
replacementJson,
|
||||
optionsJson,
|
||||
});
|
||||
}
|
||||
|
||||
export async function mongoUpdateDocuments(connectionId: string, database: string, collection: string, filterJson: string, updateJson: string, many: boolean, optionsJson?: string): Promise<{ affected_rows: number }> {
|
||||
return post("/api/mongo/update-documents", {
|
||||
connectionId,
|
||||
|
||||
@@ -4440,6 +4440,18 @@ export async function documentUpdateDocument(connectionId: string, database: str
|
||||
});
|
||||
}
|
||||
|
||||
export async function mongoReplaceDocument(connectionId: string, database: string, collection: string, filterJson: string, replacementJson: string, optionsJson?: string): Promise<{ affected_rows: number }> {
|
||||
const affectedRows = await invoke<number>("mongo_replace_document", {
|
||||
connectionId,
|
||||
database,
|
||||
collection,
|
||||
filterJson,
|
||||
replacementJson,
|
||||
optionsJson,
|
||||
});
|
||||
return { affected_rows: affectedRows };
|
||||
}
|
||||
|
||||
export async function mongoUpdateDocuments(connectionId: string, database: string, collection: string, filterJson: string, updateJson: string, many: boolean, optionsJson?: string): Promise<{ affected_rows: number }> {
|
||||
const affectedRows = await invoke<number>("mongo_update_documents", {
|
||||
connectionId,
|
||||
|
||||
@@ -93,6 +93,7 @@ const COLLECTION_METHODS = [
|
||||
{ label: "insertMany", detail: "Insert multiple documents", apply: "insertMany([{}])" },
|
||||
{ label: "updateOne", detail: "Update one matching document", apply: "updateOne({}, { $set: {} })" },
|
||||
{ label: "updateMany", detail: "Update all matching documents", apply: "updateMany({}, { $set: {} })" },
|
||||
{ label: "replaceOne", detail: "Replace one matching document", apply: "replaceOne({}, {})" },
|
||||
{ label: "deleteOne", detail: "Delete one matching document", apply: "deleteOne({})" },
|
||||
{ label: "deleteMany", detail: "Delete all matching documents", apply: "deleteMany({})" },
|
||||
{ label: "findOneAndUpdate", detail: "Atomically update and return a document", apply: "findOneAndUpdate({}, { $set: {} })" },
|
||||
@@ -120,6 +121,7 @@ const COLLECTION_METHOD_BOOST: Record<(typeof COLLECTION_METHODS)[number]["label
|
||||
insertMany: 170,
|
||||
updateOne: 160,
|
||||
updateMany: 150,
|
||||
replaceOne: 145,
|
||||
deleteOne: 140,
|
||||
deleteMany: 130,
|
||||
findOneAndUpdate: 120,
|
||||
@@ -190,6 +192,7 @@ const METHOD_ARG_ROLES: Record<string, readonly MongoArgRole[]> = {
|
||||
findOneAndDelete: ["filter", "options"],
|
||||
updateOne: ["filter", "update", "options"],
|
||||
updateMany: ["filter", "update", "options"],
|
||||
replaceOne: ["filter", "replacement", "options"],
|
||||
findOneAndUpdate: ["filter", "update", "options"],
|
||||
findOneAndReplace: ["filter", "replacement", "options"],
|
||||
insertOne: ["document", "options"],
|
||||
|
||||
@@ -48,6 +48,7 @@ const COLLECTION_METHOD_SHAPES: Record<string, MongoMethodShape> = {
|
||||
update: { expects: "a filter, an update, and optional options", roles: ["filter", "update", "options"] },
|
||||
updateOne: { expects: "a filter, an update, and optional options", roles: ["filter", "update", "options"] },
|
||||
updateMany: { expects: "a filter, an update, and optional options", roles: ["filter", "update", "options"] },
|
||||
replaceOne: { expects: "a filter, a replacement document, and optional options", roles: ["filter", "replacement", "options"] },
|
||||
deleteOne: { expects: "a filter", roles: ["filter"] },
|
||||
deleteMany: { expects: "a filter", roles: ["filter"] },
|
||||
findOneAndUpdate: { expects: "a filter, an update, and optional options", roles: ["filter", "update", "options"] },
|
||||
@@ -76,6 +77,7 @@ const SUPPORTED_COLLECTION_METHODS = [
|
||||
"insertMany",
|
||||
"updateOne",
|
||||
"updateMany",
|
||||
"replaceOne",
|
||||
"deleteOne",
|
||||
"deleteMany",
|
||||
"findOneAndUpdate",
|
||||
@@ -157,6 +159,11 @@ function diagnoseMongoCommand(source: string): string | null {
|
||||
|
||||
const tail = source.slice(closeIndex + 1).trim();
|
||||
if (tail) return `Unexpected text after ${method}(...): "${tail.length > 40 ? `${tail.slice(0, 40)}…` : tail}".`;
|
||||
if (method === "replaceOne" && args[1]) {
|
||||
const replacement = parseMongoObjectArgument(args[1]);
|
||||
const operator = replacement ? Object.keys(JSON.parse(replacement) as Record<string, unknown>).find((key) => key.startsWith("$")) : undefined;
|
||||
if (operator) return `replaceOne() replaces the whole document, so it must not contain update operators such as ${operator}; use updateOne() to modify fields.`;
|
||||
}
|
||||
return `${method}() expects ${shapeSpec.expects}.`;
|
||||
}
|
||||
|
||||
@@ -256,7 +263,7 @@ export interface MongoDistinctCommand {
|
||||
filter?: string;
|
||||
}
|
||||
|
||||
type MongoWriteKind = "runCommand" | "insert" | "update" | "delete" | "createIndex" | "createUser" | "dropIndex" | "dropIndexes" | "dropCollection" | "findOneAndUpdate" | "findOneAndReplace" | "findOneAndDelete";
|
||||
type MongoWriteKind = "runCommand" | "insert" | "update" | "replace" | "delete" | "createIndex" | "createUser" | "dropIndex" | "dropIndexes" | "dropCollection" | "findOneAndUpdate" | "findOneAndReplace" | "findOneAndDelete";
|
||||
|
||||
export type MongoCommand =
|
||||
| ({ kind: "find" } & MongoFindCommand)
|
||||
@@ -273,6 +280,7 @@ export type MongoCommand =
|
||||
| ({ kind: "runCommand" } & MongoRunCommand)
|
||||
| { kind: "insert"; collection: string; docsJson: string }
|
||||
| { kind: "update"; collection: string; filter: string; update: string; options?: string; many: boolean }
|
||||
| { kind: "replace"; collection: string; filter: string; replacement: string; options?: string }
|
||||
| { kind: "delete"; collection: string; filter: string; many: boolean }
|
||||
| { kind: "createIndex"; collection: string; keys: string; options?: string }
|
||||
| { kind: "dropIndex"; collection: string; index: string }
|
||||
@@ -744,6 +752,20 @@ export function parseMongoWriteCommand(input: string): MongoWriteCommand | null
|
||||
return value !== null && typeof value === "object" ? { kind: "insert", collection: insert.collection, docsJson: docs } : null;
|
||||
}
|
||||
|
||||
const replaceOne = parseCollectionMethodTarget(source, "replaceOne");
|
||||
if (replaceOne) {
|
||||
const args = parseMethodArgs(source, replaceOne.methodCallIndex);
|
||||
if (!args || args.length < 2 || args.length > 3) return null;
|
||||
const filter = normalizeJsonArgument(args[0]);
|
||||
const replacement = parseMongoObjectArgument(args[1]);
|
||||
if (!filter || !replacement) return null;
|
||||
// A replacement is a whole document; `{$set: ...}` here means updateOne() was intended.
|
||||
if (Object.keys(JSON.parse(replacement) as Record<string, unknown>).some((key) => key.startsWith("$"))) return null;
|
||||
const options = args[2]?.trim() ? normalizeJsonArgument(args[2]) : undefined;
|
||||
if (args[2]?.trim() && !options) return null;
|
||||
return { kind: "replace", collection: replaceOne.collection, filter, replacement, ...(options ? { options } : {}) };
|
||||
}
|
||||
|
||||
for (const method of ["updateOne", "updateMany"] as const) {
|
||||
const target = parseCollectionMethodTarget(source, method);
|
||||
if (!target) continue;
|
||||
@@ -1516,6 +1538,7 @@ function isNonEmptyRecord(value: unknown): value is Record<string, unknown> {
|
||||
function mongoWriteFilter(command: MongoWriteCommand): string | null {
|
||||
switch (command.kind) {
|
||||
case "update":
|
||||
case "replace":
|
||||
case "delete":
|
||||
case "findOneAndUpdate":
|
||||
case "findOneAndReplace":
|
||||
|
||||
@@ -6642,6 +6642,7 @@ export const useQueryStore = defineStore("query", () => {
|
||||
}
|
||||
case "insert":
|
||||
case "update":
|
||||
case "replace":
|
||||
case "delete":
|
||||
case "createIndex":
|
||||
case "createUser":
|
||||
@@ -6665,6 +6666,9 @@ export const useQueryStore = defineStore("query", () => {
|
||||
} else if (mongoCommand.kind === "update") {
|
||||
const result = await api.mongoUpdateDocuments(executionConnectionId, currentDatabase, mongoCommand.collection, mongoCommand.filter, mongoCommand.update, mongoCommand.many, mongoCommand.options);
|
||||
allResults.push(markQueryResultRowsRaw(annotateMongoResult(mongoWriteToQueryResult(result.affected_rows, performance.now() - commandStartedAt))));
|
||||
} else if (mongoCommand.kind === "replace") {
|
||||
const result = await api.mongoReplaceDocument(executionConnectionId, currentDatabase, mongoCommand.collection, mongoCommand.filter, mongoCommand.replacement, mongoCommand.options);
|
||||
allResults.push(markQueryResultRowsRaw(annotateMongoResult(mongoWriteToQueryResult(result.affected_rows, performance.now() - commandStartedAt))));
|
||||
} else if (mongoCommand.kind === "createIndex") {
|
||||
const result = await api.mongoCreateIndex(executionConnectionId, currentDatabase, mongoCommand.collection, mongoCommand.keys, mongoCommand.options);
|
||||
allResults.push(markQueryResultRowsRaw(annotateMongoResult(mongoCreateIndexToQueryResult(result.name, performance.now() - commandStartedAt))));
|
||||
|
||||
Reference in new issue
Block a user