attach method

Future<bool> attach(
  1. Model sibling, {
  2. required ModelRelationshipType relationship,
  3. PivotTable<Model, Model>? table,
  4. DatabaseDisk disk = Model.defaultDisk,
})

Attaches sibling to this model using the given relationship type.

Behavior depends on the relationship:

  • hasOne / hasMany: writes this model's foreign key onto sibling
  • belongsToOne: writes the sibling foreign key onto this model
  • belongsToMany: inserts a pivot-table record

For belongsToMany, table is required.

Returns true when the relationship is successfully attached; otherwise returns false.

Example:

await user.attach(
  profile,
  relationship: ModelRelationshipType.hasOne,
);

await user.attach(
  role,
  relationship: ModelRelationshipType.belongsToMany,
  table: UserRolePivotTable,
  disk: DatabaseDisk.sqlite,
);

Implementation

Future<bool> attach(Model sibling, {required ModelRelationshipType relationship, PivotTable? table, DatabaseDisk disk = Model.defaultDisk,}) async {
  try {

    final childPrefix = getInstanceTableSingularName();
    final siblingPrefix = sibling.getInstanceTableSingularName();

    switch (relationship) {

      case .hasOne:
      case .hasMany:

        switch (disk) {
          case .sqlite:
          case .pgsql:
            final childField = "${childPrefix}_id";
            return await sibling.update(withJson: {childField: id});

          case .file:
          case .s3:
            final childField = "${childPrefix}_uuid";
            return await sibling.update(withJson: {childField: uuid});
        }

      case .belongsToOne:
        switch (disk) {
          case .sqlite:
          case .pgsql:
            final siblingField = "${siblingPrefix}_id";
            return  update(withJson: {siblingField: sibling.id});

          case .file:
          case .s3:
            final siblingField = "${siblingPrefix}_uuid";
            return await update(withJson: {siblingField: sibling.uuid});
        }

      case .belongsToMany:

        if(table == null) {
          return false;
        }

        switch(disk) {
          case .sqlite:

            final sqliteDB = App().container.make<SQLiteDatabase>();
            final tableName = table.name;

            final childPrefix = getInstanceTableSingularName();
            final childField = "${childPrefix}_id";

            final siblingPrefix = sibling.getInstanceTableSingularName();
            final siblingField = "${siblingPrefix}_id";

            final createdAt = DateTime.now().toIso8601String();
            final updatedAt = DateTime.now().toIso8601String();

            await sqliteDB.rawInsert(
                'INSERT INTO $tableName ($childField, $siblingField, created_at, updated_at) VALUES(?, ?, ?, ?)',
                [id, sibling.id, createdAt, updatedAt]
            );

            return true;

        // todo : pivot tables currently implemented for sqlite.
          case DatabaseDisk.file:
            throw UnimplementedError();
          case DatabaseDisk.pgsql:
            throw UnimplementedError();
          case DatabaseDisk.s3:
            throw UnimplementedError();
        }
    }
  } catch(e,stack) {
    App().archeryLogger.error("Error attaching sibling", {"origin": "ext ModelRelationshipOps attach", "error": e.toString(), "stack": stack.toString()});
    return false;
  }
}