executeCascadeDeleteWithOptions method
Future<CascadeResult<T> >
executeCascadeDeleteWithOptions(
- String entityId,
- String userId,
- CascadeOptions options
Executes cascade delete with enhanced options (dry-run, progress, etc.).
Implementation
Future<CascadeResult<T>> executeCascadeDeleteWithOptions(
String entityId,
String userId,
CascadeOptions options,
) async {
final analyticsBuilder = CascadeAnalyticsBuilder();
analyticsBuilder.startOperation(dryRun: options.dryRun);
try {
_ensureInitialized();
// Check for cancellation at the start
if (options.cancellationToken?.isCancelled ?? false) {
analyticsBuilder.completeOperation();
return CascadeFailure<T>(
entity: null,
error: CascadeError.cancelled(),
);
}
// Check for user switch before proceeding.
await _syncEngineInstance.checkForUserSwitch(userId);
final entity = await localAdapter.read(entityId, userId: userId);
analyticsBuilder.recordQueryExecuted();
if (entity == null) {
analyticsBuilder.completeOperation();
return CascadeFailure<T>(
entity: null,
error: CascadeError.entityNotFound(entityId),
);
}
analyticsBuilder.recordEntityProcessed(entity.runtimeType);
if (!entity.isRelational) {
// Fall back to regular delete for non-relational entities
if (options.dryRun) {
analyticsBuilder.recordEntityDeleted(entity.runtimeType);
analyticsBuilder.completeOperation();
return CascadeSuccess<T>(
entity: entity,
totalDeleted: 1,
deletedEntities: {
T: [entity]
},
restrictedRelations: {},
analytics: analyticsBuilder.build(),
);
}
final deleted = await delete(id: entityId, userId: userId);
if (deleted) {
analyticsBuilder.recordEntityDeleted(entity.runtimeType);
analyticsBuilder.completeOperation();
return CascadeSuccess<T>(
entity: entity,
totalDeleted: 1,
deletedEntities: {
T: [entity]
},
restrictedRelations: {},
analytics: analyticsBuilder.build(),
);
} else {
analyticsBuilder.recordError();
analyticsBuilder.completeOperation();
return CascadeFailure<T>(
entity: entity,
error: CascadeError.deleteFailed(T.toString(), entityId, 'Delete operation failed'),
);
}
}
final deletePlan = await _buildCascadeDeletePlan(entity, userId, analyticsBuilder);
// For dry-run, just return the plan without executing
if (options.dryRun) {
final deletedEntities = <Type, List<DatumEntityInterface>>{};
var completed = 0;
// Simulate progress for dry-run
for (final step in deletePlan.steps) {
deletedEntities.putIfAbsent(step.entity.runtimeType, () => []).add(step.entity);
analyticsBuilder.recordEntityDeleted(step.entity.runtimeType);
completed++;
options.onProgress?.call(CascadeProgress(
completed: completed,
total: deletePlan.steps.length,
currentEntityType: step.entity.runtimeType.toString(),
currentEntityId: step.entity.id,
message: 'Planning deletion of ${step.entity.runtimeType.toString()}',
));
}
analyticsBuilder.completeOperation();
return CascadeSuccess<T>(
entity: entity,
totalDeleted: deletePlan.steps.length,
deletedEntities: deletedEntities,
restrictedRelations: deletePlan.restrictedRelations,
analytics: analyticsBuilder.build(),
);
}
if (!deletePlan.canDelete) {
final restrictedEntityIds = deletePlan.restrictedRelations.values.expand((entities) => entities).map((e) => e.id).toList();
analyticsBuilder.recordRestrictViolation();
analyticsBuilder.completeOperation();
return CascadeFailure<T>(
entity: entity,
error: CascadeError.restrictViolation(
deletePlan.restrictedRelations.keys.first,
restrictedEntityIds,
),
);
}
// Execute the delete plan with progress tracking
final result = await _executeCascadeDeletePlanWithProgress(
deletePlan,
userId,
DataSource.local,
false,
options,
analyticsBuilder,
);
// Emit the main entity delete event
_eventController.add(
DataChangeEvent<T>(
userId: userId,
data: entity,
changeType: ChangeType.deleted,
source: DataSource.local,
),
);
analyticsBuilder.completeOperation();
if (result.success) {
return CascadeSuccess<T>(
entity: entity,
totalDeleted: result.totalDeleted,
deletedEntities: result.deletedEntities,
restrictedRelations: result.restrictedRelations,
analytics: analyticsBuilder.build(),
);
} else {
analyticsBuilder.recordError();
return CascadeFailure<T>(
entity: entity,
error: CascadeError.deleteFailed(T.toString(), entityId, result.errors.join(', ')),
errors: result.errors,
);
}
} catch (e) {
analyticsBuilder.recordError();
analyticsBuilder.completeOperation();
rethrow;
}
}