From 5d41f028ea2e428b3fb3d0b3bc85ece666a9962d Mon Sep 17 00:00:00 2001 From: Ziyang Hu Date: Wed, 16 Nov 2022 16:17:13 +0800 Subject: [PATCH] time functions for WASM --- Cargo.lock | 1 + Cargo.toml | 4 +- cozo-core/Cargo.toml | 3 +- cozo-core/src/data/functions.rs | 55 +++++++++++++++------------- cozo-core/src/runtime/db.rs | 8 ++-- cozo-lib-wasm/cozo_web_wasm/index.js | 4 ++ 6 files changed, 43 insertions(+), 32 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e993fb34..68efded5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -494,6 +494,7 @@ dependencies = [ "either", "env_logger", "itertools 0.10.5", + "js-sys", "lazy_static", "log", "miette", diff --git a/Cargo.toml b/Cargo.toml index 149db5bd..5e47a7eb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,5 @@ -[profile.release] -lto = true +#[profile.release] +#lto = true [workspace] members = ["cozorocks", "cozo-lib-c", "cozo-lib-java", "cozo-core", "cozoserver", "cozo-lib-wasm"] diff --git a/cozo-core/Cargo.toml b/cozo-core/Cargo.toml index 6a56cffd..92e2f8c8 100644 --- a/cozo-core/Cargo.toml +++ b/cozo-core/Cargo.toml @@ -38,7 +38,7 @@ jemalloc = ["dep:tikv-jemallocator-global", "cozorocks?/jemalloc"] ## Enables io-uring option for the RocksDB storage io-uring = ["cozorocks?/io-uring"] ## Enables the WASM target -wasm = ["uuid/js"] +wasm = ["uuid/js", "dep:js-sys"] ## Allows threading and enables the use of the `rayon` library for parallelizing algorithms rayon = ["dep:rayon"] ## Disallows the use of threads @@ -94,5 +94,6 @@ sled = { version = "0.34.7", optional = true } tikv-client = { version = "0.1.0", optional = true } tokio = { version = "1.21.2", optional = true } sqlite = { version = "0.30.1", optional = true } +js-sys = { version = "0.3.60", optional = true } #redb = "0.9.0" #ouroboros = "0.15.5" diff --git a/cozo-core/src/data/functions.rs b/cozo-core/src/data/functions.rs index f65152e1..9e7be314 100644 --- a/cozo-core/src/data/functions.rs +++ b/cozo-core/src/data/functions.rs @@ -13,6 +13,8 @@ use std::time::{SystemTime, UNIX_EPOCH}; use chrono::{DateTime, TimeZone, Utc}; use itertools::Itertools; +#[cfg(feature = "wasm")] +use js_sys::Date; use miette::{bail, ensure, miette, Result}; use num_traits::FloatConst; use rand::prelude::*; @@ -1434,7 +1436,8 @@ pub(crate) fn op_to_uuid(args: &[DataValue]) -> Result { define_op!(OP_NOW, 0, false); #[cfg(feature = "wasm")] pub(crate) fn op_now(_args: &[DataValue]) -> Result { - bail!("`op_now` is not supported under WASM runtime") + let d: f64 = Date::now() / 1000.; + Ok(DataValue::from(d)) } #[cfg(not(feature = "wasm"))] pub(crate) fn op_now(_args: &[DataValue]) -> Result { @@ -1445,20 +1448,22 @@ pub(crate) fn op_now(_args: &[DataValue]) -> Result { } define_op!(OP_FORMAT_TIMESTAMP, 1, true); -#[cfg(feature = "wasm")] -pub(crate) fn op_format_timestamp(_args: &[DataValue]) -> Result { - bail!("`format_timestamp` is not supported under WASM") -} -#[cfg(not(feature = "wasm"))] pub(crate) fn op_format_timestamp(args: &[DataValue]) -> Result { - let f = args[0] - .get_float() - .ok_or_else(|| miette!("'format_timestamp' expects a number"))?; - let millis = (f * 1000.) as i64; + #[cfg(feature = "wasm")] let dt = Utc - .timestamp_millis_opt(millis) + .timestamp_millis_opt(Date::now() as i64) .latest() - .ok_or_else(|| miette!("bad time: {}", f))?; + .ok_or_else(|| miette!("bad time input"))?; + #[cfg(not(feature = "wasm"))] + let dt = { + let f = args[0] + .get_float() + .ok_or_else(|| miette!("'format_timestamp' expects a number"))?; + let millis = (f * 1000.) as i64; + Utc.timestamp_millis_opt(millis) + .latest() + .ok_or_else(|| miette!("bad time: {}", f))? + }; match args.get(1) { Some(tz_v) => { let tz_s = tz_v.get_string().ok_or_else(|| { @@ -1478,11 +1483,6 @@ pub(crate) fn op_format_timestamp(args: &[DataValue]) -> Result { } define_op!(OP_PARSE_TIMESTAMP, 1, false); -#[cfg(feature = "wasm")] -pub(crate) fn op_parse_timestamp(_args: &[DataValue]) -> Result { - bail!("`parse_timestamp` is not supported under WASM") -} -#[cfg(not(feature = "wasm"))] pub(crate) fn op_parse_timestamp(args: &[DataValue]) -> Result { let s = args[0] .get_string() @@ -1495,17 +1495,22 @@ pub(crate) fn op_parse_timestamp(args: &[DataValue]) -> Result { } define_op!(OP_RAND_UUID_V1, 0, false); -#[cfg(feature = "wasm")] -pub(crate) fn op_rand_uuid_v1(_args: &[DataValue]) -> Result { - bail!("`rand_uuid_v1` is not supported under WASM") -} -#[cfg(not(feature = "wasm"))] pub(crate) fn op_rand_uuid_v1(_args: &[DataValue]) -> Result { let mut rng = rand::thread_rng(); let uuid_ctx = uuid::v1::Context::new(rng.gen()); - let now = SystemTime::now(); - let since_epoch = now.duration_since(UNIX_EPOCH).unwrap(); - let ts = Timestamp::from_unix(uuid_ctx, since_epoch.as_secs(), since_epoch.subsec_nanos()); + #[cfg(feature = "wasm")] + let ts = { + let since_epoch: f64 = Date::now(); + let seconds = since_epoch.floor(); + let fractional = (since_epoch - seconds) * 1.0e9; + Timestamp::from_unix(uuid_ctx, seconds as u64, fractional as u32) + }; + #[cfg(not(feature = "wasm"))] + let ts = { + let now = SystemTime::now(); + let since_epoch = now.duration_since(UNIX_EPOCH).unwrap(); + Timestamp::from_unix(uuid_ctx, since_epoch.as_secs(), since_epoch.subsec_nanos()) + }; let mut rand_vals = [0u8; 6]; rng.fill(&mut rand_vals); let id = uuid::Uuid::new_v1(ts, &rand_vals); diff --git a/cozo-core/src/runtime/db.rs b/cozo-core/src/runtime/db.rs index 13892f1a..62fe5beb 100644 --- a/cozo-core/src/runtime/db.rs +++ b/cozo-core/src/runtime/db.rs @@ -8,8 +8,8 @@ use std::collections::BTreeMap; use std::fmt::{Debug, Formatter}; -use std::sync::{Arc, Mutex}; use std::sync::atomic::{AtomicBool, AtomicU64, Ordering}; +use std::sync::{Arc, Mutex}; use std::thread; use std::time::{Duration, Instant, SystemTime, UNIX_EPOCH}; @@ -17,7 +17,7 @@ use either::{Left, Right}; use itertools::Itertools; use lazy_static::lazy_static; use miette::{ - bail, Diagnostic, ensure, GraphicalReportHandler, GraphicalTheme, IntoDiagnostic, + bail, ensure, Diagnostic, GraphicalReportHandler, GraphicalTheme, IntoDiagnostic, JSONReportHandler, Result, WrapErr, }; use serde_json::{json, Map}; @@ -28,8 +28,8 @@ use crate::data::json::JsonValue; use crate::data::program::{InputProgram, QueryAssertion, RelationOp}; use crate::data::tuple::Tuple; use crate::data::value::{DataValue, LARGEST_UTF_CHAR}; -use crate::parse::{CozoScript, parse_script, SourceSpan}; use crate::parse::sys::SysOp; +use crate::parse::{parse_script, CozoScript, SourceSpan}; use crate::query::compile::{CompiledProgram, CompiledRule, CompiledRuleSet}; use crate::query::relation::{ FilteredRA, InMemRelationRA, InnerJoin, NegJoin, RelAlgebra, ReorderRA, StoredRA, UnificationRA, @@ -573,7 +573,7 @@ impl<'s, S: Storage<'s>> Db { .as_secs_f64(); #[cfg(feature = "wasm")] - let since_the_epoch = 0.; + let since_the_epoch = js_sys::Date::now(); let handle = RunningQueryHandle { started_at: since_the_epoch, diff --git a/cozo-lib-wasm/cozo_web_wasm/index.js b/cozo-lib-wasm/cozo_web_wasm/index.js index 6a8420eb..9d54e47f 100644 --- a/cozo-lib-wasm/cozo_web_wasm/index.js +++ b/cozo-lib-wasm/cozo_web_wasm/index.js @@ -61,6 +61,10 @@ query(` ?[loved_by_e_not_b] := *love['eve', loved_by_e_not_b], not *love['bob', loved_by_e_not_b] `); +query(` +?[] <- [[parse_timestamp(format_timestamp(now(), 'Asia/Shanghai')),]] +`); + query(` ?[] <- [[rand_uuid_v1()]] `); \ No newline at end of file