Skip to content

Commit 4fde8ee

Browse files
committed
chore: support extract document sub page
1 parent ca88546 commit 4fde8ee

File tree

4 files changed

+643
-0
lines changed

4 files changed

+643
-0
lines changed

collab/src/database/database.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -395,6 +395,18 @@ impl Database {
395395
.collect()
396396
}
397397

398+
pub fn get_all_view_ids(&self, include_embedded: bool) -> Vec<DatabaseViewId> {
399+
let txn = self.collab.transact();
400+
self
401+
.body
402+
.views
403+
.get_all_views(&txn, include_embedded)
404+
.into_iter()
405+
.filter(|view| !view.is_inline && !view.embedded)
406+
.map(|view| view.id)
407+
.collect()
408+
}
409+
398410
pub fn get_database_view_layout(&self, view_id: &str) -> DatabaseLayout {
399411
let txn = self.collab.transact();
400412
match self.body.parse_view_id(view_id) {

collab/src/document/document.rs

Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -278,6 +278,121 @@ impl Document {
278278
Ok(block_ids)
279279
}
280280

281+
/// Database block types that can be embedded in a document
282+
pub const DATABASE_BLOCK_TYPES: &'static [&'static str] = &["grid", "board", "calendar"];
283+
284+
/// Get all embedded database blocks (grid, board, calendar) from the document.
285+
///
286+
/// Returns a vector of tuples containing:
287+
/// - block_id: The block's ID
288+
/// - block_type: The block type ("grid", "board", or "calendar")
289+
/// - view_ids: The database view IDs associated with this block
290+
/// - parent_id: The parent view ID (document ID for inline, original DB ID for linked)
291+
/// - database_id: The database storage ID
292+
pub fn get_embedded_database_blocks(
293+
&self,
294+
) -> Vec<EmbeddedDatabaseBlock> {
295+
let txn = self.collab.transact();
296+
let blocks = self.body.block_operation.get_all_blocks(&txn);
297+
298+
blocks
299+
.values()
300+
.filter(|block| Self::DATABASE_BLOCK_TYPES.contains(&block.ty.as_str()))
301+
.map(|block| {
302+
let view_ids = Self::extract_view_ids_from_block_data(&block.data);
303+
let parent_id = block
304+
.data
305+
.get("parent_id")
306+
.and_then(|v| v.as_str())
307+
.and_then(|s| Uuid::parse_str(s).ok());
308+
let database_id = block
309+
.data
310+
.get("database_id")
311+
.and_then(|v| v.as_str())
312+
.and_then(|s| Uuid::parse_str(s).ok());
313+
314+
EmbeddedDatabaseBlock {
315+
block_id: block.id.clone(),
316+
block_type: block.ty.clone(),
317+
view_ids,
318+
parent_id,
319+
database_id,
320+
}
321+
})
322+
.collect()
323+
}
324+
325+
/// Get all database view IDs from embedded database blocks.
326+
///
327+
/// This is a convenience method that returns just the view IDs
328+
/// without the full block information.
329+
pub fn get_embedded_database_view_ids(&self) -> Vec<Uuid> {
330+
self
331+
.get_embedded_database_blocks()
332+
.into_iter()
333+
.flat_map(|block| block.view_ids)
334+
.collect()
335+
}
336+
337+
/// Sub-page block type constant
338+
pub const SUB_PAGE_BLOCK_TYPE: &'static str = "sub_page";
339+
340+
/// Get all sub-page (linked document) IDs from the document.
341+
///
342+
/// This function iterates through all blocks and extracts the view_id
343+
/// from blocks with type "sub_page". Sub-pages are documents that are
344+
/// linked/embedded within another document.
345+
///
346+
/// # Returns
347+
/// A vector of UUIDs representing the view IDs of all linked sub-pages.
348+
pub fn get_sub_page_ids(&self) -> Vec<Uuid> {
349+
let txn = self.collab.transact();
350+
let blocks = self.body.block_operation.get_all_blocks(&txn);
351+
352+
blocks
353+
.values()
354+
.filter(|block| block.ty == Self::SUB_PAGE_BLOCK_TYPE)
355+
.filter_map(|block| {
356+
block
357+
.data
358+
.get("view_id")
359+
.and_then(|v| v.as_str())
360+
.and_then(|s| Uuid::parse_str(s).ok())
361+
})
362+
.collect()
363+
}
364+
365+
/// Extract view IDs from block data with backward compatibility.
366+
///
367+
/// Checks for new `view_ids` array first, then falls back to legacy `view_id`.
368+
fn extract_view_ids_from_block_data(data: &HashMap<String, Value>) -> Vec<Uuid> {
369+
// Try new format: view_ids array
370+
if let Some(view_ids_value) = data.get("view_ids") {
371+
if let Some(view_ids_array) = view_ids_value.as_array() {
372+
let view_ids: Vec<Uuid> = view_ids_array
373+
.iter()
374+
.filter_map(|v| v.as_str())
375+
.filter_map(|s| Uuid::parse_str(s).ok())
376+
.collect();
377+
378+
if !view_ids.is_empty() {
379+
return view_ids;
380+
}
381+
}
382+
}
383+
384+
// Fall back to legacy format: single view_id
385+
if let Some(view_id_value) = data.get("view_id") {
386+
if let Some(view_id_str) = view_id_value.as_str() {
387+
if let Ok(view_id) = Uuid::parse_str(view_id_str) {
388+
return vec![view_id];
389+
}
390+
}
391+
}
392+
393+
Vec::new()
394+
}
395+
281396
/// Get the plain text from the text block with the given id.
282397
///
283398
/// If the block is not found, return None.
@@ -1028,3 +1143,38 @@ impl From<&Document> for DocumentIndexContent {
10281143
Self { page_id, text }
10291144
}
10301145
}
1146+
1147+
/// Information about an embedded database block in a document.
1148+
///
1149+
/// Documents can contain embedded database blocks (grid, board, calendar) that reference
1150+
/// database views. This struct contains the extracted information from such blocks.
1151+
#[derive(Debug, Clone)]
1152+
pub struct EmbeddedDatabaseBlock {
1153+
/// The block ID in the document
1154+
pub block_id: String,
1155+
/// The block type: "grid", "board", or "calendar"
1156+
pub block_type: String,
1157+
/// The view IDs associated with this database block
1158+
pub view_ids: Vec<Uuid>,
1159+
/// The parent view ID (typically the document ID for inline databases,
1160+
/// or the original database ID for linked/referenced databases)
1161+
pub parent_id: Option<Uuid>,
1162+
/// The database storage ID
1163+
pub database_id: Option<Uuid>,
1164+
}
1165+
1166+
impl EmbeddedDatabaseBlock {
1167+
/// Returns true if this is an inline/embedded database (parent_id matches the document)
1168+
pub fn is_inline_database(&self, document_id: &Uuid) -> bool {
1169+
self.parent_id.as_ref() == Some(document_id)
1170+
}
1171+
1172+
/// Returns true if this is a linked/referenced database (parent_id differs from the document)
1173+
pub fn is_linked_database(&self, document_id: &Uuid) -> bool {
1174+
self
1175+
.parent_id
1176+
.as_ref()
1177+
.map(|pid| pid != document_id)
1178+
.unwrap_or(false)
1179+
}
1180+
}

0 commit comments

Comments
 (0)