tinybird 0.0.1.dev178__tar.gz → 0.0.1.dev180__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.

Potentially problematic release.


This version of tinybird might be problematic. Click here for more details.

Files changed (110) hide show
  1. {tinybird-0.0.1.dev178 → tinybird-0.0.1.dev180}/PKG-INFO +1 -1
  2. {tinybird-0.0.1.dev178 → tinybird-0.0.1.dev180}/tinybird/sql_toolset.py +79 -0
  3. {tinybird-0.0.1.dev178 → tinybird-0.0.1.dev180}/tinybird/tb/__cli__.py +2 -2
  4. {tinybird-0.0.1.dev178 → tinybird-0.0.1.dev180}/tinybird/tb/modules/build.py +5 -8
  5. {tinybird-0.0.1.dev178 → tinybird-0.0.1.dev180}/tinybird/tb/modules/deployment.py +3 -8
  6. {tinybird-0.0.1.dev178 → tinybird-0.0.1.dev180}/tinybird.egg-info/PKG-INFO +1 -1
  7. {tinybird-0.0.1.dev178 → tinybird-0.0.1.dev180}/setup.cfg +0 -0
  8. {tinybird-0.0.1.dev178 → tinybird-0.0.1.dev180}/tinybird/__cli__.py +0 -0
  9. {tinybird-0.0.1.dev178 → tinybird-0.0.1.dev180}/tinybird/ch_utils/constants.py +0 -0
  10. {tinybird-0.0.1.dev178 → tinybird-0.0.1.dev180}/tinybird/ch_utils/engine.py +0 -0
  11. {tinybird-0.0.1.dev178 → tinybird-0.0.1.dev180}/tinybird/check_pypi.py +0 -0
  12. {tinybird-0.0.1.dev178 → tinybird-0.0.1.dev180}/tinybird/client.py +0 -0
  13. {tinybird-0.0.1.dev178 → tinybird-0.0.1.dev180}/tinybird/config.py +0 -0
  14. {tinybird-0.0.1.dev178 → tinybird-0.0.1.dev180}/tinybird/connectors.py +0 -0
  15. {tinybird-0.0.1.dev178 → tinybird-0.0.1.dev180}/tinybird/context.py +0 -0
  16. {tinybird-0.0.1.dev178 → tinybird-0.0.1.dev180}/tinybird/datafile.py +0 -0
  17. {tinybird-0.0.1.dev178 → tinybird-0.0.1.dev180}/tinybird/datatypes.py +0 -0
  18. {tinybird-0.0.1.dev178 → tinybird-0.0.1.dev180}/tinybird/feedback_manager.py +0 -0
  19. {tinybird-0.0.1.dev178 → tinybird-0.0.1.dev180}/tinybird/git_settings.py +0 -0
  20. {tinybird-0.0.1.dev178 → tinybird-0.0.1.dev180}/tinybird/prompts.py +0 -0
  21. {tinybird-0.0.1.dev178 → tinybird-0.0.1.dev180}/tinybird/sql.py +0 -0
  22. {tinybird-0.0.1.dev178 → tinybird-0.0.1.dev180}/tinybird/sql_template.py +0 -0
  23. {tinybird-0.0.1.dev178 → tinybird-0.0.1.dev180}/tinybird/sql_template_fmt.py +0 -0
  24. {tinybird-0.0.1.dev178 → tinybird-0.0.1.dev180}/tinybird/syncasync.py +0 -0
  25. {tinybird-0.0.1.dev178 → tinybird-0.0.1.dev180}/tinybird/tb/check_pypi.py +0 -0
  26. {tinybird-0.0.1.dev178 → tinybird-0.0.1.dev180}/tinybird/tb/cli.py +0 -0
  27. {tinybird-0.0.1.dev178 → tinybird-0.0.1.dev180}/tinybird/tb/client.py +0 -0
  28. {tinybird-0.0.1.dev178 → tinybird-0.0.1.dev180}/tinybird/tb/config.py +0 -0
  29. {tinybird-0.0.1.dev178 → tinybird-0.0.1.dev180}/tinybird/tb/modules/cicd.py +0 -0
  30. {tinybird-0.0.1.dev178 → tinybird-0.0.1.dev180}/tinybird/tb/modules/cli.py +0 -0
  31. {tinybird-0.0.1.dev178 → tinybird-0.0.1.dev180}/tinybird/tb/modules/common.py +0 -0
  32. {tinybird-0.0.1.dev178 → tinybird-0.0.1.dev180}/tinybird/tb/modules/config.py +0 -0
  33. {tinybird-0.0.1.dev178 → tinybird-0.0.1.dev180}/tinybird/tb/modules/connection.py +0 -0
  34. {tinybird-0.0.1.dev178 → tinybird-0.0.1.dev180}/tinybird/tb/modules/copy.py +0 -0
  35. {tinybird-0.0.1.dev178 → tinybird-0.0.1.dev180}/tinybird/tb/modules/create.py +0 -0
  36. {tinybird-0.0.1.dev178 → tinybird-0.0.1.dev180}/tinybird/tb/modules/datafile/build.py +0 -0
  37. {tinybird-0.0.1.dev178 → tinybird-0.0.1.dev180}/tinybird/tb/modules/datafile/build_common.py +0 -0
  38. {tinybird-0.0.1.dev178 → tinybird-0.0.1.dev180}/tinybird/tb/modules/datafile/build_datasource.py +0 -0
  39. {tinybird-0.0.1.dev178 → tinybird-0.0.1.dev180}/tinybird/tb/modules/datafile/build_pipe.py +0 -0
  40. {tinybird-0.0.1.dev178 → tinybird-0.0.1.dev180}/tinybird/tb/modules/datafile/common.py +0 -0
  41. {tinybird-0.0.1.dev178 → tinybird-0.0.1.dev180}/tinybird/tb/modules/datafile/diff.py +0 -0
  42. {tinybird-0.0.1.dev178 → tinybird-0.0.1.dev180}/tinybird/tb/modules/datafile/exceptions.py +0 -0
  43. {tinybird-0.0.1.dev178 → tinybird-0.0.1.dev180}/tinybird/tb/modules/datafile/fixture.py +0 -0
  44. {tinybird-0.0.1.dev178 → tinybird-0.0.1.dev180}/tinybird/tb/modules/datafile/format_common.py +0 -0
  45. {tinybird-0.0.1.dev178 → tinybird-0.0.1.dev180}/tinybird/tb/modules/datafile/format_datasource.py +0 -0
  46. {tinybird-0.0.1.dev178 → tinybird-0.0.1.dev180}/tinybird/tb/modules/datafile/format_pipe.py +0 -0
  47. {tinybird-0.0.1.dev178 → tinybird-0.0.1.dev180}/tinybird/tb/modules/datafile/parse_datasource.py +0 -0
  48. {tinybird-0.0.1.dev178 → tinybird-0.0.1.dev180}/tinybird/tb/modules/datafile/parse_pipe.py +0 -0
  49. {tinybird-0.0.1.dev178 → tinybird-0.0.1.dev180}/tinybird/tb/modules/datafile/pipe_checker.py +0 -0
  50. {tinybird-0.0.1.dev178 → tinybird-0.0.1.dev180}/tinybird/tb/modules/datafile/playground.py +0 -0
  51. {tinybird-0.0.1.dev178 → tinybird-0.0.1.dev180}/tinybird/tb/modules/datafile/pull.py +0 -0
  52. {tinybird-0.0.1.dev178 → tinybird-0.0.1.dev180}/tinybird/tb/modules/datasource.py +0 -0
  53. {tinybird-0.0.1.dev178 → tinybird-0.0.1.dev180}/tinybird/tb/modules/deprecations.py +0 -0
  54. {tinybird-0.0.1.dev178 → tinybird-0.0.1.dev180}/tinybird/tb/modules/dev_server.py +0 -0
  55. {tinybird-0.0.1.dev178 → tinybird-0.0.1.dev180}/tinybird/tb/modules/endpoint.py +0 -0
  56. {tinybird-0.0.1.dev178 → tinybird-0.0.1.dev180}/tinybird/tb/modules/exceptions.py +0 -0
  57. {tinybird-0.0.1.dev178 → tinybird-0.0.1.dev180}/tinybird/tb/modules/feedback_manager.py +0 -0
  58. {tinybird-0.0.1.dev178 → tinybird-0.0.1.dev180}/tinybird/tb/modules/info.py +0 -0
  59. {tinybird-0.0.1.dev178 → tinybird-0.0.1.dev180}/tinybird/tb/modules/infra.py +0 -0
  60. {tinybird-0.0.1.dev178 → tinybird-0.0.1.dev180}/tinybird/tb/modules/job.py +0 -0
  61. {tinybird-0.0.1.dev178 → tinybird-0.0.1.dev180}/tinybird/tb/modules/llm.py +0 -0
  62. {tinybird-0.0.1.dev178 → tinybird-0.0.1.dev180}/tinybird/tb/modules/llm_utils.py +0 -0
  63. {tinybird-0.0.1.dev178 → tinybird-0.0.1.dev180}/tinybird/tb/modules/local.py +0 -0
  64. {tinybird-0.0.1.dev178 → tinybird-0.0.1.dev180}/tinybird/tb/modules/local_common.py +0 -0
  65. {tinybird-0.0.1.dev178 → tinybird-0.0.1.dev180}/tinybird/tb/modules/login.py +0 -0
  66. {tinybird-0.0.1.dev178 → tinybird-0.0.1.dev180}/tinybird/tb/modules/logout.py +0 -0
  67. {tinybird-0.0.1.dev178 → tinybird-0.0.1.dev180}/tinybird/tb/modules/materialization.py +0 -0
  68. {tinybird-0.0.1.dev178 → tinybird-0.0.1.dev180}/tinybird/tb/modules/mock.py +0 -0
  69. {tinybird-0.0.1.dev178 → tinybird-0.0.1.dev180}/tinybird/tb/modules/open.py +0 -0
  70. {tinybird-0.0.1.dev178 → tinybird-0.0.1.dev180}/tinybird/tb/modules/pipe.py +0 -0
  71. {tinybird-0.0.1.dev178 → tinybird-0.0.1.dev180}/tinybird/tb/modules/project.py +0 -0
  72. {tinybird-0.0.1.dev178 → tinybird-0.0.1.dev180}/tinybird/tb/modules/regions.py +0 -0
  73. {tinybird-0.0.1.dev178 → tinybird-0.0.1.dev180}/tinybird/tb/modules/secret.py +0 -0
  74. {tinybird-0.0.1.dev178 → tinybird-0.0.1.dev180}/tinybird/tb/modules/shell.py +0 -0
  75. {tinybird-0.0.1.dev178 → tinybird-0.0.1.dev180}/tinybird/tb/modules/table.py +0 -0
  76. {tinybird-0.0.1.dev178 → tinybird-0.0.1.dev180}/tinybird/tb/modules/telemetry.py +0 -0
  77. {tinybird-0.0.1.dev178 → tinybird-0.0.1.dev180}/tinybird/tb/modules/test.py +0 -0
  78. {tinybird-0.0.1.dev178 → tinybird-0.0.1.dev180}/tinybird/tb/modules/tinyunit/tinyunit.py +0 -0
  79. {tinybird-0.0.1.dev178 → tinybird-0.0.1.dev180}/tinybird/tb/modules/tinyunit/tinyunit_lib.py +0 -0
  80. {tinybird-0.0.1.dev178 → tinybird-0.0.1.dev180}/tinybird/tb/modules/token.py +0 -0
  81. {tinybird-0.0.1.dev178 → tinybird-0.0.1.dev180}/tinybird/tb/modules/watch.py +0 -0
  82. {tinybird-0.0.1.dev178 → tinybird-0.0.1.dev180}/tinybird/tb/modules/workspace.py +0 -0
  83. {tinybird-0.0.1.dev178 → tinybird-0.0.1.dev180}/tinybird/tb/modules/workspace_members.py +0 -0
  84. {tinybird-0.0.1.dev178 → tinybird-0.0.1.dev180}/tinybird/tb_cli.py +0 -0
  85. {tinybird-0.0.1.dev178 → tinybird-0.0.1.dev180}/tinybird/tb_cli_modules/auth.py +0 -0
  86. {tinybird-0.0.1.dev178 → tinybird-0.0.1.dev180}/tinybird/tb_cli_modules/branch.py +0 -0
  87. {tinybird-0.0.1.dev178 → tinybird-0.0.1.dev180}/tinybird/tb_cli_modules/cicd.py +0 -0
  88. {tinybird-0.0.1.dev178 → tinybird-0.0.1.dev180}/tinybird/tb_cli_modules/cli.py +0 -0
  89. {tinybird-0.0.1.dev178 → tinybird-0.0.1.dev180}/tinybird/tb_cli_modules/common.py +0 -0
  90. {tinybird-0.0.1.dev178 → tinybird-0.0.1.dev180}/tinybird/tb_cli_modules/config.py +0 -0
  91. {tinybird-0.0.1.dev178 → tinybird-0.0.1.dev180}/tinybird/tb_cli_modules/connection.py +0 -0
  92. {tinybird-0.0.1.dev178 → tinybird-0.0.1.dev180}/tinybird/tb_cli_modules/datasource.py +0 -0
  93. {tinybird-0.0.1.dev178 → tinybird-0.0.1.dev180}/tinybird/tb_cli_modules/exceptions.py +0 -0
  94. {tinybird-0.0.1.dev178 → tinybird-0.0.1.dev180}/tinybird/tb_cli_modules/fmt.py +0 -0
  95. {tinybird-0.0.1.dev178 → tinybird-0.0.1.dev180}/tinybird/tb_cli_modules/job.py +0 -0
  96. {tinybird-0.0.1.dev178 → tinybird-0.0.1.dev180}/tinybird/tb_cli_modules/pipe.py +0 -0
  97. {tinybird-0.0.1.dev178 → tinybird-0.0.1.dev180}/tinybird/tb_cli_modules/regions.py +0 -0
  98. {tinybird-0.0.1.dev178 → tinybird-0.0.1.dev180}/tinybird/tb_cli_modules/tag.py +0 -0
  99. {tinybird-0.0.1.dev178 → tinybird-0.0.1.dev180}/tinybird/tb_cli_modules/telemetry.py +0 -0
  100. {tinybird-0.0.1.dev178 → tinybird-0.0.1.dev180}/tinybird/tb_cli_modules/test.py +0 -0
  101. {tinybird-0.0.1.dev178 → tinybird-0.0.1.dev180}/tinybird/tb_cli_modules/tinyunit/tinyunit.py +0 -0
  102. {tinybird-0.0.1.dev178 → tinybird-0.0.1.dev180}/tinybird/tb_cli_modules/tinyunit/tinyunit_lib.py +0 -0
  103. {tinybird-0.0.1.dev178 → tinybird-0.0.1.dev180}/tinybird/tb_cli_modules/workspace.py +0 -0
  104. {tinybird-0.0.1.dev178 → tinybird-0.0.1.dev180}/tinybird/tb_cli_modules/workspace_members.py +0 -0
  105. {tinybird-0.0.1.dev178 → tinybird-0.0.1.dev180}/tinybird/tornado_template.py +0 -0
  106. {tinybird-0.0.1.dev178 → tinybird-0.0.1.dev180}/tinybird.egg-info/SOURCES.txt +0 -0
  107. {tinybird-0.0.1.dev178 → tinybird-0.0.1.dev180}/tinybird.egg-info/dependency_links.txt +0 -0
  108. {tinybird-0.0.1.dev178 → tinybird-0.0.1.dev180}/tinybird.egg-info/entry_points.txt +0 -0
  109. {tinybird-0.0.1.dev178 → tinybird-0.0.1.dev180}/tinybird.egg-info/requires.txt +0 -0
  110. {tinybird-0.0.1.dev178 → tinybird-0.0.1.dev180}/tinybird.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: tinybird
