@@ -2,11 +2,11 @@ import { AdminForthPlugin, Filters } from "adminforth";
22import type { IAdminForth , IHttpServer , AdminForthResourcePages , AdminForthResourceColumn , AdminForthDataTypes , AdminForthResource } from "adminforth" ;
33import type { PluginOptions } from './types.js' ;
44
5- let junctionResource = null ;
6- let linkedColumnNameInJunctionResource = null ;
7- let resourceColumnNameInJunctionResource = null ;
8- export default class extends AdminForthPlugin {
5+ export default class ManyToManyPlugin extends AdminForthPlugin {
96 options : PluginOptions ;
7+ private junctionResource : AdminForthResource | null = null ;
8+ private linkedColumnNameInJunctionResource : string | null = null ;
9+ private resourceColumnNameInJunctionResource : string | null = null ;
1010
1111 constructor ( options : PluginOptions ) {
1212 super ( options , import . meta. url ) ;
@@ -27,23 +27,29 @@ export default class extends AdminForthPlugin {
2727 }
2828 }
2929 if ( wasLinkedResourceFound && wasCurrentResourceFound ) {
30- junctionResource = resource ;
30+ this . junctionResource = resource ;
3131 break ;
3232 }
3333 }
34- if ( ! junctionResource ) {
35- throw new Error ( `Junction resource not found for many-to-many relation between ${ resourceConfig . resourceId } and ${ this . options . linkedResourceId } ` ) ;
34+ if ( ! this . junctionResource ) {
35+ throw new Error (
36+ `Junction resource not found for many-to-many relation between ${ resourceConfig . resourceId } and ${ this . options . linkedResourceId } . ` +
37+ `Checked resources: ${ this . adminforth . config . resources . map ( r => r . resourceId ) . join ( ", " ) } `
38+ ) ;
3639 }
40+ this . linkedColumnNameInJunctionResource = this . junctionResource . columns . find ( c => c . foreignResource ?. resourceId === this . options . linkedResourceId ) ?. name || null ;
41+ this . resourceColumnNameInJunctionResource = this . junctionResource . columns . find ( c => c . foreignResource ?. resourceId === resourceConfig . resourceId ) ?. name || null ;
3742
38- linkedColumnNameInJunctionResource = junctionResource . columns . find ( c => c . foreignResource ?. resourceId === this . options . linkedResourceId ) ?. name ;
39- resourceColumnNameInJunctionResource = junctionResource . columns . find ( c => c . foreignResource ?. resourceId === resourceConfig . resourceId ) ?. name ;
43+ if ( ! this . linkedColumnNameInJunctionResource || ! this . resourceColumnNameInJunctionResource ) {
44+ throw new Error ( `Junction resource is missing foreign key columns for relation ${ resourceConfig . resourceId } <-> ${ this . options . linkedResourceId } ` ) ;
45+ }
4046
4147 const pluginFrontendOptions = {
4248 pluginInstanceId : this . pluginInstanceId ,
4349 resourceId : resourceConfig . resourceId ,
4450 linkedResourceId : this . options . linkedResourceId ,
45- junctionResourceId : junctionResource ? junctionResource . resourceId : null ,
46- linkedColumnName : linkedColumnNameInJunctionResource ,
51+ junctionResourceId : this . junctionResource . resourceId ,
52+ linkedColumnName : this . linkedColumnNameInJunctionResource ,
4753 resourcePrimaryKeyColumnName : resourceConfig . columns . find ( c => c . primaryKey ) ?. name ,
4854 }
4955
@@ -86,10 +92,10 @@ export default class extends AdminForthPlugin {
8692 if ( recordWithVirtualColumns [ `many2many_${ this . pluginInstanceId } ` ] ) {
8793 for ( const linkedId of recordWithVirtualColumns [ `many2many_${ this . pluginInstanceId } ` ] ) {
8894 await this . adminforth . createResourceRecord ( {
89- resource : junctionResource ,
95+ resource : this . junctionResource ,
9096 record : {
91- [ resourceColumnNameInJunctionResource ] : recordId ,
92- [ linkedColumnNameInJunctionResource ] : linkedId ,
97+ [ this . resourceColumnNameInJunctionResource ] : recordId ,
98+ [ this . linkedColumnNameInJunctionResource ] : linkedId ,
9399 } ,
94100 adminUser
95101 } ) ;
@@ -102,27 +108,28 @@ export default class extends AdminForthPlugin {
102108
103109 resourceConfig . hooks . edit . beforeSave . push ( async ( { recordId, updates, adminUser } : { recordId : any , updates : any , adminUser : any } ) => {
104110 if ( updates [ `many2many_${ this . pluginInstanceId } ` ] ) {
105- const existingJunctionRecords = await this . adminforth . resource ( junctionResource . resourceId ) . list ( [ Filters . EQ ( resourceColumnNameInJunctionResource , recordId ) ] ) ;
111+ const existingJunctionRecords = await this . adminforth . resource ( this . junctionResource . resourceId ) . list ( [ Filters . EQ ( this . resourceColumnNameInJunctionResource , recordId ) ] ) ;
112+ const junctionPkName = this . junctionResource . columns . find ( c => c . primaryKey ) ?. name ;
106113 const updatedLinkedIds = updates [ `many2many_${ this . pluginInstanceId } ` ] ;
107114 for ( const jr of existingJunctionRecords ) {
108- const linkedId = jr [ linkedColumnNameInJunctionResource ] ;
115+ const linkedId = jr [ this . linkedColumnNameInJunctionResource ] ;
109116 if ( ! updatedLinkedIds . includes ( linkedId ) ) {
110117 await this . adminforth . deleteResourceRecord ( {
111- resource : junctionResource ,
112- recordId : jr [ junctionResource . columns . find ( c => c . primaryKey ) . name ] ,
118+ resource : this . junctionResource ,
119+ recordId : jr [ junctionPkName ] ,
113120 record : jr ,
114121 adminUser
115122 } ) ;
116123 }
117124 }
118125 for ( const linkedId of updatedLinkedIds ) {
119- const alreadyExists = existingJunctionRecords . find ( jr => jr [ linkedColumnNameInJunctionResource ] === linkedId ) ;
126+ const alreadyExists = existingJunctionRecords . find ( jr => jr [ this . linkedColumnNameInJunctionResource ] === linkedId ) ;
120127 if ( ! alreadyExists ) {
121128 await this . adminforth . createResourceRecord ( {
122- resource : junctionResource ,
129+ resource : this . junctionResource ,
123130 record : {
124- [ resourceColumnNameInJunctionResource ] : recordId ,
125- [ linkedColumnNameInJunctionResource ] : linkedId ,
131+ [ this . resourceColumnNameInJunctionResource ] : recordId ,
132+ [ this . linkedColumnNameInJunctionResource ] : linkedId ,
126133 } ,
127134 adminUser
128135 } ) ;
@@ -135,24 +142,35 @@ export default class extends AdminForthPlugin {
135142 // ** HOOKS FOR DELETE **//
136143 if ( ! this . options . dontDeleteJunctionRecords ) {
137144 resourceConfig . hooks . delete . beforeSave . push ( async ( { recordId, record, adminUser } : { recordId : any , record : any , adminUser : any } ) => {
138- const existingJunctionRecords = await this . adminforth . resource ( junctionResource . resourceId ) . list ( [ Filters . EQ ( resourceColumnNameInJunctionResource , recordId ) ] ) ;
145+ if ( recordId === undefined || recordId === null || recordId === '' ) {
146+ return { ok : true } ;
147+ }
148+ const existingJunctionRecords = await this . adminforth . resource ( this . junctionResource . resourceId ) . list ( [ Filters . EQ ( this . resourceColumnNameInJunctionResource , recordId ) ] ) ;
149+ const junctionPkName = this . junctionResource . columns . find ( c => c . primaryKey ) ?. name ;
139150 for ( const jr of existingJunctionRecords ) {
140151 await this . adminforth . deleteResourceRecord ( {
141- resource : junctionResource ,
142- recordId : jr [ junctionResource . columns . find ( c => c . primaryKey ) . name ] ,
152+ resource : this . junctionResource ,
153+ recordId : jr [ junctionPkName ] ,
143154 record : jr ,
144155 adminUser
145156 } ) ;
146157 }
147158 return { ok : true } ;
148159 } ) ;
149160 const linkedResource = this . adminforth . config . resources . find ( r => r . resourceId === this . options . linkedResourceId ) ;
161+ if ( ! linkedResource ) {
162+ throw new Error ( `Linked resource not found: ${ this . options . linkedResourceId } ` ) ;
163+ }
150164 linkedResource . hooks . delete . beforeSave . push ( async ( { recordId, record, adminUser } : { recordId : any , record : any , adminUser : any } ) => {
151- const existingJunctionRecords = await this . adminforth . resource ( junctionResource . resourceId ) . list ( [ Filters . EQ ( linkedColumnNameInJunctionResource , recordId ) ] ) ;
165+ if ( recordId === undefined || recordId === null || recordId === '' ) {
166+ return { ok : true } ;
167+ }
168+ const existingJunctionRecords = await this . adminforth . resource ( this . junctionResource . resourceId ) . list ( [ Filters . EQ ( this . linkedColumnNameInJunctionResource , recordId ) ] ) ;
169+ const junctionPkName = this . junctionResource . columns . find ( c => c . primaryKey ) ?. name ;
152170 for ( const jr of existingJunctionRecords ) {
153171 await this . adminforth . deleteResourceRecord ( {
154- resource : junctionResource ,
155- recordId : jr [ junctionResource . columns . find ( c => c . primaryKey ) . name ] ,
172+ resource : this . junctionResource ,
173+ recordId : jr [ junctionPkName ] ,
156174 record : jr ,
157175 adminUser
158176 } ) ;
@@ -181,22 +199,30 @@ export default class extends AdminForthPlugin {
181199 if ( recordId === undefined || recordId === null || recordId === '' ) {
182200 return { ok : true , data : [ ] } ;
183201 }
184- const junctionRecords = await this . adminforth . resource ( junctionResource . resourceId ) . list ( [ Filters . EQ ( resourceColumnNameInJunctionResource , recordId ) ] ) ;
185- let dataToReturn = [ ] ;
186- const junctionResourcePkColumn = junctionResource . columns . find ( c => c . primaryKey ) ;
187- const linkedResource = this . adminforth . resource ( this . options . linkedResourceId ) ;
202+ const junctionRecords = await this . adminforth . resource ( this . junctionResource . resourceId ) . list ( [ Filters . EQ ( this . resourceColumnNameInJunctionResource , recordId ) ] ) ;
203+ const dataToReturn = [ ] ;
204+ const linkedResourceConfig = this . adminforth . config . resources . find ( r => r . resourceId === this . options . linkedResourceId ) ;
205+ if ( ! linkedResourceConfig ) {
206+ throw new Error ( `Linked resource not found: ${ this . options . linkedResourceId } ` ) ;
207+ }
208+ const linkedPkColumn = linkedResourceConfig . columns . find ( c => c . primaryKey ) ;
209+ if ( ! linkedPkColumn ) {
210+ throw new Error ( `Linked resource ${ this . options . linkedResourceId } has no primary key` ) ;
211+ }
212+ const linkedOperationalResource = this . adminforth . resource ( this . options . linkedResourceId ) ;
188213 for ( const jr of junctionRecords ) {
189- const record = await this . adminforth . resource ( this . options . linkedResourceId ) . get ( [ Filters . EQ ( junctionResourcePkColumn . name , jr [ linkedColumnNameInJunctionResource ] ) ] ) ;
190- if ( ! returnLabels ) {
191- dataToReturn . push ( record [ junctionResourcePkColumn . name ] ) ;
214+ const linkedId = jr [ this . linkedColumnNameInJunctionResource ] ;
215+ if ( ! returnLabels ) {
216+ dataToReturn . push ( linkedId ) ;
192217 } else {
193- dataToReturn . push (
194- ( linkedResource as any ) . resourceConfig . recordLabel ? {
195- label : ( linkedResource as any ) . resourceConfig . recordLabel ( record ) ,
196- value : record [ junctionResourcePkColumn . name ]
218+ const linkedRecord = await linkedOperationalResource . get ( [ Filters . EQ ( linkedPkColumn . name , linkedId ) ] ) ;
219+ dataToReturn . push (
220+ ( linkedOperationalResource as any ) . resourceConfig . recordLabel ? {
221+ label : ( linkedOperationalResource as any ) . resourceConfig . recordLabel ( linkedRecord ) ,
222+ value : linkedRecord [ linkedPkColumn . name ]
197223 } : {
198- label : record [ junctionResourcePkColumn . name ] ,
199- value : record [ junctionResourcePkColumn . name ]
224+ label : linkedRecord [ linkedPkColumn . name ] ,
225+ value : linkedRecord [ linkedPkColumn . name ]
200226 }
201227 ) ;
202228 }
0 commit comments