@@ -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