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
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,6 @@ import org.graalvm.polyglot.Context
import org.graalvm.polyglot.Source
import org.graalvm.polyglot.Value
import org.graalvm.polyglot.proxy.ProxyExecutable
import org.graalvm.polyglot.proxy.ProxyObject
import org.graalvm.polyglot.proxy.ProxyObject.fromMap
import org.intellij.lang.annotations.Language
import java.io.Closeable
import java.time.LocalDateTime
Expand All @@ -34,7 +32,7 @@ import java.util.concurrent.TimeUnit
import java.util.regex.Pattern

internal class MongoShellContext(client: MongoClient) : Closeable {
private val ctx: Context = Context.create()
val ctx: Context = Context.create()
private val serviceProvider = JavaServiceProvider(client, this)
private val shellEvaluator: Value
private val bsonTypes: BsonTypes
Expand Down Expand Up @@ -227,6 +225,7 @@ internal class MongoShellContext(client: MongoClient) : Closeable {
v.fitsInLong() -> LongResult(v.asLong())
v.fitsInFloat() -> FloatResult(v.asFloat())
v.fitsInDouble() -> DoubleResult(v.asDouble())
v.equalsTo("undefined") -> VoidResult
v.isNull -> NullResult
v.isHostObject && v.asHostObject<Any?>() is Unit -> VoidResult
v.isHostObject && v.asHostObject<Any?>() is Document -> DocumentResult(v.asHostObject())
Expand All @@ -253,7 +252,7 @@ internal class MongoShellContext(client: MongoClient) : Closeable {

fun <T> toJsPromise(promise: Either<T>): Value {
return when (promise) {
is Right -> evalInner("(v) => new Promise(((resolve) => resolve(v)))", "resolved_promise_script").execute(promise.value)
is Right -> evalInner("(v) => new Promise(((resolve) => resolve(v)))", "resolved_promise_script").execute(toJs(promise.value))
is Left -> evalInner("(v) => new Promise(((_, reject) => reject(v)))", "rejected_promise_script").execute(promise.value)
}
}
Expand All @@ -266,19 +265,23 @@ internal class MongoShellContext(client: MongoClient) : Closeable {

private fun Value.instanceOf(@Language("js") clazz: String): Boolean = evalInner("(x) => x instanceof $clazz", "instance_of_script").execute(this).asBoolean()

private fun Value.equalsTo(@Language("js") value: String): Boolean = evalInner("(x) => x === $value", "equals_script").execute(this).asBoolean()

fun toJs(o: Any?): Any? {
return when (o) {
is Iterable<*> -> toJs(o)
is Map<*, *> -> toJs(o)
Unit -> evalInner("undefined")
else -> o
}
}

private fun toJs(map: Map<*, *>): ProxyObject {
val convertedMap: Map<String, Any?> = map.entries.asSequence()
.filter { (key, _) -> key is String }
.associate { e -> e.key as String to toJs(e.value) }
return fromMap(convertedMap)
private fun toJs(map: Map<*, *>): Value {
val jsMap = evalInner("new Object()")
for ((key, value) in map.entries) {
jsMap.putMember(key as String, toJs(value))
}
return jsMap
}

private fun toJs(list: Iterable<Any?>): Value {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import com.mongodb.client.result.UpdateResult
import com.mongodb.mongosh.MongoShellContext
import com.mongodb.mongosh.result.ArrayResult
import com.mongodb.mongosh.result.CommandException
import com.mongodb.mongosh.result.DeleteResult
import com.mongodb.mongosh.result.DocumentResult
import org.bson.Document
import org.graalvm.polyglot.HostAccess
Expand All @@ -25,9 +24,9 @@ internal class JavaServiceProvider(private val client: MongoClient, private val
override fun runCommand(database: String, spec: Value): Value = promise {
getDatabase(database, null).map { db ->
if (spec.isString) {
context.toJs(db.runCommand(Document(spec.asString(), 1)))
db.runCommand(Document(spec.asString(), 1))
} else {
context.toJs(db.runCommand(toDocument(spec, "spec")))
db.runCommand(toDocument(spec, "spec"))
}
}
}
Expand All @@ -44,7 +43,7 @@ internal class JavaServiceProvider(private val client: MongoClient, private val
if (!isOk) {
throw Exception(res.toJson())
}
context.toJs(res)
res
}
}

Expand All @@ -54,9 +53,8 @@ internal class JavaServiceProvider(private val client: MongoClient, private val
val dbOptions = toDocument(dbOptions, "dbOptions")
getDatabase(database, dbOptions).map { db ->
db.getCollection(collection).insertOne(document)
context.toJs(mapOf(
"result" to mapOf("ok" to true),
"insertedId" to "UNKNOWN"))
mapOf("result" to mapOf("ok" to true),
"insertedId" to "UNKNOWN")
}
}

Expand All @@ -69,13 +67,11 @@ internal class JavaServiceProvider(private val client: MongoClient, private val
getDatabase(database, dbOptions).flatMap { db ->
convert(ReplaceOptions(), replaceOptionsConverters, replaceOptionsDefaultConverters, options).map { options ->
val res = db.getCollection(collection).replaceOne(filter, replacement, options)
context.toJs(mapOf(
"result" to mapOf("ok" to res.wasAcknowledged()),
mapOf("result" to mapOf("ok" to res.wasAcknowledged()),
"matchedCount" to res.matchedCount,
"modifiedCount" to res.modifiedCount,
"upsertedCount" to if (res.upsertedId == null) 0 else 1,
"upsertedId" to res.upsertedId
))
"upsertedId" to res.upsertedId)
}
}
}
Expand All @@ -95,11 +91,11 @@ internal class JavaServiceProvider(private val client: MongoClient, private val
update.hasMembers() -> Right(db.getCollection(collection).updateMany(filter, toDocument(update, "update"), updateOptions))
else -> Left<UpdateResult>(IllegalArgumentException("updatePipeline must be a list or object"))
}.map { res ->
context.toJs(mapOf("result" to mapOf("ok" to res.wasAcknowledged()),
mapOf("result" to mapOf("ok" to res.wasAcknowledged()),
"matchedCount" to res.matchedCount,
"modifiedCount" to res.modifiedCount,
"upsertedCount" to if (res.upsertedId == null) 0 else 1,
"upsertedId" to res.upsertedId))
"upsertedId" to res.upsertedId)
}
}
}
Expand Down Expand Up @@ -127,12 +123,11 @@ internal class JavaServiceProvider(private val client: MongoClient, private val
val pipeline = toList(update, "update")?.map { it as Document }
coll.updateOne(filter, pipeline, updateOptions)
} else coll.updateOne(filter, toDocument(update, "update"), updateOptions)
context.toJs(mapOf("result" to mapOf("ok" to res.wasAcknowledged()),
mapOf("result" to mapOf("ok" to res.wasAcknowledged()),
"matchedCount" to res.matchedCount,
"modifiedCount" to res.modifiedCount,
"upsertedCount" to if (res.upsertedId == null) 0 else 1,
"upsertedId" to res.upsertedId
))
"upsertedId" to res.upsertedId)
}
}
}
Expand Down Expand Up @@ -164,15 +159,15 @@ internal class JavaServiceProvider(private val client: MongoClient, private val
val writeModels = requests.map { getWriteModel(it as Document) }
unwrap(writeModels).map { requests ->
val result = db.getCollection(collection).bulkWrite(requests, options)
context.toJs(mapOf(
mapOf(
"result" to mapOf("ok" to result.wasAcknowledged()),
"insertedCount" to result.insertedCount,
"insertedIds" to "UNKNOWN",
"matchedCount" to result.matchedCount,
"modifiedCount" to result.modifiedCount,
"deletedCount" to result.deletedCount,
"upsertedCount" to result.upserts.size,
"upsertedIds" to result.upserts.map { it.id }))
"upsertedIds" to result.upserts.map { it.id })
}
}
}
Expand Down Expand Up @@ -218,9 +213,8 @@ internal class JavaServiceProvider(private val client: MongoClient, private val
getDatabase(database, dbOptions).flatMap { db ->
convert(DeleteOptions(), deleteConverters, deleteDefaultConverter, options).map { deleteOptions ->
val result = db.getCollection(collection).deleteMany(filter, deleteOptions)
context.toJs(mapOf(
"result" to mapOf("ok" to result.wasAcknowledged()),
"deletedCount" to result.deletedCount))
mapOf("result" to mapOf("ok" to result.wasAcknowledged()),
"deletedCount" to result.deletedCount)
}
}
}
Expand All @@ -233,9 +227,8 @@ internal class JavaServiceProvider(private val client: MongoClient, private val
getDatabase(database, dbOptions).flatMap { db ->
convert(DeleteOptions(), deleteConverters, deleteDefaultConverter, options).map { deleteOptions ->
val result = db.getCollection(collection).deleteOne(filter, deleteOptions)
context.toJs(mapOf(
"result" to mapOf("ok" to result.wasAcknowledged()),
"deletedCount" to result.deletedCount))
mapOf("result" to mapOf("ok" to result.wasAcknowledged()),
"deletedCount" to result.deletedCount)
}
}
}
Expand All @@ -247,7 +240,7 @@ internal class JavaServiceProvider(private val client: MongoClient, private val
getDatabase(database, null).flatMap { db ->
convert(FindOneAndDeleteOptions(), findOneAndDeleteConverters, findOneAndDeleteDefaultConverter, options).map { options ->
val res = db.getCollection(collection).findOneAndDelete(filter, options)
context.toJs(mapOf("value" to res))
mapOf("value" to res)
}
}
}
Expand All @@ -261,7 +254,7 @@ internal class JavaServiceProvider(private val client: MongoClient, private val
convert(FindOneAndReplaceOptions(), findOneAndReplaceOptionsConverters, findOneAndReplaceOptionsDefaultConverters, options)
.map { options ->
val res = db.getCollection(collection).findOneAndReplace(filter, replacement, options)
context.toJs(mapOf("value" to res))
mapOf("value" to res)
}
}
}
Expand All @@ -274,7 +267,7 @@ internal class JavaServiceProvider(private val client: MongoClient, private val
getDatabase(database, null).flatMap { db ->
convert(FindOneAndUpdateOptions(), findOneAndUpdateConverters, findOneAndUpdateDefaultConverter, options).map { options ->
val res = db.getCollection(collection).findOneAndUpdate(filter, update, options)
context.toJs(mapOf("value" to res))
mapOf("value" to res)
}
}

Expand All @@ -287,9 +280,8 @@ internal class JavaServiceProvider(private val client: MongoClient, private val
if (docs == null || docs.any { it !is Document }) return@promise Left(IllegalArgumentException("docs must be a list of objects"))
getDatabase(database, dbOptions).map { db ->
db.getCollection(collection).insertMany(docs.filterIsInstance<Document>())
context.toJs(mapOf(
"result" to mapOf("ok" to true),
"insertedIds" to emptyList<String>()))
mapOf("result" to mapOf("ok" to true),
"insertedIds" to emptyList<String>())
}
}

Expand Down Expand Up @@ -392,7 +384,7 @@ internal class JavaServiceProvider(private val client: MongoClient, private val

@HostAccess.Export
override fun listDatabases(database: String): Value = promise {
Right(context.toJs(mapOf("databases" to client.listDatabases())))
Right(mapOf("databases" to client.listDatabases()))
}

@HostAccess.Export
Expand All @@ -407,7 +399,7 @@ internal class JavaServiceProvider(private val client: MongoClient, private val
@HostAccess.Export
override fun getIndexes(database: String, collection: String): Value = promise {
getDatabase(database, null).map { db ->
context.toJs(db.getCollection(collection).listIndexes())
db.getCollection(collection).listIndexes()
}
}

Expand All @@ -417,26 +409,26 @@ internal class JavaServiceProvider(private val client: MongoClient, private val
getDatabase(database, null).map { db ->
val list = db.listCollections()
if (filter != null) list.filter(filter)
context.toJs(list)
list
}
}

@HostAccess.Export
override fun stats(database: String, collection: String, options: Value?): Value = promise<Any?> {
getDatabase(database, null).map { db ->
context.toJs(db.runCommand(Document("collStats", collection)))
db.runCommand(Document("collStats", collection))
}
}

@HostAccess.Export
override fun remove(database: String, collection: String, query: Value, options: Value?, dbOptions: Value?): Value {
override fun remove(database: String, collection: String, query: Value, options: Value?, dbOptions: Value?): Value = promise {
val query = toDocument(query, "query")
val dbOptions = toDocument(dbOptions, "dbOptions")
val promise = getDatabase(database, dbOptions).map { db ->
getDatabase(database, dbOptions).map { db ->
val result = db.getCollection(collection).deleteMany(query)
DeleteResult(result.wasAcknowledged(), result.deletedCount)
mapOf("acknowledged" to result.wasAcknowledged(),
"deletedCount" to result.deletedCount)
}
return context.toJsPromise(promise)
}

@HostAccess.Export
Expand All @@ -454,7 +446,7 @@ internal class JavaServiceProvider(private val client: MongoClient, private val
}
val indexes = unwrap(convertedIndexes)
indexes.map { indexes ->
context.toJs(db.getCollection(collection).createIndexes(indexes))
db.getCollection(collection).createIndexes(indexes)
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
null
{ "acknowledged": true, "insertedId": "UNKNOWN" }
true
[ { "_id": <ObjectID>, "a": 1, "objectId": <ObjectID>, "maxKey": { "$maxKey" : 1}, "minKey": { "$minKey" : 1}, "binData": { "$binary" : "MTIzNA==" , "$type" : 16}, "date": { "$date" : 1355875200000}, "isoDate": { "$date" : 1355875200000}, "numberInt": 24, "timestamp": Timestamp{value=429496729600, seconds=100, inc=0} } ]
Original file line number Diff line number Diff line change
@@ -1 +1 @@
NullResult: null
VoidResult: