use super::classes;
use super::fetch;
use super::globals;
use super::modules;
use super::modules::loader;
use super::modules::resolver;
use super::modules::surrealdb::query::QueryContext;
use super::modules::surrealdb::query::QUERY_DATA_PROP_NAME;
use crate::ctx::Context;
use crate::dbs::{Options, Transaction};
use crate::doc::CursorDoc;
use crate::err::Error;
use crate::value::Value;
use js::async_with;
use js::object::Property;
use js::prelude::Promise;
use js::prelude::Rest;
use js::prelude::This;
use js::CatchResultExt;
use js::Class;
use js::Ctx;
use js::Function;
use js::Module;
pub unsafe fn create_query_data<'a>(
context: &'a Context<'a>,
opt: &'a Options,
txn: &'a Transaction,
doc: Option<&'a CursorDoc<'a>>,
ctx: &Ctx<'_>,
) -> Result<(), js::Error> {
let ctx = Ctx::from_raw(ctx.as_raw());
let object = Class::instance(
ctx.clone(),
QueryContext {
context,
opt,
txn,
doc,
},
)?;
let prop = Property::from(object);
ctx.globals().prop(QUERY_DATA_PROP_NAME, prop)?;
Ok(())
}
pub async fn run(
context: &Context<'_>,
opt: &Options,
txn: &Transaction,
doc: Option<&CursorDoc<'_>>,
src: &str,
arg: Vec<Value>,
) -> Result<Value, Error> {
if context.is_done() {
return Ok(Value::None);
}
let run = js::AsyncRuntime::new().unwrap();
run.set_max_stack_size(262_144).await;
run.set_memory_limit(2_000_000).await;
let cancellation = context.cancellation();
let handler = Box::new(move || cancellation.is_done());
run.set_interrupt_handler(Some(handler)).await;
let ctx = js::AsyncContext::full(&run).await.unwrap();
run.set_loader(resolver(), loader()).await;
let src = format!(
"export default async function() {{ try {{ {src} }} catch(e) {{ return (e instanceof Error) ? e : new Error(e); }} }}"
);
async_with!(ctx => |ctx|{
let res = async{
let global = ctx.globals();
unsafe{ create_query_data(context,opt,txn,doc,&ctx) }?;
global.set(
"surrealdb",
Module::evaluate_def::<modules::surrealdb::Package, _>(ctx.clone(), "surrealdb")?
.get::<_, js::Value>("default")?,
)?;
fetch::register(&ctx)?;
let console = globals::console::console(&ctx)?;
global.set("console",console)?;
classes::init(&ctx)?;
let res = ctx.clone().compile("script", src)?;
let fnc = res.get::<_, Function>("default")?;
let doc = doc.map(|v|v.doc.as_ref());
let promise: Promise<Value> = fnc.call((This(doc), Rest(arg)))?;
promise.await
}.await;
res.catch(&ctx).map_err(Error::from)
})
.await
}