belongsToMany<T extends Model> method
- required PivotTable<
Model, Model> table, - DatabaseDisk disk = Model.defaultDisk,
Resolves many-to-many related models through a pivot table.
For SQLite, this method queries the pivot table, extracts sibling IDs, and
then loads all matching models with Model.whereIn.
Currently, pivot-table resolution is implemented for sqlite only.
Parameters:
table: The pivot table definition used to join the two models.disk: The storage backend. Defaults to Model.defaultDisk.
Returns an empty list when no related models are found or resolution fails.
Example:
final roles = await user.belongsToMany<Role>(
table: userRolesPivot,
disk: DatabaseDisk.sqlite,
);
Implementation
Future<List<T>> belongsToMany<T extends Model>({required PivotTable table, DatabaseDisk disk = Model.defaultDisk}) async {
try {
final pivotTableName = table.name;
final childPrefix = getInstanceTableSingularName();
final siblingPrefix = Model.getTableSingularName<T>();
switch (disk) {
case DatabaseDisk.sqlite:
final constructor = SQLiteModel.migrations[T];
if (constructor == null) return [];
// e.g user_role pivot table
final childField = "${childPrefix}_id";
final siblingField = "${siblingPrefix}_id";
//
final pivotRecords = await SQLiteModel.database.query(pivotTableName, where: '$childField = ?', whereArgs: [id]);
if (pivotRecords.isEmpty) return [];
final siblingIDs = pivotRecords.map((record) => record[siblingField]).toList();
if (siblingIDs.isEmpty) return [];
return await Model.whereIn<T>(column: 'id', values: siblingIDs);
case DatabaseDisk.file:
// TODO: Handle case.
throw UnimplementedError();
case DatabaseDisk.pgsql:
// TODO: Handle case.
throw UnimplementedError();
case DatabaseDisk.s3:
// TODO: Handle case.
throw UnimplementedError();
}
} catch(e, stack) {
App().archeryLogger.error("Error resolving belongsToMany", {"origin": "ext ModelRelationships belongsToMany", "error": e.toString(), "stack": stack.toString()});
return [];
}
}