Files
AFFiNE-Mirror/packages/common/y-octo/node/src/doc.rs
T
Brooooooklyn 83f7093144 chore(y-octo): migrate away depracated JsExternal API (#12130)
<!-- This is an auto-generated comment: release notes by coderabbit.ai -->

## Summary by CodeRabbit

- **Refactor**
  - Updated usage of JavaScript interop types to newer API versions for improved compatibility and consistency.
  - Changed method and type signatures to use updated types in several areas.
  - Removed an unused constructor from one component.
  - Adjusted a method to use a different JavaScript array buffer type for update callbacks.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-05-06 07:24:54 +00:00

177 lines
3.8 KiB
Rust

use napi::{
bindgen_prelude::Uint8Array,
threadsafe_function::{ThreadsafeFunction, ThreadsafeFunctionCallMode},
};
use y_octo::{CrdtRead, Doc as YDoc, History, RawDecoder, StateVector};
use super::*;
#[napi]
pub struct Doc {
doc: YDoc,
}
#[napi]
impl Doc {
#[napi(constructor)]
pub fn new(client_id: Option<i64>) -> Self {
Self {
doc: if let Some(client_id) = client_id {
YDoc::with_client(client_id as u64)
} else {
YDoc::default()
},
}
}
#[napi(getter)]
pub fn client_id(&self) -> i64 {
self.doc.client() as i64
}
#[napi(getter)]
pub fn guid(&self) -> &str {
self.doc.guid()
}
#[napi(getter)]
pub fn keys(&self) -> Vec<String> {
self.doc.keys()
}
#[napi]
pub fn get_or_create_array(&self, key: String) -> Result<YArray> {
self
.doc
.get_or_create_array(key)
.map(YArray::inner_new)
.map_err(anyhow::Error::from)
}
#[napi]
pub fn get_or_create_text(&self, key: String) -> Result<YText> {
self
.doc
.get_or_create_text(key)
.map(YText::inner_new)
.map_err(anyhow::Error::from)
}
#[napi]
pub fn get_or_create_map(&self, key: String) -> Result<YMap> {
self
.doc
.get_or_create_map(key)
.map(YMap::inner_new)
.map_err(anyhow::Error::from)
}
#[napi]
pub fn create_array(&self) -> Result<YArray> {
self
.doc
.create_array()
.map(YArray::inner_new)
.map_err(anyhow::Error::from)
}
#[napi]
pub fn create_text(&self) -> Result<YText> {
self
.doc
.create_text()
.map(YText::inner_new)
.map_err(anyhow::Error::from)
}
#[napi]
pub fn create_map(&self) -> Result<YMap> {
self
.doc
.create_map()
.map(YMap::inner_new)
.map_err(anyhow::Error::from)
}
#[napi]
pub fn apply_update(&mut self, update: &[u8]) -> Result<()> {
self.doc.apply_update_from_binary_v1(update)?;
Ok(())
}
#[napi]
pub fn encode_state_as_update_v1(&self, state: Option<&[u8]>) -> Result<Uint8Array> {
let result = match state {
Some(state) => {
let mut decoder = RawDecoder::new(state);
let state = StateVector::read(&mut decoder)?;
self.doc.encode_state_as_update_v1(&state)
}
None => self.doc.encode_update_v1(),
};
result.map(|v| v.into()).map_err(anyhow::Error::from)
}
#[napi]
pub fn gc(&self) -> Result<()> {
self.doc.gc().map_err(anyhow::Error::from)
}
#[napi(ts_args_type = "callback: (result: Uint8Array) => void")]
pub fn on_update(&mut self, callback: ThreadsafeFunction<Uint8Array>) -> Result<()> {
let callback = move |update: &[u8], _h: &[History]| {
callback.call(
Ok(update.to_vec().into()),
ThreadsafeFunctionCallMode::Blocking,
);
};
self.doc.subscribe(Box::new(callback));
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_doc_client() {
let client_id = 1;
let doc = Doc::new(Some(client_id));
assert_eq!(doc.client_id(), 1);
}
#[test]
fn test_doc_guid() {
let doc = Doc::new(None);
assert_eq!(doc.guid().len(), 21);
}
#[test]
fn test_create_array() {
let doc = Doc::new(None);
let array = doc.get_or_create_array("array".into()).unwrap();
assert_eq!(array.length(), 0);
}
#[test]
fn test_create_text() {
let doc = Doc::new(None);
let text = doc.get_or_create_text("text".into()).unwrap();
assert_eq!(text.len(), 0);
}
#[test]
fn test_keys() {
let doc = Doc::new(None);
doc.get_or_create_array("array".into()).unwrap();
doc.get_or_create_text("text".into()).unwrap();
doc.get_or_create_map("map".into()).unwrap();
let mut keys = doc.keys();
keys.sort();
assert_eq!(keys, vec!["array", "map", "text"]);
}
}