updateExistingPivot method
Updates pivot table attributes for an existing pivot record.
Unlike attach with pivotData, this only updates the pivot attributes
for an already attached related model.
Example:
final post = await Post.query().find(1);
// Post has tag 5 attached with order=1
await post.updateExistingPivot('tags', 5, {'order': 2, 'featured': true});
// Pivot record updated
Implementation
Future<TModel> updateExistingPivot(
String relationName,
dynamic id,
Map<String, dynamic> pivotData,
) async {
final def = expectDefinition();
final resolver = _resolveResolverFor(def);
final relationDef = def.relations.cast<RelationDefinition?>().firstWhere(
(r) => r?.name == relationName,
orElse: () => null,
);
if (relationDef == null) {
throw ArgumentError(
'Relation "$relationName" not found on ${def.modelName}',
);
}
if (relationDef.kind != RelationKind.manyToMany) {
throw ArgumentError(
'updateExistingPivot() can only be used with manyToMany relations. '
'Relation "$relationName" is ${relationDef.kind}',
);
}
// Get this model's primary key value
final pk = def.primaryKeyField;
if (pk == null) {
throw StateError('Model ${def.modelName} must have a primary key');
}
final pkValue = _primaryKeyValue(def);
if (pkValue == null) {
throw StateError('Model ${def.modelName} primary key value is null');
}
final pivotTable = relationDef.through;
if (pivotTable == null) {
throw StateError(
'Relation "$relationName" is missing pivot table name (through)',
);
}
final pivotForeignKey = relationDef.pivotForeignKey!;
final pivotRelatedKey = relationDef.pivotRelatedKey!;
// Get the related model definition
final relatedModelName = relationDef.targetModel;
final relatedDef = resolver.registry.expectByName(relatedModelName);
final relatedPk = relatedDef.primaryKeyField;
if (relatedPk == null) {
throw StateError(
'Related model $relatedModelName must have a primary key',
);
}
final pivotValues = _mergePivotTimestamps(
relationDef,
pivotData,
isInsert: false,
);
final pivotFieldDefs = _pivotModelFieldDefinitions(
relationDef,
resolver,
);
final pivotDef = _createPivotDefinition(
pivotTable,
def.schema,
_pivotColumnDefinitions(
pivotFieldDefs: pivotFieldDefs,
foreignKey: pivotForeignKey,
foreignKeyField: pk,
relatedKey: pivotRelatedKey,
relatedKeyField: relatedPk,
pivotValues: pivotValues,
timestampFields: _pivotTimestampFieldDefinitions(relationDef),
),
);
// Update the pivot record
final plan = MutationPlan.update(
definition: pivotDef,
rows: [
MutationRow(
values: pivotValues,
keys: {pivotForeignKey: pkValue, pivotRelatedKey: id},
),
],
);
await resolver.runMutation(plan);
await _touchIfTouching(relationDef, def, resolver);
// Reload the relation to sync cache
await load(relationName);
return _self();
}