moose-lib 0.6.129__tar.gz → 0.6.131__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 (49) hide show
  1. {moose_lib-0.6.129 → moose_lib-0.6.131}/PKG-INFO +1 -1
  2. {moose_lib-0.6.129 → moose_lib-0.6.131}/moose_lib/data_models.py +44 -0
  3. {moose_lib-0.6.129 → moose_lib-0.6.131}/moose_lib.egg-info/PKG-INFO +1 -1
  4. {moose_lib-0.6.129 → moose_lib-0.6.131}/moose_lib.egg-info/SOURCES.txt +2 -1
  5. moose_lib-0.6.131/tests/test_simple_aggregate.py +112 -0
  6. {moose_lib-0.6.129 → moose_lib-0.6.131}/README.md +0 -0
  7. {moose_lib-0.6.129 → moose_lib-0.6.131}/moose_lib/__init__.py +0 -0
  8. {moose_lib-0.6.129 → moose_lib-0.6.131}/moose_lib/blocks.py +0 -0
  9. {moose_lib-0.6.129 → moose_lib-0.6.131}/moose_lib/clients/__init__.py +0 -0
  10. {moose_lib-0.6.129 → moose_lib-0.6.131}/moose_lib/clients/redis_client.py +0 -0
  11. {moose_lib-0.6.129 → moose_lib-0.6.131}/moose_lib/commons.py +0 -0
  12. {moose_lib-0.6.129 → moose_lib-0.6.131}/moose_lib/config/__init__.py +0 -0
  13. {moose_lib-0.6.129 → moose_lib-0.6.131}/moose_lib/config/config_file.py +0 -0
  14. {moose_lib-0.6.129 → moose_lib-0.6.131}/moose_lib/config/runtime.py +0 -0
  15. {moose_lib-0.6.129 → moose_lib-0.6.131}/moose_lib/dmv2/__init__.py +0 -0
  16. {moose_lib-0.6.129 → moose_lib-0.6.131}/moose_lib/dmv2/_registry.py +0 -0
  17. {moose_lib-0.6.129 → moose_lib-0.6.131}/moose_lib/dmv2/consumption.py +0 -0
  18. {moose_lib-0.6.129 → moose_lib-0.6.131}/moose_lib/dmv2/ingest_api.py +0 -0
  19. {moose_lib-0.6.129 → moose_lib-0.6.131}/moose_lib/dmv2/ingest_pipeline.py +0 -0
  20. {moose_lib-0.6.129 → moose_lib-0.6.131}/moose_lib/dmv2/life_cycle.py +0 -0
  21. {moose_lib-0.6.129 → moose_lib-0.6.131}/moose_lib/dmv2/materialized_view.py +0 -0
  22. {moose_lib-0.6.129 → moose_lib-0.6.131}/moose_lib/dmv2/olap_table.py +0 -0
  23. {moose_lib-0.6.129 → moose_lib-0.6.131}/moose_lib/dmv2/registry.py +0 -0
  24. {moose_lib-0.6.129 → moose_lib-0.6.131}/moose_lib/dmv2/sql_resource.py +0 -0
  25. {moose_lib-0.6.129 → moose_lib-0.6.131}/moose_lib/dmv2/stream.py +0 -0
  26. {moose_lib-0.6.129 → moose_lib-0.6.131}/moose_lib/dmv2/types.py +0 -0
  27. {moose_lib-0.6.129 → moose_lib-0.6.131}/moose_lib/dmv2/view.py +0 -0
  28. {moose_lib-0.6.129 → moose_lib-0.6.131}/moose_lib/dmv2/workflow.py +0 -0
  29. {moose_lib-0.6.129 → moose_lib-0.6.131}/moose_lib/dmv2_serializer.py +0 -0
  30. {moose_lib-0.6.129 → moose_lib-0.6.131}/moose_lib/internal.py +0 -0
  31. {moose_lib-0.6.129 → moose_lib-0.6.131}/moose_lib/main.py +0 -0
  32. {moose_lib-0.6.129 → moose_lib-0.6.131}/moose_lib/query_builder.py +0 -0
  33. {moose_lib-0.6.129 → moose_lib-0.6.131}/moose_lib/query_param.py +0 -0
  34. {moose_lib-0.6.129 → moose_lib-0.6.131}/moose_lib/streaming/__init__.py +0 -0
  35. {moose_lib-0.6.129 → moose_lib-0.6.131}/moose_lib/streaming/streaming_function_runner.py +0 -0
  36. {moose_lib-0.6.129 → moose_lib-0.6.131}/moose_lib/utilities/__init__.py +0 -0
  37. {moose_lib-0.6.129 → moose_lib-0.6.131}/moose_lib/utilities/sql.py +0 -0
  38. {moose_lib-0.6.129 → moose_lib-0.6.131}/moose_lib.egg-info/dependency_links.txt +0 -0
  39. {moose_lib-0.6.129 → moose_lib-0.6.131}/moose_lib.egg-info/requires.txt +0 -0
  40. {moose_lib-0.6.129 → moose_lib-0.6.131}/moose_lib.egg-info/top_level.txt +0 -0
  41. {moose_lib-0.6.129 → moose_lib-0.6.131}/setup.cfg +0 -0
  42. {moose_lib-0.6.129 → moose_lib-0.6.131}/setup.py +0 -0
  43. {moose_lib-0.6.129 → moose_lib-0.6.131}/tests/__init__.py +0 -0
  44. {moose_lib-0.6.129 → moose_lib-0.6.131}/tests/conftest.py +0 -0
  45. {moose_lib-0.6.129 → moose_lib-0.6.131}/tests/test_moose.py +0 -0
  46. {moose_lib-0.6.129 → moose_lib-0.6.131}/tests/test_olap_table_versioning.py +0 -0
  47. {moose_lib-0.6.129 → moose_lib-0.6.131}/tests/test_query_builder.py +0 -0
  48. {moose_lib-0.6.129 → moose_lib-0.6.131}/tests/test_redis_client.py +0 -0
  49. {moose_lib-0.6.129 → moose_lib-0.6.131}/tests/test_s3queue_config.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: moose_lib
