mainsequence 4.4.25__tar.gz → 4.4.26__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.
- {mainsequence-4.4.25 → mainsequence-4.4.26}/PKG-INFO +1 -1
- {mainsequence-4.4.25 → mainsequence-4.4.26}/mainsequence/cli/migrations.py +6 -0
- {mainsequence-4.4.25 → mainsequence-4.4.26}/mainsequence/client/metatables/core.py +105 -3
- {mainsequence-4.4.25 → mainsequence-4.4.26}/mainsequence/meta_tables/data_nodes/data_nodes.py +59 -3
- {mainsequence-4.4.25 → mainsequence-4.4.26}/mainsequence/meta_tables/data_nodes/persist_managers.py +96 -8
- {mainsequence-4.4.25 → mainsequence-4.4.26}/mainsequence/meta_tables/migrations/__init__.py +182 -66
- {mainsequence-4.4.25 → mainsequence-4.4.26}/mainsequence/meta_tables/sqlalchemy_contracts.py +60 -0
- {mainsequence-4.4.25 → mainsequence-4.4.26}/mainsequence.egg-info/PKG-INFO +1 -1
- {mainsequence-4.4.25 → mainsequence-4.4.26}/pyproject.toml +1 -1
- {mainsequence-4.4.25 → mainsequence-4.4.26}/tests/test_data_access_mixin_dimension_audit.py +3 -0
- {mainsequence-4.4.25 → mainsequence-4.4.26}/tests/test_meta_table_migrations.py +37 -11
- {mainsequence-4.4.25 → mainsequence-4.4.26}/tests/test_meta_tables_client_models.py +40 -0
- {mainsequence-4.4.25 → mainsequence-4.4.26}/tests/test_meta_tables_sqlalchemy_contracts.py +9 -1
- {mainsequence-4.4.25 → mainsequence-4.4.26}/tests/test_run_configuration.py +2 -1
- {mainsequence-4.4.25 → mainsequence-4.4.26}/LICENSE +0 -0
- {mainsequence-4.4.25 → mainsequence-4.4.26}/README.md +0 -0
- {mainsequence-4.4.25 → mainsequence-4.4.26}/agent_scaffold/AGENTS.md +0 -0
- {mainsequence-4.4.25 → mainsequence-4.4.26}/agent_scaffold/skills/a2a_communication/SKILL.md +0 -0
- {mainsequence-4.4.25 → mainsequence-4.4.26}/agent_scaffold/skills/application_surfaces/api_surfaces/SKILL.md +0 -0
- {mainsequence-4.4.25 → mainsequence-4.4.26}/agent_scaffold/skills/command_center/adapter_from_api/SKILL.md +0 -0
- {mainsequence-4.4.25 → mainsequence-4.4.26}/agent_scaffold/skills/command_center/api_mock_prototyping/SKILL.md +0 -0
- {mainsequence-4.4.25 → mainsequence-4.4.26}/agent_scaffold/skills/command_center/connections/SKILL.md +0 -0
- {mainsequence-4.4.25 → mainsequence-4.4.26}/agent_scaffold/skills/command_center/widgets/app_components/SKILL.md +0 -0
- {mainsequence-4.4.25 → mainsequence-4.4.26}/agent_scaffold/skills/command_center/widgets/tables/SKILL.md +0 -0
- {mainsequence-4.4.25 → mainsequence-4.4.26}/agent_scaffold/skills/command_center/widgets/tabular_transform/SKILL.md +0 -0
- {mainsequence-4.4.25 → mainsequence-4.4.26}/agent_scaffold/skills/command_center/workspace_analysis/SKILL.md +0 -0
- {mainsequence-4.4.25 → mainsequence-4.4.26}/agent_scaffold/skills/command_center/workspace_builder/SKILL.md +0 -0
- {mainsequence-4.4.25 → mainsequence-4.4.26}/agent_scaffold/skills/command_center/workspace_design/SKILL.md +0 -0
- {mainsequence-4.4.25 → mainsequence-4.4.26}/agent_scaffold/skills/dashboards/streamlit/SKILL.md +0 -0
- {mainsequence-4.4.25 → mainsequence-4.4.26}/agent_scaffold/skills/data_access/exploration/SKILL.md +0 -0
- {mainsequence-4.4.25 → mainsequence-4.4.26}/agent_scaffold/skills/data_publishing/data_nodes/SKILL.md +0 -0
- {mainsequence-4.4.25 → mainsequence-4.4.26}/agent_scaffold/skills/data_publishing/meta_table_migrations/SKILL.md +0 -0
- {mainsequence-4.4.25 → mainsequence-4.4.26}/agent_scaffold/skills/data_publishing/meta_tables/SKILL.md +0 -0
- {mainsequence-4.4.25 → mainsequence-4.4.26}/agent_scaffold/skills/maintenance/bug_auditor/SKILL.md +0 -0
- {mainsequence-4.4.25 → mainsequence-4.4.26}/agent_scaffold/skills/ms-markets/SKILL.md +0 -0
- {mainsequence-4.4.25 → mainsequence-4.4.26}/agent_scaffold/skills/platform_operations/access_control_and_sharing/SKILL.md +0 -0
- {mainsequence-4.4.25 → mainsequence-4.4.26}/agent_scaffold/skills/platform_operations/orchestration_and_releases/SKILL.md +0 -0
- {mainsequence-4.4.25 → mainsequence-4.4.26}/agent_scaffold/skills/project_builder/SKILL.md +0 -0
- {mainsequence-4.4.25 → mainsequence-4.4.26}/agent_scaffold/skills/project_to_agent/SKILL.md +0 -0
- {mainsequence-4.4.25 → mainsequence-4.4.26}/mainsequence/__init__.py +0 -0
- {mainsequence-4.4.25 → mainsequence-4.4.26}/mainsequence/__main__.py +0 -0
- {mainsequence-4.4.25 → mainsequence-4.4.26}/mainsequence/bootstrap.py +0 -0
- {mainsequence-4.4.25 → mainsequence-4.4.26}/mainsequence/cli/__init__.py +0 -0
- {mainsequence-4.4.25 → mainsequence-4.4.26}/mainsequence/cli/api.py +0 -0
- {mainsequence-4.4.25 → mainsequence-4.4.26}/mainsequence/cli/browser_auth.py +0 -0
- {mainsequence-4.4.25 → mainsequence-4.4.26}/mainsequence/cli/cli.py +0 -0
- {mainsequence-4.4.25 → mainsequence-4.4.26}/mainsequence/cli/config.py +0 -0
- {mainsequence-4.4.25 → mainsequence-4.4.26}/mainsequence/cli/docker_utils.py +0 -0
- {mainsequence-4.4.25 → mainsequence-4.4.26}/mainsequence/cli/doctor.py +0 -0
- {mainsequence-4.4.25 → mainsequence-4.4.26}/mainsequence/cli/local_ops.py +0 -0
- {mainsequence-4.4.25 → mainsequence-4.4.26}/mainsequence/cli/model_filters.py +0 -0
- {mainsequence-4.4.25 → mainsequence-4.4.26}/mainsequence/cli/project_status.py +0 -0
- {mainsequence-4.4.25 → mainsequence-4.4.26}/mainsequence/cli/pydantic_cli.py +0 -0
- {mainsequence-4.4.25 → mainsequence-4.4.26}/mainsequence/cli/sdk_utils.py +0 -0
- {mainsequence-4.4.25 → mainsequence-4.4.26}/mainsequence/cli/ssh_utils.py +0 -0
- {mainsequence-4.4.25 → mainsequence-4.4.26}/mainsequence/cli/ui.py +0 -0
- {mainsequence-4.4.25 → mainsequence-4.4.26}/mainsequence/client/__init__.py +0 -0
- {mainsequence-4.4.25 → mainsequence-4.4.26}/mainsequence/client/agent_runtime_models.py +0 -0
- {mainsequence-4.4.25 → mainsequence-4.4.26}/mainsequence/client/base.py +0 -0
- {mainsequence-4.4.25 → mainsequence-4.4.26}/mainsequence/client/client.py +0 -0
- {mainsequence-4.4.25 → mainsequence-4.4.26}/mainsequence/client/command_center/__init__.py +0 -0
- {mainsequence-4.4.25 → mainsequence-4.4.26}/mainsequence/client/command_center/app_component.py +0 -0
- {mainsequence-4.4.25 → mainsequence-4.4.26}/mainsequence/client/command_center/connections.py +0 -0
- {mainsequence-4.4.25 → mainsequence-4.4.26}/mainsequence/client/command_center/contracts/__init__.py +0 -0
- {mainsequence-4.4.25 → mainsequence-4.4.26}/mainsequence/client/command_center/contracts/adapter_from_api.py +0 -0
- {mainsequence-4.4.25 → mainsequence-4.4.26}/mainsequence/client/command_center/contracts/response_mapping.py +0 -0
- {mainsequence-4.4.25 → mainsequence-4.4.26}/mainsequence/client/command_center/contracts/table_visuals.py +0 -0
- {mainsequence-4.4.25 → mainsequence-4.4.26}/mainsequence/client/command_center/contracts/tabular.py +0 -0
- {mainsequence-4.4.25 → mainsequence-4.4.26}/mainsequence/client/command_center/contracts/ui.py +0 -0
- {mainsequence-4.4.25 → mainsequence-4.4.26}/mainsequence/client/command_center/data_models.py +0 -0
- {mainsequence-4.4.25 → mainsequence-4.4.26}/mainsequence/client/command_center/providers/__init__.py +0 -0
- {mainsequence-4.4.25 → mainsequence-4.4.26}/mainsequence/client/command_center/providers/adapter_from_api.py +0 -0
- {mainsequence-4.4.25 → mainsequence-4.4.26}/mainsequence/client/command_center/widgets/__init__.py +0 -0
- {mainsequence-4.4.25 → mainsequence-4.4.26}/mainsequence/client/command_center/widgets/bindings.py +0 -0
- {mainsequence-4.4.25 → mainsequence-4.4.26}/mainsequence/client/command_center/widgets/connection_query.py +0 -0
- {mainsequence-4.4.25 → mainsequence-4.4.26}/mainsequence/client/command_center/widgets/registry.py +0 -0
- {mainsequence-4.4.25 → mainsequence-4.4.26}/mainsequence/client/command_center/widgets/table.py +0 -0
- {mainsequence-4.4.25 → mainsequence-4.4.26}/mainsequence/client/command_center/widgets/tabular_transform.py +0 -0
- {mainsequence-4.4.25 → mainsequence-4.4.26}/mainsequence/client/command_center/workspace.py +0 -0
- {mainsequence-4.4.25 → mainsequence-4.4.26}/mainsequence/client/command_center/workspace_snapshot.py +0 -0
- {mainsequence-4.4.25 → mainsequence-4.4.26}/mainsequence/client/command_center/workspaces/__init__.py +0 -0
- {mainsequence-4.4.25 → mainsequence-4.4.26}/mainsequence/client/command_center/workspaces/documents.py +0 -0
- {mainsequence-4.4.25 → mainsequence-4.4.26}/mainsequence/client/command_center/workspaces/mounted_widgets.py +0 -0
- {mainsequence-4.4.25 → mainsequence-4.4.26}/mainsequence/client/compute_validation.py +0 -0
- {mainsequence-4.4.25 → mainsequence-4.4.26}/mainsequence/client/data_sources_interfaces/__init__.py +0 -0
- {mainsequence-4.4.25 → mainsequence-4.4.26}/mainsequence/client/data_sources_interfaces/duckdb.py +0 -0
- {mainsequence-4.4.25 → mainsequence-4.4.26}/mainsequence/client/data_sources_interfaces/local_paths.py +0 -0
- {mainsequence-4.4.25 → mainsequence-4.4.26}/mainsequence/client/data_sources_interfaces/sqlite.py +0 -0
- {mainsequence-4.4.25 → mainsequence-4.4.26}/mainsequence/client/dtype_codec.py +0 -0
- {mainsequence-4.4.25 → mainsequence-4.4.26}/mainsequence/client/exceptions.py +0 -0
- {mainsequence-4.4.25 → mainsequence-4.4.26}/mainsequence/client/fastapi/__init__.py +0 -0
- {mainsequence-4.4.25 → mainsequence-4.4.26}/mainsequence/client/fastapi/auth.py +0 -0
- {mainsequence-4.4.25 → mainsequence-4.4.26}/mainsequence/client/metatables/__init__.py +0 -0
- {mainsequence-4.4.25 → mainsequence-4.4.26}/mainsequence/client/models_foundry.py +0 -0
- {mainsequence-4.4.25 → mainsequence-4.4.26}/mainsequence/client/models_helpers.py +0 -0
- {mainsequence-4.4.25 → mainsequence-4.4.26}/mainsequence/client/models_user.py +0 -0
- {mainsequence-4.4.25 → mainsequence-4.4.26}/mainsequence/client/utils.py +0 -0
- {mainsequence-4.4.25 → mainsequence-4.4.26}/mainsequence/defaults.py +0 -0
- {mainsequence-4.4.25 → mainsequence-4.4.26}/mainsequence/instrumentation/__init__.py +0 -0
- {mainsequence-4.4.25 → mainsequence-4.4.26}/mainsequence/instrumentation/utils.py +0 -0
- {mainsequence-4.4.25 → mainsequence-4.4.26}/mainsequence/logconf.py +0 -0
- {mainsequence-4.4.25 → mainsequence-4.4.26}/mainsequence/meta_tables/__init__.py +0 -0
- {mainsequence-4.4.25 → mainsequence-4.4.26}/mainsequence/meta_tables/__main__.py +0 -0
- {mainsequence-4.4.25 → mainsequence-4.4.26}/mainsequence/meta_tables/compiled_sql/__init__.py +0 -0
- {mainsequence-4.4.25 → mainsequence-4.4.26}/mainsequence/meta_tables/compiled_sql/v1.py +0 -0
- {mainsequence-4.4.25 → mainsequence-4.4.26}/mainsequence/meta_tables/data_nodes/__init__.py +0 -0
- {mainsequence-4.4.25 → mainsequence-4.4.26}/mainsequence/meta_tables/data_nodes/build_operations.py +0 -0
- {mainsequence-4.4.25 → mainsequence-4.4.26}/mainsequence/meta_tables/data_nodes/models.py +0 -0
- {mainsequence-4.4.25 → mainsequence-4.4.26}/mainsequence/meta_tables/data_nodes/namespacing.py +0 -0
- {mainsequence-4.4.25 → mainsequence-4.4.26}/mainsequence/meta_tables/data_nodes/run_operations.py +0 -0
- {mainsequence-4.4.25 → mainsequence-4.4.26}/mainsequence/meta_tables/data_nodes/utils.py +0 -0
- {mainsequence-4.4.25 → mainsequence-4.4.26}/mainsequence/meta_tables/future_registry.py +0 -0
- {mainsequence-4.4.25 → mainsequence-4.4.26}/mainsequence/meta_tables/hashing.py +0 -0
- {mainsequence-4.4.25 → mainsequence-4.4.26}/mainsequence/meta_tables/migrations/alembic.py +0 -0
- {mainsequence-4.4.25 → mainsequence-4.4.26}/mainsequence/meta_tables/migrations/env.py +0 -0
- {mainsequence-4.4.25 → mainsequence-4.4.26}/mainsequence/meta_tables/migrations/provider.py +0 -0
- {mainsequence-4.4.25 → mainsequence-4.4.26}/mainsequence/meta_tables/migrations/registry.py +0 -0
- {mainsequence-4.4.25 → mainsequence-4.4.26}/mainsequence/meta_tables/migrations/scaffold.py +0 -0
- {mainsequence-4.4.25 → mainsequence-4.4.26}/mainsequence/meta_tables/migrations/templates/__init__.py +0 -0
- {mainsequence-4.4.25 → mainsequence-4.4.26}/mainsequence/meta_tables/migrations/templates/env.py.mako +0 -0
- {mainsequence-4.4.25 → mainsequence-4.4.26}/mainsequence/meta_tables/migrations/templates/script.py.mako +0 -0
- {mainsequence-4.4.25 → mainsequence-4.4.26}/mainsequence/meta_tables/pydantic_metadata.py +0 -0
- {mainsequence-4.4.25 → mainsequence-4.4.26}/mainsequence/meta_tables/schema_names.py +0 -0
- {mainsequence-4.4.25 → mainsequence-4.4.26}/mainsequence/runtime_flags.py +0 -0
- {mainsequence-4.4.25 → mainsequence-4.4.26}/mainsequence/scaffold_skills.py +0 -0
- {mainsequence-4.4.25 → mainsequence-4.4.26}/mainsequence.egg-info/SOURCES.txt +0 -0
- {mainsequence-4.4.25 → mainsequence-4.4.26}/mainsequence.egg-info/dependency_links.txt +0 -0
- {mainsequence-4.4.25 → mainsequence-4.4.26}/mainsequence.egg-info/entry_points.txt +0 -0
- {mainsequence-4.4.25 → mainsequence-4.4.26}/mainsequence.egg-info/requires.txt +0 -0
- {mainsequence-4.4.25 → mainsequence-4.4.26}/mainsequence.egg-info/top_level.txt +0 -0
- {mainsequence-4.4.25 → mainsequence-4.4.26}/setup.cfg +0 -0
- {mainsequence-4.4.25 → mainsequence-4.4.26}/tests/test_auth_precedence.py +0 -0
- {mainsequence-4.4.25 → mainsequence-4.4.26}/tests/test_build_operations_hashing.py +0 -0
- {mainsequence-4.4.25 → mainsequence-4.4.26}/tests/test_cli.py +0 -0
- {mainsequence-4.4.25 → mainsequence-4.4.26}/tests/test_cli_browser_auth.py +0 -0
- {mainsequence-4.4.25 → mainsequence-4.4.26}/tests/test_cli_migrations.py +0 -0
- {mainsequence-4.4.25 → mainsequence-4.4.26}/tests/test_client.py +0 -0
- {mainsequence-4.4.25 → mainsequence-4.4.26}/tests/test_command_center_app_component_models.py +0 -0
- {mainsequence-4.4.25 → mainsequence-4.4.26}/tests/test_command_center_data_models.py +0 -0
- {mainsequence-4.4.25 → mainsequence-4.4.26}/tests/test_command_center_models.py +0 -0
- {mainsequence-4.4.25 → mainsequence-4.4.26}/tests/test_command_center_table_contracts.py +0 -0
- {mainsequence-4.4.25 → mainsequence-4.4.26}/tests/test_command_center_tabular_transform.py +0 -0
- {mainsequence-4.4.25 → mainsequence-4.4.26}/tests/test_data_node_storage_dimension_queries.py +0 -0
- {mainsequence-4.4.25 → mainsequence-4.4.26}/tests/test_data_node_update_flow.py +0 -0
- {mainsequence-4.4.25 → mainsequence-4.4.26}/tests/test_dependency_extras.py +0 -0
- {mainsequence-4.4.25 → mainsequence-4.4.26}/tests/test_duckdb_interface_dimensions.py +0 -0
- {mainsequence-4.4.25 → mainsequence-4.4.26}/tests/test_filter_normalization.py +0 -0
- {mainsequence-4.4.25 → mainsequence-4.4.26}/tests/test_instrumentation.py +0 -0
- {mainsequence-4.4.25 → mainsequence-4.4.26}/tests/test_logconf.py +0 -0
- {mainsequence-4.4.25 → mainsequence-4.4.26}/tests/test_models_user_request_bound_auth.py +0 -0
- {mainsequence-4.4.25 → mainsequence-4.4.26}/tests/test_pod_project_resolution.py +0 -0
- {mainsequence-4.4.25 → mainsequence-4.4.26}/tests/test_project_batch_jobs_from_file.py +0 -0
- {mainsequence-4.4.25 → mainsequence-4.4.26}/tests/test_scaffold_skills.py +0 -0
- {mainsequence-4.4.25 → mainsequence-4.4.26}/tests/test_schema_names.py +0 -0
- {mainsequence-4.4.25 → mainsequence-4.4.26}/tests/test_secret_client_model.py +0 -0
- {mainsequence-4.4.25 → mainsequence-4.4.26}/tests/test_source_table_configuration.py +0 -0
- {mainsequence-4.4.25 → mainsequence-4.4.26}/tests/test_sqlite_interface_dimensions.py +0 -0
- {mainsequence-4.4.25 → mainsequence-4.4.26}/tests/test_update_runner_uid_runtime.py +0 -0
- {mainsequence-4.4.25 → mainsequence-4.4.26}/tests/test_update_statistics.py +0 -0
- {mainsequence-4.4.25 → mainsequence-4.4.26}/tests/test_update_uid_guards.py +0 -0
- {mainsequence-4.4.25 → mainsequence-4.4.26}/tests/test_workspace_snapshot.py +0 -0
|
@@ -260,6 +260,9 @@ def _contract_physical_table_name(item: Any) -> Any:
|
|
|
260
260
|
|
|
261
261
|
|
|
262
262
|
def _contract_physical_schema(item: Any) -> Any:
|
|
263
|
+
physical_schema = _item_value(item, "physical_schema")
|
|
264
|
+
if physical_schema not in (None, ""):
|
|
265
|
+
return physical_schema
|
|
263
266
|
contract = _item_value(item, "table_contract")
|
|
264
267
|
if contract is None:
|
|
265
268
|
return None
|
|
@@ -323,6 +326,7 @@ def _metatable_message(
|
|
|
323
326
|
or model_name
|
|
324
327
|
)
|
|
325
328
|
uid = _item_value(item, "meta_table_uid") or _item_value(item, "uid")
|
|
329
|
+
physical_schema = _contract_physical_schema(item)
|
|
326
330
|
physical_table_name = _item_value(item, "physical_table_name") or _contract_physical_table_name(
|
|
327
331
|
item
|
|
328
332
|
)
|
|
@@ -341,6 +345,8 @@ def _metatable_message(
|
|
|
341
345
|
parts.append(f"model={model_name}")
|
|
342
346
|
if uid not in (None, ""):
|
|
343
347
|
parts.append(f"uid={uid}")
|
|
348
|
+
if physical_schema not in (None, ""):
|
|
349
|
+
parts.append(f"physical_schema={physical_schema}")
|
|
344
350
|
if physical_table_name not in (None, ""):
|
|
345
351
|
parts.append(f"physical_table={physical_table_name}")
|
|
346
352
|
if provisioning_status not in (None, ""):
|
|
@@ -229,6 +229,46 @@ def _normalize_contract_mapping(contract: Mapping[str, Any]) -> dict[str, Any]:
|
|
|
229
229
|
return normalized
|
|
230
230
|
|
|
231
231
|
|
|
232
|
+
def _contract_physical_mapping(contract: Any) -> Any:
|
|
233
|
+
if isinstance(contract, Mapping):
|
|
234
|
+
return contract.get("physical")
|
|
235
|
+
return getattr(contract, "physical", None)
|
|
236
|
+
|
|
237
|
+
|
|
238
|
+
def _contract_physical_schema(contract: Any) -> str | None:
|
|
239
|
+
physical = _contract_physical_mapping(contract)
|
|
240
|
+
if isinstance(physical, Mapping):
|
|
241
|
+
value = (
|
|
242
|
+
physical.get("schema")
|
|
243
|
+
or physical.get("schema_")
|
|
244
|
+
or physical.get("physical_schema")
|
|
245
|
+
)
|
|
246
|
+
else:
|
|
247
|
+
value = getattr(physical, "schema_", None) or getattr(
|
|
248
|
+
physical,
|
|
249
|
+
"physical_schema",
|
|
250
|
+
None,
|
|
251
|
+
)
|
|
252
|
+
if value in (None, ""):
|
|
253
|
+
return None
|
|
254
|
+
return str(value)
|
|
255
|
+
|
|
256
|
+
|
|
257
|
+
def _set_contract_physical_schema(contract: Any, schema: str) -> Any:
|
|
258
|
+
if isinstance(contract, Mapping):
|
|
259
|
+
normalized = dict(contract)
|
|
260
|
+
physical = normalized.get("physical")
|
|
261
|
+
physical_mapping = dict(physical) if isinstance(physical, Mapping) else {}
|
|
262
|
+
physical_mapping["schema"] = schema
|
|
263
|
+
normalized["physical"] = physical_mapping
|
|
264
|
+
return normalized
|
|
265
|
+
|
|
266
|
+
physical = getattr(contract, "physical", None)
|
|
267
|
+
if physical is not None and hasattr(physical, "schema_"):
|
|
268
|
+
physical.schema_ = schema
|
|
269
|
+
return contract
|
|
270
|
+
|
|
271
|
+
|
|
232
272
|
def _temporal_parameter_names(parameters: dict[str, Any] | list[Any]) -> set[str]:
|
|
233
273
|
if isinstance(parameters, Mapping):
|
|
234
274
|
items = parameters.items()
|
|
@@ -246,8 +286,10 @@ class MetaTablePhysicalContract(BasePydanticModel):
|
|
|
246
286
|
default=None,
|
|
247
287
|
alias="schema",
|
|
248
288
|
serialization_alias="schema",
|
|
249
|
-
|
|
250
|
-
|
|
289
|
+
description=(
|
|
290
|
+
"Physical database schema. This is part of MetaTable physical identity "
|
|
291
|
+
"together with data_source_uid and table_name."
|
|
292
|
+
),
|
|
251
293
|
)
|
|
252
294
|
table_name: str | None = Field(
|
|
253
295
|
default=None,
|
|
@@ -257,7 +299,7 @@ class MetaTablePhysicalContract(BasePydanticModel):
|
|
|
257
299
|
),
|
|
258
300
|
)
|
|
259
301
|
|
|
260
|
-
model_config = ConfigDict(populate_by_name=True)
|
|
302
|
+
model_config = ConfigDict(populate_by_name=True, serialize_by_alias=True)
|
|
261
303
|
|
|
262
304
|
|
|
263
305
|
class MetaTableColumnContract(BasePydanticModel):
|
|
@@ -413,6 +455,10 @@ class MetaTableForeignKeyPayload(BasePydanticModel):
|
|
|
413
455
|
None,
|
|
414
456
|
description="Physical table name of the target MetaTable.",
|
|
415
457
|
)
|
|
458
|
+
target_table_physical_schema: str | None = Field(
|
|
459
|
+
None,
|
|
460
|
+
description="Physical schema of the target MetaTable.",
|
|
461
|
+
)
|
|
416
462
|
target_columns: list[str] = Field(
|
|
417
463
|
default_factory=list,
|
|
418
464
|
description="Target MetaTable physical column names.",
|
|
@@ -550,6 +596,14 @@ class MetaTableRequestFields(BasePydanticModel):
|
|
|
550
596
|
...,
|
|
551
597
|
description="Public UID of the DynamicTableDataSource that owns this MetaTable.",
|
|
552
598
|
)
|
|
599
|
+
physical_schema: str | None = Field(
|
|
600
|
+
None,
|
|
601
|
+
description=(
|
|
602
|
+
"Physical database schema. This is part of the MetaTable physical "
|
|
603
|
+
"identity and must match table_contract.physical.schema when both "
|
|
604
|
+
"are provided."
|
|
605
|
+
),
|
|
606
|
+
)
|
|
553
607
|
table_contract: MetaTableContract | dict[str, Any]
|
|
554
608
|
identifier: str | None = Field(
|
|
555
609
|
default=None,
|
|
@@ -575,6 +629,19 @@ class MetaTableRequestFields(BasePydanticModel):
|
|
|
575
629
|
def _normalize_table_contract(self) -> MetaTableRequestFields:
|
|
576
630
|
if isinstance(self.table_contract, Mapping):
|
|
577
631
|
self.table_contract = _normalize_contract_mapping(self.table_contract)
|
|
632
|
+
contract_schema = _contract_physical_schema(self.table_contract)
|
|
633
|
+
if self.physical_schema not in (None, "") and contract_schema not in (None, ""):
|
|
634
|
+
if str(self.physical_schema) != str(contract_schema):
|
|
635
|
+
raise ValueError(
|
|
636
|
+
"physical_schema must match table_contract.physical.schema."
|
|
637
|
+
)
|
|
638
|
+
if self.physical_schema in (None, "") and contract_schema not in (None, ""):
|
|
639
|
+
self.physical_schema = str(contract_schema)
|
|
640
|
+
elif self.physical_schema not in (None, "") and contract_schema in (None, ""):
|
|
641
|
+
self.table_contract = _set_contract_physical_schema(
|
|
642
|
+
self.table_contract,
|
|
643
|
+
str(self.physical_schema),
|
|
644
|
+
)
|
|
578
645
|
return self
|
|
579
646
|
|
|
580
647
|
@model_validator(mode="before")
|
|
@@ -713,6 +780,10 @@ class ManagedMetaTableFinalizeTableResult(BasePydanticModel):
|
|
|
713
780
|
None,
|
|
714
781
|
description="Physical table name reconciled against the data source.",
|
|
715
782
|
)
|
|
783
|
+
physical_schema: str | None = Field(
|
|
784
|
+
None,
|
|
785
|
+
description="Physical schema reconciled against the data source.",
|
|
786
|
+
)
|
|
716
787
|
previous_provisioning_status: str = Field(
|
|
717
788
|
...,
|
|
718
789
|
description="Provisioning status before the finalize-managed attempt.",
|
|
@@ -1200,6 +1271,7 @@ class MetaTable(BasePydanticModel, LabelableObjectMixin, ShareableObjectMixin, B
|
|
|
1200
1271
|
"provisioning_status": ["exact", "in"],
|
|
1201
1272
|
"schema_management_mode": ["exact", "in"],
|
|
1202
1273
|
"migration_provider_key": ["exact", "in"],
|
|
1274
|
+
"physical_schema": ["exact", "in"],
|
|
1203
1275
|
"physical_table_name": ["exact", "contains", "in"],
|
|
1204
1276
|
"labels": ["exact", "in", "contains"],
|
|
1205
1277
|
}
|
|
@@ -1208,6 +1280,8 @@ class MetaTable(BasePydanticModel, LabelableObjectMixin, ShareableObjectMixin, B
|
|
|
1208
1280
|
"uid__in": "str",
|
|
1209
1281
|
"data_source__uid": "uid",
|
|
1210
1282
|
"data_source__uid__in": "uid",
|
|
1283
|
+
"physical_schema": "str",
|
|
1284
|
+
"physical_schema__in": "str",
|
|
1211
1285
|
"labels": "str",
|
|
1212
1286
|
"labels__in": "str",
|
|
1213
1287
|
"labels__contains": "str",
|
|
@@ -1254,6 +1328,7 @@ class MetaTable(BasePydanticModel, LabelableObjectMixin, ShareableObjectMixin, B
|
|
|
1254
1328
|
migration_provider_key: str | None = None
|
|
1255
1329
|
alembic_version_meta_table_uid: str | None = None
|
|
1256
1330
|
alembic_revision: str | None = None
|
|
1331
|
+
physical_schema: str | None = None
|
|
1257
1332
|
physical_table_name: str
|
|
1258
1333
|
table_contract: dict[str, Any] = Field(default_factory=dict)
|
|
1259
1334
|
contract_version: str = "relational-table.v1"
|
|
@@ -1945,6 +2020,13 @@ class TimeIndexMetaTableRegistrationRequest(BasePydanticModel):
|
|
|
1945
2020
|
model_config = ConfigDict(extra="forbid")
|
|
1946
2021
|
|
|
1947
2022
|
data_source_uid: str = Field(..., description="Public uid of the storage data source")
|
|
2023
|
+
physical_schema: str | None = Field(
|
|
2024
|
+
None,
|
|
2025
|
+
description=(
|
|
2026
|
+
"Physical database schema. This must match table_contract.physical.schema "
|
|
2027
|
+
"when both are provided."
|
|
2028
|
+
),
|
|
2029
|
+
)
|
|
1948
2030
|
identifier: str | None = Field(
|
|
1949
2031
|
None,
|
|
1950
2032
|
description=(
|
|
@@ -2027,6 +2109,23 @@ class TimeIndexMetaTableRegistrationRequest(BasePydanticModel):
|
|
|
2027
2109
|
data["table_contract"] = normalized_contract
|
|
2028
2110
|
return data
|
|
2029
2111
|
|
|
2112
|
+
@model_validator(mode="after")
|
|
2113
|
+
def _normalize_physical_schema(self) -> TimeIndexMetaTableRegistrationRequest:
|
|
2114
|
+
contract_schema = _contract_physical_schema(self.table_contract)
|
|
2115
|
+
if self.physical_schema not in (None, "") and contract_schema not in (None, ""):
|
|
2116
|
+
if str(self.physical_schema) != str(contract_schema):
|
|
2117
|
+
raise ValueError(
|
|
2118
|
+
"physical_schema must match table_contract.physical.schema."
|
|
2119
|
+
)
|
|
2120
|
+
if self.physical_schema in (None, "") and contract_schema not in (None, ""):
|
|
2121
|
+
self.physical_schema = str(contract_schema)
|
|
2122
|
+
elif self.physical_schema not in (None, "") and contract_schema in (None, ""):
|
|
2123
|
+
self.table_contract = _set_contract_physical_schema(
|
|
2124
|
+
self.table_contract,
|
|
2125
|
+
str(self.physical_schema),
|
|
2126
|
+
)
|
|
2127
|
+
return self
|
|
2128
|
+
|
|
2030
2129
|
@field_validator("cadence")
|
|
2031
2130
|
@classmethod
|
|
2032
2131
|
def _normalize_cadence(cls, value: str | None) -> str | None:
|
|
@@ -3025,6 +3124,7 @@ class TimeIndexMetaTable(MetaTable):
|
|
|
3025
3124
|
"uid": ["in", "exact"],
|
|
3026
3125
|
"data_source__uid": ["in", "exact"],
|
|
3027
3126
|
"namespace": ["exact", "contains", "in", "isnull"],
|
|
3127
|
+
"physical_schema": ["exact", "in"],
|
|
3028
3128
|
"physical_table_name": ["exact", "contains", "in"],
|
|
3029
3129
|
"labels": ["exact", "in", "contains"],
|
|
3030
3130
|
}
|
|
@@ -3033,6 +3133,8 @@ class TimeIndexMetaTable(MetaTable):
|
|
|
3033
3133
|
"uid__in": "uid",
|
|
3034
3134
|
"data_source__uid": "uid",
|
|
3035
3135
|
"data_source__uid__in": "uid",
|
|
3136
|
+
"physical_schema": "str",
|
|
3137
|
+
"physical_schema__in": "str",
|
|
3036
3138
|
"labels": "str",
|
|
3037
3139
|
"labels__in": "str",
|
|
3038
3140
|
"labels__contains": "str",
|
{mainsequence-4.4.25 → mainsequence-4.4.26}/mainsequence/meta_tables/data_nodes/data_nodes.py
RENAMED
|
@@ -134,6 +134,8 @@ class DataAccessMixin:
|
|
|
134
134
|
|
|
135
135
|
|
|
136
136
|
class APIDataNode(DataAccessMixin):
|
|
137
|
+
LEGACY_DEFAULT_PHYSICAL_SCHEMA = "public"
|
|
138
|
+
|
|
137
139
|
@staticmethod
|
|
138
140
|
def _require_data_source_uid(data_source: Any, *, context: str) -> str:
|
|
139
141
|
if isinstance(data_source, dict):
|
|
@@ -172,6 +174,24 @@ class APIDataNode(DataAccessMixin):
|
|
|
172
174
|
raise ValueError(f"{context} requires storage_table.physical_table_name.")
|
|
173
175
|
return str(table_name)
|
|
174
176
|
|
|
177
|
+
@classmethod
|
|
178
|
+
def _storage_table_physical_schema(cls, storage_table: Any) -> str:
|
|
179
|
+
if isinstance(storage_table, dict):
|
|
180
|
+
physical_schema = storage_table.get("physical_schema")
|
|
181
|
+
table_contract = storage_table.get("table_contract")
|
|
182
|
+
else:
|
|
183
|
+
physical_schema = getattr(storage_table, "physical_schema", None)
|
|
184
|
+
table_contract = getattr(storage_table, "table_contract", None)
|
|
185
|
+
if physical_schema not in (None, ""):
|
|
186
|
+
return str(physical_schema)
|
|
187
|
+
if isinstance(table_contract, dict):
|
|
188
|
+
physical = table_contract.get("physical") or {}
|
|
189
|
+
if isinstance(physical, dict):
|
|
190
|
+
contract_schema = physical.get("schema") or physical.get("schema_")
|
|
191
|
+
if contract_schema not in (None, ""):
|
|
192
|
+
return str(contract_schema)
|
|
193
|
+
return cls.LEGACY_DEFAULT_PHYSICAL_SCHEMA
|
|
194
|
+
|
|
175
195
|
@classmethod
|
|
176
196
|
def build_from_local_time_serie(cls, source_table: "DataNodeUpdate") -> "APIDataNode":
|
|
177
197
|
physical_table_name = getattr(source_table, "physical_table_name", None) or getattr(
|
|
@@ -202,6 +222,7 @@ class APIDataNode(DataAccessMixin):
|
|
|
202
222
|
storage_table,
|
|
203
223
|
context=context,
|
|
204
224
|
),
|
|
225
|
+
physical_schema=cls._storage_table_physical_schema(storage_table),
|
|
205
226
|
physical_table_name=cls._require_physical_table_name(
|
|
206
227
|
storage_table,
|
|
207
228
|
context=context,
|
|
@@ -215,22 +236,55 @@ class APIDataNode(DataAccessMixin):
|
|
|
215
236
|
return cls.build_from_meta_table(storage_table)
|
|
216
237
|
|
|
217
238
|
@classmethod
|
|
218
|
-
def
|
|
239
|
+
def build_from_physical_identity(
|
|
240
|
+
cls,
|
|
241
|
+
*,
|
|
242
|
+
schema: str,
|
|
243
|
+
table_name: str,
|
|
244
|
+
data_source_uid: str | None = None,
|
|
245
|
+
) -> "APIDataNode":
|
|
246
|
+
if schema in (None, ""):
|
|
247
|
+
raise ValueError("APIDataNode.build_from_physical_identity requires schema.")
|
|
248
|
+
filters = {
|
|
249
|
+
"physical_schema": str(schema),
|
|
250
|
+
"physical_table_name": table_name,
|
|
251
|
+
}
|
|
252
|
+
if data_source_uid not in (None, ""):
|
|
253
|
+
filters["data_source__uid"] = str(data_source_uid)
|
|
219
254
|
storage_table = TimeIndexMetaTable.get_or_none(
|
|
220
|
-
|
|
255
|
+
**filters,
|
|
221
256
|
)
|
|
222
257
|
if storage_table is None:
|
|
223
258
|
raise DoesNotExist(
|
|
224
259
|
"No TimeIndexMetaTable found matching "
|
|
225
|
-
f"{{'physical_table_name': {table_name!r}}}"
|
|
260
|
+
f"{{'physical_schema': {schema!r}, 'physical_table_name': {table_name!r}}}"
|
|
226
261
|
)
|
|
227
262
|
return cls.build_from_meta_table(storage_table)
|
|
228
263
|
|
|
264
|
+
@classmethod
|
|
265
|
+
def build_from_table_name(
|
|
266
|
+
cls,
|
|
267
|
+
table_name: str,
|
|
268
|
+
*,
|
|
269
|
+
schema: str = LEGACY_DEFAULT_PHYSICAL_SCHEMA,
|
|
270
|
+
data_source_uid: str | None = None,
|
|
271
|
+
) -> "APIDataNode":
|
|
272
|
+
logger.warning(
|
|
273
|
+
"APIDataNode.build_from_table_name is ambiguous across schemas; "
|
|
274
|
+
"use build_from_physical_identity(schema=..., table_name=...) instead."
|
|
275
|
+
)
|
|
276
|
+
return cls.build_from_physical_identity(
|
|
277
|
+
schema=schema,
|
|
278
|
+
table_name=table_name,
|
|
279
|
+
data_source_uid=data_source_uid,
|
|
280
|
+
)
|
|
281
|
+
|
|
229
282
|
def __init__(
|
|
230
283
|
self,
|
|
231
284
|
data_source_uid: str,
|
|
232
285
|
physical_table_name: str | None = None,
|
|
233
286
|
*,
|
|
287
|
+
physical_schema: str | None = None,
|
|
234
288
|
storage_hash: str | None = None,
|
|
235
289
|
data_source_local_lake: DataSource | None = None,
|
|
236
290
|
storage_table: MetaTable | None = None,
|
|
@@ -255,6 +309,7 @@ class APIDataNode(DataAccessMixin):
|
|
|
255
309
|
if resolved_physical_table_name in (None, ""):
|
|
256
310
|
raise ValueError("APIDataNode requires physical_table_name.")
|
|
257
311
|
self.data_source_uid = str(data_source_uid)
|
|
312
|
+
self.physical_schema = str(physical_schema or self.LEGACY_DEFAULT_PHYSICAL_SCHEMA)
|
|
258
313
|
self.physical_table_name = str(resolved_physical_table_name)
|
|
259
314
|
self.storage_table = storage_table
|
|
260
315
|
self.data_source = data_source_local_lake
|
|
@@ -321,6 +376,7 @@ class APIDataNode(DataAccessMixin):
|
|
|
321
376
|
self._verify_local_data_source()
|
|
322
377
|
self._local_persist_manager = APIPersistManager(
|
|
323
378
|
physical_table_name=self.physical_table_name,
|
|
379
|
+
physical_schema=self.physical_schema,
|
|
324
380
|
data_source_uid=self.data_source_uid,
|
|
325
381
|
)
|
|
326
382
|
storage_table = self._local_persist_manager.storage_table
|
{mainsequence-4.4.25 → mainsequence-4.4.26}/mainsequence/meta_tables/data_nodes/persist_managers.py
RENAMED
|
@@ -31,10 +31,13 @@ from mainsequence.meta_tables import PlatformTimeIndexMetaTable, compute_metatab
|
|
|
31
31
|
from .. import future_registry
|
|
32
32
|
|
|
33
33
|
_STORAGE_TABLE_LOOKUP_LIMIT = 20
|
|
34
|
+
_LEGACY_POSTGRES_SCHEMA = "public"
|
|
34
35
|
|
|
35
36
|
|
|
36
37
|
@dataclass(frozen=True)
|
|
37
38
|
class _StorageTableLookupResult:
|
|
39
|
+
data_source_uid: str | None
|
|
40
|
+
physical_schema: str | None
|
|
38
41
|
table_name: str | None
|
|
39
42
|
filters: dict[str, Any]
|
|
40
43
|
matches: list[TimeIndexMetaTable]
|
|
@@ -144,21 +147,51 @@ def _registered_storage_table_lookup(
|
|
|
144
147
|
storage_table: type[PlatformTimeIndexMetaTable],
|
|
145
148
|
) -> _StorageTableLookupResult:
|
|
146
149
|
table_name = _storage_table_physical_table_name(storage_table)
|
|
147
|
-
|
|
150
|
+
physical_schema = _storage_table_physical_schema(storage_table)
|
|
151
|
+
data_source_uid = storage_table.get_data_source_uid()
|
|
152
|
+
if table_name and physical_schema and data_source_uid:
|
|
148
153
|
filters = {
|
|
154
|
+
"data_source__uid": data_source_uid,
|
|
155
|
+
"physical_schema__in": [physical_schema],
|
|
149
156
|
"physical_table_name__in": [table_name],
|
|
150
157
|
"limit": _STORAGE_TABLE_LOOKUP_LIMIT,
|
|
151
158
|
}
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
159
|
+
raw_matches = TimeIndexMetaTable.filter_by_body(**filters)
|
|
160
|
+
matches = [
|
|
161
|
+
match
|
|
162
|
+
for match in raw_matches
|
|
163
|
+
if _time_index_meta_table_identity(match)
|
|
164
|
+
== (data_source_uid, physical_schema, table_name)
|
|
165
|
+
]
|
|
155
166
|
return _StorageTableLookupResult(
|
|
167
|
+
data_source_uid=data_source_uid,
|
|
168
|
+
physical_schema=physical_schema,
|
|
156
169
|
table_name=table_name,
|
|
157
170
|
filters=filters,
|
|
158
171
|
matches=matches,
|
|
159
172
|
)
|
|
160
173
|
|
|
161
|
-
return _StorageTableLookupResult(
|
|
174
|
+
return _StorageTableLookupResult(
|
|
175
|
+
data_source_uid=data_source_uid,
|
|
176
|
+
physical_schema=physical_schema,
|
|
177
|
+
table_name=table_name,
|
|
178
|
+
filters={},
|
|
179
|
+
matches=[],
|
|
180
|
+
)
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
def _storage_table_physical_schema(
|
|
184
|
+
storage_table: type[PlatformTimeIndexMetaTable],
|
|
185
|
+
) -> str | None:
|
|
186
|
+
schema_getter = getattr(storage_table, "get_physical_schema", None)
|
|
187
|
+
physical_schema = schema_getter() if callable(schema_getter) else None
|
|
188
|
+
if physical_schema not in (None, ""):
|
|
189
|
+
return str(physical_schema)
|
|
190
|
+
table = getattr(storage_table, "__table__", None)
|
|
191
|
+
table_schema = getattr(table, "schema", None)
|
|
192
|
+
if table_schema not in (None, ""):
|
|
193
|
+
return str(table_schema)
|
|
194
|
+
return _LEGACY_POSTGRES_SCHEMA
|
|
162
195
|
|
|
163
196
|
|
|
164
197
|
def _storage_table_physical_table_name(
|
|
@@ -175,8 +208,9 @@ def _storage_table_physical_table_name(
|
|
|
175
208
|
|
|
176
209
|
|
|
177
210
|
def _storage_table_lookup_label(storage_table: type[PlatformTimeIndexMetaTable]) -> str:
|
|
211
|
+
physical_schema = _storage_table_physical_schema(storage_table) or "<unknown-schema>"
|
|
178
212
|
table_name = _storage_table_physical_table_name(storage_table) or "<unknown-table>"
|
|
179
|
-
return f"{storage_table.__name__}(table={table_name})"
|
|
213
|
+
return f"{storage_table.__name__}(schema={physical_schema}, table={table_name})"
|
|
180
214
|
|
|
181
215
|
|
|
182
216
|
def _unbound_storage_table_message(
|
|
@@ -204,6 +238,16 @@ def _unbound_storage_table_message(
|
|
|
204
238
|
f"{message} The SDK could not determine a physical table name from "
|
|
205
239
|
"the storage model, so no backend catalog lookup was possible."
|
|
206
240
|
)
|
|
241
|
+
if lookup_result.physical_schema is None:
|
|
242
|
+
return (
|
|
243
|
+
f"{message} The SDK could not determine a physical schema from "
|
|
244
|
+
"the storage model, so no backend catalog lookup was possible."
|
|
245
|
+
)
|
|
246
|
+
if lookup_result.data_source_uid is None:
|
|
247
|
+
return (
|
|
248
|
+
f"{message} The SDK could not determine a data-source UID from "
|
|
249
|
+
"the storage model, so no backend catalog lookup was possible."
|
|
250
|
+
)
|
|
207
251
|
|
|
208
252
|
filters = _format_lookup_filters(lookup_result.filters)
|
|
209
253
|
match_count = len(lookup_result.matches)
|
|
@@ -248,6 +292,12 @@ def _storage_table_identity_summary(storage_table: type[PlatformTimeIndexMetaTab
|
|
|
248
292
|
data_source_uid = storage_table.get_data_source_uid()
|
|
249
293
|
if data_source_uid not in (None, ""):
|
|
250
294
|
parts.append(f"model_data_source_uid={data_source_uid!r}")
|
|
295
|
+
physical_schema = _storage_table_physical_schema(storage_table)
|
|
296
|
+
if physical_schema not in (None, ""):
|
|
297
|
+
parts.append(f"physical_schema={physical_schema!r}")
|
|
298
|
+
table_name = _storage_table_physical_table_name(storage_table)
|
|
299
|
+
if table_name not in (None, ""):
|
|
300
|
+
parts.append(f"physical_table_name={table_name!r}")
|
|
251
301
|
if not parts:
|
|
252
302
|
return "Storage identity is incomplete."
|
|
253
303
|
return "Storage identity: " + ", ".join(parts) + "."
|
|
@@ -262,6 +312,7 @@ def _time_index_meta_table_candidate_summary(meta_table: TimeIndexMetaTable) ->
|
|
|
262
312
|
for attr in (
|
|
263
313
|
"uid",
|
|
264
314
|
"data_source_uid",
|
|
315
|
+
"physical_schema",
|
|
265
316
|
"identifier",
|
|
266
317
|
"physical_table_name",
|
|
267
318
|
"provisioning_status",
|
|
@@ -272,6 +323,35 @@ def _time_index_meta_table_candidate_summary(meta_table: TimeIndexMetaTable) ->
|
|
|
272
323
|
return "{" + ", ".join(parts) + "}" if parts else "{unidentified TimeIndexMetaTable}"
|
|
273
324
|
|
|
274
325
|
|
|
326
|
+
def _time_index_meta_table_identity(
|
|
327
|
+
meta_table: TimeIndexMetaTable,
|
|
328
|
+
) -> tuple[str, str, str] | None:
|
|
329
|
+
data_source_uid = getattr(meta_table, "data_source_uid", None)
|
|
330
|
+
if data_source_uid in (None, ""):
|
|
331
|
+
data_source = getattr(meta_table, "data_source", None)
|
|
332
|
+
if isinstance(data_source, dict):
|
|
333
|
+
data_source_uid = data_source.get("uid") or data_source.get("data_source_uid")
|
|
334
|
+
else:
|
|
335
|
+
data_source_uid = getattr(data_source, "uid", None) or getattr(
|
|
336
|
+
data_source,
|
|
337
|
+
"data_source_uid",
|
|
338
|
+
None,
|
|
339
|
+
)
|
|
340
|
+
physical_schema = getattr(meta_table, "physical_schema", None)
|
|
341
|
+
if physical_schema in (None, ""):
|
|
342
|
+
table_contract = getattr(meta_table, "table_contract", None)
|
|
343
|
+
if isinstance(table_contract, dict):
|
|
344
|
+
physical = table_contract.get("physical") or {}
|
|
345
|
+
if isinstance(physical, dict):
|
|
346
|
+
physical_schema = physical.get("schema") or physical.get("schema_")
|
|
347
|
+
if physical_schema in (None, ""):
|
|
348
|
+
physical_schema = _LEGACY_POSTGRES_SCHEMA
|
|
349
|
+
table_name = getattr(meta_table, "physical_table_name", None)
|
|
350
|
+
if data_source_uid in (None, "") or table_name in (None, ""):
|
|
351
|
+
return None
|
|
352
|
+
return str(data_source_uid), str(physical_schema), str(table_name)
|
|
353
|
+
|
|
354
|
+
|
|
275
355
|
class BasePersistManager:
|
|
276
356
|
UPDATE_CLASS: ClassVar[type[Any] | None] = None
|
|
277
357
|
UPDATE_DETAILS_CLASS: ClassVar[type[Any] | None] = None
|
|
@@ -420,10 +500,12 @@ class BasePersistManager:
|
|
|
420
500
|
)
|
|
421
501
|
if result is None:
|
|
422
502
|
meta_table_uid = self.storage_table.get_meta_table_uid()
|
|
503
|
+
physical_schema = _storage_table_physical_schema(self.storage_table)
|
|
423
504
|
physical_table_name = _storage_table_physical_table_name(self.storage_table)
|
|
424
505
|
self.logger.warning(
|
|
425
506
|
f"DataNodeUpdate {self.update_hash} for MetaTable {meta_table_uid} "
|
|
426
|
-
f"(
|
|
507
|
+
f"(physical_schema={physical_schema}, "
|
|
508
|
+
f"physical_table_name={physical_table_name}) not found in backend"
|
|
427
509
|
)
|
|
428
510
|
new_future.set_result(result)
|
|
429
511
|
except Exception as exc:
|
|
@@ -650,15 +732,20 @@ class APIPersistManager:
|
|
|
650
732
|
self,
|
|
651
733
|
*,
|
|
652
734
|
physical_table_name: str | None = None,
|
|
735
|
+
physical_schema: str | None = None,
|
|
653
736
|
storage_hash: str | None = None,
|
|
654
737
|
data_source_uid: str,
|
|
655
738
|
):
|
|
656
739
|
if data_source_uid in (None, ""):
|
|
657
740
|
raise ValueError("APIPersistManager requires data_source_uid.")
|
|
658
741
|
self.data_source_uid: str = str(data_source_uid)
|
|
742
|
+
self.physical_schema: str = str(physical_schema or _LEGACY_POSTGRES_SCHEMA)
|
|
659
743
|
self.physical_table_name: str | None = physical_table_name or storage_hash
|
|
660
744
|
|
|
661
|
-
logger.debug(
|
|
745
|
+
logger.debug(
|
|
746
|
+
"Initializing APIDataNode storage "
|
|
747
|
+
f"{self.physical_schema}.{self.physical_table_name}"
|
|
748
|
+
)
|
|
662
749
|
|
|
663
750
|
self._storage_table_future = Future()
|
|
664
751
|
future_registry.add_future(self._storage_table_future)
|
|
@@ -678,6 +765,7 @@ class APIPersistManager:
|
|
|
678
765
|
def _init_storage_table(self) -> None:
|
|
679
766
|
try:
|
|
680
767
|
result = TimeIndexMetaTable.get_or_none(
|
|
768
|
+
physical_schema=self.physical_schema,
|
|
681
769
|
physical_table_name=self.physical_table_name,
|
|
682
770
|
data_source__uid=self.data_source_uid,
|
|
683
771
|
)
|