package com.mongodb.mongosh.service import com.mongodb.client.FindIterable import com.mongodb.client.MongoCursor import com.mongodb.mongosh.MongoShellContext import org.bson.Document import org.graalvm.polyglot.HostAccess import org.graalvm.polyglot.Value import org.graalvm.polyglot.proxy.ProxyExecutable internal class Cursor(private val findIterable: FindIterable, private val context: MongoShellContext) { private val iterator: MongoCursor = findIterable.iterator() private var closed = false /** Java functions don't have js methods such as apply, bind, call etc. * So we need to create a real js function that wraps Java code */ private val functionProducer = context.eval("(fun) => function inner() { return fun(this, ...arguments); }") @JvmField @HostAccess.Export val limit = jsFun { args -> if (args.isEmpty() || !args[0].fitsInInt()) { throw IllegalArgumentException("Expected one argument of type int. Got: $args") } Cursor(this.findIterable.limit(args[0].asInt()), context) } @JvmField @HostAccess.Export val hasNext = jsFun { this.iterator.hasNext() } @JvmField @HostAccess.Export val next = jsFun { this.iterator.next() } @JvmField @HostAccess.Export val isClosed = jsFun { closed } @JvmField @HostAccess.Export val close = jsFun { closed = true this.iterator.close() } @JvmField @HostAccess.Export val readPref = jsFun { throw UnsupportedOperationException() } @JvmField @HostAccess.Export val batchSize = jsFun { args -> if (args.isEmpty() || !args[0].fitsInInt()) { throw IllegalArgumentException("Expected one argument of type int. Got: $args") } Cursor(this.findIterable.batchSize(args[0].asInt()), context) } private fun jsFun(block: T.(List) -> Any?): Any { return functionProducer.execute(ProxyExecutable { args -> val that = args[0].asHostObject() that.block(args.drop(1)) }) } }