Skip to content

Commit efd8e46

Browse files
authored
chore: clean up ShellResult usage (#371)
Provide more encapsulation by using a fixed interface for other packages to work with `shell-api`, without the need to use internal methods of `shell-api` objects. - Inside `shell-api`: - Consistently use `async [asPrintable]()`, `[resultSource]`, `[shellApiType]` (all as symbol properties) - These are all non-exported, local symbol properties, i.e. not for outside access - Remove `_asPrintable` - Deprecate `ShellResult.value` in favor of more expressively named `.rawValue` and `.printable` (`.value` is very generic, and in particular I would have expected it to be the evaluation result and not a formatting-ready version of it) - Remove `[asShellResult]()` - Make `[asPrintable]` methods on the Cursor classed idempotent - On the API surface of `shell-api`: - Remove `asShellResult` and `shellApiType` - Provide `getShellApiType()` and `toShellResult()` as the sole APIs to turn an evaluation result into a `ShellResult` - In particular, this applies for *all* values – no special handling is necessary in `shell-evaluator` anymore - Remove the special handling for the Java shell that we had in the Cursor methods This is partly in preparation for MONGOSH-237, so that we do not start introducing calls to half-internal methods like `_asPrintable()` in more places than we already do.
1 parent 32d52ad commit efd8e46

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

45 files changed

+448
-409
lines changed

packages/browser-repl/src/components/shell.spec.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ describe('<Shell />', () => {
3535
elementFocus = sinon.spy(HTMLElement.prototype, 'focus');
3636

3737
fakeRuntime = {
38-
evaluate: sinon.fake.returns({ value: 'some result' })
38+
evaluate: sinon.fake.returns({ printable: 'some result' })
3939
};
4040

4141
onOutputChangedSpy = sinon.spy();

packages/browser-repl/src/components/shell.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ export class Shell extends Component<ShellProps, ShellState> {
108108
outputLine = {
109109
format: 'output',
110110
type: result.type,
111-
value: result.value
111+
value: result.printable
112112
};
113113
} catch (error) {
114114
outputLine = {

packages/browser-repl/src/iframe-runtime/iframe-runtime.spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ describe('IframeRuntime', () => {
5151
await other.evaluate('x = 2');
5252

5353
expect(
54-
(await runtime.evaluate('x')).value
54+
(await runtime.evaluate('x')).printable
5555
).to.equal(1);
5656
});
5757
});

packages/cli-repl/src/cli-repl.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/* eslint no-console: 0, no-sync: 0*/
22

33
import { CliServiceProvider, NodeOptions, CliOptions } from '@mongosh/service-provider-server';
4-
import { shellApiType, ShellInternalState } from '@mongosh/shell-api';
4+
import { getShellApiType, ShellInternalState } from '@mongosh/shell-api';
55
import ShellEvaluator from '@mongosh/shell-evaluator';
66
import formatOutput, { formatError } from './format-output';
77
import { LineByLineInput } from './line-by-line-input';
@@ -227,7 +227,7 @@ class CliRepl {
227227
this.internalState.setCtx(this.repl.context);
228228
Object.defineProperty(this.repl.context, 'db', {
229229
set: (newDb) => {
230-
if (newDb === undefined || newDb[shellApiType] !== 'Database') {
230+
if (getShellApiType(newDb) !== 'Database') {
231231
const warn = new MongoshWarning('Cannot reassign \'db\' to non-Database type');
232232
console.log(warn);
233233
return;
@@ -357,7 +357,7 @@ class CliRepl {
357357
return formatOutput({ type: 'Error', value: output });
358358
}
359359

360-
return formatOutput(result);
360+
return formatOutput({ type: result.type, value: result.printable });
361361
};
362362

363363
verifyNodeVersion(): void {

packages/java-shell/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
/src/main/resources/js/all-standalone.js
22
/build/
3+
/.gradle/

packages/java-shell/src/main/js/all.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,7 @@ const ShellEvaluator = require('../../../../shell-evaluator/').default;
44
/** temporal object that is used to access symbols from closures generated by browserify */
55
_global = {
66
ShellInternalState: ShellApi.ShellInternalState,
7-
ShellEvaluator: ShellEvaluator
7+
ShellEvaluator: ShellEvaluator,
8+
toShellResult: ShellApi.toShellResult,
9+
getShellApiType: ShellApi.getShellApiType,
810
};

packages/java-shell/src/main/kotlin/com/mongodb/mongosh/MongoShell.kt

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,8 @@ class MongoShell(client: MongoClient) {
88

99
fun eval(script: String): MongoShellResult<*> {
1010
val result = context.unwrapPromise(context.eval(script, "user_script"))
11-
val value = result.getMember("value")
12-
val type = result.getMember("type")
13-
return context.extract(value, if (type.isString) type.asString() else null)
11+
val value = result.getMember("rawValue")
12+
return context.extract(null, value)
1413
}
1514

1615
fun close() = context.close()

packages/java-shell/src/main/kotlin/com/mongodb/mongosh/MongoShellContext.kt

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@ internal class MongoShellContext(client: MongoClient) {
3636
private val serviceProvider = JavaServiceProvider(client, this)
3737
private val shellEvaluator: Value
3838
private val shellInternalState: Value
39+
private val toShellResultFn: Value
40+
private val getShellApiTypeFn: Value
3941
private val bsonTypes: BsonTypes
4042

4143
/** Java functions don't have js methods such as apply, bind, call etc.
@@ -51,6 +53,8 @@ internal class MongoShellContext(client: MongoClient) {
5153
context.removeMember("_global")
5254
shellInternalState = global.getMember("ShellInternalState").newInstance(serviceProvider)
5355
shellEvaluator = global.getMember("ShellEvaluator").newInstance(shellInternalState)
56+
toShellResultFn = global.getMember("toShellResult")
57+
getShellApiTypeFn = global.getMember("getShellApiType")
5458
val jsSymbol = context["Symbol"]!!
5559
shellInternalState.invokeMember("setCtx", context)
5660
initContext(context, jsSymbol)
@@ -161,13 +165,31 @@ internal class MongoShellContext(client: MongoClient) {
161165
}
162166
}
163167

164-
fun extract(v: Value, type: String? = null): MongoShellResult<*> {
168+
fun getShellApiType(rawValue: Value): String? {
169+
val rawType = getShellApiTypeFn.execute(rawValue)
170+
return if (rawType.isString) rawType.asString() else null
171+
}
172+
173+
fun toShellResult(rawValue: Value): Value {
174+
return unwrapPromise(toShellResultFn.execute(rawValue));
175+
}
176+
177+
fun extract(printable: Value?, rawValue: Value? = null): MongoShellResult<*> {
178+
val v: Value
179+
val type: String?
180+
if (printable == null) {
181+
type = getShellApiType(rawValue as Value)
182+
v = toShellResult(rawValue)["printable"]!!
183+
} else {
184+
type = null
185+
v = printable
186+
}
187+
165188
return when {
166-
v.instanceOf("Promise") -> extract(unwrapPromise(v))
167189
type == "Help" -> extract(v["attr"]!!)
168-
type == "Cursor" -> FindCursorResult(FindCursor<Any?>(v, this))
190+
type == "Cursor" -> FindCursorResult(FindCursor<Any?>(rawValue, this))
169191
// document with aggregation explain result also has type AggregationCursor, so we need to make sure that value contains cursor
170-
type == "AggregationCursor" && v.hasMember("_cursor") -> AggregationCursorResult(AggregationCursor<Any?>(v, this))
192+
type == "AggregationCursor" && rawValue!!.hasMember("_cursor") -> AggregationCursorResult(AggregationCursor<Any?>(rawValue, this))
171193
type == "InsertOneResult" -> InsertOneResult(v["acknowledged"]!!.asBoolean(), v["insertedId"]!!.asString())
172194
type == "DeleteResult" -> DeleteResult(v["acknowledged"]!!.asBoolean(), v["deletedCount"]!!.asLong())
173195
type == "UpdateResult" -> {
@@ -345,4 +367,4 @@ private val DATE_FORMATTER = DateTimeFormatterBuilder()
345367
.appendLiteral('Z')
346368
.optionalEnd()
347369
.optionalEnd()
348-
.toFormatter()
370+
.toFormatter()

packages/java-shell/src/main/kotlin/com/mongodb/mongosh/result/AggregationCursor.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ class AggregationCursor<out T> internal constructor(private var cursor: Value?,
1717

1818
override fun _asPrintable(): String {
1919
val (cursor, context) = checkClosed()
20-
return context.extract(cursor.invokeMember("_asPrintable"))._asPrintable()
20+
return context.extract(context.toShellResult(cursor).getMember("printable"))._asPrintable()
2121
}
2222

2323
override fun close() {
@@ -33,4 +33,4 @@ class AggregationCursor<out T> internal constructor(private var cursor: Value?,
3333
if (cursor == null || context == null) throw IllegalStateException("Cursor has already been closed")
3434
return cursor to context
3535
}
36-
}
36+
}

packages/java-shell/src/main/kotlin/com/mongodb/mongosh/result/FindCursor.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ class FindCursor<out T> internal constructor(private var cursor: Value?, private
2222

2323
override fun _asPrintable(): String {
2424
val (cursor, context) = checkClosed()
25-
return context.extract(cursor.invokeMember("_asPrintable"))._asPrintable()
25+
return context.extract(context.toShellResult(cursor).getMember("printable"))._asPrintable()
2626
}
2727

2828
override fun close() {
@@ -38,4 +38,4 @@ class FindCursor<out T> internal constructor(private var cursor: Value?, private
3838
if (cursor == null || context == null) throw IllegalStateException("Cursor has already been closed")
3939
return cursor to context
4040
}
41-
}
41+
}

0 commit comments

Comments
 (0)