3
- Version: 0.0.1.dev178
3
+ Version: 0.0.1.dev180
4
4
  Summary: Tinybird Command Line Tool
5
5
  Home-page: https://www.tinybird.co/docs/forward/commands
6
6
  Author: Tinybird
@@ -1,5 +1,6 @@
1
1
  import copy
2
2
  import logging
3
+ import re
3
4
  from collections import defaultdict
4
5
  from datetime import datetime
5
6
  from functools import lru_cache
@@ -42,10 +43,88 @@ class InvalidResource(ValueError):
42
43
  self.table = table
43
44
 
44
45
 
46
+ class UnoptimizedJoinException(Exception):
47
+ def __init__(self, sql: str):
48
+ self.sql = sql
49
+ self.msg = f"Materialized node SQL contains a join that is not optimized: {sql}"
50
+ self.documentation = (
51
+ "/docs/work-with-data/optimization/opt201-fix-mistakes#understanding-the-materialized-join-issue"
52
+ )
53
+ super().__init__(self.msg)
54
+
55
+
56
+ ChQueryTable = Tuple[Optional[str], Optional[str], Optional[str]]
57
+
58
+
59
+ def get_left_table(sql: str, default_database: Optional[str] = None) -> ChQueryTable:
60
+ if default_database is None:
61
+ left_table = chquery.get_left_table(sql)
62
+ else:
63
+ left_table = chquery.get_left_table(sql, default_database=default_database)
64
+ return left_table
65
+
66
+
45
67
  def format_sql(sql: str) -> str:
