mainsequence 4.3.20__tar.gz → 4.3.24__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 (138) hide show
  1. {mainsequence-4.3.20/mainsequence.egg-info → mainsequence-4.3.24}/PKG-INFO +1 -1
  2. {mainsequence-4.3.20 → mainsequence-4.3.24}/mainsequence/client/metatables/core.py +73 -4
  3. {mainsequence-4.3.20 → mainsequence-4.3.24/mainsequence.egg-info}/PKG-INFO +1 -1
  4. {mainsequence-4.3.20 → mainsequence-4.3.24}/pyproject.toml +1 -1
  5. {mainsequence-4.3.20 → mainsequence-4.3.24}/tests/test_meta_tables_client_models.py +202 -1
  6. {mainsequence-4.3.20 → mainsequence-4.3.24}/LICENSE +0 -0
  7. {mainsequence-4.3.20 → mainsequence-4.3.24}/README.md +0 -0
  8. {mainsequence-4.3.20 → mainsequence-4.3.24}/agent_scaffold/AGENTS.md +0 -0
  9. {mainsequence-4.3.20 → mainsequence-4.3.24}/agent_scaffold/skills/a2a_communication/SKILL.md +0 -0
  10. {mainsequence-4.3.20 → mainsequence-4.3.24}/agent_scaffold/skills/application_surfaces/api_surfaces/SKILL.md +0 -0
  11. {mainsequence-4.3.20 → mainsequence-4.3.24}/agent_scaffold/skills/command_center/adapter_from_api/SKILL.md +0 -0
  12. {mainsequence-4.3.20 → mainsequence-4.3.24}/agent_scaffold/skills/command_center/api_mock_prototyping/SKILL.md +0 -0
  13. {mainsequence-4.3.20 → mainsequence-4.3.24}/agent_scaffold/skills/command_center/app_components/SKILL.md +0 -0
  14. {mainsequence-4.3.20 → mainsequence-4.3.24}/agent_scaffold/skills/command_center/connections/SKILL.md +0 -0
  15. {mainsequence-4.3.20 → mainsequence-4.3.24}/agent_scaffold/skills/command_center/workspace_analysis/SKILL.md +0 -0
  16. {mainsequence-4.3.20 → mainsequence-4.3.24}/agent_scaffold/skills/command_center/workspace_builder/SKILL.md +0 -0
  17. {mainsequence-4.3.20 → mainsequence-4.3.24}/agent_scaffold/skills/command_center/workspace_design/SKILL.md +0 -0
  18. {mainsequence-4.3.20 → mainsequence-4.3.24}/agent_scaffold/skills/dashboards/streamlit/SKILL.md +0 -0
  19. {mainsequence-4.3.20 → mainsequence-4.3.24}/agent_scaffold/skills/data_access/exploration/SKILL.md +0 -0
  20. {mainsequence-4.3.20 → mainsequence-4.3.24}/agent_scaffold/skills/data_publishing/data_nodes/SKILL.md +0 -0
  21. {mainsequence-4.3.20 → mainsequence-4.3.24}/agent_scaffold/skills/data_publishing/meta_table_migrations/SKILL.md +0 -0
  22. {mainsequence-4.3.20 → mainsequence-4.3.24}/agent_scaffold/skills/data_publishing/meta_tables/SKILL.md +0 -0
  23. {mainsequence-4.3.20 → mainsequence-4.3.24}/agent_scaffold/skills/maintenance/bug_auditor/SKILL.md +0 -0
  24. {mainsequence-4.3.20 → mainsequence-4.3.24}/agent_scaffold/skills/ms-markets/SKILL.md +0 -0
  25. {mainsequence-4.3.20 → mainsequence-4.3.24}/agent_scaffold/skills/platform_operations/access_control_and_sharing/SKILL.md +0 -0
  26. {mainsequence-4.3.20 → mainsequence-4.3.24}/agent_scaffold/skills/platform_operations/orchestration_and_releases/SKILL.md +0 -0
  27. {mainsequence-4.3.20 → mainsequence-4.3.24}/agent_scaffold/skills/project_builder/SKILL.md +0 -0
  28. {mainsequence-4.3.20 → mainsequence-4.3.24}/agent_scaffold/skills/project_to_agent/SKILL.md +0 -0
  29. {mainsequence-4.3.20 → mainsequence-4.3.24}/mainsequence/__init__.py +0 -0
  30. {mainsequence-4.3.20 → mainsequence-4.3.24}/mainsequence/__main__.py +0 -0
  31. {mainsequence-4.3.20 → mainsequence-4.3.24}/mainsequence/bootstrap.py +0 -0
  32. {mainsequence-4.3.20 → mainsequence-4.3.24}/mainsequence/cli/__init__.py +0 -0
  33. {mainsequence-4.3.20 → mainsequence-4.3.24}/mainsequence/cli/api.py +0 -0
  34. {mainsequence-4.3.20 → mainsequence-4.3.24}/mainsequence/cli/browser_auth.py +0 -0
  35. {mainsequence-4.3.20 → mainsequence-4.3.24}/mainsequence/cli/cli.py +0 -0
  36. {mainsequence-4.3.20 → mainsequence-4.3.24}/mainsequence/cli/config.py +0 -0
  37. {mainsequence-4.3.20 → mainsequence-4.3.24}/mainsequence/cli/docker_utils.py +0 -0
  38. {mainsequence-4.3.20 → mainsequence-4.3.24}/mainsequence/cli/doctor.py +0 -0
  39. {mainsequence-4.3.20 → mainsequence-4.3.24}/mainsequence/cli/local_ops.py +0 -0
  40. {mainsequence-4.3.20 → mainsequence-4.3.24}/mainsequence/cli/migrations.py +0 -0
  41. {mainsequence-4.3.20 → mainsequence-4.3.24}/mainsequence/cli/model_filters.py +0 -0
  42. {mainsequence-4.3.20 → mainsequence-4.3.24}/mainsequence/cli/project_status.py +0 -0
  43. {mainsequence-4.3.20 → mainsequence-4.3.24}/mainsequence/cli/pydantic_cli.py +0 -0
  44. {mainsequence-4.3.20 → mainsequence-4.3.24}/mainsequence/cli/sdk_utils.py +0 -0
  45. {mainsequence-4.3.20 → mainsequence-4.3.24}/mainsequence/cli/ssh_utils.py +0 -0
  46. {mainsequence-4.3.20 → mainsequence-4.3.24}/mainsequence/cli/ui.py +0 -0
  47. {mainsequence-4.3.20 → mainsequence-4.3.24}/mainsequence/client/__init__.py +0 -0
  48. {mainsequence-4.3.20 → mainsequence-4.3.24}/mainsequence/client/agent_runtime_models.py +0 -0
  49. {mainsequence-4.3.20 → mainsequence-4.3.24}/mainsequence/client/base.py +0 -0
  50. {mainsequence-4.3.20 → mainsequence-4.3.24}/mainsequence/client/client.py +0 -0
  51. {mainsequence-4.3.20 → mainsequence-4.3.24}/mainsequence/client/command_center/__init__.py +0 -0
  52. {mainsequence-4.3.20 → mainsequence-4.3.24}/mainsequence/client/command_center/app_component.py +0 -0
  53. {mainsequence-4.3.20 → mainsequence-4.3.24}/mainsequence/client/command_center/connections.py +0 -0
  54. {mainsequence-4.3.20 → mainsequence-4.3.24}/mainsequence/client/command_center/data_models.py +0 -0
  55. {mainsequence-4.3.20 → mainsequence-4.3.24}/mainsequence/client/command_center/workspace.py +0 -0
  56. {mainsequence-4.3.20 → mainsequence-4.3.24}/mainsequence/client/command_center/workspace_snapshot.py +0 -0
  57. {mainsequence-4.3.20 → mainsequence-4.3.24}/mainsequence/client/compute_validation.py +0 -0
  58. {mainsequence-4.3.20 → mainsequence-4.3.24}/mainsequence/client/data_sources_interfaces/__init__.py +0 -0
  59. {mainsequence-4.3.20 → mainsequence-4.3.24}/mainsequence/client/data_sources_interfaces/duckdb.py +0 -0
  60. {mainsequence-4.3.20 → mainsequence-4.3.24}/mainsequence/client/data_sources_interfaces/local_paths.py +0 -0
  61. {mainsequence-4.3.20 → mainsequence-4.3.24}/mainsequence/client/data_sources_interfaces/sqlite.py +0 -0
  62. {mainsequence-4.3.20 → mainsequence-4.3.24}/mainsequence/client/dtype_codec.py +0 -0
  63. {mainsequence-4.3.20 → mainsequence-4.3.24}/mainsequence/client/exceptions.py +0 -0
  64. {mainsequence-4.3.20 → mainsequence-4.3.24}/mainsequence/client/fastapi/__init__.py +0 -0
  65. {mainsequence-4.3.20 → mainsequence-4.3.24}/mainsequence/client/fastapi/auth.py +0 -0
  66. {mainsequence-4.3.20 → mainsequence-4.3.24}/mainsequence/client/metatables/__init__.py +0 -0
  67. {mainsequence-4.3.20 → mainsequence-4.3.24}/mainsequence/client/models_foundry.py +0 -0
  68. {mainsequence-4.3.20 → mainsequence-4.3.24}/mainsequence/client/models_helpers.py +0 -0
  69. {mainsequence-4.3.20 → mainsequence-4.3.24}/mainsequence/client/models_user.py +0 -0
  70. {mainsequence-4.3.20 → mainsequence-4.3.24}/mainsequence/client/utils.py +0 -0
  71. {mainsequence-4.3.20 → mainsequence-4.3.24}/mainsequence/defaults.py +0 -0
  72. {mainsequence-4.3.20 → mainsequence-4.3.24}/mainsequence/instrumentation/__init__.py +0 -0
  73. {mainsequence-4.3.20 → mainsequence-4.3.24}/mainsequence/instrumentation/utils.py +0 -0
  74. {mainsequence-4.3.20 → mainsequence-4.3.24}/mainsequence/logconf.py +0 -0
  75. {mainsequence-4.3.20 → mainsequence-4.3.24}/mainsequence/meta_tables/__init__.py +0 -0
  76. {mainsequence-4.3.20 → mainsequence-4.3.24}/mainsequence/meta_tables/__main__.py +0 -0
  77. {mainsequence-4.3.20 → mainsequence-4.3.24}/mainsequence/meta_tables/compiled_sql/__init__.py +0 -0
  78. {mainsequence-4.3.20 → mainsequence-4.3.24}/mainsequence/meta_tables/compiled_sql/v1.py +0 -0
  79. {mainsequence-4.3.20 → mainsequence-4.3.24}/mainsequence/meta_tables/data_nodes/__init__.py +0 -0
  80. {mainsequence-4.3.20 → mainsequence-4.3.24}/mainsequence/meta_tables/data_nodes/build_operations.py +0 -0
  81. {mainsequence-4.3.20 → mainsequence-4.3.24}/mainsequence/meta_tables/data_nodes/data_nodes.py +0 -0
  82. {mainsequence-4.3.20 → mainsequence-4.3.24}/mainsequence/meta_tables/data_nodes/models.py +0 -0
  83. {mainsequence-4.3.20 → mainsequence-4.3.24}/mainsequence/meta_tables/data_nodes/namespacing.py +0 -0
  84. {mainsequence-4.3.20 → mainsequence-4.3.24}/mainsequence/meta_tables/data_nodes/persist_managers.py +0 -0
  85. {mainsequence-4.3.20 → mainsequence-4.3.24}/mainsequence/meta_tables/data_nodes/run_operations.py +0 -0
  86. {mainsequence-4.3.20 → mainsequence-4.3.24}/mainsequence/meta_tables/data_nodes/utils.py +0 -0
  87. {mainsequence-4.3.20 → mainsequence-4.3.24}/mainsequence/meta_tables/future_registry.py +0 -0
  88. {mainsequence-4.3.20 → mainsequence-4.3.24}/mainsequence/meta_tables/hashing.py +0 -0
  89. {mainsequence-4.3.20 → mainsequence-4.3.24}/mainsequence/meta_tables/migrations/__init__.py +0 -0
  90. {mainsequence-4.3.20 → mainsequence-4.3.24}/mainsequence/meta_tables/migrations/alembic.py +0 -0
  91. {mainsequence-4.3.20 → mainsequence-4.3.24}/mainsequence/meta_tables/migrations/env.py +0 -0
  92. {mainsequence-4.3.20 → mainsequence-4.3.24}/mainsequence/meta_tables/migrations/provider.py +0 -0
  93. {mainsequence-4.3.20 → mainsequence-4.3.24}/mainsequence/meta_tables/migrations/registry.py +0 -0
  94. {mainsequence-4.3.20 → mainsequence-4.3.24}/mainsequence/meta_tables/migrations/scaffold.py +0 -0
  95. {mainsequence-4.3.20 → mainsequence-4.3.24}/mainsequence/meta_tables/migrations/templates/__init__.py +0 -0
  96. {mainsequence-4.3.20 → mainsequence-4.3.24}/mainsequence/meta_tables/migrations/templates/env.py.mako +0 -0
  97. {mainsequence-4.3.20 → mainsequence-4.3.24}/mainsequence/meta_tables/migrations/templates/script.py.mako +0 -0
  98. {mainsequence-4.3.20 → mainsequence-4.3.24}/mainsequence/meta_tables/pydantic_metadata.py +0 -0
  99. {mainsequence-4.3.20 → mainsequence-4.3.24}/mainsequence/meta_tables/schema_names.py +0 -0
  100. {mainsequence-4.3.20 → mainsequence-4.3.24}/mainsequence/meta_tables/sqlalchemy_contracts.py +0 -0
  101. {mainsequence-4.3.20 → mainsequence-4.3.24}/mainsequence/runtime_flags.py +0 -0
  102. {mainsequence-4.3.20 → mainsequence-4.3.24}/mainsequence.egg-info/SOURCES.txt +0 -0
  103. {mainsequence-4.3.20 → mainsequence-4.3.24}/mainsequence.egg-info/dependency_links.txt +0 -0
  104. {mainsequence-4.3.20 → mainsequence-4.3.24}/mainsequence.egg-info/entry_points.txt +0 -0
  105. {mainsequence-4.3.20 → mainsequence-4.3.24}/mainsequence.egg-info/requires.txt +0 -0
  106. {mainsequence-4.3.20 → mainsequence-4.3.24}/mainsequence.egg-info/top_level.txt +0 -0
  107. {mainsequence-4.3.20 → mainsequence-4.3.24}/setup.cfg +0 -0
  108. {mainsequence-4.3.20 → mainsequence-4.3.24}/tests/test_auth_precedence.py +0 -0
  109. {mainsequence-4.3.20 → mainsequence-4.3.24}/tests/test_build_operations_hashing.py +0 -0
  110. {mainsequence-4.3.20 → mainsequence-4.3.24}/tests/test_cli.py +0 -0
  111. {mainsequence-4.3.20 → mainsequence-4.3.24}/tests/test_cli_browser_auth.py +0 -0
  112. {mainsequence-4.3.20 → mainsequence-4.3.24}/tests/test_cli_migrations.py +0 -0
  113. {mainsequence-4.3.20 → mainsequence-4.3.24}/tests/test_client.py +0 -0
  114. {mainsequence-4.3.20 → mainsequence-4.3.24}/tests/test_command_center_app_component_models.py +0 -0
  115. {mainsequence-4.3.20 → mainsequence-4.3.24}/tests/test_command_center_data_models.py +0 -0
  116. {mainsequence-4.3.20 → mainsequence-4.3.24}/tests/test_command_center_models.py +0 -0
  117. {mainsequence-4.3.20 → mainsequence-4.3.24}/tests/test_data_access_mixin_dimension_audit.py +0 -0
  118. {mainsequence-4.3.20 → mainsequence-4.3.24}/tests/test_data_node_storage_dimension_queries.py +0 -0
  119. {mainsequence-4.3.20 → mainsequence-4.3.24}/tests/test_data_node_update_flow.py +0 -0
  120. {mainsequence-4.3.20 → mainsequence-4.3.24}/tests/test_dependency_extras.py +0 -0
  121. {mainsequence-4.3.20 → mainsequence-4.3.24}/tests/test_duckdb_interface_dimensions.py +0 -0
  122. {mainsequence-4.3.20 → mainsequence-4.3.24}/tests/test_filter_normalization.py +0 -0
  123. {mainsequence-4.3.20 → mainsequence-4.3.24}/tests/test_instrumentation.py +0 -0
  124. {mainsequence-4.3.20 → mainsequence-4.3.24}/tests/test_logconf.py +0 -0
  125. {mainsequence-4.3.20 → mainsequence-4.3.24}/tests/test_meta_table_migrations.py +0 -0
  126. {mainsequence-4.3.20 → mainsequence-4.3.24}/tests/test_meta_tables_sqlalchemy_contracts.py +0 -0
  127. {mainsequence-4.3.20 → mainsequence-4.3.24}/tests/test_models_user_request_bound_auth.py +0 -0
  128. {mainsequence-4.3.20 → mainsequence-4.3.24}/tests/test_pod_project_resolution.py +0 -0
  129. {mainsequence-4.3.20 → mainsequence-4.3.24}/tests/test_project_batch_jobs_from_file.py +0 -0
  130. {mainsequence-4.3.20 → mainsequence-4.3.24}/tests/test_run_configuration.py +0 -0
  131. {mainsequence-4.3.20 → mainsequence-4.3.24}/tests/test_schema_names.py +0 -0
  132. {mainsequence-4.3.20 → mainsequence-4.3.24}/tests/test_secret_client_model.py +0 -0
  133. {mainsequence-4.3.20 → mainsequence-4.3.24}/tests/test_source_table_configuration.py +0 -0
  134. {mainsequence-4.3.20 → mainsequence-4.3.24}/tests/test_sqlite_interface_dimensions.py +0 -0
  135. {mainsequence-4.3.20 → mainsequence-4.3.24}/tests/test_update_runner_uid_runtime.py +0 -0
  136. {mainsequence-4.3.20 → mainsequence-4.3.24}/tests/test_update_statistics.py +0 -0
  137. {mainsequence-4.3.20 → mainsequence-4.3.24}/tests/test_update_uid_guards.py +0 -0
  138. {mainsequence-4.3.20 → mainsequence-4.3.24}/tests/test_workspace_snapshot.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mainsequence