3
- Version: 0.6.129
3
+ Version: 0.6.131
4
4
  Home-page: https://www.fiveonefour.com/moose
5
5
  Author: Fiveonefour Labs Inc.
6
6
  Author-email: support@fiveonefour.com
@@ -78,6 +78,46 @@ class AggregateFunction:
78
78
  }
79
79
 
80
80
 
81
+ def simple_aggregated[T](
82
+ agg_func: str,
83
+ arg_type: Type[T]
84
+ ) -> Type[T]:
85
+ """Helper to create a SimpleAggregateFunction type annotation.
86
+
87
+ SimpleAggregateFunction is a ClickHouse type for storing aggregated values directly
88
+ instead of intermediate states. It's more efficient for functions like sum, max, min, etc.
89
+
90
+ Args:
91
+ agg_func: The aggregation function name (e.g., "sum", "max", "anyLast")
92
+ arg_type: The argument type for the function (also the result type)
93
+
94
+ Returns:
95
+ An Annotated type with SimpleAggregateFunction metadata
96
+
97
+ Example:
98
+ ```python
99
+ from moose_lib import simple_aggregated
100
+
101
+ row_count: simple_aggregated("sum", int)
102
+ max_value: simple_aggregated("max", float)
103
+ last_status: simple_aggregated("anyLast", str)
104
+ ```
105
+ """
106
+ return Annotated[arg_type, SimpleAggregateFunction(agg_func=agg_func, arg_type=arg_type)]
107
+
108
+
109
+ @dataclasses.dataclass(frozen=True)
110
+ class SimpleAggregateFunction:
111
+ agg_func: str
112
+ arg_type: type | GenericAlias | _BaseGenericAlias
113
+
114
+ def to_dict(self):
115
+ return {
116
+ "functionName": self.agg_func,
117
+ "argumentType": py_type_to_column_type(self.arg_type, [])[2]
118
+ }
119
+
120
+
81
121
  def enum_value_serializer(value: int | str):
82
122
  if isinstance(value, int):
83
123
  return {"Int": value}
@@ -352,6 +392,10 @@ def _to_columns(model: type[BaseModel]) -> list[Column]:
352
392
  annotations.append(
353
393
  ("aggregationFunction", md.to_dict())
354
394
  )
395
+ if isinstance(md, SimpleAggregateFunction):
396
+ annotations.append(
397
+ ("simpleAggregationFunction", md.to_dict())
398
+ )
355
399
  if md == "LowCardinality":
