Skip to content

Commit 3b1a572

Browse files
committed
Default to existing through table if inverse m2m assoc exists
1 parent 3df3b43 commit 3b1a572

File tree

1 file changed

+40
-13
lines changed

1 file changed

+40
-13
lines changed

src/ui/components/ModelForm/AssociationFieldset.tsx

Lines changed: 40 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -98,35 +98,37 @@ function AssociationFieldset({
9898
return
9999

100100
case AssociationTypeType.ManyToMany: {
101-
const table_name = defaultThroughTableName(model.name, targetModel.name)
101+
const table_name = defaultThroughTableName(model, targetModel, schema)
102102
handleChange({ type: manyToManyTableType(table_name) })
103103
return
104104
}
105105
}
106106
},
107-
[model.name, targetModel?.name, handleChange],
107+
[model, targetModel, schema, handleChange],
108108
)
109109

110110
const handleChangeTarget = React.useCallback(
111111
(newTargetModel: Model) => {
112+
// if current through table name is default, update table name to match new target
112113
if (
113114
isManytoMany(association) &&
114115
isThroughTable(association.type.through) &&
115-
snakeCase(association.type.through.table) ==
116-
defaultThroughTableName(model.name, targetModel.name)
116+
(snakeCase(association.type.through.table) ==
117+
throughTableName(model.name, targetModel.name) ||
118+
snakeCase(association.type.through.table) ==
119+
throughTableName(targetModel.name, model.name))
117120
) {
121+
const tableName = defaultThroughTableName(model, newTargetModel, schema)
122+
118123
handleChange({
119124
targetModelId: newTargetModel.id,
120-
type: {
121-
...association.type,
122-
through: throughTable(defaultThroughTableName(model.name, newTargetModel.name)),
123-
},
125+
type: { ...association.type, through: throughTable(tableName) },
124126
})
125127
} else {
126128
handleChange({ targetModelId: newTargetModel.id })
127129
}
128130
},
129-
[handleChange, association, targetModel, model],
131+
[handleChange, association, targetModel, model, schema],
130132
)
131133

132134
const handleChangeAlias = React.useCallback(
@@ -143,12 +145,13 @@ function AssociationFieldset({
143145
(type: ThroughType) => {
144146
if (!isManytoMany(association)) return
145147

146-
const table = defaultThroughTableName(model.name, targetModel.name)
147-
148148
if (type === ThroughType.ThroughTable) {
149+
const table = defaultThroughTableName(model, targetModel, schema)
150+
149151
handleChangeManyToMany({ through: throughTable(table) })
150152
return
151153
}
154+
const table = throughTableName(model.name, targetModel.name)
152155

153156
const throughModel =
154157
schema.models.find((m) => snakeCase(m.name) === table) || schema.models[0]
@@ -157,7 +160,7 @@ function AssociationFieldset({
157160
handleChangeManyToMany({ through: buildThroughModel(throughModel.id) })
158161
}
159162
},
160-
[association, model.name, targetModel, schema.models, handleChangeManyToMany],
163+
[association, model, targetModel, schema, handleChangeManyToMany],
161164
)
162165

163166
const handleChangeThroughModel = React.useCallback(
@@ -286,10 +289,34 @@ function aliasPlaceholder(association: Association, model: Model): string | unde
286289
: plural(model.name)
287290
}
288291

289-
function defaultThroughTableName(modelName: string, targetModelName: string): string {
292+
function throughTableName(modelName: string, targetModelName: string): string {
290293
return snakeCase(`${modelName} ${targetModelName}`)
291294
}
292295

296+
function defaultThroughTableName(sourceModel: Model, targetModel: Model, schema: Schema): string {
297+
const inverseAssociation = schema.models.reduce<string | undefined>(
298+
(acc, m) =>
299+
acc ||
300+
m.associations.reduce<string | undefined>(
301+
(acc, assoc) =>
302+
!acc &&
303+
assoc.targetModelId === sourceModel.id &&
304+
assoc.sourceModelId == targetModel.id &&
305+
assoc.type.type == AssociationTypeType.ManyToMany &&
306+
assoc.type.through.type === ThroughType.ThroughTable &&
307+
assoc.type.through.table == throughTableName(targetModel.name, sourceModel.name)
308+
? assoc.type.through.table
309+
: acc,
310+
undefined,
311+
),
312+
undefined,
313+
)
314+
315+
return inverseAssociation
316+
? throughTableName(targetModel.name, sourceModel.name)
317+
: throughTableName(sourceModel.name, targetModel.name)
318+
}
319+
293320
export function associationTypeId(association: Association): string {
294321
return `association-type-${association.id}`
295322
}

0 commit comments

Comments
 (0)