@@ -4,12 +4,14 @@ import { useMemo } from "react";
44import { useQuery } from "@tanstack/react-query" ;
55import { schemaAPI , brainAPI , companyKnowledgeAPI } from "@/lib/api/client" ;
66import { queryKeys } from "@/lib/queryKeys" ;
7+ import {
8+ canonicalTableReference ,
9+ isDefaultSchema ,
10+ stripIdentQuotes ,
11+ } from "@/lib/schemaNames" ;
712
813function normalizeIdentifier ( value ) {
9- return ( value || "" )
10- . trim ( )
11- . replace ( / [ ` " \[ \] ] / g, "" )
12- . toLowerCase ( ) ;
14+ return stripIdentQuotes ( value ) . toLowerCase ( ) ;
1315}
1416
1517function identifierTail ( value , segments = 1 ) {
@@ -26,16 +28,6 @@ function referenceAliases(value) {
2628 return new Set ( [ normalized , identifierTail ( normalized , 1 ) , identifierTail ( normalized , 2 ) ] . filter ( Boolean ) )
2729}
2830
29- function canonicalTableReference ( table ) {
30- const tableName = ( table ?. tableName || table ?. name || "" ) . trim ( ) . replace ( / [ ` " \[ \] ] / g, "" )
31- const schemaName = ( table ?. schema || table ?. schemaName || "" ) . trim ( ) . replace ( / [ ` " \[ \] ] / g, "" )
32- if ( ! tableName ) return ""
33- if ( ! schemaName || schemaName === "public" || schemaName === "dbo" ) {
34- return tableName
35- }
36- return `${ schemaName } .${ tableName } `
37- }
38-
3931function tableAliases ( table ) {
4032 const canonical = normalizeIdentifier ( canonicalTableReference ( table ) )
4133 const bare = normalizeIdentifier ( table ?. tableName || table ?. name || "" )
@@ -140,7 +132,10 @@ export function useSchemaDocsData(connectionId) {
140132 const bareName = rawName . includes ( "." )
141133 ? rawName . split ( "." ) . pop ( )
142134 : rawName ;
143- const keys = rawName === bareName ? [ rawName ] : [ rawName , bareName ] ;
135+ // Index qualified notes only under their full key so crm.orders and
136+ // sales.orders never share a slot. Bare notes stay under the bare key
137+ // for default-schema / legacy rows.
138+ const keys = rawName . includes ( "." ) ? [ rawName ] : [ bareName ] ;
144139 if ( note . scopeType === "TABLE" || ( ! note . scopeType && ! note . columnName ) ) {
145140 for ( const k of keys ) {
146141 tableNotes [ k ] = considerWinner ( tableNotes [ k ] , note ) ;
@@ -154,10 +149,16 @@ export function useSchemaDocsData(connectionId) {
154149 }
155150 }
156151
157- // Build classification lookup (case-insensitive)
152+ // Build classification lookup (case-insensitive). Prefer schema.table keys.
158153 const roleMap = { } ;
159154 for ( const c of classifications ) {
160- roleMap [ ( c . tableName || "" ) . toLowerCase ( ) ] = c . role || c . tableRole ;
155+ const bare = ( c . tableName || "" ) . toLowerCase ( ) ;
156+ const schema = ( c . schemaName || c . schema || "" ) . toLowerCase ( ) ;
157+ const qualified =
158+ schema && ! isDefaultSchema ( schema ) ? `${ schema } .${ bare } ` : bare ;
159+ if ( qualified ) roleMap [ qualified ] = c . role || c . tableRole ;
160+ // Bare fallback only when classification itself is unqualified.
161+ if ( bare && ! schema ) roleMap [ bare ] = c . role || c . tableRole ;
161162 }
162163
163164 let totalTablesDocumented = 0 ;
@@ -168,10 +169,17 @@ export function useSchemaDocsData(connectionId) {
168169 // Normalize: API uses `name`, plan assumed `tableName`
169170 const tableName = table . tableName || table . name || "" ;
170171 const tableReference = canonicalTableReference ( table )
171- const tKey = tableName . toLowerCase ( ) ;
172- const tableNote = tableNotes [ tKey ] || null ;
173- const colNotes = columnNotes [ tKey ] || { } ;
174- const role = roleMap [ tKey ] || null ;
172+ const refKey = normalizeIdentifier ( tableReference ) ;
173+ const bareKey = normalizeIdentifier ( tableName ) ;
174+ // Prefer exact reference match; only fall back to bare for default-schema tables.
175+ const tableNote =
176+ tableNotes [ refKey ] ||
177+ ( refKey === bareKey ? tableNotes [ bareKey ] : null ) ;
178+ const colNotes =
179+ columnNotes [ refKey ] ||
180+ ( refKey === bareKey ? columnNotes [ bareKey ] : { } ) ||
181+ { } ;
182+ const role = roleMap [ refKey ] || ( refKey === bareKey ? roleMap [ bareKey ] : null ) || null ;
175183 const tableAliasSet = tableAliases ( table )
176184 const linkedKnowledge = knowledgeEntries . filter ( ( entry ) => {
177185 const linkedTables = Array . isArray ( entry ?. linkedTables ) ? entry . linkedTables : [ ]
@@ -220,6 +228,7 @@ export function useSchemaDocsData(connectionId) {
220228 return {
221229 tableName,
222230 tableReference,
231+ schemaName : table . schema || table . schemaName || "" ,
223232 rowCount : table . rowCount ,
224233 note : tableNote ,
225234 role,
@@ -230,8 +239,10 @@ export function useSchemaDocsData(connectionId) {
230239 } ;
231240 } ) ;
232241
233- // Sort tables alphabetically
234- tables . sort ( ( a , b ) => a . tableName . localeCompare ( b . tableName ) ) ;
242+ // Sort by qualified reference so schemas cluster together
243+ tables . sort ( ( a , b ) =>
244+ ( a . tableReference || a . tableName ) . localeCompare ( b . tableReference || b . tableName )
245+ ) ;
235246
236247 return {
237248 tables,
0 commit comments