Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 1 addition & 1 deletion packages/java-shell/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ compileJava.dependsOn browserifyShellApi
dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8"
testCompile group: 'junit', name: 'junit', version: '4.12'
compile group: 'org.graalvm.js', name: 'js', version: '20.0.0'
compile group: 'org.graalvm.js', name: 'js', version: '20.2.0'
compile group: 'org.mongodb', name: 'mongo-java-driver', version: '3.12.7'
compile group: 'org.apache.commons', name: 'commons-text', version: '1.8'
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,8 @@ package com.mongodb.mongosh

import com.mongodb.client.MongoClient
import com.mongodb.mongosh.result.MongoShellResult
import java.io.Closeable

class MongoShell(client: MongoClient) : Closeable {
class MongoShell(client: MongoClient) {
private val context = MongoShellContext(client)

fun eval(script: String): MongoShellResult<*> {
Expand All @@ -14,5 +13,5 @@ class MongoShell(client: MongoClient) : Closeable {
return context.extract(value, if (type.isString) type.asString() else null)
}

override fun close() = context.close()
fun close() = context.close()
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import org.graalvm.polyglot.Source
import org.graalvm.polyglot.Value
import org.graalvm.polyglot.proxy.ProxyExecutable
import org.intellij.lang.annotations.Language
import java.io.Closeable
import java.lang.IllegalStateException
import java.time.LocalDateTime
import java.time.ZoneOffset
import java.time.format.DateTimeFormatter
Expand All @@ -31,8 +31,8 @@ import java.util.concurrent.ExecutionException
import java.util.concurrent.TimeUnit
import java.util.regex.Pattern

internal class MongoShellContext(client: MongoClient) : Closeable {
val ctx: Context = Context.create()
internal class MongoShellContext(client: MongoClient) {
private var ctx: Context? = Context.create()
private val serviceProvider = JavaServiceProvider(client, this)
private val shellEvaluator: Value
private val bsonTypes: BsonTypes
Expand All @@ -44,6 +44,7 @@ internal class MongoShellContext(client: MongoClient) : Closeable {
init {
val setupScript = MongoShell::class.java.getResource("/js/all-standalone.js").readText()
evalInner(setupScript, "all-standalone.js")
val ctx = checkClosed()
val context = ctx.getBindings("js")
val global = context["_global"]!!
context.removeMember("_global")
Expand Down Expand Up @@ -76,6 +77,7 @@ internal class MongoShellContext(client: MongoClient) : Closeable {
context.putMember("Date", date)
val isoDate = functionProducer.execute(ProxyExecutable { args -> dateHelper(true, args.toList()) })
context.putMember("ISODate", isoDate)
context.putMember("UUID", functionProducer.execute(ProxyExecutable { args -> if (args.isEmpty()) UUID.randomUUID() else UUID.fromString(args[0].asString()) }))
}

private fun dateHelper(createObject: Boolean, args: List<Value>): Any {
Expand Down Expand Up @@ -124,9 +126,14 @@ internal class MongoShellContext(client: MongoClient) : Closeable {
}

operator fun get(value: String): Value? {
val ctx = checkClosed()
return ctx.getBindings("js")[value]
}

private fun checkClosed(): Context {
return this.ctx ?: throw IllegalStateException("Context has already been closed")
}

internal operator fun Value.get(identifier: String): Value? {
return getMember(identifier)
}
Expand Down Expand Up @@ -158,7 +165,8 @@ internal class MongoShellContext(client: MongoClient) : Closeable {
v.instanceOf("Promise") -> extract(unwrapPromise(v))
type == "Help" -> extract(v["attr"]!!)
type == "Cursor" -> FindCursorResult(FindCursor<Any?>(v, this))
type == "AggregationCursor" -> AggregationCursorResult(AggregationCursor<Any?>(v, this))
// document with aggregation explain result also has type AggregationCursor, so we need to make sure that value contains cursor
type == "AggregationCursor" && v.hasMember("_cursor") -> AggregationCursorResult(AggregationCursor<Any?>(v, this))
type == "InsertOneResult" -> InsertOneResult(v["acknowledged"]!!.asBoolean(), v["insertedId"]!!.asString())
type == "DeleteResult" -> DeleteResult(v["acknowledged"]!!.asBoolean(), v["deletedCount"]!!.asLong())
type == "UpdateResult" -> {
Expand Down Expand Up @@ -240,6 +248,7 @@ internal class MongoShellContext(client: MongoClient) : Closeable {
}

private fun evalInner(@Language("js") script: String, name: String = "Unnamed"): Value {
val ctx = checkClosed()
return ctx.eval(Source.newBuilder("js", script, name).buildLiteral())
}

Expand All @@ -257,7 +266,11 @@ internal class MongoShellContext(client: MongoClient) : Closeable {
}
}

override fun close() = serviceProvider.close()
fun close() {
val ctx = checkClosed()
ctx.close(true)
this.ctx = null
}

private fun Value.instanceOf(clazz: Value?): Boolean {
return clazz != null && evalInner("(o, clazz) => o instanceof clazz", "instance_of_class_script").execute(this, clazz).asBoolean()
Expand Down
Original file line number Diff line number Diff line change
@@ -1,20 +1,36 @@
package com.mongodb.mongosh.result

import com.mongodb.mongosh.MongoShellContext
import org.bson.Document
import org.graalvm.polyglot.Value

class AggregationCursor<out T> internal constructor(private val cursor: Value, private val context: MongoShellContext) : Cursor<T> {
class AggregationCursor<out T> internal constructor(private var cursor: Value?, private var context: MongoShellContext?) : Cursor<T> {
override fun hasNext(): Boolean {
val (cursor, _) = checkClosed()
return cursor.invokeMember("hasNext").asBoolean()
}

override fun next(): T {
val (cursor, context) = checkClosed()
if (!hasNext()) throw NoSuchElementException()
return context.extract(cursor.invokeMember("next")).value as T
}

override fun _asPrintable(): String {
val (cursor, context) = checkClosed()
return context.extract(cursor.invokeMember("_asPrintable"))._asPrintable()
}

override fun close() {
val (c, _) = checkClosed()
c.invokeMember("close")
cursor = null
context = null
}

private fun checkClosed(): Pair<Value, MongoShellContext> {
val cursor = this.cursor
val context = this.context
if (cursor == null || context == null) throw IllegalStateException("Cursor has already been closed")
return cursor to context
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@ package com.mongodb.mongosh.result

interface Cursor<out T> : Iterator<T> {
fun _asPrintable(): String
fun close()
}
Original file line number Diff line number Diff line change
@@ -1,24 +1,41 @@
package com.mongodb.mongosh.result

import com.mongodb.mongosh.MongoShellContext
import org.bson.Document
import org.graalvm.polyglot.Value

class FindCursor<out T> internal constructor(private val cursor: Value, private val context: MongoShellContext) : Cursor<T> {
class FindCursor<out T> internal constructor(private var cursor: Value?, private var context: MongoShellContext?) : Cursor<T> {
override fun hasNext(): Boolean {
val (cursor, _) = checkClosed()
return cursor.invokeMember("hasNext").asBoolean()
}

override fun next(): T {
val (cursor, context) = checkClosed()
if (!hasNext()) throw NoSuchElementException()
return context.extract(cursor.invokeMember("next")).value as T
}

fun batchSize(size: Int) {
val (cursor, _) = checkClosed()
cursor.invokeMember("batchSize", size)
}

override fun _asPrintable(): String {
val (cursor, context) = checkClosed()
return context.extract(cursor.invokeMember("_asPrintable"))._asPrintable()
}

override fun close() {
val (c, _) = checkClosed()
c.invokeMember("close")
cursor = null
context = null
}

private fun checkClosed(): Pair<Value, MongoShellContext> {
val cursor = this.cursor
val context = this.context
if (cursor == null || context == null) throw IllegalStateException("Cursor has already been closed")
return cursor to context
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.mongodb.mongosh.service

import org.graalvm.polyglot.Value

/**
* see service-provider-core/src/admin.ts
*/
internal interface AdminServiceProvider {
fun createCollection(database: String, collection: String, options: Value?): Value
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package com.mongodb.mongosh.service

import com.mongodb.client.MongoCursor
import com.mongodb.client.model.Collation
import com.mongodb.mongosh.MongoShellContext
import com.mongodb.mongosh.result.DocumentResult
import org.bson.Document
Expand Down Expand Up @@ -56,7 +55,7 @@ internal class Cursor(private var helper: MongoIterableHelper<*>, private val co
@HostAccess.Export
override fun close() {
closed = true
getOrCreateIterator().close()
iterator?.close()
}

@HostAccess.Export
Expand All @@ -76,9 +75,7 @@ internal class Cursor(private var helper: MongoIterableHelper<*>, private val co
if (!v.hasMembers()) {
throw IllegalArgumentException("Expected one argument of type object. Got: $v")
}
val collation = convert(Collation.builder(), collationConverters, collationDefaultConverter, toDocument(context, v))
.getOrThrow()
.build()
val collation = toDocument(context, v)
helper.collation(collation)
return this
}
Expand All @@ -97,8 +94,9 @@ internal class Cursor(private var helper: MongoIterableHelper<*>, private val co
}

@HostAccess.Export
override fun explain(verbosity: String) {
throw NotImplementedError("explain is not supported")
override fun explain(verbosity: String?): Any? {
checkQueryNotExecuted()
return context.toJs(helper.explain(verbosity))
}

@HostAccess.Export
Expand Down Expand Up @@ -205,9 +203,10 @@ internal class Cursor(private var helper: MongoIterableHelper<*>, private val co
}

@HostAccess.Export
override fun setReadPreference(v: Value): Cursor {
override fun setReadPreference(v: String): Cursor {
checkQueryNotExecuted()
throw NotImplementedError("setReadPreference is not supported")
helper = helper.readPrev(v, null)
return this
}

override fun showRecordId(v: Boolean): ServiceProviderCursor {
Expand Down
Loading