3
- Version: 4.3.20
3
+ Version: 4.3.24
4
4
  Summary: Main Sequence SDK
5
5
  Author-email: Main Sequence GmbH <dev@main-sequence.io>
6
6
  License: MainSequence GmbH SDK License Agreement
@@ -500,9 +500,17 @@ class MetaTableOperationScope(BasePydanticModel):
500
500
  return self
501
501
 
502
502
 
503
+ DEFAULT_META_TABLE_OPERATION_MAX_ROWS = 1_000
504
+ DEFAULT_META_TABLE_OPERATION_STATEMENT_TIMEOUT_MS = 15_000
505
+
506
+
503
507
  class MetaTableOperationLimits(BasePydanticModel):
504
- max_rows: int | None = Field(default=None, ge=1)
505
- statement_timeout_ms: int | None = Field(default=None, ge=1)
508
+ max_rows: int = Field(default=DEFAULT_META_TABLE_OPERATION_MAX_ROWS, ge=1)
509
+ offset: int = Field(default=0, ge=0)
510
+ statement_timeout_ms: int = Field(
511
+ default=DEFAULT_META_TABLE_OPERATION_STATEMENT_TIMEOUT_MS,
512
+ ge=1,
513
+ )
506
514
 
507
515
 
508
516
  class MetaTableCompiledSQLOperation(BasePydanticModel):