356
400
  annotations.append(
357
401
  ("LowCardinality", True)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: moose_lib
3
- Version: 0.6.129
3
+ Version: 0.6.131
4
4
  Home-page: https://www.fiveonefour.com/moose
5
5
  Author: Fiveonefour Labs Inc.
6
6
  Author-email: support@fiveonefour.com
@@ -43,4 +43,5 @@ tests/test_moose.py
43
43
  tests/test_olap_table_versioning.py
44
44
  tests/test_query_builder.py
45
45
  tests/test_redis_client.py
46
- tests/test_s3queue_config.py
46
+ tests/test_s3queue_config.py
47
+ tests/test_simple_aggregate.py
@@ -0,0 +1,112 @@
1
+ import datetime
2
+ from pydantic import BaseModel
3
+
4
+ from moose_lib import simple_aggregated, Key
5
+ from moose_lib.data_models import SimpleAggregateFunction, _to_columns
6
+
7
+
8
+ def test_simple_aggregated_helper():
9
+ """Test that simple_aggregated helper creates correct annotation"""
10
+ annotated_type = simple_aggregated('sum', int)
11
+
12
+ # Check that it's annotated
13
+ assert hasattr(annotated_type, '__metadata__')
14
+ metadata = annotated_type.__metadata__[0]
15
+
16
+ # Check metadata is SimpleAggregateFunction instance
17
+ assert isinstance(metadata, SimpleAggregateFunction)
18
+ assert metadata.agg_func == 'sum'
19
+ assert metadata.arg_type == int
20
+
21
+
22
+ def test_simple_aggregate_function_to_dict():
23
+ """Test that SimpleAggregateFunction.to_dict() creates correct structure"""
24
+ func = SimpleAggregateFunction(agg_func='sum', arg_type=int)
25
+ result = func.to_dict()
26
+
27
+ assert result['functionName'] == 'sum'
28
+ assert 'argumentType' in result
29
+ # Python int maps to "Int" by default (not "Int64")
30
+ assert result['argumentType'] == 'Int'
31
+
32
+
33
+ def test_simple_aggregate_function_to_dict_with_different_types():
34
+ """Test SimpleAggregateFunction.to_dict() with various types"""
35
+ # Test with float
36
+ func_float = SimpleAggregateFunction(agg_func='max', arg_type=float)
37
+ result_float = func_float.to_dict()
38
+ assert result_float['functionName'] == 'max'
39
+ assert result_float['argumentType'] == 'Float64'
40
+
41
+ # Test with str
42
+ func_str = SimpleAggregateFunction(agg_func='anyLast', arg_type=str)
43
+ result_str = func_str.to_dict()
44
+ assert result_str['functionName'] == 'anyLast'
45
+ assert result_str['argumentType'] == 'String'
46
+
47
+
48
+ def test_dataclass_with_simple_aggregated():
49
+ """Test that BaseModel with simple_aggregated field converts correctly"""
50
+ class TestModel(BaseModel):
51
+ date_stamp: Key[datetime.datetime]
52
+ table_name: Key[str]
53
+ row_count: simple_aggregated('sum', int)
54
+
55
+ columns = _to_columns(TestModel)
56
+
57
+ # Find the row_count column
58
+ row_count_col = next(c for c in columns if c.name == 'row_count')
59
+
60
+ # Check basic type - Python int maps to "Int"
61
+ assert row_count_col.data_type == 'Int'
62
+
63
+ # Check annotation
64
+ simple_agg_annotation = next(
65
+ (a for a in row_count_col.annotations if a[0] == 'simpleAggregationFunction'),
66
+ None
67
+ )
68
+ assert simple_agg_annotation is not None
69
+ assert simple_agg_annotation[1]['functionName'] == 'sum'
70
+ assert simple_agg_annotation[1]['argumentType'] == 'Int'
71
+
72
+
73
+ def test_multiple_simple_aggregated_fields():
74
+ """Test BaseModel with multiple SimpleAggregateFunction fields"""
75
+ class StatsModel(BaseModel):
76
+ timestamp: Key[datetime.datetime]
77
+ total_count: simple_aggregated('sum', int)
78
+ max_value: simple_aggregated('max', int)
79
+ min_value: simple_aggregated('min', int)
80
+ last_seen: simple_aggregated('anyLast', datetime.datetime)
81
+
82
+ columns = _to_columns(StatsModel)
83
+
84
+ # Test sum
85
+ sum_col = next(c for c in columns if c.name == 'total_count')
86
+ sum_annotation = next(
87
+ a for a in sum_col.annotations if a[0] == 'simpleAggregationFunction'
88
+ )
89
+ assert sum_annotation[1]['functionName'] == 'sum'
90
+
91
+ # Test max
92
+ max_col = next(c for c in columns if c.name == 'max_value')
93
+ max_annotation = next(
94
+ a for a in max_col.annotations if a[0] == 'simpleAggregationFunction'
95
+ )
96
+ assert max_annotation[1]['functionName'] == 'max'
97
+
98
+ # Test min
99
+ min_col = next(c for c in columns if c.name == 'min_value')
100
+ min_annotation = next(
101
+ a for a in min_col.annotations if a[0] == 'simpleAggregationFunction'
102
+ )
103
+ assert min_annotation[1]['functionName'] == 'min'
104
+
105
+ # Test anyLast with datetime
106
+ last_col = next(c for c in columns if c.name == 'last_seen')
107
+ assert last_col.data_type == 'DateTime'
108
+ last_annotation = next(
109
+ a for a in last_col.annotations if a[0] == 'simpleAggregationFunction'
110
+ )
111
+ assert last_annotation[1]['functionName'] == 'anyLast'
112
+ assert last_annotation[1]['argumentType'] == 'DateTime'
File without changes
File without changes
File without changes