Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
5bf3b3a
refactor(node-runtime-worker-thread): Simplify promisified type
gribnoysup Jan 20, 2021
1e32106
feat(node-runtime-worker-thread): Better serialization for errors thr…
gribnoysup Jan 20, 2021
262e8d8
feat(node-runtime-worker-thread): Serialize errors thrown or returned…
gribnoysup Jan 20, 2021
a6ae152
refactor(node-runtime-worker-thread): Propagate serialization errors …
gribnoysup Jan 21, 2021
355cd29
feat(node-runtime-worker-thread): Inspect complex, non-distinguishabl…
gribnoysup Jan 22, 2021
b917c98
fix(node-runtime-worker-thread): Use caller defined in beforeEach
gribnoysup Jan 22, 2021
d9b38f7
feat(node-runtime-worker-thread): Serialize shell-api return types fo…
gribnoysup Jan 22, 2021
0c29a96
test(node-runtime-worker-thread): Add more tests for different types …
gribnoysup Jan 25, 2021
3963910
fix(node-runtime-worker-thread): Fix bson missing from package-lock
gribnoysup Jan 25, 2021
2944834
test(node-runtime-worker-thread): Fix anonymous fn inspection check f…
gribnoysup Jan 25, 2021
9acceee
refactor(browser-runtime-core, node-runtime-worker-thread): Runtimes …
gribnoysup Jan 26, 2021
e42b23b
refactor(node-runtime-worker-thread): Simplify {de}serialization impl…
gribnoysup Jan 26, 2021
d0f3aef
refactor(node-runtime-worker-thread): Move v8 {de}serialize to rpc he…
gribnoysup Jan 26, 2021
38be23a
refactor(shell-api, browser-repl, cli-repl, node-runtime-worker-threa…
gribnoysup Jan 27, 2021
042da3d
fix(shell-api): Fix failing tests
gribnoysup Jan 27, 2021
4846f1e
refactor(node-runtime-worker-thread): Remove custom bson assertion
gribnoysup Jan 27, 2021
be9ba41
fix(browser-repl): Fix more failing tests that depended on cursor pri…
gribnoysup Jan 27, 2021
75b9cfb
Merge remote-tracking branch 'origin/master' into compass-4557-advanc…
gribnoysup Jan 27, 2021
1ab1e9d
refactor(node-runtime-worker-thread): Pick properties instead of omit…
gribnoysup Jan 27, 2021
6cd0e3b
refactor(node-runtime-worker-thread): Explicitly pass typed payloads …
gribnoysup Jan 27, 2021
8a77045
chore(node-runtime-worker-thread): Remove confusing comments and repl…
gribnoysup Jan 28, 2021
7066f06
refactor(node-runtime-worker-thread): Use enums instead of hardcoded …
gribnoysup Jan 28, 2021
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,18 @@ import { ObjectOutput } from './object-output';

describe('CursorIterationResultOutput', () => {
it('renders no ObjectOutput if value is empty', () => {
const wrapper = shallow(<CursorIterationResultOutput value={[]} />);
const printable = { documents: [], cursorHasMore: false };
const wrapper = shallow(<CursorIterationResultOutput value={printable} />);

expect(wrapper.text()).to.contain('no cursor');
});

it('renders a ObjectOutput for each element in value', () => {
const wrapper = shallow(<CursorIterationResultOutput value={[{ doc: 1 }, { doc: 2 }]} />);
const printable = {
documents: [{ doc: 1 }, { doc: 2 }],
cursorHasMore: false
};
const wrapper = shallow(<CursorIterationResultOutput value={printable} />);

expect(wrapper.find(ObjectOutput)).to.have.lengthOf(2);
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ export interface Document {
}

interface CursorIterationResultOutputProps {
value: Document[] & { cursorHasMore: boolean };
value: { documents: Document[]; cursorHasMore: boolean };
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

}

export class CursorIterationResultOutput extends Component<CursorIterationResultOutputProps> {
Expand All @@ -17,17 +17,22 @@ export class CursorIterationResultOutput extends Component<CursorIterationResult
};

render(): JSX.Element {
if (!this.props.value.length) {
return <div>{i18n.__('shell-api.classes.Cursor.iteration.no-cursor')}</div>;
if (!this.props.value.documents.length) {
return (
<div>{i18n.__('shell-api.classes.Cursor.iteration.no-cursor')}</div>
);
}

const more = this.props.value.cursorHasMore ?
(<pre>{i18n.__('shell-api.classes.Cursor.iteration.type-it-for-more')}</pre>) :
'';
return (<div>
{this.props.value.map(this.renderDocument)}
{more}
</div>);

return (
<div>
{this.props.value.documents.map(this.renderDocument)}
{more}
</div>
);
}

renderDocument = (document: Document, i: number): JSX.Element => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,22 +7,23 @@ import { CursorIterationResultOutput } from './cursor-iteration-result-output';

describe('CursorOutput', () => {
it('renders "no cursor" if value is empty', () => {
const wrapper = shallow(<CursorOutput value={[]} />);
const docs = { documents: [], cursorHasMore: false };
const wrapper = shallow(<CursorOutput value={docs} />);

expect(wrapper.find(CursorIterationResultOutput)).to.have.lengthOf(0);
});


it('renders a CursorIterationResultOutput if value contains elements', () => {
const docs = [{ doc: 1 }, { doc: 2 }];
const docs = { documents: [{ doc: 1 }, { doc: 2 }], cursorHasMore: false };
const wrapper = shallow(<CursorOutput value={docs} />);

expect(wrapper.find(CursorIterationResultOutput).prop('value')).to.deep.equal(docs);
});

context('when value has more elements available', () => {
it('prompts to type "it"', () => {
const docs = Object.assign([{}], { cursorHasMore: true });
const docs = { documents: [{}], cursorHasMore: true };
const wrapper = mount(<CursorOutput value={docs} />);

expect(wrapper.find(CursorIterationResultOutput).text()).to.contain('Type "it" for more');
Expand All @@ -31,7 +32,7 @@ describe('CursorOutput', () => {

context('when value does not have more elements available', () => {
it('does not prompt to type "it"', () => {
const docs = Object.assign([{}], { cursorHasMore: false });
const docs = { documents: [{}], cursorHasMore: false };
const wrapper = mount(<CursorOutput value={docs} />);

expect(wrapper.find(CursorIterationResultOutput).text()).not.to.contain('Type "it" for more');
Expand Down
4 changes: 2 additions & 2 deletions packages/browser-repl/src/components/types/cursor-output.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import PropTypes from 'prop-types';
import { CursorIterationResultOutput, Document } from './cursor-iteration-result-output';

interface CursorOutputProps {
value: Document[] & { cursorHasMore: boolean };
value: { documents: Document[], cursorHasMore: boolean };
}

export class CursorOutput extends Component<CursorOutputProps> {
Expand All @@ -12,7 +12,7 @@ export class CursorOutput extends Component<CursorOutputProps> {
};

render(): JSX.Element {
if (!this.props.value.length) {
if (!this.props.value.documents.length) {
return <pre/>;
}

Expand Down
9 changes: 5 additions & 4 deletions packages/browser-repl/src/iframe-runtime/iframe-runtime.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,26 +4,27 @@ import {

import {
Runtime,
RuntimeEvaluationListener,
RuntimeEvaluationResult,
Completion,
OpenContextRuntime
} from '@mongosh/browser-runtime-core';

import { ServiceProvider } from '@mongosh/service-provider-core';
import { ShellResult, EvaluationListener } from '@mongosh/shell-evaluator';

export class IframeRuntime implements Runtime {
private openContextRuntime: OpenContextRuntime | null = null;
private readyPromise: Promise<void> | null = null;
private iframe: HTMLIFrameElement | null = null;
private container: HTMLDivElement | null = null;
private serviceProvider: ServiceProvider;
private evaluationListener: EvaluationListener | null = null;
private evaluationListener: RuntimeEvaluationListener | null = null;

constructor(serviceProvider: ServiceProvider) {
this.serviceProvider = serviceProvider;
}

setEvaluationListener(listener: EvaluationListener): EvaluationListener | null {
setEvaluationListener(listener: RuntimeEvaluationListener): RuntimeEvaluationListener | null {
const prev = this.evaluationListener;
this.evaluationListener = listener;
if (this.openContextRuntime) {
Expand All @@ -32,7 +33,7 @@ export class IframeRuntime implements Runtime {
return prev;
}

async evaluate(code: string): Promise<ShellResult> {
async evaluate(code: string): Promise<RuntimeEvaluationResult> {
const runtime = await this.initialize();
return await runtime.evaluate(code);
}
Expand Down
2 changes: 1 addition & 1 deletion packages/browser-runtime-core/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
export { Runtime } from './runtime';
export { Runtime, RuntimeEvaluationListener, RuntimeEvaluationResult } from './runtime';
export { ContextValue, InterpreterEnvironment } from './interpreter';
export { OpenContextRuntime } from './open-context-runtime';
export { Autocompleter, Completion } from './autocompleter/autocompleter';
19 changes: 12 additions & 7 deletions packages/browser-runtime-core/src/open-context-runtime.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,15 @@ import { Completion } from './autocompleter/autocompleter';
import { ServiceProvider } from '@mongosh/service-provider-core';
import { ShellApiAutocompleter } from './autocompleter/shell-api-autocompleter';
import { Interpreter, InterpreterEnvironment } from './interpreter';
import { Runtime } from './runtime';
import {
Runtime,
RuntimeEvaluationResult,
RuntimeEvaluationListener
} from './runtime';
import { EventEmitter } from 'events';
import { ShellInternalState, ShellResult } from '@mongosh/shell-api';
import { ShellInternalState } from '@mongosh/shell-api';

import { ShellEvaluator, EvaluationListener } from '@mongosh/shell-evaluator';
import { ShellEvaluator } from '@mongosh/shell-evaluator';
import type { MongoshBus } from '@mongosh/types';

/**
Expand All @@ -23,7 +27,7 @@ export class OpenContextRuntime implements Runtime {
private autocompleter: ShellApiAutocompleter | null = null;
private shellEvaluator: ShellEvaluator;
private internalState: ShellInternalState;
private evaluationListener: EvaluationListener | null = null;
private evaluationListener: RuntimeEvaluationListener | null = null;
private updatedConnectionInfo = false;

constructor(
Expand All @@ -48,17 +52,18 @@ export class OpenContextRuntime implements Runtime {
return this.autocompleter.getCompletions(code);
}

async evaluate(code: string): Promise<ShellResult> {
async evaluate(code: string): Promise<RuntimeEvaluationResult> {
const evalFn = this.interpreter.evaluate.bind(this.interpreter);
return await this.shellEvaluator.customEval(
const { type, printable, source } = await this.shellEvaluator.customEval(
evalFn,
code,
this.interpreterEnvironment.getContextObject(),
''
);
return { type, printable, source };
}

setEvaluationListener(listener: EvaluationListener): EvaluationListener | null {
setEvaluationListener(listener: RuntimeEvaluationListener): RuntimeEvaluationListener | null {
const prev = this.evaluationListener;
this.evaluationListener = listener;
this.internalState.setEvaluationListener(listener);
Expand Down
21 changes: 16 additions & 5 deletions packages/browser-runtime-core/src/runtime.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,23 +3,34 @@ import { ShellResult, EvaluationListener } from '@mongosh/shell-evaluator';

export type ContextValue = any;

export type RuntimeEvaluationResult = Pick<
ShellResult,
'type' | 'printable' | 'source'
>;

export interface RuntimeEvaluationListener extends EvaluationListener {
onPrint?: (value: RuntimeEvaluationResult[]) => Promise<void> | void;
}

export interface Runtime {
/**
* Sets a listener for certain events, e.g. onPrint() when print() is called
* in the shell.
*
* @param {EvaluationListener} listener - The new listener.
* @return {EvaluationListener | null} The previous listener, if any.
* @param {RuntimeEvaluationListener} listener - The new listener.
* @return {RuntimeEvaluationListener | null} The previous listener, if any.
*/
setEvaluationListener(listener: EvaluationListener): EvaluationListener | null;
setEvaluationListener(
listener: RuntimeEvaluationListener
): RuntimeEvaluationListener | null;

/**
* Evaluates code
*
* @param {string} code - A string of code
* @return {Promise<ShellResult>} the result of the evaluation
* @return {Promise<RuntimeEvaluationResult>} the result of the evaluation
*/
evaluate(code: string): Promise<ShellResult>;
evaluate(code: string): Promise<RuntimeEvaluationResult>;

/**
* Get shell api completions give a code prefix
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,12 @@ import { CliServiceProvider } from '@mongosh/service-provider-server';
import { bson } from '@mongosh/service-provider-core';
import { ElectronRuntime } from './electron-runtime';
import { EventEmitter } from 'events';
import { EvaluationListener } from '@mongosh/shell-evaluator';
import { RuntimeEvaluationListener } from '@mongosh/browser-runtime-core';

describe('Electron runtime', function() {
let serviceProvider: SinonStubbedInstance<CliServiceProvider>;
let messageBus: SinonStubbedInstance<EventEmitter>;
let evaluationListener: SinonStubbedInstance<EvaluationListener>;
let evaluationListener: SinonStubbedInstance<RuntimeEvaluationListener>;
let electronRuntime: ElectronRuntime;

beforeEach(async() => {
Expand Down
9 changes: 5 additions & 4 deletions packages/browser-runtime-electron/src/electron-runtime.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,12 @@ import {
import {
Runtime,
OpenContextRuntime,
Completion
Completion,
RuntimeEvaluationListener,
RuntimeEvaluationResult
} from '@mongosh/browser-runtime-core';

import { ServiceProvider } from '@mongosh/service-provider-core';
import { ShellResult, EvaluationListener } from '@mongosh/shell-evaluator';
import type { MongoshBus } from '@mongosh/types';

declare const __webpack_require__: any;
Expand Down Expand Up @@ -42,11 +43,11 @@ export class ElectronRuntime implements Runtime {
);
}

setEvaluationListener(listener: EvaluationListener): EvaluationListener | null {
setEvaluationListener(listener: RuntimeEvaluationListener): RuntimeEvaluationListener | null {
return this.openContextRuntime.setEvaluationListener(listener);
}

async evaluate(code: string): Promise<ShellResult> {
async evaluate(code: string): Promise<RuntimeEvaluationResult> {
return await this.openContextRuntime.evaluate(code);
}

Expand Down
42 changes: 25 additions & 17 deletions packages/cli-repl/src/format-output.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,12 @@ for (const colors of [ false, true ]) {
context('when the result is a Cursor', () => {
context('when the Cursor is not empty', () => {
it('returns the inspection', () => {
const output = stripAnsiColors(format({
value: Object.assign([{ doc: 1 }, { doc: 2 }], { cursorHasMore: true }),
type: 'Cursor'
}));
const output = stripAnsiColors(
format({
value: { documents: [{ doc: 1 }, { doc: 2 }], cursorHasMore: true },
type: 'Cursor'
})
);

expect(output).to.include('doc: 1');
expect(output).to.include('doc: 2');
Expand All @@ -42,10 +44,12 @@ for (const colors of [ false, true ]) {

context('when the Cursor is empty', () => {
it('returns an empty string', () => {
const output = stripAnsiColors(format({
value: Object.assign([], { cursorHasMore: false }),
type: 'Cursor'
}));
const output = stripAnsiColors(
format({
value: { documents: [], cursorHasMore: false },
type: 'Cursor'
})
);

expect(output).to.equal('');
});
Expand All @@ -55,10 +59,12 @@ for (const colors of [ false, true ]) {
context('when the result is a CursorIterationResult', () => {
context('when the CursorIterationResult is not empty', () => {
it('returns the inspection', () => {
const output = stripAnsiColors(format({
value: Object.assign([{ doc: 1 }, { doc: 2 }], { cursorHasMore: true }),
type: 'CursorIterationResult'
}));
const output = stripAnsiColors(
format({
value: { documents: [{ doc: 1 }, { doc: 2 }], cursorHasMore: true },
type: 'CursorIterationResult'
})
);

expect(output).to.include('doc: 1');
expect(output).to.include('doc: 2');
Expand All @@ -68,10 +74,12 @@ for (const colors of [ false, true ]) {

context('when the CursorIterationResult is not empty but exhausted', () => {
it('returns the inspection', () => {
const output = stripAnsiColors(format({
value: Object.assign([{ doc: 1 }, { doc: 2 }], { cursorHasMore: false }),
type: 'CursorIterationResult'
}));
const output = stripAnsiColors(
format({
value: { documents: [{ doc: 1 }, { doc: 2 }], cursorHasMore: false },
type: 'CursorIterationResult'
})
);

expect(output).to.include('doc: 1');
expect(output).to.include('doc: 2');
Expand All @@ -82,7 +90,7 @@ for (const colors of [ false, true ]) {
context('when the CursorIterationResult is empty', () => {
it('returns "no cursor"', () => {
const output = stripAnsiColors(format({
value: Object.assign([], { cursorHasMore: false }),
value: { documents: [], cursorHasMore: false },
type: 'CursorIterationResult'
}));

Expand Down
6 changes: 3 additions & 3 deletions packages/cli-repl/src/format-output.ts
Original file line number Diff line number Diff line change
Expand Up @@ -168,19 +168,19 @@ function inspect(output: any, options: FormatOptions): any {
}

function formatCursor(value: any, options: FormatOptions): any {
if (!value.length) {
if (!value.documents.length) {
return '';
}

return formatCursorIterationResult(value, options);
}

function formatCursorIterationResult(value: any, options: FormatOptions): any {
if (!value.length) {
if (!value.documents.length) {
return i18n.__('shell-api.classes.Cursor.iteration.no-cursor');
}

let ret = inspect(value, options);
let ret = inspect(value.documents, options);
if (value.cursorHasMore) {
ret += '\n' + i18n.__('shell-api.classes.Cursor.iteration.type-it-for-more');
}
Expand Down
Loading