@@ -511,7 +519,12 @@ class MetaTableCompiledSQLOperation(BasePydanticModel):
511
519
  dialect: MetaTableCompiledSQLDialect = "postgresql"
512
520
  statement: MetaTableStatementPayload
513
521
  scope: MetaTableOperationScope
514
- limits: MetaTableOperationLimits | None = None
522
+ limits: MetaTableOperationLimits = Field(default_factory=MetaTableOperationLimits)
523
+
524
+ @field_validator("limits", mode="before")
525
+ @classmethod
526
+ def default_limits(cls, value):
527
+ return {} if value is None else value
515
528
 
516
529
 
517
530
  class MetaTableRequestFields(BasePydanticModel):
@@ -1704,12 +1717,68 @@ class MetaTable(BasePydanticModel, LabelableObjectMixin, ShareableObjectMixin, B
1704
1717
  if isinstance(operation, MetaTableCompiledSQLOperation)
1705
1718
  else MetaTableCompiledSQLOperation(**operation)
1706
1719
  )
1707
- return cls._post_action(
1720
+ response = cls._post_action(
1708
1721
  "execute-operation",
1709
1722
  payload,
1710
1723
  timeout=timeout,
1711
1724
  expected_statuses=(200,),
1712
1725
  )
1726
+ if payload.operation != "select":
1727
+ return response
1728
+
1729
+ rows = response.get("rows")
1730
+ if not isinstance(rows, list):
1731
+ return response
1732
+
1733
+ requested_max_rows = payload.limits.max_rows
1734
+ if len(rows) >= requested_max_rows:
1735
+ return response
1736
+
1737
+ pagination = response.get("pagination") or {}
1738
+ has_more = bool(pagination.get("has_more"))
1739
+ next_offset = pagination.get("next_offset")
1740
+ if not has_more or next_offset in (None, ""):
1741
+ return response
1742
+
1743
+ accumulated_rows = list(rows)
1744
+ last_pagination = pagination
1745
+ while (
1746
+ has_more
1747
+ and next_offset not in (None, "")
1748
+ and len(accumulated_rows) < requested_max_rows
1749
+ ):
1750
+ remaining_rows = requested_max_rows - len(accumulated_rows)
1751
+ next_payload = payload.model_copy(deep=True)
1752
+ next_payload.limits.offset = int(next_offset)
1753
+ next_payload.limits.max_rows = remaining_rows
1754
+ page_response = cls._post_action(
1755
+ "execute-operation",
1756
+ next_payload,
1757
+ timeout=timeout,
1758
+ expected_statuses=(200,),
1759
+ )
1760
+ page_rows = page_response.get("rows") or []
1761
+ if not isinstance(page_rows, list) or not page_rows:
1762
+ last_pagination = page_response.get("pagination") or {}
1763
+ break
1764
+
1765
+ accumulated_rows.extend(page_rows[:remaining_rows])
1766
+ last_pagination = page_response.get("pagination") or {}
1767
+ has_more = bool(last_pagination.get("has_more"))
1768
+ next_offset = last_pagination.get("next_offset")
1769
+
1770
+ response["rows"] = accumulated_rows
1771
+ response["row_count"] = len(accumulated_rows)
1772
+ response["max_rows"] = requested_max_rows
1773
+ response["truncated"] = bool(last_pagination.get("has_more"))
1774
+ response["pagination"] = {
1775
+ "limit": requested_max_rows,
1776
+ "offset": payload.limits.offset,
1777
+ "returned_count": len(accumulated_rows),
1778
+ "has_more": bool(last_pagination.get("has_more")),
1779
+ "next_offset": last_pagination.get("next_offset"),
1780
+ }
1781
+ return response
1713
1782
 
1714
1783
 
1715
1784
  # Global executor (or you could define one on your class)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mainsequence
3
- Version: 4.3.20
3
+ Version: 4.3.24
4
4
  Summary: Main Sequence SDK
5
5
  Author-email: Main Sequence GmbH <dev@main-sequence.io>
6
6
  License: MainSequence GmbH SDK License Agreement
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "mainsequence"
7
- version = "4.3.20"
7
+ version = "4.3.24"
8
8
  description = "Main Sequence SDK "
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.11"
@@ -410,6 +410,182 @@ def test_meta_table_execute_operation_serializes_scope_uid(monkeypatch):
410
410
  assert captured["payload"]["json"]["statement"]["parameters"] == {
411
411
  "symbol_1": "%BTC%",
412
412
  }
413
+ assert captured["payload"]["json"]["limits"]["offset"] == 0
414
+
415
+
416
+ def test_meta_table_execute_operation_fetches_requested_rows_with_backend_pagination(
417
+ monkeypatch,
418
+ ):
419
+ calls = []
420
+
421
+ def fake_make_request(**kwargs):
422
+ payload = kwargs["payload"]["json"]
423
+ calls.append(payload)
424
+ offset = payload["limits"]["offset"]
425
+ if offset == 0:
426
+ return _Response(
427
+ {
428
+ "ok": True,
429
+ "operation": "select",
430
+ "dialect": "postgresql",
431
+ "row_count": 2,
432
+ "rows": [{"value": 1}, {"value": 2}],
433
+ "truncated": True,
434
+ "max_rows": 2,
435
+ "pagination": {
436
+ "limit": 2,
437
+ "offset": 0,
438
+ "returned_count": 2,
439
+ "has_more": True,
440
+ "next_offset": 2,
441
+ },
442
+ }
443
+ )
444
+ if offset == 2:
445
+ return _Response(
446
+ {
447
+ "ok": True,
448
+ "operation": "select",
449
+ "dialect": "postgresql",
450
+ "row_count": 2,
451
+ "rows": [{"value": 3}, {"value": 4}],
452
+ "truncated": True,
453
+ "max_rows": 2,
454
+ "pagination": {
455
+ "limit": 2,
456
+ "offset": 2,
457
+ "returned_count": 2,
458
+ "has_more": True,
459
+ "next_offset": 4,
460
+ },
461
+ }
462
+ )
463
+ return _Response(
464
+ {
465
+ "ok": True,
466
+ "operation": "select",
467
+ "dialect": "postgresql",
468
+ "row_count": 1,
469
+ "rows": [{"value": 5}],
470
+ "truncated": False,
471
+ "max_rows": 1,
472
+ "pagination": {
473
+ "limit": 1,
474
+ "offset": 4,
475
+ "returned_count": 1,
476
+ "has_more": False,
477
+ "next_offset": None,
478
+ },
479
+ }
480
+ )
481
+
482
+ monkeypatch.setattr(meta_table_models, "make_request", fake_make_request)
483
+ monkeypatch.setattr(
484
+ meta_table_models.MetaTable,
485
+ "build_session",
486
+ classmethod(lambda cls: SimpleNamespace(headers={})),
487
+ )
488
+
489
+ result = meta_table_models.MetaTable.execute_operation(
490
+ {
491
+ "operation": "select",
492
+ "statement": {
493
+ "sql": "SELECT value FROM public.asset ORDER BY value",
494
+ "parameters": {},
495
+ },
496
+ "scope": {
497
+ "data_source_uid": "dddddddd-dddd-4ddd-8ddd-dddddddddddd",
498
+ "tables": [
499
+ {
500
+ "meta_table_uid": "aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa",
501
+ "alias": "asset",
502
+ }
503
+ ],
504
+ },
505
+ "limits": {
506
+ "max_rows": 5,
507
+ "statement_timeout_ms": 15000,
508
+ },
509
+ }
510
+ )
511
+
512
+ assert [row["value"] for row in result["rows"]] == [1, 2, 3, 4, 5]
513
+ assert result["row_count"] == 5
514
+ assert result["max_rows"] == 5
515
+ assert result["truncated"] is False
516
+ assert result["pagination"] == {
517
+ "limit": 5,
518
+ "offset": 0,
519
+ "returned_count": 5,
520
+ "has_more": False,
521
+ "next_offset": None,
522
+ }
523
+ assert [call["limits"]["offset"] for call in calls] == [0, 2, 4]
524
+ assert [call["limits"]["max_rows"] for call in calls] == [5, 3, 1]
525
+
526
+
527
+ def test_meta_table_execute_operation_does_not_paginate_upsert(monkeypatch):
528
+ calls = []
529
+
530
+ def fake_make_request(**kwargs):
531
+ calls.append(kwargs["payload"]["json"])
532
+ return _Response(
533
+ {
534
+ "ok": True,
535
+ "operation": "upsert",
536
+ "dialect": "postgresql",
537
+ "row_count": 1,
538
+ "rows": [{"uid": "aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa"}],
539
+ "truncated": True,
540
+ "max_rows": 1,
541
+ "pagination": {
542
+ "limit": 1,
543
+ "offset": 0,
544
+ "returned_count": 1,
545
+ "has_more": True,
546
+ "next_offset": 1,
547
+ },
548
+ }
549
+ )
550
+
551
+ monkeypatch.setattr(meta_table_models, "make_request", fake_make_request)
552
+ monkeypatch.setattr(
553
+ meta_table_models.MetaTable,
554
+ "build_session",
555
+ classmethod(lambda cls: SimpleNamespace(headers={})),
556
+ )
557
+
558
+ result = meta_table_models.MetaTable.execute_operation(
559
+ {
560
+ "operation": "upsert",
561
+ "statement": {
562
+ "sql": (
563
+ "INSERT INTO public.asset (uid) VALUES (%(uid)s::UUID) "
564
+ "ON CONFLICT (uid) DO UPDATE SET uid = %(uid)s::UUID "
565
+ "RETURNING uid"
566
+ ),
567
+ "parameters": {"uid": "aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa"},
568
+ },
569
+ "scope": {
570
+ "data_source_uid": "dddddddd-dddd-4ddd-8ddd-dddddddddddd",
571
+ "tables": [
572
+ {
573
+ "meta_table_uid": "aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa",
574
+ "alias": "asset",
575
+ "access": "write",
576
+ }
577
+ ],
578
+ },
579
+ "limits": {
580
+ "max_rows": 1,
581
+ "statement_timeout_ms": 15000,
582
+ },
583
+ }
584
+ )
585
+
586
+ assert result["operation"] == "upsert"
587
+ assert len(calls) == 1
588
+ assert calls[0]["limits"]["offset"] == 0
413
589
 
414
590
 
415
591
  def test_dynamic_table_data_source_issue_migration_connection_posts_scope(monkeypatch):
@@ -728,6 +904,31 @@ def test_compiled_sql_v1_protocol_is_validated_by_pydantic():
728
904
  )
