feat: delete command — batch delete from CSV with confirmation

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
2026-04-21 16:02:06 +08:00
parent cb7d9212e0
commit 57c985ee3e
3 changed files with 134 additions and 0 deletions

View File

@@ -57,5 +57,33 @@ def backup(ctx, start, end, scan_path):
)
@main.command()
@click.option("--csv", "csv_path", required=True, type=click.Path(exists=True), help="Path to backup CSV to delete")
@click.pass_context
def delete(ctx, csv_path):
cfg = load_config(ctx.obj["config_path"])
from azure.data.tables import TableClient
from order_bak.delete import delete_orders
csv_file = Path(csv_path)
import csv as csv_mod
with open(csv_file, newline="") as f:
count = sum(1 for _ in csv_mod.DictReader(f))
click.echo(f"Will delete {count} orders from {csv_file}")
if not click.confirm("Continue?"):
click.echo("Aborted")
return
table = TableClient.from_connection_string(cfg.azure_connection_string, table_name="order")
delete_orders(
table_client=table,
csv_path=csv_file,
batch_size=cfg.delete_batch_size,
delay_ms=cfg.delete_delay_ms,
)
if __name__ == "__main__":
main()

39
src/order_bak/delete.py Normal file
View File

@@ -0,0 +1,39 @@
import csv
import time
from collections import defaultdict
from itertools import islice
from pathlib import Path
def _chunked(iterable, size):
it = iter(iterable)
while chunk := list(islice(it, size)):
yield chunk
def delete_orders(
table_client,
csv_path: Path,
batch_size: int,
delay_ms: int,
) -> int:
by_partition: dict[str, list[dict]] = defaultdict(list)
with open(csv_path, newline="") as f:
reader = csv.DictReader(f)
for row in reader:
pk = row["PartitionKey"]
rk = row["RowKey"]
by_partition[pk].append({"PartitionKey": pk, "RowKey": rk})
total_deleted = 0
for pk, entities in by_partition.items():
for batch in _chunked(entities, batch_size):
operations = [("delete", e) for e in batch]
table_client.submit_transaction(operations)
total_deleted += len(batch)
if delay_ms > 0:
time.sleep(delay_ms / 1000.0)
print(f"Deleted {total_deleted} orders across {len(by_partition)} partitions")
return total_deleted