mirror of
https://github.com/loro-dev/loro.git
synced 2025-01-22 21:07:43 +00:00
feat: get sub container directly when getting value (#175)
This commit is contained in:
parent
ef90e61ec5
commit
1ff1505933
5 changed files with 103 additions and 19 deletions
|
@ -38,6 +38,8 @@ pub enum LoroError {
|
|||
ArgErr(Box<str>),
|
||||
#[error("Auto commit has not started. The doc is readonly when detached. You should ensure autocommit is on and the doc and the state is attached.")]
|
||||
AutoCommitNotStarted,
|
||||
#[error("The doc is already dropped")]
|
||||
DocDropError,
|
||||
// #[error("the data for key `{0}` is not available")]
|
||||
// Redaction(String),
|
||||
// #[error("invalid header (expected {expected:?}, found {found:?})")]
|
||||
|
|
|
@ -124,18 +124,24 @@ impl Handler {
|
|||
impl Handler {
|
||||
fn new(
|
||||
txn: Weak<Mutex<Option<Transaction>>>,
|
||||
value: ContainerIdx,
|
||||
idx: ContainerIdx,
|
||||
state: Weak<Mutex<DocState>>,
|
||||
) -> Self {
|
||||
match value.get_type() {
|
||||
ContainerType::Map => Self::Map(MapHandler::new(txn, value, state)),
|
||||
ContainerType::List => Self::List(ListHandler::new(txn, value, state)),
|
||||
ContainerType::Tree => Self::Tree(TreeHandler::new(txn, value, state)),
|
||||
ContainerType::Text => Self::Text(TextHandler::new(txn, value, state)),
|
||||
match idx.get_type() {
|
||||
ContainerType::Map => Self::Map(MapHandler::new(txn, idx, state)),
|
||||
ContainerType::List => Self::List(ListHandler::new(txn, idx, state)),
|
||||
ContainerType::Tree => Self::Tree(TreeHandler::new(txn, idx, state)),
|
||||
ContainerType::Text => Self::Text(TextHandler::new(txn, idx, state)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, EnumAsInner, Debug)]
|
||||
pub enum ValueOrContainer {
|
||||
Value(LoroValue),
|
||||
Container(Handler),
|
||||
}
|
||||
|
||||
impl TextHandler {
|
||||
pub fn new(
|
||||
txn: Weak<Mutex<Option<Transaction>>>,
|
||||
|
@ -758,6 +764,30 @@ impl ListHandler {
|
|||
})
|
||||
}
|
||||
|
||||
/// Get value at given index, if it's a container, return a handler to the container
|
||||
pub fn get_(&self, index: usize) -> Option<ValueOrContainer> {
|
||||
let mutex = &self.state.upgrade().unwrap();
|
||||
let doc_state = &mutex.lock().unwrap();
|
||||
doc_state.with_state(self.container_idx, |state| {
|
||||
let a = state.as_list_state().unwrap();
|
||||
match a.get(index) {
|
||||
Some(v) => {
|
||||
if let LoroValue::Container(id) = v {
|
||||
let idx = doc_state.arena.register_container(id);
|
||||
Some(ValueOrContainer::Container(Handler::new(
|
||||
self.txn.clone(),
|
||||
idx,
|
||||
self.state.clone(),
|
||||
)))
|
||||
} else {
|
||||
Some(ValueOrContainer::Value(v.clone()))
|
||||
}
|
||||
}
|
||||
None => None,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub fn for_each<I>(&self, mut f: I)
|
||||
where
|
||||
I: FnMut(&LoroValue),
|
||||
|
@ -946,6 +976,28 @@ impl MapHandler {
|
|||
})
|
||||
}
|
||||
|
||||
/// Get the value at given key, if value is a container, return a handler to the container
|
||||
pub fn get_(&self, key: &str) -> Option<ValueOrContainer> {
|
||||
let mutex = &self.state.upgrade().unwrap();
|
||||
let doc_state = mutex.lock().unwrap();
|
||||
doc_state.with_state(self.container_idx, |state| {
|
||||
let a = state.as_map_state().unwrap();
|
||||
let value = a.get(key);
|
||||
match value {
|
||||
Some(LoroValue::Container(container_id)) => {
|
||||
let idx = doc_state.arena.register_container(container_id);
|
||||
Some(ValueOrContainer::Container(Handler::new(
|
||||
self.txn.clone(),
|
||||
idx,
|
||||
self.state.clone(),
|
||||
)))
|
||||
}
|
||||
Some(value) => Some(ValueOrContainer::Value(value.clone())),
|
||||
None => None,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub fn id(&self) -> ContainerID {
|
||||
self.state
|
||||
.upgrade()
|
||||
|
|
|
@ -6,7 +6,9 @@ use loro_internal::{
|
|||
ContainerID,
|
||||
},
|
||||
event::{Diff, Index},
|
||||
handler::{ListHandler, MapHandler, TextDelta, TextHandler, TreeHandler},
|
||||
handler::{
|
||||
Handler, ListHandler, MapHandler, TextDelta, TextHandler, TreeHandler, ValueOrContainer,
|
||||
},
|
||||
id::{Counter, PeerID, TreeID, ID},
|
||||
obs::SubID,
|
||||
version::Frontiers,
|
||||
|
@ -1231,7 +1233,7 @@ impl LoroMap {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
/// Get the value of the key.
|
||||
/// Get the value of the key. If the value is a container, the corresponding handler will be returned.
|
||||
///
|
||||
/// @example
|
||||
/// ```ts
|
||||
|
@ -1243,7 +1245,12 @@ impl LoroMap {
|
|||
/// const bar = map.get("foo");
|
||||
/// ```
|
||||
pub fn get(&self, key: &str) -> JsValue {
|
||||
self.0.get(key).into()
|
||||
let v = self.0.get_(key);
|
||||
match v {
|
||||
Some(ValueOrContainer::Container(c)) => handler_to_js_value(c),
|
||||
Some(ValueOrContainer::Value(v)) => v.into(),
|
||||
None => JsValue::UNDEFINED,
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the keys of the map.
|
||||
|
@ -1461,6 +1468,15 @@ impl LoroMap {
|
|||
}
|
||||
}
|
||||
|
||||
fn handler_to_js_value(handler: Handler) -> JsValue {
|
||||
match handler {
|
||||
Handler::Text(t) => LoroText(t).into(),
|
||||
Handler::Map(m) => LoroMap(m).into(),
|
||||
Handler::List(l) => LoroList(l).into(),
|
||||
Handler::Tree(t) => LoroTree(t).into(),
|
||||
}
|
||||
}
|
||||
|
||||
/// The handler of a list container.
|
||||
#[wasm_bindgen]
|
||||
pub struct LoroList(ListHandler);
|
||||
|
@ -1502,7 +1518,7 @@ impl LoroList {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
/// Get the value at the index.
|
||||
/// Get the value at the index. If the value is a container, the corresponding handler will be returned.
|
||||
///
|
||||
/// @example
|
||||
/// ```ts
|
||||
|
@ -1515,11 +1531,14 @@ impl LoroList {
|
|||
/// console.log(list.get(1)); // undefined
|
||||
/// ```
|
||||
pub fn get(&self, index: usize) -> JsValue {
|
||||
let Some(v) = self.0.get(index) else {
|
||||
let Some(v) = self.0.get_(index) else {
|
||||
return JsValue::UNDEFINED;
|
||||
};
|
||||
|
||||
JsValue::from(v)
|
||||
match v {
|
||||
ValueOrContainer::Value(v) => v.into(),
|
||||
ValueOrContainer::Container(h) => handler_to_js_value(h),
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the id of this container.
|
||||
|
|
|
@ -53,6 +53,7 @@ export type Value =
|
|||
| Uint8Array
|
||||
| Value[];
|
||||
|
||||
export type Container = LoroList | LoroMap | LoroText | LoroTree;
|
||||
export type Prelim = PrelimList | PrelimMap | PrelimText;
|
||||
|
||||
/**
|
||||
|
@ -109,8 +110,8 @@ export type MapDiff = {
|
|||
export type TreeDiff = {
|
||||
type: "tree";
|
||||
diff:
|
||||
| { target: TreeID; action: "create" | "delete" }
|
||||
| { target: TreeID; action: "move"; parent: TreeID };
|
||||
| { target: TreeID; action: "create" | "delete" }
|
||||
| { target: TreeID; action: "move"; parent: TreeID };
|
||||
};
|
||||
|
||||
export type Diff = ListDiff | TextDiff | MapDiff | TreeDiff;
|
||||
|
@ -148,7 +149,7 @@ declare module "loro-wasm" {
|
|||
insertContainer(pos: number, container: "Tree"): LoroTree;
|
||||
insertContainer(pos: number, container: string): never;
|
||||
|
||||
get(index: number): Value;
|
||||
get(index: number): undefined | Value | Container;
|
||||
getTyped<Key extends keyof T & number>(loro: Loro, index: Key): T[Key];
|
||||
insertTyped<Key extends keyof T & number>(pos: Key, value: T[Key]): void;
|
||||
insert(pos: number, value: Value | Prelim): void;
|
||||
|
@ -163,7 +164,7 @@ declare module "loro-wasm" {
|
|||
setContainer(key: string, container_type: "Tree"): LoroTree;
|
||||
setContainer(key: string, container_type: string): never;
|
||||
|
||||
get(key: string): Value;
|
||||
get(key: string): undefined | Value | Container;
|
||||
getTyped<Key extends keyof T & string>(txn: Loro, key: Key): T[Key];
|
||||
set(key: string, value: Value | Prelim): void;
|
||||
setTyped<Key extends keyof T & string>(key: Key, value: T[Key]): void;
|
||||
|
|
|
@ -84,14 +84,24 @@ describe("list", () => {
|
|||
map.set("key", "value");
|
||||
const v = list.get(0);
|
||||
console.log(v);
|
||||
expect(typeof v).toBe("string");
|
||||
const m = doc.getMap(v as ContainerID);
|
||||
expect(m.getDeepValue()).toStrictEqual({ key: "value" });
|
||||
expect(v instanceof LoroMap).toBeTruthy();
|
||||
expect(v.getDeepValue()).toStrictEqual({ key: "value" });
|
||||
});
|
||||
|
||||
it.todo("iterate");
|
||||
});
|
||||
|
||||
describe("map", () => {
|
||||
it("get child container", () => {
|
||||
const doc = new Loro();
|
||||
const map = doc.getMap("map");
|
||||
const list = map.setContainer("key", "List");
|
||||
list.insert(0, 1);
|
||||
expect(map.get("key") instanceof LoroList).toBeTruthy();
|
||||
expect(map.get("key").getDeepValue()).toStrictEqual([1]);
|
||||
});
|
||||
});
|
||||
|
||||
describe("import", () => {
|
||||
it("pending", () => {
|
||||
const a = new Loro();
|
||||
|
|
Loading…
Reference in a new issue