729
905
 
730
906
 
907
+ def test_compiled_sql_v1_operation_uses_backend_limit_defaults():
908
+ operation = build_operation(
909
+ operation="select",
910
+ sql="SELECT asset.symbol FROM public.asset AS asset",
911
+ scope={
912
+ "dataSourceUid": "dddddddd-dddd-4ddd-8ddd-dddddddddddd",
913
+ "tables": [
914
+ {
915
+ "metaTableUid": "aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa",
916
+ "alias": "asset",
917
+ }
918
+ ]
919
+ },
920
+ )
921
+
922
+ assert operation.limits.max_rows == 1_000
923
+ assert operation.limits.offset == 0
924
+ assert operation.limits.statement_timeout_ms == 15_000
925
+ assert meta_table_models._payload_json(operation)["limits"] == {
926
+ "max_rows": 1_000,
927
+ "offset": 0,
928
+ "statement_timeout_ms": 15_000,
929
+ }
930
+
931
+
731
932
  def test_compiled_sql_v1_scope_resolves_session_data_source(monkeypatch):
732
933
  monkeypatch.setattr(
733
934
  meta_table_models,
@@ -774,7 +975,7 @@ def test_compiled_sql_v1_serializes_typed_temporal_parameters():
774
975
  "metaTableUid": "aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa",
775
976
  "alias": "asset",
776
977
  }
777
- ]
978
+ ],
778
979
  },
779
980
  )
780
981
 
File without changes
File without changes
File without changes