SDK API And Backend Contract
This page maps the SDK objects to the TS Manager backend routes.
MetaTables use the backend route namespace:
/orm/api/ts_manager/meta_table/
Use the MetaTable route namespace for registration, validation, introspection, and compiled execution.
SDK Modules
Transport models:
from mainsequence.client import MetaTable
from mainsequence.client.metatables import (
MetaTableCompiledSQLOperation,
MetaTableContract,
MetaTableRegistrationRequest,
MetaTableValidateContractRequest,
)
SQLAlchemy helpers:
from mainsequence.meta_tables import (
AlembicMetaTableMigration,
AlembicVersionMetaTable,
PlatformManagedMetaTable,
external_registered_registration_request_from_sqlalchemy_model,
register_external_sqlalchemy_model,
schema_table_name,
sqlalchemy_naming_convention,
)
from mainsequence.meta_tables.compiled_sql.v1 import compile_sqlalchemy_statement
SQLAlchemy is a core SDK dependency for MetaTable declarations. The SDK uses it to inspect table contracts, compile governed SQL operations, and define the provider-based Alembic migration scope used by MetaTable schema migrations.
Registration Primitive
Low-level SDK call:
meta_table = MetaTable.register(request)
For platform-managed SQLAlchemy models this is SDK plumbing used by the migration workflow, not a bootstrap call users should place in application code. External-registered callers may still build a request and call this primitive directly when the application owns the physical table lifecycle.
Backend route:
POST /orm/api/ts_manager/meta_table/register/
Request fields:
| Field | Meaning |
|---|---|
data_source_uid |
TS Manager DynamicTableDataSource that owns connection, credentials, capabilities, and execution. |
management_mode |
external_registered or platform_managed. |
identifier |
Optional logical MetaTable identifier, such as Asset. Non-empty values are globally unique per organization. Alembic migration preparation resolves provider MetaTables by authored SQLAlchemy table name instead. |
namespace |
Logical namespace, such as sdk-examples. |
description |
Optional discovery text. |
labels |
Optional table labels. |
protect_from_deletion |
Prevent accidental deletion through the platform. |
provisioning |
Platform-managed DDL options, such as create_table and if_not_exists. |
introspect |
Ask the backend to refresh the physical metadata snapshot during registration. |
table_contract |
Neutral relational contract. It does not include data_source_uid. |
For platform_managed, table_contract.physical.table_name is the authored
SQLAlchemy table name that Alembic sees. The platform identity is the MetaTable
uid; the stable logical application identity is identifier when provided.
PlatformManagedMetaTable exists so SQLAlchemy table construction and
migration-managed registration produce the same table contract while preserving
the authored physical table name. Prefix explicit table names with the project
or package name.
Use schema_table_name(project_or_app, concept) and
sqlalchemy_naming_convention() to keep authored table, index, constraint, and
Alembic version names collision-resistant and within PostgreSQL identifier
limits.
If a caller needs a deterministic contract fingerprint, use
compute_metatable_contract_hash(model_or_table). It is an explicit utility,
not a MetaTable API field, and it includes the physical table name by default.
Contract Validation
Validate a new contract before registration:
result = MetaTable.validate_contract(
table_contract=request.table_contract,
management_mode=request.management_mode,
)
Backend route:
POST /orm/api/ts_manager/meta_table/validate-contract/
Validate a replacement contract for an existing table:
result = meta_table.validate_existing_contract(
table_contract=request.table_contract,
)
Backend route:
POST /orm/api/ts_manager/meta_table/<uid>/validate-contract/
Validation normalizes column, index, and foreign-key fragments and returns the normalized contract. It does not import application code.
Schema Graph
SDK call for outgoing relationships:
graph = meta_table.get_schema_graph(depth=1)
SDK call for outgoing and incoming relationships:
graph = meta_table.get_schema_graph(depth=1, include_incoming=True)
Backend route:
GET /orm/api/ts_manager/meta_table/<uid>/schema-graph/?depth=<n>&include_incoming=<bool>
Use this graph for dependency analysis. Graph edges include both source_uid
and target_uid, which is the shape needed to identify dependent MetaTables.
Return shape:
{
"root_uid": "aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa",
"depth": 1,
"include_incoming": True,
"nodes": [...],
"edges": [
{
"name": "fk_account_holdings_asset",
"source_uid": "cccccccc-cccc-4ccc-8ccc-cccccccccccc",
"target_uid": "aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa",
"source_columns": ["asset_uid"],
"target_columns": ["uid"],
"on_delete": "restrict",
"relationship_type": "meta_table_to_meta_table",
}
],
}
For inbound dependencies:
incoming_edges = [
edge for edge in graph["edges"] if edge["target_uid"] == meta_table.uid
]
dependent_table_uids = [edge["source_uid"] for edge in incoming_edges]
Use depth=1 when you only need direct dependents. Increase depth when you
need transitive relationship context; the backend enforces its supported maximum.
Introspection
SDK call:
result = meta_table.introspect()
snapshot = result["introspection_snapshot"]
Backend route:
POST /orm/api/ts_manager/meta_table/<uid>/introspect/
The backend stores the snapshot on MetaTable.introspection_snapshot. The
current PostgreSQL path returns schema, table name, columns, indexes, and
constraints when the selected data source supports table introspection.
Compiled Execution
SDK call:
result = MetaTable.execute_operation(operation)
Backend route:
POST /orm/api/ts_manager/meta_table/execute-operation/
Execution expects a compiled-sql.v1 operation:
operation = compile_sqlalchemy_statement(
stmt,
operation="select",
data_source_uid=data_source.uid,
scope_tables=[
{"metaTableUid": asset_meta_table.uid, "alias": "asset", "access": "read"},
{"metaTableUid": account_meta_table.uid, "alias": "account", "access": "read"},
],
limits={"max_rows": 1000, "statement_timeout_ms": 15000},
)
result = MetaTable.execute_operation(operation)
The SDK accepts metaTableUid and meta_table_uid when building scope objects.
The serialized backend payload uses meta_table_uid. If
scope.data_source_uid is omitted, the SDK resolves the configured
project/session default data source before sending the request.
Backend checks include:
- every scoped MetaTable is visible to the caller
- write operations require edit access
- the selected data source supports the requested compiled operation
versioniscompiled-sql.v1dialectispostgresqlstatement.paramstyleispyformat- the SQL is one statement
- the SQL statement type matches
operation
The response shape is:
{
"ok": true,
"operation": "select",
"dialect": "postgresql",
"row_count": 25,
"rows": [
{
"uid": "aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa",
"symbol": "BTC"
}
],
"truncated": false,
"max_rows": 1000,
"pagination": {
"limit": 1000,
"offset": 0,
"returned_count": 1,
"has_more": false,
"next_offset": null
},
"scope": {
"meta_table_uids": ["aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa"],
"data_source_uid": "dddddddd-dddd-4ddd-8ddd-dddddddddddd"
}
}
Rows are returned only for statements that produce rows. For result sets larger
than one backend page, MetaTable.execute_operation(...) follows
pagination.next_offset automatically for select operations until it has
returned the requested limits.max_rows rows or pagination.has_more is
false. Include a deterministic ORDER BY in paginated select SQL.
Migration Execution
MetaTable schema migrations are executed by Alembic. The SDK migration CLI is a provider adapter that:
- loads the selected
AlembicMetaTableMigrationprovider; - asks the backend for a temporary migration URI when a command needs database access and no explicit SQLAlchemy URL was supplied;
- for
current,upgrade, anddowngrade, registers or resolves itsAlembicVersionMetaTable; - for
upgradeanddowngrade, creates or resolves provider platform-managed MetaTable rows before Alembic runs and finalizes them after successful DDL; - calls Alembic
current,revision,upgrade, ordowngradedirectly.
Backend coordination uses:
POST /orm/api/ts_manager/meta_table/
POST /orm/api/ts_manager/dynamic_table/
POST /orm/api/ts_manager/dynamic_table_data_source/<uid>/migration-connection/
POST /orm/api/ts_manager/meta_table/finalize-managed/
The migration-connection request does not include MetaTable UIDs; the provider
and namespace define the migration context. The backend does not receive an
SDK-rendered SQL artifact and does not execute a client-defined migration
operation. After a successful Alembic upgrade, the CLI finalizes provider
MetaTable catalog rows through finalize-managed/.
Backend Capabilities
The selected DynamicTableDataSource must expose the capability required by
the requested operation:
| Capability | Required for |
|---|---|
supports_table_registration |
all MetaTable registration |
supports_table_introspection |
introspect=True and the introspection action |
supports_table_ddl |
platform-managed physical table creation |
supports_compiled_select |
select operations |
supports_compiled_insert |
insert operations |
supports_compiled_update |
update operations |
supports_compiled_upsert |
upsert operations |
supports_compiled_delete |
delete operations |
supports_table_migration |
Alembic migration connections |
If a capability is missing, the backend returns a structured error instead of falling back to direct database access.
This is the main platform-managed tradeoff: users get governed table creation and execution without direct database credentials, but only for operations that the selected data source explicitly supports.
Search And Discovery
After registration, TS Manager stores:
- the
MetaTablerow - normalized
MetaTableColumnrows - normalized
MetaTableIndexrows - normalized foreign-key projection rows
- an optional
introspection_snapshot - a
TableSearchIndexdocument
Command Center and table discovery read those MetaTable records directly.