@@ -675,6 +675,196 @@ describe('OpenAPI Lookup field (e2e)', () => {
675675 } ) ;
676676 } ) ;
677677
678+ describe ( 'nested lookup dependencies' , ( ) => {
679+ let usersTable : ITableFullVo ;
680+ let projectsTable : ITableFullVo ;
681+ let tasksTable : ITableFullVo ;
682+ let userNameField : IFieldVo ;
683+ let projectNameField : IFieldVo ;
684+ let taskNameField : IFieldVo ;
685+ let projectOwnerLookupField : IFieldVo ;
686+ let taskOwnerLookupField : IFieldVo ;
687+ let projectLinkFieldId : string ;
688+ let taskLinkFieldId : string ;
689+ let userRecordId : string ;
690+ let projectRecordId : string ;
691+ let taskRecordId : string ;
692+
693+ const refreshFields = async ( table : ITableFullVo ) => {
694+ table . fields = await getFields ( table . id ) ;
695+ } ;
696+
697+ const getFieldByName = ( fields : IFieldVo [ ] , name : string ) => {
698+ const field = fields . find ( ( f ) => f . name === name ) ;
699+ if ( ! field ) {
700+ throw new Error ( `Field ${ name } not found` ) ;
701+ }
702+ return field ;
703+ } ;
704+
705+ beforeAll ( async ( ) => {
706+ usersTable = await createTable ( baseId , {
707+ name : 'lookup-nested-users' ,
708+ fields : [
709+ {
710+ name : 'User Name' ,
711+ type : FieldType . SingleLineText ,
712+ options : { } ,
713+ } ,
714+ ] ,
715+ } ) ;
716+
717+ projectsTable = await createTable ( baseId , {
718+ name : 'lookup-nested-projects' ,
719+ fields : [
720+ {
721+ name : 'Project Name' ,
722+ type : FieldType . SingleLineText ,
723+ options : { } ,
724+ } ,
725+ ] ,
726+ } ) ;
727+
728+ tasksTable = await createTable ( baseId , {
729+ name : 'lookup-nested-tasks' ,
730+ fields : [
731+ {
732+ name : 'Task Name' ,
733+ type : FieldType . SingleLineText ,
734+ options : { } ,
735+ } ,
736+ ] ,
737+ } ) ;
738+
739+ await refreshFields ( usersTable ) ;
740+ await refreshFields ( projectsTable ) ;
741+ await refreshFields ( tasksTable ) ;
742+
743+ userNameField = getFieldByName ( usersTable . fields , 'User Name' ) ;
744+ projectNameField = getFieldByName ( projectsTable . fields , 'Project Name' ) ;
745+ taskNameField = getFieldByName ( tasksTable . fields , 'Task Name' ) ;
746+
747+ const projectLinkField = await createField ( projectsTable . id , {
748+ name : 'Project -> User' ,
749+ type : FieldType . Link ,
750+ options : {
751+ relationship : Relationship . ManyOne ,
752+ foreignTableId : usersTable . id ,
753+ } ,
754+ } ) ;
755+ projectLinkFieldId = projectLinkField . id ;
756+
757+ await refreshFields ( projectsTable ) ;
758+ await refreshFields ( usersTable ) ;
759+
760+ projectOwnerLookupField = await createField ( projectsTable . id , {
761+ name : 'Project Owner (lookup)' ,
762+ type : FieldType . SingleLineText ,
763+ isLookup : true ,
764+ lookupOptions : {
765+ foreignTableId : usersTable . id ,
766+ linkFieldId : projectLinkFieldId ,
767+ lookupFieldId : userNameField . id ,
768+ } as ILookupOptionsRo ,
769+ } ) ;
770+
771+ await refreshFields ( projectsTable ) ;
772+
773+ const taskLinkField = await createField ( tasksTable . id , {
774+ name : 'Task -> Project' ,
775+ type : FieldType . Link ,
776+ options : {
777+ relationship : Relationship . ManyOne ,
778+ foreignTableId : projectsTable . id ,
779+ } ,
780+ } ) ;
781+ taskLinkFieldId = taskLinkField . id ;
782+
783+ await refreshFields ( tasksTable ) ;
784+ await refreshFields ( projectsTable ) ;
785+
786+ taskOwnerLookupField = await createField ( tasksTable . id , {
787+ name : 'Task Project Owner (lookup)' ,
788+ type : FieldType . SingleLineText ,
789+ isLookup : true ,
790+ lookupOptions : {
791+ foreignTableId : projectsTable . id ,
792+ linkFieldId : taskLinkFieldId ,
793+ lookupFieldId : projectOwnerLookupField . id ,
794+ } as ILookupOptionsRo ,
795+ } ) ;
796+
797+ await refreshFields ( tasksTable ) ;
798+
799+ const createdUsers = await createRecords ( usersTable . id , {
800+ fieldKeyType : FieldKeyType . Id ,
801+ records : [
802+ {
803+ fields : {
804+ [ userNameField . id ] : 'Alice' ,
805+ } ,
806+ } ,
807+ ] ,
808+ } ) ;
809+ userRecordId = createdUsers . records [ 0 ] . id ;
810+
811+ const createdProjects = await createRecords ( projectsTable . id , {
812+ fieldKeyType : FieldKeyType . Id ,
813+ records : [
814+ {
815+ fields : {
816+ [ projectNameField . id ] : 'Project Alpha' ,
817+ } ,
818+ } ,
819+ ] ,
820+ } ) ;
821+ projectRecordId = createdProjects . records [ 0 ] . id ;
822+
823+ await updateRecordByApi ( projectsTable . id , projectRecordId , projectLinkFieldId , {
824+ id : userRecordId ,
825+ } ) ;
826+
827+ const createdTasks = await createRecords ( tasksTable . id , {
828+ fieldKeyType : FieldKeyType . Id ,
829+ records : [
830+ {
831+ fields : {
832+ [ taskNameField . id ] : 'Task 1' ,
833+ } ,
834+ } ,
835+ ] ,
836+ } ) ;
837+ taskRecordId = createdTasks . records [ 0 ] . id ;
838+
839+ await updateRecordByApi ( tasksTable . id , taskRecordId , taskLinkFieldId , {
840+ id : projectRecordId ,
841+ } ) ;
842+ } ) ;
843+
844+ afterAll ( async ( ) => {
845+ await permanentDeleteTable ( baseId , tasksTable . id ) ;
846+ await permanentDeleteTable ( baseId , projectsTable . id ) ;
847+ await permanentDeleteTable ( baseId , usersTable . id ) ;
848+ } ) ;
849+
850+ it ( 'should recompute nested lookup values after relinking' , async ( ) => {
851+ let taskRecord = await getRecord ( tasksTable . id , taskRecordId ) ;
852+ expect ( taskRecord . fields [ taskOwnerLookupField . id ] ) . toEqual ( 'Alice' ) ;
853+
854+ await updateRecordByApi ( tasksTable . id , taskRecordId , taskLinkFieldId , null ) ;
855+
856+ taskRecord = await getRecord ( tasksTable . id , taskRecordId ) ;
857+ expect ( taskRecord . fields [ taskOwnerLookupField . id ] ) . toBeUndefined ( ) ;
858+
859+ await updateRecordByApi ( tasksTable . id , taskRecordId , taskLinkFieldId , {
860+ id : projectRecordId ,
861+ } ) ;
862+
863+ taskRecord = await getRecord ( tasksTable . id , taskRecordId ) ;
864+ expect ( taskRecord . fields [ taskOwnerLookupField . id ] ) . toEqual ( 'Alice' ) ;
865+ } ) ;
866+ } ) ;
867+
678868 describe ( 'lookup filter' , ( ) => {
679869 let table1 : ITableFullVo ;
680870 let table2 : ITableFullVo ;
0 commit comments