tinybird-toolset 2.5.0__tar.gz → 2.5.4__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.
Files changed (30) hide show
  1. {tinybird_toolset-2.5.0/src/tinybird_toolset.egg-info → tinybird_toolset-2.5.4}/PKG-INFO +1 -1
  2. {tinybird_toolset-2.5.0 → tinybird_toolset-2.5.4}/setup.py +17 -21
  3. {tinybird_toolset-2.5.0 → tinybird_toolset-2.5.4/src/tinybird_toolset.egg-info}/PKG-INFO +1 -1
  4. {tinybird_toolset-2.5.0 → tinybird_toolset-2.5.4}/tests/test_convert_to_row_binary.py +64 -0
  5. {tinybird_toolset-2.5.0 → tinybird_toolset-2.5.4}/tests/test_tables.py +1 -0
  6. {tinybird_toolset-2.5.0 → tinybird_toolset-2.5.4}/tests/test_validate_ttl.py +42 -0
  7. {tinybird_toolset-2.5.0 → tinybird_toolset-2.5.4}/LICENSE +0 -0
  8. {tinybird_toolset-2.5.0 → tinybird_toolset-2.5.4}/MANIFEST.in +0 -0
  9. {tinybird_toolset-2.5.0 → tinybird_toolset-2.5.4}/README.md +0 -0
  10. {tinybird_toolset-2.5.0 → tinybird_toolset-2.5.4}/conf.py +0 -0
  11. {tinybird_toolset-2.5.0 → tinybird_toolset-2.5.4}/setup.cfg +0 -0
  12. {tinybird_toolset-2.5.0 → tinybird_toolset-2.5.4}/src/chtoolset/__init__.py +0 -0
  13. {tinybird_toolset-2.5.0 → tinybird_toolset-2.5.4}/src/chtoolset/query.py +0 -0
  14. {tinybird_toolset-2.5.0 → tinybird_toolset-2.5.4}/src/tinybird_toolset.egg-info/SOURCES.txt +0 -0
  15. {tinybird_toolset-2.5.0 → tinybird_toolset-2.5.4}/src/tinybird_toolset.egg-info/dependency_links.txt +0 -0
  16. {tinybird_toolset-2.5.0 → tinybird_toolset-2.5.4}/src/tinybird_toolset.egg-info/requires.txt +0 -0
  17. {tinybird_toolset-2.5.0 → tinybird_toolset-2.5.4}/src/tinybird_toolset.egg-info/top_level.txt +0 -0
  18. {tinybird_toolset-2.5.0 → tinybird_toolset-2.5.4}/tests/test_check_compatible_types.py +0 -0
  19. {tinybird_toolset-2.5.0 → tinybird_toolset-2.5.4}/tests/test_check_write_query.py +0 -0
  20. {tinybird_toolset-2.5.0 → tinybird_toolset-2.5.4}/tests/test_chquery.py +0 -0
  21. {tinybird_toolset-2.5.0 → tinybird_toolset-2.5.4}/tests/test_explain_ast.py +0 -0
  22. {tinybird_toolset-2.5.0 → tinybird_toolset-2.5.4}/tests/test_get_columns_from_create_query.py +0 -0
  23. {tinybird_toolset-2.5.0 → tinybird_toolset-2.5.4}/tests/test_get_left_table.py +0 -0
  24. {tinybird_toolset-2.5.0 → tinybird_toolset-2.5.4}/tests/test_internal_cache.py +0 -0
  25. {tinybird_toolset-2.5.0 → tinybird_toolset-2.5.4}/tests/test_normalize_query_keep_names.py +0 -0
  26. {tinybird_toolset-2.5.0 → tinybird_toolset-2.5.4}/tests/test_normalize_table_column.py +0 -0
  27. {tinybird_toolset-2.5.0 → tinybird_toolset-2.5.4}/tests/test_parse_create_materialized_view_target_table.py +0 -0
  28. {tinybird_toolset-2.5.0 → tinybird_toolset-2.5.4}/tests/test_replace_tables.py +0 -0
  29. {tinybird_toolset-2.5.0 → tinybird_toolset-2.5.4}/tests/test_replace_tables_backward_compat.py +0 -0
  30. {tinybird_toolset-2.5.0 → tinybird_toolset-2.5.4}/tests/test_rewrite_aggregation_states.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: tinybird-toolset
3
- Version: 2.5.0
3
+ Version: 2.5.4
4
4
  Home-page: https://gitlab.com/tinybird/clickhouse-toolset
5
5
  Author: Tinybird.co
6
6
  Author-email: support@tinybird.co
@@ -1,7 +1,21 @@
1
1
  from setuptools import setup, Extension
2
2
 
3
3
  NAME = 'tinybird-toolset'
