@@ -101,14 +101,42 @@ impl SqlDoc {
101101 ///
102102 /// # Parameters
103103 /// - the table `name` as a [`str`]
104+ /// - the table schema as `Option` of [`str`]
104105 ///
105106 /// # Errors
106107 /// - Will return [`DocError::TableNotFound`] if the expected table is not found
107- pub fn table ( & self , name : & str ) -> Result < & TableDoc , DocError > {
108- self . tables ( ) . binary_search_by ( |t| t. name ( ) . cmp ( name) ) . map_or_else (
109- |_| Err ( DocError :: TableNotFound { name : name. to_owned ( ) } ) ,
110- |id| Ok ( & self . tables ( ) [ id] ) ,
111- )
108+ /// - Will return [`DocError::TableWithSchemaNotFound`] if the table name exists but no table matches the given schema
109+ /// - Will return [`DocError::DuplicateTablesFound`] if more than one matching table is found
110+ pub fn table ( & self , name : & str , schema : Option < & str > ) -> Result < & TableDoc , DocError > {
111+ let tables = self . tables ( ) ;
112+ let start = tables. partition_point ( |n| n. name ( ) < name) ;
113+ if start == tables. len ( ) || tables[ start] . name ( ) != name {
114+ return Err ( DocError :: TableNotFound { name : name. to_owned ( ) } ) ;
115+ }
116+ let end = tables. partition_point ( |t| t. name ( ) <= name) ;
117+ match & tables[ start..end] {
118+ [ single] => Ok ( single) ,
119+ multiple => {
120+ let mut schemas = multiple. iter ( ) . filter ( |v| v. schema ( ) == schema) ;
121+ let first = schemas. next ( ) . ok_or_else ( || DocError :: TableWithSchemaNotFound {
122+ name : name. to_owned ( ) ,
123+ schema : schema. map_or_else (
124+ || "No schema provided" . to_owned ( ) ,
125+ std:: borrow:: ToOwned :: to_owned,
126+ ) ,
127+ } ) ?;
128+ if schemas. next ( ) . is_some ( ) {
129+ return Err ( DocError :: DuplicateTablesFound {
130+ tables : multiple
131+ . iter ( )
132+ . filter ( |v| v. schema ( ) == schema)
133+ . map ( std:: borrow:: ToOwned :: to_owned)
134+ . collect ( ) ,
135+ } ) ;
136+ }
137+ Ok ( first)
138+ }
139+ }
112140 }
113141
114142 /// Method for finding a specific [`TableDoc`] from `schema` and table `name`
@@ -374,7 +402,7 @@ mod tests {
374402 let expected_doc = SqlDoc :: new ( expected_tables) ;
375403 assert_eq ! ( sql_doc, expected_doc) ;
376404 let table = "users" ;
377- assert_eq ! ( sql_doc. table( table) ?, expected_doc. table( table) ?) ;
405+ assert_eq ! ( sql_doc. table( table, None ) ?, expected_doc. table( table, None ) ?) ;
378406 let schema = "analytics" ;
379407 let schema_table = "events" ;
380408 assert_eq ! (
@@ -388,7 +416,7 @@ mod tests {
388416 #[ test]
389417 fn test_table_err ( ) {
390418 let empty_set = SqlDoc :: new ( vec ! [ ] ) ;
391- let empty_table_err = empty_set. table ( "name" ) ;
419+ let empty_table_err = empty_set. table ( "name" , None ) ;
392420 assert ! ( empty_table_err. is_err( ) ) ;
393421 assert ! ( matches!(
394422 empty_table_err,
@@ -769,4 +797,46 @@ mod tests {
769797 . unwrap_or_else ( |_| panic ! ( "expected to find table `users` via binary search" ) ) ;
770798 assert_eq ! ( sql_doc. tables( ) [ id] . name( ) , "users" ) ;
771799 }
800+
801+ #[ test]
802+ fn test_table_with_schema_not_found_when_name_exists ( ) {
803+ let sql_doc = SqlDoc :: new ( vec ! [
804+ TableDoc :: new( Some ( "analytics" . to_owned( ) ) , "events" . to_owned( ) , None , vec![ ] , None ) ,
805+ TableDoc :: new( Some ( "public" . to_owned( ) ) , "events" . to_owned( ) , None , vec![ ] , None ) ,
806+ ] ) ;
807+
808+ match sql_doc. table ( "events" , Some ( "missing" ) ) {
809+ Err ( DocError :: TableWithSchemaNotFound { name, schema } )
810+ if name == "events" && schema == "missing" => { }
811+ Err ( e) => panic ! ( "expected TableWithSchemaNotFound(events, missing), got: {e:?}" ) ,
812+ Ok ( _) => panic ! ( "expected error, got Ok" ) ,
813+ }
814+ }
815+
816+ #[ test]
817+ fn test_table_duplicate_tables_found_for_same_name_and_schema ( ) {
818+ let sql_doc = SqlDoc :: new ( vec ! [
819+ TableDoc :: new( Some ( "analytics" . to_owned( ) ) , "events" . to_owned( ) , None , vec![ ] , None ) ,
820+ TableDoc :: new( Some ( "analytics" . to_owned( ) ) , "events" . to_owned( ) , None , vec![ ] , None ) ,
821+ ] ) ;
822+
823+ match sql_doc. table ( "events" , Some ( "analytics" ) ) {
824+ Err ( DocError :: DuplicateTablesFound { .. } ) => { }
825+ Err ( e) => panic ! ( "expected DuplicateTablesFound, got: {e:?}" ) ,
826+ Ok ( _) => panic ! ( "expected error, got Ok" ) ,
827+ }
828+ }
829+
830+ #[ test]
831+ fn test_table_selects_correct_schema_when_multiple_exist ( )
832+ -> Result < ( ) , Box < dyn std:: error:: Error > > {
833+ let sql_doc = SqlDoc :: new ( vec ! [
834+ TableDoc :: new( Some ( "analytics" . to_owned( ) ) , "events" . to_owned( ) , None , vec![ ] , None ) ,
835+ TableDoc :: new( Some ( "public" . to_owned( ) ) , "events" . to_owned( ) , None , vec![ ] , None ) ,
836+ ] ) ;
837+
838+ let t = sql_doc. table ( "events" , Some ( "public" ) ) ?;
839+ assert_eq ! ( t. schema( ) , Some ( "public" ) ) ;
840+ Ok ( ( ) )
841+ }
772842}
0 commit comments