Skip to content
Merged
1 change: 1 addition & 0 deletions l10n/bundle.l10n.json
Original file line number Diff line number Diff line change
Expand Up @@ -1085,6 +1085,7 @@
"This will also delete {0}.": "This will also delete {0}.",
"This will execute all statements in the file against the connected cluster.": "This will execute all statements in the file against the connected cluster.",
"This will prevent the query planner from using this index.": "This will prevent the query planner from using this index.",
"Tip: use .maxTimeMS() to increase the time limit for this query.": "Tip: use .maxTimeMS() to increase the time limit for this query.",
"TLS/SSL Disabled": "TLS/SSL Disabled",
"TLS/SSL Enabled": "TLS/SSL Enabled",
"To connect to Azure resources, you need to sign in to Azure accounts.": "To connect to Azure resources, you need to sign in to Azure accounts.",
Expand Down
5 changes: 0 additions & 5 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -1167,11 +1167,6 @@
"default": 50,
"minimum": 1
},
"documentDB.timeout": {
"type": "number",
"description": "Maximum time (in seconds) allowed for a query to execute in the Query Playground or Interactive Shell before the operation is cancelled.",
"default": 30
},
"documentDB.shell.initTimeout": {
"type": "number",
"description": "Maximum time (in seconds) to wait for the Interactive Shell to connect during initialization. Default value is 60 seconds.",
Comment thread
tnaum-ms marked this conversation as resolved.
Expand Down
129 changes: 128 additions & 1 deletion packages/documentdb-shell-runtime/src/DocumentDBShellRuntime.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

import { type MongoClient } from 'mongodb';
import { DocumentDBServiceProvider } from './DocumentDBServiceProvider';
import { DocumentDBShellRuntime } from './DocumentDBShellRuntime';
import { DocumentDBShellRuntime, normalizeDirectCommands } from './DocumentDBShellRuntime';

// Mock @mongosh modules to avoid needing a real database connection
jest.mock('@mongosh/shell-api', () => ({
Expand Down Expand Up @@ -119,3 +119,130 @@ describe('DocumentDBShellRuntime', () => {
});
});
});

describe('normalizeDirectCommands', () => {
describe('single-line input (no transformation)', () => {
it('leaves bare use unchanged', () => {
expect(normalizeDirectCommands('use mydb')).toBe('use mydb');
});

it('leaves bare show unchanged', () => {
expect(normalizeDirectCommands('show dbs')).toBe('show dbs');
});

it('leaves function-call form unchanged', () => {
expect(normalizeDirectCommands('use("mydb")')).toBe('use("mydb")');
});

it('leaves regular code unchanged', () => {
expect(normalizeDirectCommands('db.test.find()')).toBe('db.test.find()');
});
});

describe('multi-line input with bare use', () => {
it('rewrites bare use followed by a query', () => {
const input = 'use mydb\ndb.test.find()';
const expected = 'use("mydb");\ndb.test.find()';
expect(normalizeDirectCommands(input)).toBe(expected);
});

it('rewrites bare use with trailing semicolon', () => {
const input = 'use mydb;\ndb.test.find()';
const expected = 'use("mydb");\ndb.test.find()';
expect(normalizeDirectCommands(input)).toBe(expected);
});

it('rewrites bare use with leading whitespace', () => {
const input = ' use mydb\ndb.test.find()';
const expected = ' use("mydb");\ndb.test.find()';
expect(normalizeDirectCommands(input)).toBe(expected);
});

it('appends a trailing semicolon to neutralize ASI hazards', () => {
// Without the trailing `;`, the next line starting with `[`
// would bind to the call expression as member access.
const input = 'use mydb\n[1, 2, 3].forEach((x) => x)';
const expected = 'use("mydb");\n[1, 2, 3].forEach((x) => x)';
expect(normalizeDirectCommands(input)).toBe(expected);
});

it('rewrites use in the middle of multi-line code', () => {
// With the AST-based implementation the rewrite covers every
// top-level `use`/`show` statement, not just the first line.
const input = 'db.test.find()\nuse otherdb\ndb.other.find()';
const expected = 'db.test.find()\nuse("otherdb");\ndb.other.find()';
expect(normalizeDirectCommands(input)).toBe(expected);
});

it('rewrites multiple top-level use/show statements in one block', () => {
const input = 'show dbs\nuse mydb\ndb.test.find()\nuse otherdb\ndb.other.find()';
const expected = 'show("dbs");\nuse("mydb");\ndb.test.find()\nuse("otherdb");\ndb.other.find()';
expect(normalizeDirectCommands(input)).toBe(expected);
});

it('leaves matching lines inside template literals unchanged', () => {
const input = 'const s = `\nuse mydb\n`;\nconsole.log(s)';
expect(normalizeDirectCommands(input)).toBe(input);
});

it('leaves matching lines inside block comments unchanged', () => {
const input = '/* use mydb\n show dbs */\ndb.test.find()';
expect(normalizeDirectCommands(input)).toBe(input);
});

it('leaves matching text inside line comments unchanged', () => {
const input = '// use mydb\ndb.test.find()';
expect(normalizeDirectCommands(input)).toBe(input);
});

it('leaves matching text inside regex literals unchanged', () => {
const input = 'const x = /use mydb/;\ndb.test.find()';
expect(normalizeDirectCommands(input)).toBe(input);
});

it('rewrites first line even when preceded by blank lines', () => {
const input = '\n\n use mydb\ndb.test.find()';
const expected = '\n\n use("mydb");\ndb.test.find()';
expect(normalizeDirectCommands(input)).toBe(expected);
});
});

describe('multi-line input with bare show', () => {
it('rewrites bare show followed by a query', () => {
const input = 'show dbs\ndb.test.find()';
const expected = 'show("dbs");\ndb.test.find()';
expect(normalizeDirectCommands(input)).toBe(expected);
});

it('rewrites bare show collections', () => {
const input = 'show collections\ndb.test.find()';
const expected = 'show("collections");\ndb.test.find()';
expect(normalizeDirectCommands(input)).toBe(expected);
});
});

describe('does not transform function-call form', () => {
it('leaves use("name") unchanged in multi-line', () => {
const input = 'use("mydb")\ndb.test.find()';
expect(normalizeDirectCommands(input)).toBe(input);
});

it("leaves use('name') unchanged in multi-line", () => {
const input = "use('mydb')\ndb.test.find()";
expect(normalizeDirectCommands(input)).toBe(input);
});

it('leaves show("dbs") unchanged in multi-line', () => {
const input = 'show("dbs")\ndb.test.find()';
expect(normalizeDirectCommands(input)).toBe(input);
});
});

describe('escapes special characters in database names', () => {
it('escapes quotes in database name', () => {
const input = 'use my"db\ndb.test.find()';
const expected = 'use("my\\"db");\ndb.test.find()';
expect(normalizeDirectCommands(input)).toBe(expected);
});
});
});
Loading
Loading