tinybird-cli 6.5.3.dev0__py3-none-any.whl → 6.5.4.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/__cli__.py +2 -2
- tinybird/client.py +19 -3
- tinybird/feedback_manager.py +5 -0
- tinybird/sql_toolset.py +5 -2
- tinybird/tb_cli_modules/datasource.py +73 -4
- {tinybird_cli-6.5.3.dev0.dist-info → tinybird_cli-6.5.4.dev0.dist-info}/METADATA +6 -1
- {tinybird_cli-6.5.3.dev0.dist-info → tinybird_cli-6.5.4.dev0.dist-info}/RECORD +10 -10
- {tinybird_cli-6.5.3.dev0.dist-info → tinybird_cli-6.5.4.dev0.dist-info}/WHEEL +0 -0
- {tinybird_cli-6.5.3.dev0.dist-info → tinybird_cli-6.5.4.dev0.dist-info}/entry_points.txt +0 -0
- {tinybird_cli-6.5.3.dev0.dist-info → tinybird_cli-6.5.4.dev0.dist-info}/top_level.txt +0 -0
tinybird/__cli__.py
CHANGED
|
@@ -4,5 +4,5 @@ __description__ = 'Tinybird Command Line Tool'
|
|
|
4
4
|
__url__ = 'https://www.tinybird.co/docs/cli'
|
|
5
5
|
__author__ = 'Tinybird'
|
|
6
6
|
__author_email__ = 'support@tinybird.co'
|
|
7
|
-
__version__ = '6.5.
|
|
8
|
-
__revision__ = '
|
|
7
|
+
__version__ = '6.5.4.dev0'
|
|
8
|
+
__revision__ = 'a87d7b3'
|
tinybird/client.py
CHANGED
|
@@ -470,10 +470,26 @@ class TinyB:
|
|
|
470
470
|
async def datasource_truncate(self, datasource_name: str):
|
|
471
471
|
return await self._req(f"/v0/datasources/{datasource_name}/truncate", method="POST", data="")
|
|
472
472
|
|
|
473
|
-
async def datasource_delete_rows(
|
|
474
|
-
|
|
473
|
+
async def datasource_delete_rows(
|
|
474
|
+
self,
|
|
475
|
+
datasource_name: str,
|
|
476
|
+
delete_condition: str,
|
|
477
|
+
dry_run: bool = False,
|
|
478
|
+
lightweight: bool = False,
|
|
479
|
+
wait: bool = True,
|
|
480
|
+
partition: Optional[str] = None,
|
|
481
|
+
projection_mode: Optional[str] = None,
|
|
482
|
+
):
|
|
483
|
+
params: Dict[str, Any] = {"delete_condition": delete_condition}
|
|
484
|
+
if lightweight:
|
|
485
|
+
params["wait"] = "true" if wait else "false"
|
|
486
|
+
if partition:
|
|
487
|
+
params["partition"] = partition
|
|
488
|
+
if projection_mode:
|
|
489
|
+
params["projection_mode"] = projection_mode
|
|
490
|
+
return await self._req(f"/v1/datasources/{datasource_name}/delete", method="POST", data=params)
|
|
475
491
|
if dry_run:
|
|
476
|
-
params
|
|
492
|
+
params["dry_run"] = "true"
|
|
477
493
|
return await self._req(f"/v0/datasources/{datasource_name}/delete", method="POST", data=params)
|
|
478
494
|
|
|
479
495
|
async def datasource_dependencies(
|
tinybird/feedback_manager.py
CHANGED
|
@@ -879,6 +879,11 @@ class FeedbackManager:
|
|
|
879
879
|
success_delete_rows_datasource = success_message(
|
|
880
880
|
"** Data Source '{datasource}' rows deleted matching condition \"{delete_condition}\""
|
|
881
881
|
)
|
|
882
|
+
success_lightweight_delete_rows_datasource = success_message(
|
|
883
|
+
"** Data Source '{datasource}' rows deleted matching condition \"{delete_condition}\""
|
|
884
|
+
"\n Rows affected: {rows_affected}"
|
|
885
|
+
"\n Partitions scanned: {partitions_scanned} (done: {partitions_done}, in progress: {partitions_in_progress})"
|
|
886
|
+
)
|
|
882
887
|
success_dry_run_delete_rows_datasource = success_message(
|
|
883
888
|
"** [DRY RUN] Data Source '{datasource}' rows '{rows}' matching condition \"{delete_condition}\" to be deleted"
|
|
884
889
|
)
|
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
|
-
|
|
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.
|
|
@@ -363,23 +363,70 @@ async def datasource_truncate(ctx, datasource_name, yes, cascade):
|
|
|
363
363
|
@click.argument("datasource_name")
|
|
364
364
|
@click.option("--sql-condition", default=None, help="SQL WHERE condition to remove rows", hidden=True, required=True)
|
|
365
365
|
@click.option("--yes", is_flag=True, default=False, help="Do not ask for confirmation")
|
|
366
|
-
@click.option(
|
|
366
|
+
@click.option(
|
|
367
|
+
"--wait/--no-wait",
|
|
368
|
+
default=None,
|
|
369
|
+
help="Wait for the delete to finish. Defaults to true with --lightweight-delete (sync request), "
|
|
370
|
+
"false otherwise (returns a job id).",
|
|
371
|
+
)
|
|
367
372
|
@click.option("--dry-run", is_flag=True, default=False, help="Run the command without deleting anything")
|
|
373
|
+
@click.option(
|
|
374
|
+
"--lightweight-delete",
|
|
375
|
+
"lightweight",
|
|
376
|
+
is_flag=True,
|
|
377
|
+
default=False,
|
|
378
|
+
help="Use ClickHouse lightweight DELETE. Defaults to waiting inline and returning rows_affected; "
|
|
379
|
+
"pass --no-wait to enqueue a job instead. Not compatible with --dry-run.",
|
|
380
|
+
)
|
|
381
|
+
@click.option(
|
|
382
|
+
"--partition",
|
|
383
|
+
default=None,
|
|
384
|
+
help="Restrict the lightweight delete to a single partition expression. Only valid with --lightweight-delete.",
|
|
385
|
+
)
|
|
386
|
+
@click.option(
|
|
387
|
+
"--projection-mode",
|
|
388
|
+
type=click.Choice(["throw", "drop", "rebuild"]),
|
|
389
|
+
default=None,
|
|
390
|
+
help="How ClickHouse should handle table projections when running the lightweight DELETE. "
|
|
391
|
+
"throw: fail the DELETE if the table has any projection defined (ClickHouse default). "
|
|
392
|
+
"drop: drop the affected projections so the DELETE can proceed; they will need to be recreated. "
|
|
393
|
+
"rebuild: rebuild the affected projections after the DELETE finishes. "
|
|
394
|
+
"Only valid with --lightweight-delete.",
|
|
395
|
+
)
|
|
368
396
|
@click.pass_context
|
|
369
397
|
@coro
|
|
370
|
-
async def datasource_delete_rows(
|
|
398
|
+
async def datasource_delete_rows(
|
|
399
|
+
ctx, datasource_name, sql_condition, yes, wait, dry_run, lightweight, partition, projection_mode
|
|
400
|
+
):
|
|
371
401
|
"""
|
|
372
402
|
Delete rows from a datasource
|
|
373
403
|
|
|
374
404
|
- Delete rows with SQL condition: `tb datasource delete [datasource_name] --sql-condition "country='ES'"`
|
|
375
405
|
|
|
376
406
|
- Delete rows with SQL condition and wait for the job to finish: `tb datasource delete [datasource_name] --sql-condition "country='ES'" --wait`
|
|
407
|
+
|
|
408
|
+
- Use ClickHouse lightweight DELETE (synchronous, no job): `tb datasource delete [datasource_name] --sql-condition "country='ES'" --lightweight-delete`
|
|
409
|
+
|
|
410
|
+
- Use ClickHouse lightweight DELETE and return immediately with a job id: `tb datasource delete [datasource_name] --sql-condition "country='ES'" --lightweight-delete --no-wait`
|
|
377
411
|
"""
|
|
378
412
|
|
|
379
413
|
semver: str = ctx.ensure_object(dict)["config"]["semver"]
|
|
380
414
|
await warn_if_in_live(semver)
|
|
381
415
|
|
|
382
416
|
client: TinyB = ctx.ensure_object(dict)["client"]
|
|
417
|
+
if lightweight and dry_run:
|
|
418
|
+
raise CLIDatasourceException(
|
|
419
|
+
FeedbackManager.error_exception(error="--lightweight-delete is not compatible with --dry-run")
|
|
420
|
+
)
|
|
421
|
+
if (partition or projection_mode) and not lightweight:
|
|
422
|
+
raise CLIDatasourceException(
|
|
423
|
+
FeedbackManager.error_exception(error="--partition and --projection-mode require --lightweight-delete")
|
|
424
|
+
)
|
|
425
|
+
# Lightweight delete is sync by default (the endpoint blocks and returns
|
|
426
|
+
# rows_affected); the classic /v0/ delete is async by default (returns a
|
|
427
|
+
# job id). The tri-state --wait/--no-wait lets users override either.
|
|
428
|
+
if wait is None:
|
|
429
|
+
wait = lightweight
|
|
383
430
|
if (
|
|
384
431
|
dry_run
|
|
385
432
|
or yes
|
|
@@ -390,7 +437,15 @@ async def datasource_delete_rows(ctx, datasource_name, sql_condition, yes, wait,
|
|
|
390
437
|
)
|
|
391
438
|
):
|
|
392
439
|
try:
|
|
393
|
-
res = await client.datasource_delete_rows(
|
|
440
|
+
res = await client.datasource_delete_rows(
|
|
441
|
+
datasource_name,
|
|
442
|
+
sql_condition,
|
|
443
|
+
dry_run,
|
|
444
|
+
lightweight=lightweight,
|
|
445
|
+
wait=wait,
|
|
446
|
+
partition=partition,
|
|
447
|
+
projection_mode=projection_mode,
|
|
448
|
+
)
|
|
394
449
|
if dry_run:
|
|
395
450
|
click.echo(
|
|
396
451
|
FeedbackManager.success_dry_run_delete_rows_datasource(
|
|
@@ -398,10 +453,24 @@ async def datasource_delete_rows(ctx, datasource_name, sql_condition, yes, wait,
|
|
|
398
453
|
)
|
|
399
454
|
)
|
|
400
455
|
return
|
|
456
|
+
# Lightweight sync path returns rows_affected directly, no job involved.
|
|
457
|
+
if lightweight and wait:
|
|
458
|
+
mutation = res.get("mutation") or {}
|
|
459
|
+
click.echo(
|
|
460
|
+
FeedbackManager.success_lightweight_delete_rows_datasource(
|
|
461
|
+
datasource=datasource_name,
|
|
462
|
+
delete_condition=sql_condition,
|
|
463
|
+
rows_affected=res.get("rows_affected", 0),
|
|
464
|
+
partitions_scanned=mutation.get("partitions_scanned", 0),
|
|
465
|
+
partitions_done=mutation.get("partitions_done", 0),
|
|
466
|
+
partitions_in_progress=mutation.get("partitions_in_progress", 0),
|
|
467
|
+
)
|
|
468
|
+
)
|
|
469
|
+
return
|
|
401
470
|
job_id = res["job_id"]
|
|
402
471
|
job_url = res["job_url"]
|
|
403
472
|
click.echo(FeedbackManager.info_datasource_delete_rows_job_url(url=job_url))
|
|
404
|
-
if wait:
|
|
473
|
+
if wait and not lightweight:
|
|
405
474
|
progress_symbols = ["-", "\\", "|", "/"]
|
|
406
475
|
progress_str = "Waiting for the job to finish"
|
|
407
476
|
# TODO: Use click.echo instead of print and see if the behavior is the same
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.2
|
|
2
2
|
Name: tinybird_cli
|
|
3
|
-
Version: 6.5.
|
|
3
|
+
Version: 6.5.4.dev0
|
|
4
4
|
Summary: Tinybird Command Line Tool
|
|
5
5
|
Home-page: https://www.tinybird.co/docs/cli
|
|
6
6
|
Author: Tinybird
|
|
@@ -43,6 +43,11 @@ The Tinybird command-line tool allows you to use all the Tinybird functionality
|
|
|
43
43
|
Changelog
|
|
44
44
|
----------
|
|
45
45
|
|
|
46
|
+
6.5.3
|
|
47
|
+
***********
|
|
48
|
+
|
|
49
|
+
- `Added` ``tb datasource delete`` now accepts ``--lightweight-delete``, ``--partition`` and ``--projection-mode``, backed by the ``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 job and receive the v0-compatible envelope.
|
|
50
|
+
|
|
46
51
|
6.5.1
|
|
47
52
|
***********
|
|
48
53
|
|
|
@@ -1,16 +1,16 @@
|
|
|
1
|
-
tinybird/__cli__.py,sha256=
|
|
1
|
+
tinybird/__cli__.py,sha256=Wf0VS-wmsRJS_MkAzra29SE6k7aD2D1mjYB3EoflQZ0,236
|
|
2
2
|
tinybird/check_pypi.py,sha256=_4NkharLyR_ELrAdit-ftqIWvOf7jZNPt3i76frlo9g,975
|
|
3
|
-
tinybird/client.py,sha256=
|
|
3
|
+
tinybird/client.py,sha256=Tql8VEj9OJIRN7znUsEGkJ5XSwLMR2lKk5GpxTqgL14,52360
|
|
4
4
|
tinybird/config.py,sha256=g74rE9jbVcyFj1bms5T3VEITLr21_WFy79Uj5ovvj90,7413
|
|
5
5
|
tinybird/context.py,sha256=o4yvlXPkMLmdh-XJl3wpmqPAMeRRz5ScKzKlHHKn_I8,1201
|
|
6
6
|
tinybird/datafile_common.py,sha256=MyMobDF6UOFFEsXnHrUWuOb0kJ6tkzZpiq1CjL7RlKY,237598
|
|
7
7
|
tinybird/datatypes.py,sha256=Lr8BIaRP--qzuZFpAdv20uQaeE1BOAMmuEwWVHheFPw,11355
|
|
8
|
-
tinybird/feedback_manager.py,sha256=
|
|
8
|
+
tinybird/feedback_manager.py,sha256=ZnRsExCkEZKuslmSxn3m706-0UIZ_qOpdek9ar16KOI,68001
|
|
9
9
|
tinybird/git_settings.py,sha256=mqWgeboOlOFsSo97qyv595UCR2R1QCAqT4GTawBNPBg,3935
|
|
10
10
|
tinybird/sql.py,sha256=qdqxsq1WPiGTk-SmZWaxvZb936ISdo1ChZhnC_uXeUE,49351
|
|
11
11
|
tinybird/sql_template.py,sha256=nSzUdaQe18Da_8qlgLW7tsZl1pOa2kDaBa8TdrF6pJ4,128667
|
|
12
12
|
tinybird/sql_template_fmt.py,sha256=Ma4qcs-2r8ZXQC4GUmrCqYz34DsnGF8k5lE2Jwnr314,10638
|
|
13
|
-
tinybird/sql_toolset.py,sha256=
|
|
13
|
+
tinybird/sql_toolset.py,sha256=TvWeH3DsB13SfJ97V_t_ZaFTJ1IAtsrxQ8E3FLL8_tE,27442
|
|
14
14
|
tinybird/syncasync.py,sha256=rIPmCvygWSFqfnlVqhZH4N9gVVTvD6DEPsfoxGizYrI,27776
|
|
15
15
|
tinybird/tb_cli.py,sha256=q1LGAsBVVMJsjR2HK62Pu6vpVtLzNmH8wHrEVUUdVkU,744
|
|
16
16
|
tinybird/tornado_template.py,sha256=1_0nYFk_xJh_TMHh6AKkJILvnNY6xYmaM-uJ3Ofv7e8,42085
|
|
@@ -23,7 +23,7 @@ tinybird/tb_cli_modules/cli.py,sha256=KvgZfdYRvgKG5QAiFmlfLbVGI-xmuxbs-EdkAslqrE
|
|
|
23
23
|
tinybird/tb_cli_modules/common.py,sha256=763GkBOgXIcB48UnuSjnGfxdfoSx5iqCniK15R0Aq5Y,77366
|
|
24
24
|
tinybird/tb_cli_modules/config.py,sha256=0kFDmsDcjKon32rgFGMHHKSbv4j5dOrXtVOlyuAyEkk,11510
|
|
25
25
|
tinybird/tb_cli_modules/connection.py,sha256=JO2v2xTGoiMeThzCncvxMFUHLghyyGXNF0FcAvi5ZOk,24543
|
|
26
|
-
tinybird/tb_cli_modules/datasource.py,sha256=
|
|
26
|
+
tinybird/tb_cli_modules/datasource.py,sha256=9j4cw02k8txabdUoRHap-oPwECbbBnzugsFIf6o_ljY,35688
|
|
27
27
|
tinybird/tb_cli_modules/exceptions.py,sha256=pmucP4kTF4irIt7dXiG-FcnI-o3mvDusPmch1L8RCWk,3367
|
|
28
28
|
tinybird/tb_cli_modules/fmt.py,sha256=edQap4tAqWMWogSIx5zriT75naLi73XTB3NwatmcrFw,3518
|
|
29
29
|
tinybird/tb_cli_modules/job.py,sha256=BxiqChDYa_4W4tFXHIUz2bOzkx8WMFywynjiPWgDlnE,2936
|
|
@@ -36,8 +36,8 @@ tinybird/tb_cli_modules/token.py,sha256=JXATKTlbXohP9ZDZjlz8E4VYG6zrknKZhuz_wh1z
|
|
|
36
36
|
tinybird/tb_cli_modules/workspace.py,sha256=Ssu-jKk7lp4Gh3qX5DXhIbImyhs9aCvL09u_T75zw1I,12421
|
|
37
37
|
tinybird/tb_cli_modules/workspace_members.py,sha256=ksXsjd233y9-sNlz4Qb-meZbX4zn1B84e_bSm2i8rhg,8731
|
|
38
38
|
tinybird/tb_cli_modules/tinyunit/tinyunit.py,sha256=50uqMgJD2BqSVONtCm55nuGRWhBNZWRc2GP1Qb8URdg,11246
|
|
39
|
-
tinybird_cli-6.5.
|
|
40
|
-
tinybird_cli-6.5.
|
|
41
|
-
tinybird_cli-6.5.
|
|
42
|
-
tinybird_cli-6.5.
|
|
43
|
-
tinybird_cli-6.5.
|
|
39
|
+
tinybird_cli-6.5.4.dev0.dist-info/METADATA,sha256=iftt91TP5EZwKaP-bhiMd6WA-k9WZrPSLvyqfDMUE78,82821
|
|
40
|
+
tinybird_cli-6.5.4.dev0.dist-info/WHEEL,sha256=beeZ86-EfXScwlR_HKu4SllMC9wUEj_8Z_4FJ3egI2w,91
|
|
41
|
+
tinybird_cli-6.5.4.dev0.dist-info/entry_points.txt,sha256=PKPKuPmA4IfJYnCFHHUiw-aAWZuBomFvwCklv1OyCjE,43
|
|
42
|
+
tinybird_cli-6.5.4.dev0.dist-info/top_level.txt,sha256=ZIQJTPCzMqnfDzM_hEGZrJqDSEcKnIK_49T86DGWpyQ,78
|
|
43
|
+
tinybird_cli-6.5.4.dev0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|