46
68
  return chquery.format(sql)
47
69
 
48
70
 
71
+ def explain_plan(sql: str) -> str:
72
+ return chquery.explain_ast(sql)
73
+
74
+
75
+ def has_join(sql: str) -> bool:
76
+ return any(line.rstrip().startswith("TableJoin") for line in explain_plan(sql).split())
77
+
78
+
79
+ def has_unoptimized_join(sql: str, left_table: Optional[Union[Tuple[str, str], Tuple[str, str, str]]] = None) -> None:
80
+ """
81
+ Check if a SQL query contains an unoptimized join.
82
+ A join is considered optimized if the right table is filtered by the left table's data.
83
+
84
+ Args:
85
+ sql: The SQL query to check
86
+ left_table: Optional tuple of (database, table) for the left table
87
+
88
+ Raises:
89
+ UnoptimizedJoin: If an unoptimized join is found
90
+ """
91
+ # TODO: We should check that we are filtering the right table by the left table's data
92
+ # TODO: We should check if using EXPLAIN AST is better than using regex
93
+
94
+ number_of_joins = sum(1 for line in explain_plan(sql).split() if line.rstrip().startswith("TableJoin"))
95
+ if number_of_joins == 0:
96
+ return
97
+
98
+ if not left_table:
99
+ left_table = chquery.get_left_table(sql)
100
+ if not left_table:
101
+ return
102
+
103
+ # Find all JOIN clauses with subqueries
104
+ # This pattern matches anything between JOIN and ON/USING
105
+ join_pattern = r"(?:LEFT\s+|RIGHT\s+|INNER\s+|FULL\s+OUTER\s+)?JOIN\s*\((.*?)\)\s+(?:AS\s+\w+)?\s*(?:ON|USING)"
106
+
107
+ # Find all joins with subqueries
108
+ join_matches = list(re.finditer(join_pattern, sql, re.IGNORECASE | re.DOTALL))
109
+
110
+ if number_of_joins != len(join_matches):
111
+ logging.debug(f"number_of_joins: {number_of_joins}, join_matches: {join_matches}")
112
+ raise UnoptimizedJoinException(sql)
113
+
114
+ # If no joins with subqueries found, probably is an unoptimized join
115
+ if not join_matches:
116
+ raise UnoptimizedJoinException(sql)
117
+
118
+ # Check if the left table is referenced in the subquery
119
+ left_table_ref = f"{left_table[0]}.{left_table[1]}"
120
+
121
+ for match in join_matches:
122
+ subquery = match.group(1) # Get the captured subquery
123
+ logging.debug(f"subquery: {subquery} left_table_ref: {left_table_ref}")
124
+ if left_table_ref not in subquery:
125
+ raise UnoptimizedJoinException(sql)
126
+
127
+
49
128
  def format_where_for_mutation_command(where_clause: str) -> str:
