tinybird-cli 3.3.1.dev9__tar.gz → 3.3.1.dev11__tar.gz
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-3.3.1.dev9 → tinybird-cli-3.3.1.dev11}/PKG-INFO +11 -1
- {tinybird-cli-3.3.1.dev9 → tinybird-cli-3.3.1.dev11}/tinybird/__cli__.py +2 -2
- {tinybird-cli-3.3.1.dev9 → tinybird-cli-3.3.1.dev11}/tinybird/datafile.py +23 -2
- {tinybird-cli-3.3.1.dev9 → tinybird-cli-3.3.1.dev11}/tinybird/feedback_manager.py +4 -0
- {tinybird-cli-3.3.1.dev9 → tinybird-cli-3.3.1.dev11}/tinybird/git_settings.py +3 -0
- {tinybird-cli-3.3.1.dev9 → tinybird-cli-3.3.1.dev11}/tinybird/sql.py +91 -3
- {tinybird-cli-3.3.1.dev9 → tinybird-cli-3.3.1.dev11}/tinybird/tb_cli_modules/cli.py +5 -0
- {tinybird-cli-3.3.1.dev9 → tinybird-cli-3.3.1.dev11}/tinybird_cli.egg-info/PKG-INFO +11 -1
- {tinybird-cli-3.3.1.dev9 → tinybird-cli-3.3.1.dev11}/setup.cfg +0 -0
- {tinybird-cli-3.3.1.dev9 → tinybird-cli-3.3.1.dev11}/tinybird/ch_utils/constants.py +0 -0
- {tinybird-cli-3.3.1.dev9 → tinybird-cli-3.3.1.dev11}/tinybird/ch_utils/engine.py +0 -0
- {tinybird-cli-3.3.1.dev9 → tinybird-cli-3.3.1.dev11}/tinybird/check_pypi.py +0 -0
- {tinybird-cli-3.3.1.dev9 → tinybird-cli-3.3.1.dev11}/tinybird/client.py +0 -0
- {tinybird-cli-3.3.1.dev9 → tinybird-cli-3.3.1.dev11}/tinybird/config.py +0 -0
- {tinybird-cli-3.3.1.dev9 → tinybird-cli-3.3.1.dev11}/tinybird/connector_settings.py +0 -0
- {tinybird-cli-3.3.1.dev9 → tinybird-cli-3.3.1.dev11}/tinybird/connectors.py +0 -0
- {tinybird-cli-3.3.1.dev9 → tinybird-cli-3.3.1.dev11}/tinybird/context.py +0 -0
- {tinybird-cli-3.3.1.dev9 → tinybird-cli-3.3.1.dev11}/tinybird/data_connectors/credentials.py +0 -0
- {tinybird-cli-3.3.1.dev9 → tinybird-cli-3.3.1.dev11}/tinybird/datatypes.py +0 -0
- {tinybird-cli-3.3.1.dev9 → tinybird-cli-3.3.1.dev11}/tinybird/sql_template.py +0 -0
- {tinybird-cli-3.3.1.dev9 → tinybird-cli-3.3.1.dev11}/tinybird/sql_template_fmt.py +0 -0
- {tinybird-cli-3.3.1.dev9 → tinybird-cli-3.3.1.dev11}/tinybird/sql_toolset.py +0 -0
- {tinybird-cli-3.3.1.dev9 → tinybird-cli-3.3.1.dev11}/tinybird/syncasync.py +0 -0
- {tinybird-cli-3.3.1.dev9 → tinybird-cli-3.3.1.dev11}/tinybird/tb_cli.py +0 -0
- {tinybird-cli-3.3.1.dev9 → tinybird-cli-3.3.1.dev11}/tinybird/tb_cli_modules/auth.py +0 -0
- {tinybird-cli-3.3.1.dev9 → tinybird-cli-3.3.1.dev11}/tinybird/tb_cli_modules/branch.py +0 -0
- {tinybird-cli-3.3.1.dev9 → tinybird-cli-3.3.1.dev11}/tinybird/tb_cli_modules/cicd.py +0 -0
- {tinybird-cli-3.3.1.dev9 → tinybird-cli-3.3.1.dev11}/tinybird/tb_cli_modules/common.py +0 -0
- {tinybird-cli-3.3.1.dev9 → tinybird-cli-3.3.1.dev11}/tinybird/tb_cli_modules/config.py +0 -0
- {tinybird-cli-3.3.1.dev9 → tinybird-cli-3.3.1.dev11}/tinybird/tb_cli_modules/connection.py +0 -0
- {tinybird-cli-3.3.1.dev9 → tinybird-cli-3.3.1.dev11}/tinybird/tb_cli_modules/datasource.py +0 -0
- {tinybird-cli-3.3.1.dev9 → tinybird-cli-3.3.1.dev11}/tinybird/tb_cli_modules/exceptions.py +0 -0
- {tinybird-cli-3.3.1.dev9 → tinybird-cli-3.3.1.dev11}/tinybird/tb_cli_modules/job.py +0 -0
- {tinybird-cli-3.3.1.dev9 → tinybird-cli-3.3.1.dev11}/tinybird/tb_cli_modules/pipe.py +0 -0
- {tinybird-cli-3.3.1.dev9 → tinybird-cli-3.3.1.dev11}/tinybird/tb_cli_modules/regions.py +0 -0
- {tinybird-cli-3.3.1.dev9 → tinybird-cli-3.3.1.dev11}/tinybird/tb_cli_modules/telemetry.py +0 -0
- {tinybird-cli-3.3.1.dev9 → tinybird-cli-3.3.1.dev11}/tinybird/tb_cli_modules/test.py +0 -0
- {tinybird-cli-3.3.1.dev9 → tinybird-cli-3.3.1.dev11}/tinybird/tb_cli_modules/tinyunit/tinyunit.py +0 -0
- {tinybird-cli-3.3.1.dev9 → tinybird-cli-3.3.1.dev11}/tinybird/tb_cli_modules/tinyunit/tinyunit_lib.py +0 -0
- {tinybird-cli-3.3.1.dev9 → tinybird-cli-3.3.1.dev11}/tinybird/tb_cli_modules/token.py +0 -0
- {tinybird-cli-3.3.1.dev9 → tinybird-cli-3.3.1.dev11}/tinybird/tb_cli_modules/workspace.py +0 -0
- {tinybird-cli-3.3.1.dev9 → tinybird-cli-3.3.1.dev11}/tinybird/tb_cli_modules/workspace_members.py +0 -0
- {tinybird-cli-3.3.1.dev9 → tinybird-cli-3.3.1.dev11}/tinybird/tornado_template.py +0 -0
- {tinybird-cli-3.3.1.dev9 → tinybird-cli-3.3.1.dev11}/tinybird_cli.egg-info/SOURCES.txt +0 -0
- {tinybird-cli-3.3.1.dev9 → tinybird-cli-3.3.1.dev11}/tinybird_cli.egg-info/dependency_links.txt +0 -0
- {tinybird-cli-3.3.1.dev9 → tinybird-cli-3.3.1.dev11}/tinybird_cli.egg-info/entry_points.txt +0 -0
- {tinybird-cli-3.3.1.dev9 → tinybird-cli-3.3.1.dev11}/tinybird_cli.egg-info/requires.txt +0 -0
- {tinybird-cli-3.3.1.dev9 → tinybird-cli-3.3.1.dev11}/tinybird_cli.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: tinybird-cli
|
|
3
|
-
Version: 3.3.1.
|
|
3
|
+
Version: 3.3.1.dev11
|
|
4
4
|
Summary: Tinybird Command Line Tool
|
|
5
5
|
Home-page: https://docs.tinybird.co/cli.html
|
|
6
6
|
Author: Tinybird
|
|
@@ -19,6 +19,16 @@ Changelog
|
|
|
19
19
|
|
|
20
20
|
---------
|
|
21
21
|
|
|
22
|
+
3.3.1.dev11
|
|
23
|
+
************
|
|
24
|
+
|
|
25
|
+
- `Add` Check backfill on preview is required when `tb deploy` modified datasources. Disable check with `TB_CHECK_BACKFILL_REQUIRED=0`.
|
|
26
|
+
|
|
27
|
+
3.3.1.dev10
|
|
28
|
+
************
|
|
29
|
+
|
|
30
|
+
- `Fixed` Fixed bug when a Data Source was created using an INDEX
|
|
31
|
+
|
|
22
32
|
3.3.1.dev9
|
|
23
33
|
************
|
|
24
34
|
|
|
@@ -4,5 +4,5 @@ __description__ = 'Tinybird Command Line Tool'
|
|
|
4
4
|
__url__ = 'https://docs.tinybird.co/cli.html'
|
|
5
5
|
__author__ = 'Tinybird'
|
|
6
6
|
__author_email__ = 'support@tinybird.co'
|
|
7
|
-
__version__ = '3.3.1.
|
|
8
|
-
__revision__ = '
|
|
7
|
+
__version__ = '3.3.1.dev11'
|
|
8
|
+
__revision__ = '6db530d'
|
|
@@ -3745,6 +3745,8 @@ async def folder_push(
|
|
|
3745
3745
|
fork: Optional[bool] = False,
|
|
3746
3746
|
is_internal: Optional[bool] = False,
|
|
3747
3747
|
release_created: Optional[bool] = False,
|
|
3748
|
+
auto_promote: Optional[bool] = False,
|
|
3749
|
+
check_backfill_required: bool = False,
|
|
3748
3750
|
): # noqa: C901
|
|
3749
3751
|
workspaces: List[Dict[str, Any]] = (await tb_client.user_workspaces_and_branches()).get("workspaces", [])
|
|
3750
3752
|
current_ws: Dict[str, Any] = next(
|
|
@@ -3879,6 +3881,7 @@ async def folder_push(
|
|
|
3879
3881
|
dry_run: bool,
|
|
3880
3882
|
fork_downstream: Optional[bool] = False,
|
|
3881
3883
|
fork: Optional[bool] = False,
|
|
3884
|
+
check_backfill_required: bool = False,
|
|
3882
3885
|
):
|
|
3883
3886
|
if name in to_run:
|
|
3884
3887
|
if not dry_run:
|
|
@@ -3970,10 +3973,23 @@ async def folder_push(
|
|
|
3970
3973
|
latest_version=resource_versions.get(name),
|
|
3971
3974
|
)
|
|
3972
3975
|
)
|
|
3976
|
+
if (
|
|
3977
|
+
check_backfill_required
|
|
3978
|
+
and auto_promote
|
|
3979
|
+
and release_created
|
|
3980
|
+
and "resource" in to_run[name]
|
|
3981
|
+
and to_run[name]["resource"] == "datasources"
|
|
3982
|
+
):
|
|
3983
|
+
error_msg = FeedbackManager.error_check_backfill_required(resource_name=name)
|
|
3984
|
+
raise click.ClickException(error_msg)
|
|
3973
3985
|
else:
|
|
3974
3986
|
click.echo(FeedbackManager.warning_dry_name_already_exists(name=name))
|
|
3975
3987
|
|
|
3976
|
-
async def push_files(
|
|
3988
|
+
async def push_files(
|
|
3989
|
+
dependency_graph: GraphDependencies,
|
|
3990
|
+
dry_run: bool = False,
|
|
3991
|
+
check_backfill_required: bool = False,
|
|
3992
|
+
):
|
|
3977
3993
|
endpoints_dep_map = dict()
|
|
3978
3994
|
processed = set()
|
|
3979
3995
|
|
|
@@ -4057,6 +4073,7 @@ async def folder_push(
|
|
|
4057
4073
|
dry_run,
|
|
4058
4074
|
fork_downstream,
|
|
4059
4075
|
fork,
|
|
4076
|
+
check_backfill_required=False, # keep it always to false for new resources
|
|
4060
4077
|
)
|
|
4061
4078
|
else:
|
|
4062
4079
|
await push(
|
|
@@ -4067,6 +4084,7 @@ async def folder_push(
|
|
|
4067
4084
|
dry_run,
|
|
4068
4085
|
fork_downstream,
|
|
4069
4086
|
fork,
|
|
4087
|
+
check_backfill_required=check_backfill_required,
|
|
4070
4088
|
)
|
|
4071
4089
|
processed.add(name)
|
|
4072
4090
|
|
|
@@ -4104,6 +4122,7 @@ async def folder_push(
|
|
|
4104
4122
|
dry_run,
|
|
4105
4123
|
fork_downstream,
|
|
4106
4124
|
fork,
|
|
4125
|
+
check_backfill_required=check_backfill_required,
|
|
4107
4126
|
)
|
|
4108
4127
|
processed.add(name)
|
|
4109
4128
|
|
|
@@ -4124,6 +4143,7 @@ async def folder_push(
|
|
|
4124
4143
|
dry_run,
|
|
4125
4144
|
fork_downstream,
|
|
4126
4145
|
fork,
|
|
4146
|
+
check_backfill_required=check_backfill_required,
|
|
4127
4147
|
)
|
|
4128
4148
|
processed.add(name)
|
|
4129
4149
|
|
|
@@ -4144,12 +4164,13 @@ async def folder_push(
|
|
|
4144
4164
|
dry_run,
|
|
4145
4165
|
fork_downstream,
|
|
4146
4166
|
fork,
|
|
4167
|
+
check_backfill_required=check_backfill_required,
|
|
4147
4168
|
)
|
|
4148
4169
|
processed.add(name)
|
|
4149
4170
|
|
|
4150
4171
|
if deployment.is_git_release:
|
|
4151
4172
|
deployment.deploying_dry_run()
|
|
4152
|
-
await push_files(dependencies_graph, dry_run=True)
|
|
4173
|
+
await push_files(dependencies_graph, dry_run=True, check_backfill_required=check_backfill_required)
|
|
4153
4174
|
|
|
4154
4175
|
await deployment.delete_resources(deleted, pipes, dry_run=True)
|
|
4155
4176
|
if not deployment.dry_run:
|
|
@@ -326,6 +326,10 @@ class FeedbackManager:
|
|
|
326
326
|
error_unsupported_diff = error_message(
|
|
327
327
|
"There are resources renamed. `tb deploy` can't deploy renamed resources, create new resources instead."
|
|
328
328
|
)
|
|
329
|
+
error_check_backfill_required = error_message(
|
|
330
|
+
"Not safe to deploy to live resource '{resource_name}', backfill might be required. Consider to deploy to preview bumping semver to major or disable 'TB_AUTO_PROMOTE'. In case you want to disable this check use 'TB_CHECK_BACKFILL_REQUIRED=0'"
|
|
331
|
+
)
|
|
332
|
+
|
|
329
333
|
info_ignoring_incl_file = info_message(
|
|
330
334
|
"** Ignoring file {filename}. .incl files are not checked independently. They are checked as part of the file that includes them. Please check the file that includes this .incl file."
|
|
331
335
|
)
|
|
@@ -70,6 +70,9 @@ VERSION=0.0.0
|
|
|
70
70
|
# Deploy a new Release in preview status (default is 1)
|
|
71
71
|
# TB_AUTO_PROMOTE=0
|
|
72
72
|
|
|
73
|
+
# Check if deploy requires backfilling on preview (default is 1)
|
|
74
|
+
# TB_CHECK_BACKFILL_REQUIRED=0
|
|
75
|
+
|
|
73
76
|
# Force old Releases deletion on promote (default is 0)
|
|
74
77
|
# Setting it to 1 will remove oldest rollback Releases even when some resource is still in use
|
|
75
78
|
# TB_FORCE_REMOVE_OLDEST_ROLLBACK=0
|
|
@@ -1,8 +1,41 @@
|
|
|
1
1
|
import re
|
|
2
2
|
import string
|
|
3
3
|
from collections import namedtuple
|
|
4
|
+
from dataclasses import dataclass
|
|
4
5
|
from typing import Any, Dict, Iterable, List, Optional
|
|
5
6
|
|
|
7
|
+
valid_chars_name: str = string.ascii_letters + string.digits + "._`*<>+-'"
|
|
8
|
+
valid_chars_fn: str = valid_chars_name + "[](),=!?:/ \n\t\r"
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
@dataclass
|
|
12
|
+
class TableIndex:
|
|
13
|
+
"""Defines a CH table INDEX"""
|
|
14
|
+
|
|
15
|
+
name: str
|
|
16
|
+
expr: str
|
|
17
|
+
type_full: str
|
|
18
|
+
granularity: Optional[str] = None
|
|
19
|
+
|
|
20
|
+
def to_datafile(self):
|
|
21
|
+
granularity_expr = f"GRANULARITY {self.granularity}" if self.granularity else ""
|
|
22
|
+
return f"{self.name} {self.expr} TYPE {self.type_full} {granularity_expr}"
|
|
23
|
+
|
|
24
|
+
def to_sql(self):
|
|
25
|
+
return f"INDEX {self.to_datafile()}"
|
|
26
|
+
|
|
27
|
+
def add_index_sql(self):
|
|
28
|
+
return f"ADD {self.to_sql()}"
|
|
29
|
+
|
|
30
|
+
def drop_index_sql(self):
|
|
31
|
+
return f"DROP INDEX IF EXISTS {self.name}"
|
|
32
|
+
|
|
33
|
+
def materialize_index_sql(self):
|
|
34
|
+
return f"MATERIALIZE INDEX IF EXISTS {self.name}"
|
|
35
|
+
|
|
36
|
+
def clear_index_sql(self):
|
|
37
|
+
return f"CLEAR INDEX IF EXISTS {self.name}"
|
|
38
|
+
|
|
6
39
|
|
|
7
40
|
def as_subquery(sql: str) -> str:
|
|
8
41
|
return f"""(\n{sql}\n)"""
|
|
@@ -177,6 +210,49 @@ def format_parse_error(
|
|
|
177
210
|
return message
|
|
178
211
|
|
|
179
212
|
|
|
213
|
+
def parse_indices_structure(indices: List[str]) -> List[TableIndex]:
|
|
214
|
+
"""
|
|
215
|
+
>>> parse_indices_structure(["index_name a TYPE set(100) GRANULARITY 100", "index_name_bf mapValues(d) TYPE bloom_filter(0.001) GRANULARITY 16"])
|
|
216
|
+
[TableIndex(name='index_name', expr='a', type_full='set(100)', granularity='100'), TableIndex(name='index_name_bf', expr='mapValues(d)', type_full='bloom_filter(0.001)', granularity='16')]
|
|
217
|
+
>>> parse_indices_structure(["INDEX index_name a TYPE set(100) GRANULARITY 100", " INDEX index_name_bf mapValues(d) TYPE bloom_filter(0.001) GRANULARITY 16"])
|
|
218
|
+
[TableIndex(name='index_name', expr='a', type_full='set(100)', granularity='100'), TableIndex(name='index_name_bf', expr='mapValues(d)', type_full='bloom_filter(0.001)', granularity='16')]
|
|
219
|
+
>>> parse_indices_structure(["index_name type TYPE set(100) GRANULARITY 100", "index_name_bf mapValues(d) TYPE bloom_filter(0.001) GRANULARITY 16"])
|
|
220
|
+
[TableIndex(name='index_name', expr='type', type_full='set(100)', granularity='100'), TableIndex(name='index_name_bf', expr='mapValues(d)', type_full='bloom_filter(0.001)', granularity='16')]
|
|
221
|
+
>>> parse_indices_structure(["index_name a TYPE set(100) GRANULARITY 100,", "index_name_bf mapValues(d) TYPE bloom_filter(0.001) GRANULARITY 16"])
|
|
222
|
+
[TableIndex(name='index_name', expr='a', type_full='set(100)', granularity='100'), TableIndex(name='index_name_bf', expr='mapValues(d)', type_full='bloom_filter(0.001)', granularity='16')]
|
|
223
|
+
>>> parse_indices_structure(["index_name a TYPE set(100)", "index_name_bf mapValues(d) TYPE bloom_filter(0.001)"])
|
|
224
|
+
[TableIndex(name='index_name', expr='a', type_full='set(100)', granularity=None), TableIndex(name='index_name_bf', expr='mapValues(d)', type_full='bloom_filter(0.001)', granularity=None)]
|
|
225
|
+
>>> parse_indices_structure(["index_name u64 * length(s) TYPE set(100)", "index_name_bf mapValues(d) TYPE bloom_filter"])
|
|
226
|
+
[TableIndex(name='index_name', expr='u64 * length(s)', type_full='set(100)', granularity=None), TableIndex(name='index_name_bf', expr='mapValues(d)', type_full='bloom_filter', granularity=None)]
|
|
227
|
+
>>> parse_indices_structure(["index_name u64 * length(s)"])
|
|
228
|
+
Traceback (most recent call last):
|
|
229
|
+
...
|
|
230
|
+
ValueError: invalid INDEX format. Usage: `name expr TYPE type_full GRANULARITY granularity`
|
|
231
|
+
>>> parse_indices_structure(["index_name a TYPE set(100) GRANULARITY 100, index_name_bf mapValues(d) TYPE bloom_filter(0.001) GRANULARITY 16"])
|
|
232
|
+
Traceback (most recent call last):
|
|
233
|
+
...
|
|
234
|
+
ValueError: invalid INDEX format. Usage: `name expr TYPE type_full GRANULARITY granularity`
|
|
235
|
+
"""
|
|
236
|
+
parsed_indices: List[TableIndex] = []
|
|
237
|
+
if not indices:
|
|
238
|
+
return parsed_indices
|
|
239
|
+
|
|
240
|
+
for index in indices:
|
|
241
|
+
index = index.strip().rstrip(",")
|
|
242
|
+
index = index.lstrip("INDEX").strip()
|
|
243
|
+
if index.count("TYPE") != 1:
|
|
244
|
+
raise ValueError("invalid INDEX format. Usage: `name expr TYPE type_full GRANULARITY granularity`")
|
|
245
|
+
|
|
246
|
+
match = re.match(r"(\w+)\s+([\w\s*()]+)\s+TYPE\s+(\w+)(?:\(([\w.]+)\))?(?:\s+GRANULARITY\s+(\d+))?", index)
|
|
247
|
+
if match:
|
|
248
|
+
index_name, a, index_type, value, granularity = match.groups()
|
|
249
|
+
index_expr = f"{index_type}({value})" if value else index_type
|
|
250
|
+
parsed_indices.append(TableIndex(index_name, a.strip(), f"{index_expr}", granularity))
|
|
251
|
+
else:
|
|
252
|
+
raise ValueError("invalid INDEX format. Usage: `name expr TYPE type_full GRANULARITY granularity`")
|
|
253
|
+
return parsed_indices
|
|
254
|
+
|
|
255
|
+
|
|
180
256
|
def parse_table_structure(schema: str) -> List[Dict[str, Any]]:
|
|
181
257
|
"""This parses the SQL schema for a CREATE TABLE
|
|
182
258
|
Columns follow the syntax: name1 [type1] [DEFAULT|MATERIALIZED|ALIAS expr1] [compression_codec] [TTL expr1][,]
|
|
@@ -308,6 +384,12 @@ def parse_table_structure(schema: str) -> List[Dict[str, Any]]:
|
|
|
308
384
|
[{'name': 'arr', 'type': 'Array(String)', 'codec': None, 'default_value': "DEFAULT array('-')", 'jsonpath': None, 'nullable': False, 'normalized_name': 'arr'}]
|
|
309
385
|
>>> parse_table_structure('`a2` Float32 CODEC(Delta, ZSTD(4)) `json:$.a2`, `a3` String `json:$.a3`\\n')
|
|
310
386
|
[{'name': 'a2', 'type': 'Float32', 'codec': 'CODEC(Delta, ZSTD(4))', 'default_value': None, 'jsonpath': '$.a2', 'nullable': False, 'normalized_name': 'a2'}, {'name': 'a3', 'type': 'String', 'codec': None, 'default_value': None, 'jsonpath': '$.a3', 'nullable': False, 'normalized_name': 'a3'}]
|
|
387
|
+
>>> parse_table_structure('`a` String, INDEX index_name a TYPE set(100) GRANULARITY 100')
|
|
388
|
+
[{'name': 'a', 'type': 'String', 'codec': None, 'default_value': None, 'jsonpath': None, 'nullable': False, 'normalized_name': 'a'}]
|
|
389
|
+
>>> parse_table_structure('`a` String, INDEX index_name a TYPE set(100, 1) GRANULARITY 100')
|
|
390
|
+
[{'name': 'a', 'type': 'String', 'codec': None, 'default_value': None, 'jsonpath': None, 'nullable': False, 'normalized_name': 'a'}]
|
|
391
|
+
>>> parse_table_structure('`index` String, INDEX index_name a TYPE set(100, 1) GRANULARITY 100')
|
|
392
|
+
[{'name': 'index', 'type': 'String', 'codec': None, 'default_value': None, 'jsonpath': None, 'nullable': False, 'normalized_name': 'index'}]
|
|
311
393
|
"""
|
|
312
394
|
return _parse_table_structure(schema)
|
|
313
395
|
|
|
@@ -367,9 +449,6 @@ def _parse_table_structure(schema: str) -> List[Dict[str, Any]]: # noqa: C901
|
|
|
367
449
|
for _ in s:
|
|
368
450
|
advance_single_char()
|
|
369
451
|
|
|
370
|
-
valid_chars_name: str = string.ascii_letters + string.digits + "._`*<>+-'"
|
|
371
|
-
valid_chars_fn: str = valid_chars_name + "[](),=!?:/ \n\t\r"
|
|
372
|
-
|
|
373
452
|
def get_backticked() -> str:
|
|
374
453
|
begin = i
|
|
375
454
|
while i < len(schema):
|
|
@@ -447,6 +526,8 @@ def _parse_table_structure(schema: str) -> List[Dict[str, Any]]: # noqa: C901
|
|
|
447
526
|
|
|
448
527
|
def add_column(found: str) -> None:
|
|
449
528
|
nonlocal name, _type, default, materialized, codec, jsonpath
|
|
529
|
+
if name == "INDEX":
|
|
530
|
+
return
|
|
450
531
|
if not name:
|
|
451
532
|
raise ValueError(
|
|
452
533
|
format_parse_error(schema, i, pos, f"Syntax error: expecting NAME, found {found}", line=line)
|
|
@@ -479,6 +560,8 @@ def _parse_table_structure(schema: str) -> List[Dict[str, Any]]: # noqa: C901
|
|
|
479
560
|
continue
|
|
480
561
|
found = lookahead_matches(
|
|
481
562
|
[NULL, NOTNULL, DEFAULT, MATERIALIZED, ALIAS, CODEC, TTL, JSONPATH, COMMA, NEW_LINE, TYPE]
|
|
563
|
+
if name != "INDEX"
|
|
564
|
+
else [COMMA, NEW_LINE]
|
|
482
565
|
)
|
|
483
566
|
if found and found not in valid_next:
|
|
484
567
|
after = f" after {last.name}" if last else ""
|
|
@@ -531,11 +614,16 @@ def _parse_table_structure(schema: str) -> List[Dict[str, Any]]: # noqa: C901
|
|
|
531
614
|
advance("`json:")
|
|
532
615
|
jsonpath = get_backticked()
|
|
533
616
|
elif found == COMMA:
|
|
617
|
+
if name == "INDEX":
|
|
618
|
+
advance(",")
|
|
619
|
+
continue
|
|
534
620
|
advance(",")
|
|
535
621
|
valid_next = []
|
|
536
622
|
add_column("COMMA")
|
|
537
623
|
elif found == NEW_LINE:
|
|
538
624
|
i += 1
|
|
625
|
+
elif name == "INDEX" and not found:
|
|
626
|
+
i += 1
|
|
539
627
|
else:
|
|
540
628
|
raise ValueError(
|
|
541
629
|
format_parse_error(
|
|
@@ -1494,6 +1494,7 @@ async def deploy(
|
|
|
1494
1494
|
|
|
1495
1495
|
release_created = False
|
|
1496
1496
|
new_release = False
|
|
1497
|
+
check_backfill_required = False
|
|
1497
1498
|
if semver and current_semver:
|
|
1498
1499
|
new_version = version.parse(semver.split("-snapshot")[0])
|
|
1499
1500
|
current_version = version.parse(current_semver.split("-snapshot")[0])
|
|
@@ -1531,6 +1532,8 @@ async def deploy(
|
|
|
1531
1532
|
raise CLIException(FeedbackManager.error_exception(error=str(e)))
|
|
1532
1533
|
release_created = True
|
|
1533
1534
|
fork_downstream = True
|
|
1535
|
+
# allows TB_CHECK_BACKFILL_REQUIRED=0 so it is not checked
|
|
1536
|
+
check_backfill_required = getenv_bool("TB_CHECK_BACKFILL_REQUIRED", True)
|
|
1534
1537
|
try:
|
|
1535
1538
|
await folder_push(
|
|
1536
1539
|
tb_client=create_tb_client(ctx),
|
|
@@ -1560,6 +1563,8 @@ async def deploy(
|
|
|
1560
1563
|
fork=fork,
|
|
1561
1564
|
is_internal=is_internal,
|
|
1562
1565
|
release_created=release_created,
|
|
1566
|
+
auto_promote=auto_promote,
|
|
1567
|
+
check_backfill_required=check_backfill_required,
|
|
1563
1568
|
)
|
|
1564
1569
|
except Exception as e:
|
|
1565
1570
|
if release_created and not dry_run:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: tinybird-cli
|
|
3
|
-
Version: 3.3.1.
|
|
3
|
+
Version: 3.3.1.dev11
|
|
4
4
|
Summary: Tinybird Command Line Tool
|
|
5
5
|
Home-page: https://docs.tinybird.co/cli.html
|
|
6
6
|
Author: Tinybird
|
|
@@ -19,6 +19,16 @@ Changelog
|
|
|
19
19
|
|
|
20
20
|
---------
|
|
21
21
|
|
|
22
|
+
3.3.1.dev11
|
|
23
|
+
************
|
|
24
|
+
|
|
25
|
+
- `Add` Check backfill on preview is required when `tb deploy` modified datasources. Disable check with `TB_CHECK_BACKFILL_REQUIRED=0`.
|
|
26
|
+
|
|
27
|
+
3.3.1.dev10
|
|
28
|
+
************
|
|
29
|
+
|
|
30
|
+
- `Fixed` Fixed bug when a Data Source was created using an INDEX
|
|
31
|
+
|
|
22
32
|
3.3.1.dev9
|
|
23
33
|
************
|
|
24
34
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{tinybird-cli-3.3.1.dev9 → tinybird-cli-3.3.1.dev11}/tinybird/data_connectors/credentials.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{tinybird-cli-3.3.1.dev9 → tinybird-cli-3.3.1.dev11}/tinybird/tb_cli_modules/tinyunit/tinyunit.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{tinybird-cli-3.3.1.dev9 → tinybird-cli-3.3.1.dev11}/tinybird/tb_cli_modules/workspace_members.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{tinybird-cli-3.3.1.dev9 → tinybird-cli-3.3.1.dev11}/tinybird_cli.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|