4
- VERSION = '2.5.0'
4
+ VERSION = '2.5.4'
5
+
6
+ # Shared metadata for both the full (extension) build and the metadata-only
7
+ # fallback below, so the two setup() calls can't drift apart.
8
+ common_kwargs = dict(
9
+ name=NAME,
10
+ version=VERSION,
11
+ url="https://gitlab.com/tinybird/clickhouse-toolset",
12
+ author="Tinybird.co",
13
+ author_email="support@tinybird.co",
14
+ packages=["chtoolset"],
15
+ package_dir={"": "src"},
16
+ python_requires=">=3.10, <3.15",
17
+ install_requires=[],
18
+ )
5
19
 
6
20
  try:
7
21
  from conf import *
@@ -32,15 +46,7 @@ try:
32
46
  ],
33
47
  )
34
48
  setup(
35
- name=NAME,
36
- version=VERSION,
37
- url="https://gitlab.com/tinybird/clickhouse-toolset",
38
- author="Tinybird.co",
39
- author_email="support@tinybird.co",
40
- packages=["chtoolset"],
41
- package_dir={"": "src"},
42
- python_requires=">=3.10, <3.15",
43
- install_requires=[],
49
+ **common_kwargs,
44
50
  extras_require={"test": requirements_from_file("requirements-test.txt")},
45
51
  cmdclass={
46
52
  "clickhouse": ClickHouseBuildExt,
@@ -51,14 +57,4 @@ try:
51
57
  )
52
58
 
53
59
  except ModuleNotFoundError:
54
- setup(
55
- name=NAME,
56
- version=VERSION,
57
- url="https://gitlab.com/tinybird/clickhouse-toolset",
58
- author="Tinybird.co",
59
- author_email="support@tinybird.co",
60
- packages=["chtoolset"],
61
- package_dir={"": "src"},
62
- python_requires=">=3.10, <3.15",
63
- install_requires=[],
64
- )
60
+ setup(**common_kwargs)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: tinybird-toolset
3
- Version: 2.5.0
3
+ Version: 2.5.4
4
4
  Home-page: https://gitlab.com/tinybird/clickhouse-toolset
5
5
  Author: Tinybird.co
6
6
  Author-email: support@tinybird.co
@@ -8467,6 +8467,70 @@ TEST_CASES = [
8467
8467
 
8468
8468
 
8469
8469
  class TestRowBinaryEncoder:
8470
+ @pytest.mark.parametrize("legacy_conversion_mode", [True, False])
8471
+ def test_convert_ipv4_to_row_binary(self, legacy_conversion_mode):
8472
+ schema = json.dumps(get_schema([('address', 'IPv4', '$.address', False)]))
8473
+
8474
+ with chquery.RowBinaryEncoder(schema, legacy_conversion_mode=legacy_conversion_mode) as encoder:
8475
+ result, quarantine, nrows, nquarantine = encoder.encode('{"address": "192.0.2.1"}')
8476
+
8477
+ assert result == b'\x00\x01\x02\x00\xc0'
8478
+ assert quarantine == b''
8479
+ assert nrows == 1
8480
+ assert nquarantine == 0
8481
+
8482
+ @pytest.mark.parametrize("legacy_conversion_mode", [True, False])
8483
+ def test_convert_ipv6_to_row_binary(self, legacy_conversion_mode):
8484
+ schema = json.dumps(get_schema([('address', 'IPv6', '$.address', False)]))
8485
+
8486
+ with chquery.RowBinaryEncoder(schema, legacy_conversion_mode=legacy_conversion_mode) as encoder:
8487
+ result, quarantine, nrows, nquarantine = encoder.encode('{"address": "2001:db8::1"}')
8488
+
8489
+ assert result == b'\x00\x20\x01\x0d\xb8' + b'\x00' * 11 + b'\x01'
8490
+ assert quarantine == b''
8491
+ assert nrows == 1
8492
+ assert nquarantine == 0
8493
+
8494
+ @pytest.mark.parametrize("legacy_conversion_mode", [True, False])
8495
+ def test_convert_ipv4_formatted_address_to_ipv6_row_binary(self, legacy_conversion_mode):
8496
+ schema = json.dumps(get_schema([('address', 'IPv6', '$.address', False)]))
8497
+
8498
+ with chquery.RowBinaryEncoder(schema, legacy_conversion_mode=legacy_conversion_mode) as encoder:
8499
+ result, quarantine, nrows, nquarantine = encoder.encode('{"address": "1.1.1.1"}')
8500
+
8501
+ assert result == b'\x00' + b'\x00' * 10 + b'\xff\xff\x01\x01\x01\x01'
8502
+ assert quarantine == b''
8503
+ assert nrows == 1
8504
+ assert nquarantine == 0
8505
+
8506
+ @pytest.mark.parametrize("legacy_conversion_mode", [True, False])
8507
+ @pytest.mark.parametrize("address_type", ["IPv4", "IPv6"])
8508
+ def test_invalid_ip_address_is_quarantined(self, legacy_conversion_mode, address_type):
8509
+ schema = json.dumps(get_schema([('address', address_type, '$.address', False)]))
8510
+
8511
+ with chquery.RowBinaryEncoder(schema, legacy_conversion_mode=legacy_conversion_mode) as encoder:
8512
+ result, quarantine, nrows, nquarantine = encoder.encode('{"address": "invalid-ip"}')
8513
+
8514
+ assert result == b''
8515
+ assert quarantine != b''
8516
+ assert b"invalid-ip" in quarantine
8517
+ assert nrows == 0
8518
+ assert nquarantine == 1
8519
+
8520
+ @pytest.mark.parametrize("legacy_conversion_mode", [True, False])
8521
+ @pytest.mark.parametrize("address", ["1.1.1.1junk", "2001:db8::1junk"])
8522
+ def test_ipv6_with_trailing_junk_is_quarantined(self, legacy_conversion_mode, address):
8523
+ schema = json.dumps(get_schema([('address', 'IPv6', '$.address', False)]))
8524
+
8525
+ with chquery.RowBinaryEncoder(schema, legacy_conversion_mode=legacy_conversion_mode) as encoder:
8526
+ result, quarantine, nrows, nquarantine = encoder.encode(json.dumps({"address": address}))
8527
+
8528
+ assert result == b''
8529
+ assert quarantine != b''
8530
+ assert address.encode() in quarantine
8531
+ assert nrows == 0
8532
+ assert nquarantine == 1
8533
+
8470
8534
  @pytest.mark.parametrize("conversion_mode, schema, data, expected_result, expected_quarantine, expected_nrows, expected_nquarantine", TEST_CASES)
8471
8535
  def test_legacy_convert_to_row_binary(self, conversion_mode, schema, data, expected_result, expected_quarantine, expected_nrows, expected_nquarantine):
8472
8536
  schema_rowbinary = get_schema(schema)
@@ -2033,6 +2033,7 @@ SELECT *
2033
2033
  optimize_aggregation_in_order = 1,
2034
2034
  use_skip_indexes = 1,
2035
2035
  use_skip_indexes_if_final = 0,
2036
+ do_not_merge_across_partitions_select_final = 1,
2036
2037
  optimize_move_to_prewhere = 1,
2037
2038
  query_plan_optimize_lazy_materialization = 0,
2038
2039
  min_bytes_to_use_direct_io = 0,
@@ -333,6 +333,48 @@ class TestValidateTTL(unittest.TestCase):
333
333
  f"{name} should be a known function in TTL WHERE clauses",
334
334
  )
335
335
 
336
+ # --- Hash functions in sorting / primary keys (KeyDescription::parse) ---
337
+ def test_valid_sorting_key_with_cityhash64(self):
338
+ self.assertIsNone(
339
+ chquery.validate_ttl(
340
+ ttl="timestamp + INTERVAL 365 DAY",
341
+ columns=[
342
+ {"name": "organizationId", "type": "String"},
343
+ {"name": "surfaceId", "type": "String"},
344
+ {"name": "timestamp", "type": "DateTime"},
345
+ {"name": "name", "type": "String"},
346
+ {"name": "traceId", "type": "String"},
347
+ {"name": "spanId", "type": "String"},
348
+ {"name": "eventIndex", "type": "UInt32"},
349
+ ],
350
+ sorting_key="organizationId, surfaceId, toDate(timestamp), name, cityHash64(traceId), spanId, eventIndex",
351
+ )
352
+ )
353
+
354
+ # --- Arithmetic functions in TTL expressions ---
355
+ def test_valid_ttl_with_int_div(self):
356
+ # Reported failure: "Unknown function intDiv".
357
+ self.assertIsNone(
358
+ chquery.validate_ttl(
359
+ ttl="toDateTime(intDiv(ts_server, 1000)) + INTERVAL 13 MONTH",
360
+ columns=[{"name": "ts_server", "type": "Int64"}],
361
+ sorting_key="ts_server",
362
+ )
363
+ )
364
+
365
+ def test_valid_ttl_with_greatest(self):
366
+ # Reported failure: "Unknown function greatest".
367
+ self.assertIsNone(
368
+ chquery.validate_ttl(
369
+ ttl="greatest(departure_date, toDateTime(creation_date)) + toIntervalDay(2)",
370
+ columns=[
371
+ {"name": "departure_date", "type": "DateTime"},
372
+ {"name": "creation_date", "type": "Date"},
373
+ ],
374
+ sorting_key="departure_date",
375
+ )
376
+ )
377
+
336
378
  # --- Input validation ---
337
379
  def test_columns_must_be_list_of_dicts(self):
338
380
  with self.assertRaises(TypeError):