50
129
  """
51
130
  >>> format_where_for_mutation_command("numnights = 99")
@@ -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__ = '0.0.1.dev178'
8
- __revision__ = 'c2632b6'
7
+ __version__ = '0.0.1.dev180'
8
+ __revision__ = '4ea1a7e'
@@ -89,7 +89,6 @@ def build_project(project: Project, tb_client: TinyB, silent: bool = False) -> O
89
89
  files = [
90
90
  ("context://", ("cli-version", "1.0.0", "text/plain")),
91
91
  ]
92
- fds = []
93
92
  project_path = project.path
94
93
  project_files = project.get_project_files()
95
94
 
@@ -98,10 +97,11 @@ def build_project(project: Project, tb_client: TinyB, silent: bool = False) -> O
98
97
 
99
98
  for file_path in project_files:
100
99
  relative_path = str(Path(file_path).relative_to(project_path))
101
- fd = open(file_path, "rb")
102
- fds.append(fd)
103
- content_type = DATAFILE_TYPE_TO_CONTENT_TYPE.get(Path(file_path).suffix, "application/unknown")
104
- files.append((MULTIPART_BOUNDARY_DATA_PROJECT, (relative_path, fd.read().decode("utf-8"), content_type)))
100
+ with open(file_path, "rb") as fd:
101
+ content_type = DATAFILE_TYPE_TO_CONTENT_TYPE.get(Path(file_path).suffix, "application/unknown")
102
+ files.append(
103
+ (MULTIPART_BOUNDARY_DATA_PROJECT, (relative_path, fd.read().decode("utf-8"), content_type))
104
+ )
105
105
  HEADERS = {"Authorization": f"Bearer {TINYBIRD_API_KEY}"}
106
106
 
107
107
  r = requests.post(TINYBIRD_API_URL, files=files, headers=HEADERS)
@@ -195,9 +195,6 @@ def build_project(project: Project, tb_client: TinyB, silent: bool = False) -> O
195
195
  error = f"Unknown build result. Error: {result.get('error')}"
196
196
  except Exception as e:
197
197
  error = str(e)
198
- finally:
199
- for fd in fds:
200
- fd.close()
201
198
 
202
199
  if error:
203
200
  raise click.ClickException(error)
@@ -524,13 +524,11 @@ def create_deployment(
524
524
  files = [
525
525
  ("context://", ("cli-version", "1.0.0", "text/plain")),
526
526
  ]
527
- fds = []
528
527
  for file_path in project.get_project_files():
529
528
  relative_path = str(Path(file_path).relative_to(project.path))
530
- fd = open(file_path, "rb")
531
- fds.append(fd)
532
- content_type = DATAFILE_TYPE_TO_CONTENT_TYPE.get(Path(file_path).suffix, "application/unknown")
533
- files.append((MULTIPART_BOUNDARY_DATA_PROJECT, (relative_path, fd.read().decode("utf-8"), content_type)))
529
+ with open(file_path, "rb") as fd:
530
+ content_type = DATAFILE_TYPE_TO_CONTENT_TYPE.get(Path(file_path).suffix, "application/unknown")
531
+ files.append((MULTIPART_BOUNDARY_DATA_PROJECT, (relative_path, fd.read().decode("utf-8"), content_type)))
534
532
 
535
533
  deployment = None
536
534
  try:
@@ -605,9 +603,6 @@ def create_deployment(
605
603
  click.echo(FeedbackManager.error(message=f"Unknown deployment result {status}"))
606
604
  except Exception as e:
607
605
  click.echo(FeedbackManager.error_exception(error=e))
608
- finally:
609
- for fd in fds:
610
- fd.close()
611
606
 
612
607
  if not deployment and not check:
613
608
  sys_exit("deployment_error", "Deployment failed")
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: tinybird
3
- Version: 0.0.1.dev178
3
+ Version: 0.0.1.dev180
4
4
  Summary: Tinybird Command Line Tool
5
5
  Home-page: https://www.tinybird.co/docs/forward/commands
6
6
  Author: Tinybird