feat(mongodb): support createview and user role shell helpers

This commit is contained in:
Loc Nguyen
2026-10-15 12:52:19 +08:00
committed by GitHub
parent 3af7e2c55d
commit b7553e6489
5 changed files with 309 additions and 7 deletions
+9 -2
View File
@@ -343,6 +343,7 @@ test("offers the newly supported count and database commands", () => {
assert.ok(dbLevel.includes("serverStatus"));
assert.ok(dbLevel.includes("createCollection"));
assert.ok(dbLevel.includes("dropDatabase"));
for (const method of ["createView", "getUsers", "getUser", "getRoles", "getRole"]) assert.ok(dbLevel.includes(method), method);
assert.ok(labels("").includes("db.stats"));
});
@@ -793,6 +794,9 @@ test("withholds illegal stages in sub-pipelines and view definitions", () => {
// View definition pipeline rejects $out and $merge, but permits $documents.
const viewStages = labels('db.createCollection("v", { viewOn: "users", pipeline: [{ $');
const createViewStages = labels('db.createView("v", "users", [{ $');
assert.ok(createViewStages.includes("$match"));
assert.equal(createViewStages.includes("$out"), false, "views cannot write");
assert.equal(viewStages.includes("$out"), false, "view pipeline must not offer $out");
assert.equal(viewStages.includes("$merge"), false, "view pipeline must not offer $merge");
assert.ok(viewStages.includes("$match"));
@@ -1701,9 +1705,9 @@ test("suggests show dbs and show subcommands", () => {
assert.ok(buildMongoCompletionItems("show", 4).some((item) => item.label === "show dbs"));
assert.ok(parseMongoCommand("show dbs"), "show dbs snippet must parse");
// show followed by space offers dbs and databases, and NOT db.* snippets
// show followed by space offers its subcommands, and NOT db.* snippets
const showSpaceItems = labels("show ");
assert.deepEqual(showSpaceItems, ["dbs", "databases"]);
assert.deepEqual(showSpaceItems, ["dbs", "databases", "users", "roles"]);
assert.equal(showSpaceItems.includes("db.collection.find"), false);
assert.equal(showSpaceItems.includes("db.version"), false);
assert.equal(showSpaceItems.includes("collections"), false, "show collections is not supported");
@@ -1712,6 +1716,9 @@ test("suggests show dbs and show subcommands", () => {
assert.deepEqual(labels("show d"), ["dbs", "databases"]);
assert.deepEqual(labels("show db"), ["dbs"]);
assert.deepEqual(labels("show dat"), ["databases"]);
assert.deepEqual(labels("show us"), ["users"]);
assert.deepEqual(labels("show ro"), ["roles"]);
for (const source of ["show users", "show roles"]) assert.ok(parseMongoCommand(source), `${source} must parse`);
assert.deepEqual(labels("show col"), []);
// Context and auto-trigger
+58
View File
@@ -1474,6 +1474,64 @@ test("parseMongoRunCommand reads db.dropDatabase() and db.createCollection() as
}
});
test("parseMongoRunCommand reads db.createView() as a create command with viewOn and pipeline", () => {
assert.deepEqual(JSON.parse(parseMongoRunCommand('db.createView("active_users", "users", [{ $match: { active: true } }])')!.commandJson), {
create: "active_users",
viewOn: "users",
pipeline: [{ $match: { active: true } }],
});
assert.deepEqual(JSON.parse(parseMongoRunCommand("db.createView('v', 'users', [], { collation: { locale: 'fr' } });")!.commandJson), {
create: "v",
viewOn: "users",
pipeline: [],
collation: { locale: "fr" },
});
assert.equal(parseMongoCommand('db.createView("v", "users", [])')?.command.kind, "runCommand");
for (const [source, expected] of [
['db.createView("v", "users")', /createView\(\) expects a view name, a source collection name, a pipeline/],
['db.createView("v", "users", {})', /createView\(\) expects/],
['db.createView("v", 1, [])', /createView\(\) expects/],
['db.createView("v", "users", [], { viewOn: "other" })', /createView\(\) expects/],
['db.createView("v", "users", [{ $match: { a: Foo() } }])', /Unsupported value Foo\(\.\.\.\) in the pipeline argument of createView\(\)/],
] as const) {
assert.equal(parseMongoCommand(source), null, source);
assert.match(describeMongoCommandParseFailure(source), expected, source);
}
});
test("parseMongoRunCommand reads user and role helpers as usersInfo and rolesInfo", () => {
for (const [source, expected] of [
["show users", { usersInfo: 1 }],
["SHOW ROLES;", { rolesInfo: 1 }],
["db.getUsers()", { usersInfo: 1 }],
["db.getUsers({ showCredentials: false, filter: { roles: { $size: 0 } } })", { usersInfo: 1, showCredentials: false, filter: { roles: { $size: 0 } } }],
['db.getUser("app")', { usersInfo: "app" }],
["db.getUser('app', { showPrivileges: true })", { usersInfo: "app", showPrivileges: true }],
["db.getRoles({ showBuiltinRoles: true })", { rolesInfo: 1, showBuiltinRoles: true }],
['db.getRole("reader")', { rolesInfo: "reader" }],
] as const) {
assert.deepEqual(JSON.parse(parseMongoRunCommand(source)?.commandJson ?? "null"), expected, source);
assert.equal(parseMongoCommand(source)?.command.kind, "runCommand", source);
}
for (const [source, expected] of [
["db.getUser()", /getUser\(\) expects a user name/],
["db.getUser(1)", /getUser\(\) expects a user name/],
["db.getUsers({ usersInfo: 2 })", /getUsers\(\) expects optional options/],
["db.getRoles({}, {})", /getRoles\(\) expects optional options/],
['db.getRole("a").x()', /Unexpected text after getRole/],
] as const) {
assert.equal(parseMongoCommand(source), null, source);
assert.match(describeMongoCommandParseFailure(source), expected, source);
}
assert.equal(parseMongoCommand("show users extra"), null);
assert.deepEqual(
splitMongoCommands("use admin\nshow users\nshow roles").map(({ command }) => command.kind),
["use", "runCommand", "runCommand"],
);
});
test("parseMongoRunCommand reads db.stats() and db.serverStatus() as run commands", () => {
assert.deepEqual(parseMongoRunCommand("db.stats()"), { commandJson: '{"dbStats":1}' });
assert.deepEqual(parseMongoRunCommand("db . serverStatus ( ) ;"), { commandJson: '{"serverStatus":1}' });