tinybird 4.6.3.dev0__py3-none-any.whl → 4.6.5.dev0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
tinybird/sql_toolset.py CHANGED
@@ -158,7 +158,7 @@ def has_unoptimized_join(sql: str, left_table: Optional[Union[Tuple[str, str], T
158
158
  raise UnoptimizedJoinException(sql)
159
159
 
160
160
 
161
- def format_where_for_mutation_command(where_clause: str) -> str:
161
+ def format_where_for_mutation_command(where_clause: str, lightweight: bool = False) -> str:
162
162
  """
163
163
  >>> format_where_for_mutation_command("numnights = 99")
164
164
  'DELETE WHERE numnights = 99'
@@ -170,11 +170,14 @@ def format_where_for_mutation_command(where_clause: str) -> str:
170
170
  "DELETE WHERE reservationid = \\\\'\\\\\\\\\\\\'foo\\\\'"
171
171
  >>> format_where_for_mutation_command("reservationid = '\\\\'foo'")
172
172
  "DELETE WHERE reservationid = \\\\'\\\\\\\\\\\\'foo\\\\'"
173
+ >>> format_where_for_mutation_command("number < 3", lightweight=True)
174
+ 'UPDATE _row_exists = 0 WHERE number < 3'
173
175
  """
174
176
  formatted_condition = chquery.format(f"""SELECT {where_clause}""").split("SELECT ")[1]
175
177
  formatted_condition = formatted_condition.replace("\\", "\\\\").replace("'", "''")
176
178
  quoted_condition = chquery.format(f"SELECT '{formatted_condition}'").split("SELECT ")[1]
177
- return f"DELETE WHERE {quoted_condition[1:-1]}"
179
+ prefix = "UPDATE _row_exists = 0 WHERE" if lightweight else "DELETE WHERE"
180
+ return f"{prefix} {quoted_condition[1:-1]}"
178
181
 
179
182
 
180
183
  # Functions that take table/dictionary names as string literal arguments.
tinybird/tb/__cli__.py CHANGED
@@ -4,5 +4,5 @@ __description__ = 'Tinybird Command Line Tool'
4
4
  __url__ = 'https://www.tinybird.co/docs/forward/commands'
5
5
  __author__ = 'Tinybird'
6
6
  __author_email__ = 'support@tinybird.co'
7
- __version__ = '4.6.3.dev0'
8
- __revision__ = '78e5916'
7
+ __version__ = '4.6.5.dev0'
8
+ __revision__ = 'cad29af'
tinybird/tb/client.py CHANGED
@@ -468,10 +468,26 @@ class TinyB:
468
468
  """Start Kafka ingestion for a datasource in a forward branch."""
469
469
  return self._req(f"/v0/datasources/{datasource_name}/start", method="POST", data="")
470
470
 
471
- def datasource_delete_rows(self, datasource_name: str, delete_condition: str, dry_run: bool = False):
472
- params = {"delete_condition": delete_condition}
473
- if dry_run:
474
- params.update({"dry_run": "true"})
471
+ def datasource_delete_rows(
472
+ self,
473
+ datasource_name: str,
474
+ delete_condition: str,
475
+ dry_run: bool = False,
476
+ lightweight: bool = False,
477
+ wait: bool = True,
478
+ partition: Optional[str] = None,
479
+ projection_mode: Optional[str] = None,
480
+ ):
481
+ params: Dict[str, Any] = {"delete_condition": delete_condition}
482
+ if lightweight:
483
+ params["wait"] = "true" if wait else "false"
484
+ if partition:
485
+ params["partition"] = partition
486
+ if projection_mode:
487
+ params["projection_mode"] = projection_mode
488
+ return self._req(f"/v1/datasources/{datasource_name}/delete", method="POST", data=params)
489
+ elif dry_run:
490
+ params["dry_run"] = "true"
475
491
  return self._req(f"/v0/datasources/{datasource_name}/delete", method="POST", data=params)
476
492
 
477
493
  def datasource_dependencies(
@@ -596,19 +596,66 @@ def datasource_start(ctx: Context, datasource_name: str) -> None:
596
596
  @click.argument("datasource_name")
597
597
  @click.option("--sql-condition", default=None, help="SQL WHERE condition to remove rows", hidden=True, required=True)
598
598
  @click.option("--yes", is_flag=True, default=False, help="Do not ask for confirmation")
599
- @click.option("--wait", is_flag=True, default=False, help="Wait for delete job to finish, disabled by default")
599
+ @click.option(
600
+ "--wait/--no-wait",
601
+ default=None,
602
+ help="Wait for the delete to finish. Defaults to true with --lightweight-delete (sync request), "
603
+ "false otherwise (returns a job id).",
604
+ )
600
605
  @click.option("--dry-run", is_flag=True, default=False, help="Run the command without deleting anything")
606
+ @click.option(
607
+ "--lightweight-delete",
608
+ "lightweight",
609
+ is_flag=True,
610
+ default=False,
611
+ help="Use ClickHouse lightweight DELETE. Defaults to waiting inline and returning rows_affected; "
612
+ "pass --no-wait to enqueue a job instead. Not compatible with --dry-run.",
613
+ )
614
+ @click.option(
615
+ "--partition",
616
+ default=None,
617
+ help="Restrict the lightweight delete to a single partition expression. Only valid with --lightweight-delete.",
618
+ )
619
+ @click.option(
620
+ "--projection-mode",
621
+ type=click.Choice(["throw", "drop", "rebuild"]),
622
+ default=None,
623
+ help="How ClickHouse should handle table projections when running the lightweight DELETE. "
624
+ "throw: fail the DELETE if the table has any projection defined (ClickHouse default). "
625
+ "drop: drop the affected projections so the DELETE can proceed; they will need to be recreated. "
626
+ "rebuild: rebuild the affected projections after the DELETE finishes. "
627
+ "Only valid with --lightweight-delete.",
628
+ )
601
629
  @click.pass_context
602
- def datasource_delete_rows(ctx, datasource_name, sql_condition, yes, wait, dry_run):
630
+ def datasource_delete_rows(
631
+ ctx, datasource_name, sql_condition, yes, wait, dry_run, lightweight, partition, projection_mode
632
+ ):
603
633
  """
604
634
  Delete rows from a datasource
605
635
 
606
636
  - Delete rows with SQL condition: `tb datasource delete [datasource_name] --sql-condition "country='ES'"`
607
637
 
608
638
  - Delete rows with SQL condition and wait for the job to finish: `tb datasource delete [datasource_name] --sql-condition "country='ES'" --wait`
639
+
640
+ - Use ClickHouse lightweight DELETE (synchronous, no job): `tb datasource delete [datasource_name] --sql-condition "country='ES'" --lightweight-delete`
641
+
642
+ - Use ClickHouse lightweight DELETE and return immediately with a job id: `tb datasource delete [datasource_name] --sql-condition "country='ES'" --lightweight-delete --no-wait`
609
643
  """
610
644
 
611
645
  client: TinyB = ctx.ensure_object(dict)["client"]
646
+ if lightweight and dry_run:
647
+ raise CLIDatasourceException(
648
+ FeedbackManager.error_exception(error="--lightweight-delete is not compatible with --dry-run")
649
+ )
650
+ if (partition or projection_mode) and not lightweight:
651
+ raise CLIDatasourceException(
652
+ FeedbackManager.error_exception(error="--partition and --projection-mode require --lightweight-delete")
653
+ )
654
+ # Lightweight delete is sync by default (the endpoint blocks and returns
655
+ # rows_affected); the classic /v0/ delete is async by default (returns a
656
+ # job id). The tri-state --wait/--no-wait lets users override either.
657
+ if wait is None:
658
+ wait = lightweight
612
659
  if (
613
660
  dry_run
614
661
  or yes
@@ -619,7 +666,15 @@ def datasource_delete_rows(ctx, datasource_name, sql_condition, yes, wait, dry_r
619
666
  )
620
667
  ):
621
668
  try:
622
- res = client.datasource_delete_rows(datasource_name, sql_condition, dry_run)
669
+ res = client.datasource_delete_rows(
670
+ datasource_name,
671
+ sql_condition,
672
+ dry_run,
673
+ lightweight=lightweight,
674
+ wait=wait,
675
+ partition=partition,
676
+ projection_mode=projection_mode,
677
+ )
623
678
  if dry_run:
624
679
  click.echo(
625
680
  FeedbackManager.success_dry_run_delete_rows_datasource(
@@ -627,10 +682,24 @@ def datasource_delete_rows(ctx, datasource_name, sql_condition, yes, wait, dry_r
627
682
  )
628
683
  )
629
684
  return
685
+ # Lightweight sync path returns rows_affected directly, no job involved.
686
+ if lightweight and wait:
687
+ mutation = res.get("mutation") or {}
688
+ click.echo(
689
+ FeedbackManager.success_lightweight_delete_rows_datasource(
690
+ datasource=datasource_name,
691
+ delete_condition=sql_condition,
692
+ rows_affected=res.get("rows_affected", 0),
693
+ partitions_scanned=mutation.get("partitions_scanned", 0),
694
+ partitions_done=mutation.get("partitions_done", 0),
695
+ partitions_in_progress=mutation.get("partitions_in_progress", 0),
696
+ )
697
+ )
698
+ return
630
699
  job_id = res["job_id"]
631
700
  job_url = res["job_url"]
632
701
  click.echo(FeedbackManager.info_datasource_delete_rows_job_url(url=job_url))
633
- if wait:
702
+ if wait and not lightweight:
634
703
  progress_symbols = ["-", "\\", "|", "/"]
635
704
  progress_str = "Waiting for the job to finish"
636
705
  # TODO: Use click.echo instead of print and see if the behavior is the same
@@ -1071,6 +1071,11 @@ STEP 3: ADD KEY TO SERVICE ACCOUNT
1071
1071
  success_delete_rows_datasource = success_message(
1072
1072
  "** Data Source '{datasource}' rows deleted matching condition \"{delete_condition}\""
1073
1073
  )
1074
+ success_lightweight_delete_rows_datasource = success_message(
1075
+ "** Data Source '{datasource}' rows deleted matching condition \"{delete_condition}\""
1076
+ "\n Rows affected: {rows_affected}"
1077
+ "\n Partitions scanned: {partitions_scanned} (done: {partitions_done}, in progress: {partitions_in_progress})"
1078
+ )
1074
1079
  success_dry_run_delete_rows_datasource = success_message(
1075
1080
  "** [DRY RUN] Data Source '{datasource}' rows '{rows}' matching condition \"{delete_condition}\" to be deleted"
1076
1081
  )
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: tinybird
3
- Version: 4.6.3.dev0
3
+ Version: 4.6.5.dev0
4
4
  Summary: Tinybird Command Line Tool
5
5
  Home-page: https://www.tinybird.co/docs/forward/commands
6
6
  Author: Tinybird
@@ -52,6 +52,11 @@ The Tinybird command-line tool allows you to use all the Tinybird functionality
52
52
  Changelog
53
53
  ----------
54
54
 
55
+ 4.6.4
56
+ *******
57
+
58
+ - `Added` ``tb datasource delete`` now accepts ``--lightweight-delete``, ``--partition`` and ``--projection-mode``, backed by the new ``POST /v1/datasources/{name}/delete`` endpoint that uses ClickHouse's lightweight ``DELETE FROM`` instead of the heavy ``ALTER TABLE ... DELETE`` mutation. Lightweight delete is synchronous by default and returns the affected row count plus a partition-level mutation block; pass ``--no-wait`` to enqueue a ``LightweightDeleteJob`` and receive the v0-compatible job envelope.
59
+
55
60
  4.6.2
56
61
  *******
57
62
 
@@ -7,7 +7,7 @@ tinybird/service_datasources.py,sha256=tt_8G6yJcr2ZbsaR99ulExe79pNS8h9dzdGm45vf1
7
7
  tinybird/sql.py,sha256=qdqxsq1WPiGTk-SmZWaxvZb936ISdo1ChZhnC_uXeUE,49351
8
8
  tinybird/sql_template.py,sha256=nSzUdaQe18Da_8qlgLW7tsZl1pOa2kDaBa8TdrF6pJ4,128667
9
9
  tinybird/sql_template_fmt.py,sha256=Ma4qcs-2r8ZXQC4GUmrCqYz34DsnGF8k5lE2Jwnr314,10638
10
- tinybird/sql_toolset.py,sha256=xWY-EtixaZKUPuNY4WBz2fDwwNnmbgtdLsmI2wy67UA,27220
10
+ tinybird/sql_toolset.py,sha256=TvWeH3DsB13SfJ97V_t_ZaFTJ1IAtsrxQ8E3FLL8_tE,27442
11
11
  tinybird/syncasync.py,sha256=rIPmCvygWSFqfnlVqhZH4N9gVVTvD6DEPsfoxGizYrI,27776
12
12
  tinybird/tornado_template.py,sha256=1_0nYFk_xJh_TMHh6AKkJILvnNY6xYmaM-uJ3Ofv7e8,42085
13
13
  tinybird/ch_utils/constants.py,sha256=yTNizMzgYNBzUc2EV3moBfdrDIggOe9hiuAgWF7sv2c,4333
@@ -19,10 +19,10 @@ tinybird/datafile/parse_datasource.py,sha256=yd58HrUF4yNJXLn6OsvKGpZJpvrcjLGAeJG
19
19
  tinybird/datafile/parse_pipe.py,sha256=-9bbgVuiWRyDYydrLVflDBt8GstZotMy6dklsrc6MUY,3859
20
20
  tinybird/iterating/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
21
21
  tinybird/iterating/data_branch_modes.py,sha256=5YuDa-gr8mKwmES8Xro6TRKbQtaOtIw4GbC606Qhu3o,184
22
- tinybird/tb/__cli__.py,sha256=eh_8cfZSX_SsoNyJmyjPZu23B2buyeF98MGawLnIsqU,245
22
+ tinybird/tb/__cli__.py,sha256=xM7igRIfbohieP2BEIHYA9bVS58bQ_S7S3iFmuBQysE,245
23
23
  tinybird/tb/check_pypi.py,sha256=Gp0HkHHDFMSDL6nxKlOY51z7z1Uv-2LRexNTZSHHGmM,552
24
24
  tinybird/tb/cli.py,sha256=IjiGfNIpxSxi1odK1kMj9s8lEhx3sAUgGA263XdmyR0,1119
25
- tinybird/tb/client.py,sha256=nrNFU8pLqzQbKqU4b2Jm1PQRthFrpFzDsetE84o-1k0,55494
25
+ tinybird/tb/client.py,sha256=Udm3YWuRmv26XwWjVwQ9toAVsL7Dlu1Lx7aJZjfkMM4,56042
26
26
  tinybird/tb/config.py,sha256=CGCfBbCMlmVcBHQ0IMGc2IE4O2-1tZEPyD564JZoTbw,5659
27
27
  tinybird/tb/modules/branch.py,sha256=U50nj2kZllCkOHQfJWQ-YQ260pvlcssgStMSovmqMiU,10157
28
28
  tinybird/tb/modules/build.py,sha256=bGFoFppR_UbGUMDWFGDzfJ4nT3CGFwzCzl2o4OpwR2o,10420
@@ -37,13 +37,13 @@ tinybird/tb/modules/connection_kafka.py,sha256=Qc8uUNl5SvUcUGb_aG3AirYKw6673FoX1
37
37
  tinybird/tb/modules/connection_s3.py,sha256=KtPLeTXLQJ2SfveHHofz_MOLkmcmpJDloYb-gvRQ_dA,16604
38
38
  tinybird/tb/modules/copy.py,sha256=Apzjxiyinp6KmgamypPKEe3BAnpxG7MwYcSYkHiG8sA,6033
39
39
  tinybird/tb/modules/create.py,sha256=G3_wCUjNVzBiowo70NgwzmUUXXOxYO2LWjF9eEfcffc,22947
40
- tinybird/tb/modules/datasource.py,sha256=tpyLT-9ALZ8uCMKFHnnEEcqNuKQaaICi4IBp94Cc428,71632
40
+ tinybird/tb/modules/datasource.py,sha256=tblNurkQXi6fps2izOjsg4xmGkPKd4FhBHPvrrN3PE8,74779
41
41
  tinybird/tb/modules/deployment.py,sha256=TNDlvaYmk-zouvaAdMXlyFPbgbnMKQOt76xpZBggJI0,21184
42
42
  tinybird/tb/modules/deployment_common.py,sha256=fLPWNNs8ZwSkWHJjLeqQUqTbKqnnhW1y8yKffBdDCo0,31948
43
43
  tinybird/tb/modules/deprecations.py,sha256=XXekrzPO9v12F1ToQDUGzLYJJ2wrEUlGKOkLCSdfHiM,4935
44
44
  tinybird/tb/modules/endpoint.py,sha256=yRTh6rQFJ98LA0hSC8rPD3EcDaJj41gk9oCsgcZPu_c,12112
45
45
  tinybird/tb/modules/exceptions.py,sha256=_1BHy0OixEkeF0fOCu1_1Pj8pJS4BNfUyucqCViJGTw,5958
46
- tinybird/tb/modules/feedback_manager.py,sha256=_tlMzju93UaOX7rk_EBpl95IdTqIC53DMBYZuKFph0A,77673
46
+ tinybird/tb/modules/feedback_manager.py,sha256=dhGgC9HwerqFSVGbsRTbpTb9pvwSzqx52AdLQXSKPFY,78007
47
47
  tinybird/tb/modules/fmt.py,sha256=ejQC1-2mK42saA2R9DA-CENYgu06SUoiCoX4bCtRXT8,3734
48
48
  tinybird/tb/modules/info.py,sha256=oO2DpPT-hpQ2Gf_TBAJHQ_xIfc1WCBpiGWhiIeM_K4w,13042
49
49
  tinybird/tb/modules/infra.py,sha256=J9Noe9aZo5Y9ZKAhqh9jnv8azfivXLLHQ2a9TeMWN9s,32673
@@ -99,8 +99,8 @@ tinybird/tb_cli_modules/config.py,sha256=0kFDmsDcjKon32rgFGMHHKSbv4j5dOrXtVOlyuA
99
99
  tinybird/tb_cli_modules/exceptions.py,sha256=pmucP4kTF4irIt7dXiG-FcnI-o3mvDusPmch1L8RCWk,3367
100
100
  tinybird/tb_cli_modules/regions.py,sha256=QjsL5H6Kg-qr0aYVLrvb1STeJ5Sx_sjvbOYO0LrEGMk,166
101
101
  tinybird/tb_cli_modules/telemetry.py,sha256=W098H6jmS4kpE7hN3tadaREBTf7oMocel-lkKWN0pU8,10466
102
- tinybird-4.6.3.dev0.dist-info/METADATA,sha256=eQdmwvUn8LjwYvXjblOOydgSuh3Fkxg7bC8pWONQVl4,13260
103
- tinybird-4.6.3.dev0.dist-info/WHEEL,sha256=beeZ86-EfXScwlR_HKu4SllMC9wUEj_8Z_4FJ3egI2w,91
104
- tinybird-4.6.3.dev0.dist-info/entry_points.txt,sha256=LwdHU6TfKx4Qs7BqqtaczEZbImgU7Abe9Lp920zb_fo,43
105
- tinybird-4.6.3.dev0.dist-info/top_level.txt,sha256=ZIQJTPCzMqnfDzM_hEGZrJqDSEcKnIK_49T86DGWpyQ,78
106
- tinybird-4.6.3.dev0.dist-info/RECORD,,
102
+ tinybird-4.6.5.dev0.dist-info/METADATA,sha256=0yXzk_43TLjLFX1ryhENtzK8rMiGdItlD7CctIJVyec,13787
103
+ tinybird-4.6.5.dev0.dist-info/WHEEL,sha256=beeZ86-EfXScwlR_HKu4SllMC9wUEj_8Z_4FJ3egI2w,91
104
+ tinybird-4.6.5.dev0.dist-info/entry_points.txt,sha256=LwdHU6TfKx4Qs7BqqtaczEZbImgU7Abe9Lp920zb_fo,43
105
+ tinybird-4.6.5.dev0.dist-info/top_level.txt,sha256=ZIQJTPCzMqnfDzM_hEGZrJqDSEcKnIK_49T86DGWpyQ,78
106
+ tinybird-4.6.5.dev0.dist-info/RECORD,,