Tipos de origen¶
Modelo de ejecución¶
Toda consulta se ejecuta en última instancia a través del motor de federación, que provee federación entre todos los orígenes. Los orígenes se dividen en tres categorías según su conectividad. [tool-verified: provisa/core/models.py lines 84–132] (REQ-550)
| Categoría | Tiene controlador directo | Tiene conector federado | Ejemplos |
|---|---|---|---|
| Con capacidad directa | Sí | Sí | PostgreSQL, MySQL, MariaDB, SingleStore, SQL Server, Oracle, DuckDB |
| Solo federación | No | Sí | Redshift, Druid, Exasol, Hive, Iceberg, Delta Lake, Hive (respaldado por S3) |
| Lectura directa (réplica) | Sí | Sí | Snowflake, Databricks, ClickHouse — el controlador lee los datos y crea una réplica; las consultas se ejecutan contra la réplica en el motor activo |
| Materializar → Federación | No | No | REST/OpenAPI, GraphQL remoto, gRPC, Neo4j Cypher, SPARQL, WebSocket, RSS, CSV, SQLite, Parquet, Ingest (receptor push), GovData, SharePoint, Splunk |
Los orígenes con capacidad directa ejecutan consultas de un solo origen mediante su controlador nativo (menos de 100 ms), evitando el motor de federación (REQ-027, REQ-229). Conservan el soporte completo del conector y participan en la federación cuando se combinan con otros orígenes (REQ-028).
Los orígenes solo federación siempre se consultan a través de la capa de federación. No existe un controlador directo (REQ-229).
Los orígenes de lectura directa (réplica) tienen un DirectDriver que lee del almacén de datos de forma nativa (nativo en Arrow cuando está disponible), crea una réplica en el almacén de materialización del motor activo, y luego las consultas se ejecutan contra esa réplica. Consulte Almacenes de datos como orígenes con nombre.
Los orígenes de materialización no tienen conector federado. Provisa obtiene sus datos (al inicio o en el momento de la consulta) y los almacena en caché como Parquet en S3 o en PostgreSQL, haciéndolos accesibles para el motor de federación en consultas entre orígenes (REQ-309).
Todos los orígenes¶
Referencia de todos los tipos de origen que soporta Provisa. "Controlador directo" significa que las consultas de un solo origen se ejecutan de forma nativa contra el origen (menos de 100 ms) (REQ-027). "Nombre del conector" es el conector federado que se usa cuando el origen participa en JOIN entre varios orígenes (REQ-028). [tool-verified: provisa/core/source_registry.py SOURCE_TO_DIALECT; provisa/federation/trino_connectors.py trino_connector_name]
RDBMS¶
| Tipo de origen | Controlador directo | Nombre del conector | Dialecto | Mutaciones |
|---|---|---|---|---|
postgresql |
asyncpg | postgresql | postgres | Sí |
mysql |
aiomysql | mysql | mysql | Sí |
mariadb |
aiomysql | mariadb | mysql | Sí |
singlestore |
— | singlestore | singlestore | Federada |
sqlserver |
aioodbc | sqlserver | tsql | Sí |
oracle |
oracledb | oracle | oracle | Sí |
duckdb |
duckdb | memory | duckdb | Sí |
cockroachdb |
asyncpg (pg wire) | postgresql | postgres | Sí |
yugabytedb |
asyncpg (pg wire) | postgresql | postgres | Sí |
greenplum |
asyncpg (pg wire) | postgresql | postgres | Sí |
tidb |
aiomysql (mysql wire) | mysql | mysql | Sí |
Las bases de datos compatibles a nivel de wire reutilizan el controlador JDBC, el controlador nativo asíncrono y el dialecto de un wire base — CockroachDB, YugabyteDB y Greenplum usan el wire de PostgreSQL; TiDB usa el wire de MySQL. Solo necesitan entradas de registro, sin código de conector nuevo. [tool-verified: provisa/core/source_registry.py _PG_WIRE_TYPES, _MYSQL_WIRE_TYPES] (REQ-950)
firebird (Firebird 3/4/5) y airport (servidor Arrow Flight) son tipos de origen registrados a los que se accede en el lugar a través de extensiones de la comunidad de DuckDB cuando DuckDB es el motor activo — sin controlador directo, sin conector federado. [tool-verified: provisa/core/models.py lines 44, 93] (REQ-899)
Almacenes de datos en la nube¶
[tool-verified: executor/drivers/snowflake.py, executor/drivers/databricks.py, executor/drivers/registry.py]
| Tipo de origen | Controlador directo | Nombre del conector | Dialecto | Mutaciones | Notas |
|---|---|---|---|---|---|
snowflake |
SnowflakeDriver | snowflake | snowflake | Federada | Lee mediante snowflake-connector-python; crea réplica; account/warehouse/role en federation_hints (REQ-988) |
bigquery |
— | bigquery | bigquery | Federada | Sin DirectDriver; se accede mediante el motor de federación o BigQuery engine ATTACH |
databricks |
DatabricksDriver | delta_lake | databricks | Federada | Lee mediante databricks-sql-connector (Cloud Fetch, Arrow); crea réplica; http_path obligatorio en federation_hints (REQ-987) |
redshift |
— | redshift | redshift | Federada | — |
fabric |
MssqlWarehouseDriver | — | tsql | Federada | Microsoft Fabric Warehouse; T-SQL sobre TDS, autenticación Azure AD; crea réplica (REQ-995) |
synapse |
MssqlWarehouseDriver | — | tsql | Federada | Azure Synapse SQL; T-SQL sobre TDS, autenticación Azure AD; crea réplica (REQ-995) |
trino |
SQLAlchemyDriver | — | — | Federada | Coordinador remoto Trino/Presto leído mediante el dialecto trino de SQLAlchemy; crea réplica en cualquier motor (REQ-994) |
Analítica / OLAP¶
[tool-verified: executor/drivers/clickhouse.py]
| Tipo de origen | Controlador directo | Nombre del conector | Dialecto | Mutaciones | Notas |
|---|---|---|---|---|---|
clickhouse |
ClickHouseDriver | clickhouse | clickhouse | Federada | Lee mediante clickhouse-connect (HTTP); secure: "true" en federation_hints para TLS (REQ-986) |
druid |
— | druid | druid | No | — |
exasol |
— | exasol | exasol | No | — |
elasticsearch |
— | elasticsearch | — | No | Las propiedades del conector provienen del DSL de mapeo del tipo [tool-verified: trino_connectors.py:309] |
pinot |
— | pinot | — | No | Conector pinot de Trino; pinot.controller-urls = host:port del controlador de Pinot [tool-verified: trino_connectors.py:199] |
Data lake / Formatos de tabla abiertos¶
Estos tipos de origen son solo de federación — sin controlador directo, sin dialecto. [tool-verified: LAKE_ONLY_SOURCES in provisa/core/source_registry.py] (REQ-229)
| Tipo de origen | Nombre del conector | Viaje en el tiempo | Notas |
|---|---|---|---|
iceberg |
iceberg | Sí (argumento as_of, REQ-372) |
— |
delta_lake |
delta_lake | Sí (argumento as_of, REQ-372) |
— |
hive |
hive | No | — |
hive_s3 |
hive | No | Hive respaldado por S3 |
NoSQL¶
mongodb, cassandra y redis tienen conectores de Trino (redis construye sus propiedades a partir del DSL de mapeo del tipo). [tool-verified: provisa/federation/trino_connectors.py; provisa/core/models.py] (REQ-017, REQ-1097)
| Tipo de origen | Nombre del conector | Mutaciones |
|---|---|---|
mongodb |
mongodb | No |
cassandra |
cassandra | No |
redis |
redis | No |
Streaming¶
| Tipo de origen | Mecanismo | Mutaciones |
|---|---|---|
kafka |
Conector Kafka federado; esquema mediante Confluent Schema Registry (Avro, Protobuf, JSON Schema), definición manual o inferencia por muestreo (REQ-147, REQ-150) | Solo sink (REQ-176) |
websocket |
Feed WebSocket externo — conecta, se suscribe, recibe eventos; los resultados se materializan (REQ-338) | No |
rss |
Feed RSS 2.0 / Atom — sondea, marca de agua por pubDate/updated; los resultados se materializan (REQ-342, REQ-343) | No |
Receptor push¶
| Tipo de origen | Mecanismo | Mutaciones |
|---|---|---|
ingest |
Servicios externos envían eventos JSON mediante POST; los resultados se materializan (REQ-331, REQ-335) | No |
Grafo y semántica¶
| Tipo de origen | Mecanismo | Mutaciones |
|---|---|---|
neo4j |
Cypher mediante API HTTP, resultados almacenados en caché en PostgreSQL (REQ-295) | No |
sparql |
SPARQL 1.1 POST, resultados almacenados en caché en PostgreSQL (REQ-297) | No |
Basados en archivos¶
Dos mecanismos cubren los archivos. Ambos usan el campo path en lugar de host/port. [tool-verified: provisa/core/models.py] (REQ-553)
Orígenes de archivo único — sqlite, csv, parquet apuntan path a un solo archivo.
| Tipo de origen | Transportes | Mutaciones |
|---|---|---|
sqlite |
local | Sí |
csv |
local | No |
parquet |
local, s3:// |
No |
Los buckets privados necesitan credenciales (región y claves de AWS desde el entorno). Para CSV sobre s3:// o http(s)://, o para registrar muchos archivos a la vez, use el origen files. [tool-verified: provisa/file_source/source.py]
Origen files — apunta path a un glob, lo recorre de forma recursiva y registra el directorio como un catálogo federado de tablas. Lee muchos formatos sobre muchos transportes; los conjuntos siguientes provienen del conector de archivos (kenstott/calcite fork). [tool-verified: provisa/core/catalog.py files branch and provisa/core/models.py SOURCE_TO_CONNECTOR; format and transport lists from the calcite file adapter — FileSchema.java, storage/StorageProviderFactory.java]
| Formatos | Transportes |
|---|---|
| CSV, TSV, JSON, YAML, Excel (XLS/XLSX), Parquet, Arrow, y documentos convertidos a tablas — HTML, Markdown, DOCX, PPTX | Sistema de archivos local, HTTP(S), s3://, hdfs://, ftp:///ftps://, sftp://, iceberg://, SharePoint (REST y Microsoft Graph) |
- id: sales_files
type: files
path: s3://bucket/sales/**/*.csv # glob; local and http(s):// also supported
Observabilidad y otros¶
prometheus tiene un conector de Trino (propiedades construidas a partir del DSL de mapeo del tipo). google_sheets es un tipo de origen registrado sin conector de Trino y se materializa a través del pipeline de caché de API. [tool-verified: provisa/federation/trino_connectors.py:314; provisa/core/models.py lines 87–88]
| Tipo de origen | Nombre del conector | Mutaciones |
|---|---|---|
google_sheets |
— (materializado) | No |
prometheus |
prometheus | No |
Conectores SaaS empresariales¶
SharePoint y Splunk se registran mediante conectores de Apache Calcite (kenstott/calcite fork). Ninguno tiene controlador directo — Provisa materializa sus filas lanzando el servidor pgwire de Calcite incluido en el conector (pgwire-sharepoint, pgwire-splunk), conectándose a él como un endpoint genérico de PostgreSQL, y llevando las filas al almacén de materialización para la federación (REQ-954). Ambos conectores siempre habilitan la coincidencia de nombres sin distinción de mayúsculas y minúsculas, coincidiendo con la semántica propia de cada producto en ese aspecto (REQ-725, REQ-730). [tool-verified: provisa/core/models.py lines 99–100; provisa/federation/trino_connectors.py lines 223–286]
sharepoint¶
Las listas de SharePoint se enumeran como esquemas y se exponen como tablas consultables (REQ-726, REQ-731). Dos métodos de autenticación: CLIENT_CREDENTIALS (predeterminado) y basado en certificado mediante un certificado PFX (REQ-727). Los valores secretos en mapping se resuelven a través del motor de secretos antes de llegar al conector (REQ-729). [tool-verified: provisa/federation/trino_connectors.py lines 230–252]
| Campo de origen | Propiedad del conector | Notas |
|---|---|---|
base_url o host |
site-url |
URL del sitio de SharePoint |
username |
client-id |
ID de cliente de la app de Azure |
password |
client-secret |
Secreto de cliente de la app de Azure |
database |
tenant-id |
UUID del inquilino de Azure |
mapping.auth_type |
auth-type |
CLIENT_CREDENTIALS (predeterminado) o CERTIFICATE |
mapping.certificate_path |
certificate-path |
Ruta del PFX cuando auth_type: CERTIFICATE |
mapping.certificate_password |
certificate-password |
Contraseña del PFX |
Cuando el conector no expone information_schema.columns, registre la tabla con definiciones de columna explícitas (obtenidas de la API de Microsoft Graph) mediante la mutación registerTable (REQ-732).
- id: hr-sharepoint
type: sharepoint
base_url: https://kenstott.sharepoint.com
username: ${env:SP_CLIENT_ID}
password: ${env:SP_CLIENT_SECRET}
database: ${env:SP_TENANT_ID}
mapping:
auth_type: CLIENT_CREDENTIALS
splunk¶
Los resultados de búsqueda de Splunk son consultables como tablas (por ejemplo, internal_server) (REQ-721). La URL del conector proviene de base_url, o se construye como https://{host}:{port} con un puerto predeterminado de 8089 (REQ-722). Autenticación: cuando mapping.use_token es true (el predeterminado), password se pasa como el token de la API; cuando es false, username y password se pasan como credenciales separadas (REQ-723). [tool-verified: provisa/federation/trino_connectors.py lines 262–286]
| Campo de origen | Propiedad del conector | Notas |
|---|---|---|
base_url / host + port |
url |
base_url, o en su defecto https://host:port (puerto predeterminado 8089) |
password |
token o password |
token cuando use_token: true |
username |
user |
solo cuando use_token: false |
database |
app |
restringe a una app de Splunk |
mapping.datamodel_filter |
datamodel-filter |
filtra a un modelo de datos |
mapping.disable_ssl_validation |
disable-ssl-validation |
para certificados autofirmados (REQ-724) |
- id: ops-splunk
type: splunk
host: splunk
port: 8089
password: ${env:SPLUNK_TOKEN}
mapping:
use_token: true
disable_ssl_validation: true
Orígenes de API¶
Registre cualquier endpoint HTTP como una tabla consultable. [tool-verified: provisa/core/models.py SourceType enum] (REQ-314, REQ-307, REQ-322)
| Tipo de API | Detección | Inferencia de columnas |
|---|---|---|
openapi |
Análisis de especificación OpenAPI (REQ-314, REQ-316) | Primitivos → nativo, objetos → JSONB |
graphql_remote |
Introspección de esquema (REQ-307, REQ-308) | Primitivos → nativo, objetos → JSONB |
grpc_remote |
Reflexión del servidor (REQ-322, REQ-325) | Primitivos → nativo, objetos → JSONB |
Las respuestas de la API se obtienen, se almacenan en caché en PostgreSQL (TTL configurable) y se exponen como tipos GraphQL (REQ-309, REQ-318, REQ-327). Las tablas en caché participan en consultas federadas como cualquier otro origen (REQ-313).
Reglas de JSONB: Las columnas complejas (objetos, arreglos) almacenadas como JSONB no son filtrables (REQ-119). El acceso a subcampos usa la extracción ->> en SQL (REQ-151). Las relaciones se declaran entre tablas usando columnas de clave foránea escalares — las columnas de blob JSONB no son destinos de join. Use la promoción de JSONB para convertir campos anidados en columnas escalares nativas cuando se necesite filtrar o hacer join sobre ellos (REQ-119).
GovData¶
Datos abiertos del gobierno de EE. UU. El acceso está particionado por agrupación temática. [tool-verified: provisa/core/models.py lines 543–609]
Cada origen govdata selecciona un tema. Ese tema determina qué esquemas de GovData se exponen. Los esquemas ref y geo siempre se incluyen como esquemas de enlace — no se listan por tema, pero siempre están presentes. [tool-verified: provisa/core/models.py line 562–563 comment]
| Tema | Esquemas expuestos |
|---|---|
COMMERCE |
sec, patents |
ECONOMY |
econ |
EDUCATION |
census, edu |
HEALTH |
health |
CYBER |
cyber_threat, cyber_vuln |
PUBLIC_SAFETY |
crime |
ENVIRONMENT |
lands |
WEATHER |
weather |
GOVERNMENT |
fedregister, fec |
ALL |
Todos los esquemas anteriores |
sources:
- id: federal-commerce
type: govdata
subject: COMMERCE
domain_id: federal-analytics
description: U.S. commerce and securities data
| Campo | Obligatorio | Predeterminado | Descripción |
|---|---|---|---|
id |
Sí | — | Identificador único |
subject |
Sí | — | Uno de los valores de tema anteriores |
domain_id |
Sí | — | Dominio al que pertenece este origen |
description |
No | "" |
Descripción legible por humanos |
Conectores personalizados (REQ-1177)¶
Los motores de federación nativos — Postgres, DuckDB y ClickHouse — obtienen accesibilidad a un nuevo tipo de origen cuando un operador declara un conector para él en config/custom_connectors.yaml. No se requiere código. [tool-verified: provisa/federation/custom_connectors.py load_custom_connectors; provisa/federation/engine.py build_pg_engine, build_duckdb_engine, build_clickhouse_engine]
La extensibilidad de conectores en sí misma es anterior a esto. El motor Trino lleva mucho tiempo siendo extensible en su propia capa — un conector JDBC genérico parametrizado por tipo de origen, un cuerpo .properties de catálogo por tipo, y los propios plugins de conector Trino personalizados de Provisa (Splunk, SharePoint, Calcite). [tool-verified: provisa/federation/trino_connectors.py _TrinoJdbcConnector, _TRINO_JDBC_TYPES; trino/plugins/trino-splunk, trino/plugins/trino-sharepoint, trino/plugins/trino-calcite] REQ-1177 lleva esa misma extensibilidad basada en configuración a los dos motores nativos sin clúster, que antes tenían un conjunto de conectores fijo.
La configuración se distribuye vacía. Los conectores integrados cubren el alcance listo para usar; todo lo que hay en este archivo lo escribe el operador. [tool-verified: config/custom_connectors.yaml line 52: connectors: []] Defina PROVISA_CUSTOM_CONNECTORS para apuntar a una ruta distinta (útil para pruebas).
Tipos de descriptor¶
| Motor | Tipo | Mecanismo | Qué proporciona el descriptor |
|---|---|---|---|
postgres |
pg_fdw |
SQL/MED (estándar ISO) | extension, server_options, user_mapping, supports_import, table_options, remote_schema |
duckdb |
duckdb_attach |
INSTALL/LOAD + ATTACH | extension, probe_symbol, attach_template, remote_schema |
duckdb |
duckdb_scan |
INSTALL/LOAD + vista de escaneo | extension, probe_symbol, scan_template |
clickhouse |
clickhouse_database |
CREATE DATABASE ENGINE=… (expone automáticamente cada tabla remota) |
ch_engine, engine_template |
clickhouse |
clickhouse_table |
CREATE TABLE ENGINE=… por tabla (columnas desde el registro) |
ch_engine, engine_template (puede llevar {table}) |
clickhouse |
clickhouse_scan |
CREATE TABLE ENGINE=…, ClickHouse infiere el esquema |
ch_engine, engine_template |
Postgres es genérico. SQL/MED es un estándar ISO, por lo que todo FDW conforme comparte la misma forma de DDL: CREATE SERVER … FOREIGN DATA WRAPPER <fdw> OPTIONS(…), opcionalmente CREATE USER MAPPING, y luego IMPORT FOREIGN SCHEMA (cuando supports_import: true) o una CREATE FOREIGN TABLE explícita por tabla (cuando es false). Un descriptor pg_fdw solo proporciona la variación específica del FDW — nombre de la extensión, claves de opciones del servidor, claves de mapeo de usuario, indicador de importación, opciones de tabla. Cualquier FDW conforme al estándar es, por lo tanto, manejable solo desde la configuración. [tool-verified: provisa/federation/custom_connectors.py GenericPgFdwConnector.details lines 98–125]
DuckDB soporta dos mecanismos. Una extensión que expone un catálogo mediante ATTACH usa duckdb_attach; una que expone una función de tabla de lectura usa duckdb_scan. Una extensión que no encaja en ninguno de los dos patrones no es compatible. [tool-verified: provisa/federation/custom_connectors.py GenericDuckDbAttachConnector, GenericDuckDbScanConnector]
ClickHouse soporta tres mecanismos, uno por cada forma de motor de integración: un motor DATABASE relacional que expone automáticamente cada tabla remota (clickhouse_database, por ejemplo Redis/MySQL), un motor por tabla cuyas columnas provee el registro (clickhouse_table, por ejemplo el puente JDBC/ODBC — el engine_template puede llevar un marcador {table} que el runtime vincula), y un motor de archivo/lake/URL cuyo esquema infiere ClickHouse (clickhouse_scan, por ejemplo HDFS/URL). SQLite (motor DATABASE, archivo, sin servidor) y Hudi (lakehouse, sin copia) vienen listos para usar. [tool-verified: provisa/federation/custom_connectors.py GenericClickHouseDatabaseConnector, GenericClickHouseTableConnector, GenericClickHouseScanConnector; provisa/federation/clickhouse_connectors.py ClickHouseSqliteConnector, ClickHouseHudiConnector] (REQ-1178)
Un valor kind desconocido falla de forma ruidosa al inicio — un error tipográfico en el descriptor no debe dejar un tipo de origen inalcanzable en silencio. [tool-verified: provisa/federation/custom_connectors.py load_custom_connectors lines 178–197]
Verificación de disponibilidad¶
La disponibilidad se verifica en el momento del attach contra el catálogo de detección estándar de cada motor:
- Postgres — verifica
pg_extension, luegopg_available_extensions. [tool-verified:provisa/federation/connector_duckdb.py_probe_pg_extensionlines 333–344] - DuckDB — ejecuta
INSTALL/LOADy verificaduckdb_functions()para elprobe_symboldeclarado. [tool-verified:provisa/federation/connector_duckdb.py_DuckDBExtensionConnector.probelines 160–180] - ClickHouse — verifica
system.table_enginespara elch_enginedeclarado; su ausencia en el build falla de forma ruidosa. [tool-verified:provisa/federation/custom_connectors.py_probe_clickhouse_engine]
Una extensión declarada que no se puede instalar falla de forma ruidosa. Sin omisión silenciosa, sin valor de respaldo. Un conector cuya verificación falla simplemente no está activo para ese despliegue.
Variables de plantilla¶
Todo valor de server_options, valor de user_mapping, attach_template y scan_template puede usar marcadores {field}. Campos disponibles: [tool-verified: provisa/federation/custom_connectors.py _source_fields lines 53–63]
{id}, {host}, {port}, {database}, {username}, {password}, {path}, {schema_name}, {table_name}, además de cualquier clave de federation_hints. Las plantillas de attach de DuckDB también reciben {alias} — el alias de catálogo interno que Provisa asigna a la base de datos adjunta.
Una plantilla que referencia un campo desconocido falla de forma ruidosa en el momento del attach, exponiendo un desajuste entre descriptor y origen antes de que un DDL roto llegue al motor.
Ejemplos¶
Postgres — MongoDB mediante mongo_fdw (sin importación de esquema; columnas provistas por tabla)
# config/custom_connectors.yaml
connectors:
- engine: postgres
source_type: mongodb
kind: pg_fdw
extension: mongo_fdw
mechanism: attach_r
server_options:
address: "{host}"
port: "{port}"
user_mapping:
username: "{username}"
password: "{password}"
supports_import: false
table_options:
database: "{database}"
collection: "{table_name}"
DuckDB — Archivos Excel mediante read_xlsx (función de tabla de escaneo)
- engine: duckdb
source_type: xlsx
kind: duckdb_scan
extension: excel
install_from_community: false
probe_symbol: read_xlsx
scan_template: "read_xlsx('{path}')"
[tool-verified: config/custom_connectors.yaml commented examples, lines 26–50]
Con cualquiera de los dos descriptores en su lugar, registrar un origen con el source_type declarado lo enruta a través del conector personalizado, sujeto a una verificación exitosa. No se necesita ningún otro cambio de configuración.
Almacenes de datos como orígenes con nombre¶
Snowflake, Databricks y ClickHouse se pueden registrar como orígenes con nombre independientemente de cuál motor de federación esté activo. [tool-verified: executor/drivers/snowflake.py (REQ-988), executor/drivers/databricks.py (REQ-987), executor/drivers/clickhouse.py (REQ-986)]
Una vez registrado, Provisa lee el almacén de datos mediante el DirectDriver del origen y crea una réplica en el almacén de materialización del motor activo. La consulta se ejecuta luego contra esa réplica. Esto difiere de la ruta tradicional con capacidad directa (asyncpg, aiomysql), donde el motor se evita por completo — aquí el motor sigue ejecutando la consulta, pero contra una réplica local en lugar de por cable hacia el almacén de datos en cada solicitud.
Las lecturas son nativas en Arrow cuando el almacén de datos lo soporta: Databricks usa Cloud Fetch, Snowflake usa fetch_arrow_table, y ClickHouse usa la interfaz HTTP columnar nativa.
Los parámetros de conexión extendidos que los campos estándar host/port/username/password no pueden llevar van en federation_hints:
sources:
- id: my-databricks
type: databricks
host: my-workspace.azuredatabricks.net
password: ${env:DATABRICKS_TOKEN}
federation_hints:
http_path: /sql/1.0/warehouses/xxxx # required — the SQL Warehouse connection detail
- id: my-snowflake
type: snowflake
host: org.snowflakecomputing.com
username: svc_provisa
password: ${env:SNOWFLAKE_PASSWORD}
federation_hints:
account: myorg-myaccount # required — Snowflake account identifier
warehouse: COMPUTE_WH # optional — virtual warehouse to use
role: PROVISA_ROLE # optional — Snowflake role
- id: my-clickhouse
type: clickhouse
host: ch.example.com
port: 8123
database: analytics
username: default
password: ${env:CLICKHOUSE_PASSWORD}
federation_hints:
secure: "true" # optional — enables TLS on the HTTP interface
El registro como origen con nombre es independiente de seleccionar ese mismo almacén de datos como motor de federación. Un origen Snowflake sobre un motor DuckDB crea una réplica en DuckDB, no en Snowflake.
Los datos de objeto/lake en la nube (archivos parquet, csv, iceberg, delta_lake en S3 / GCS / R2) son un tipo de origen independiente que se adjunta en el lugar cuando el motor activo tiene un conector ATTACH para ese tipo. No se crea réplica alguna — el motor escanea el almacenamiento de objetos directamente. Las credenciales de esos orígenes también van en federation_hints:
sources:
- id: r2-events
type: parquet
path: s3://my-bucket/events/2026/*.parquet
federation_hints:
access_key_id: ${env:R2_ACCESS_KEY}
secret_access_key: ${env:R2_SECRET}
account_id: ${env:R2_ACCOUNT_ID} # Cloudflare R2 account (S3-compatible)
Campos de configuración de origen¶
Todos los orígenes comparten un conjunto común de campos. [tool-verified: provisa/core/models.py Source class, lines 138–204]
| Campo | Obligatorio | Predeterminado | Descripción |
|---|---|---|---|
id |
Sí | — | Identificador único; alfanumérico con guiones/guiones bajos |
type |
Sí | — | Tipo de origen (ver tablas anteriores) |
host |
No | "" |
Nombre de host o IP |
port |
No | 0 |
Número de puerto |
database |
No | "" |
Nombre de la base de datos |
username |
No | "" |
Nombre de usuario |
password |
No | "" |
Contraseña; use ${env:VAR} para resolución de secretos |
path |
No | null |
Ruta de archivo o URI en la nube para orígenes basados en archivo y de objeto/lake |
base_url |
No | null |
URL base para orígenes OpenAPI |
pool_min |
No | 1 |
Tamaño mínimo del pool de conexiones (REQ-052) |
pool_max |
No | 5 |
Tamaño máximo del pool de conexiones (REQ-052) |
use_pgbouncer |
No | false |
Enruta las conexiones a través de PgBouncer (REQ-053) |
pgbouncer_port |
No | 6432 |
Puerto de PgBouncer (REQ-053) |
cache_enabled |
No | true |
Habilita el almacenamiento en caché de respuestas de API |
cache_ttl |
No | null |
TTL de la caché en segundos; hereda el predeterminado global cuando es null |
cache_catalog |
No | null |
Catálogo federado para la caché de API; por defecto usa el catálogo propio del origen |
cache_schema |
No | api_cache |
Esquema dentro del catálogo de caché |
naming_convention |
No | null |
Anula la convención de nombres global para este origen (REQ-194) |
federation_hints |
No | {} |
Propiedades de sesión pasadas al motor de federación, y parámetros de conexión extendidos para orígenes de almacén de datos (REQ-278, REQ-281) |
mapping |
No | {} |
Configuración de conector específica del tipo para orígenes NoSQL y SaaS (por ejemplo, auth_type de SharePoint, use_token de Splunk) (REQ-251) |
allowed_domains |
No | [] |
Restringe el origen a dominios específicos; vacío = sin restricción |
description |
No | "" |
Descripción legible por humanos |
Orígenes Kafka¶
Los tópicos de Kafka se configuran por separado bajo kafka_sources, indexados por el id de origen de un origen kafka registrado. [tool-verified: config/provisa.yaml lines 138–151] (REQ-147)
kafka_sources:
- id: kafka-support
topics:
- id: tickets
topic: support.tickets
domain_id: sales-analytics
description: "Inbound support tickets"
default_window: 1h
columns:
- name: id
- name: subject
- name: status
- name: created_at
| Campo | Descripción |
|---|---|
id |
Debe coincidir con el id de un origen con type: kafka |
topics[].id |
Nombre lógico de este tópico dentro de Provisa |
topics[].topic |
Nombre del tópico de Kafka |
topics[].domain_id |
Dominio al que pertenece este tópico |
topics[].description |
Descripción legible por humanos |
topics[].default_window |
Ventana de tiempo predeterminada para consultas con ventana (por ejemplo, 1h) (REQ-148) |
topics[].columns |
Definiciones de columna para el esquema del tópico (REQ-150) |
Visibilidad de columnas¶
El campo visible_to en cada columna es una lista de ID de rol que pueden ver esa columna. [tool-verified: provisa/core/models.py Column class line 248; config/provisa.yaml lines 39–51]
columns:
- name: email
visible_to: [admin] # only admin role sees this column
- name: region
visible_to: [admin, analyst] # both roles see this column
Las columnas omitidas de la lista visible_to de un rol no aparecen en el esquema GraphQL de ese rol y no se pueden consultar ni referenciar en filtros (REQ-039).
Relaciones¶
Las relaciones conectan dos tablas registradas y aparecen como campos anidados en GraphQL. [tool-verified: provisa/core/models.py Relationship class lines 323–343; config/provisa.yaml lines 103–110] (REQ-019)
relationships:
- id: orders-to-customers
source_table_id: orders
target_table_id: customers
source_column: customer_id
target_column: id
cardinality: many-to-one
| Campo | Obligatorio | Descripción |
|---|---|---|
id |
Sí | Identificador único para esta relación |
source_table_id |
Sí | Tabla que contiene la clave foránea |
target_table_id |
Sí | Tabla referenciada; vacío para relaciones calculadas |
source_column |
Sí | Columna en la tabla de origen |
target_column |
Sí | Columna en la tabla de destino; vacío para relaciones calculadas |
cardinality |
Sí | many-to-one o one-to-many (REQ-019) |
materialize |
No | Crea automáticamente una vista materializada para joins entre orígenes (REQ-158) |
refresh_interval |
No | Intervalo de actualización de la vista materializada en segundos (predeterminado: 300) |
target_function_name |
No | Nombre de función de base de datos para relaciones calculadas |
function_arg |
No | Qué argumento de la función recibe el valor de la columna de origen |
alias |
No | Tipo de relación legible por humanos (por ejemplo, WORKS_FOR) |
graphql_alias |
No | Nombra el campo SDL que esta relación expone en el tipo padre. Cuando está ausente, el nombre se deriva del field_name de la tabla destino y la cardinalidad de la relación. [tool-verified: provisa/compiler/schema_gen.py:1050] |
disable_cypher |
No | Cuando es true, excluye esta relación de las aristas del grafo Cypher |
source_json_key |
No | Extrae esta clave de la columna de origen como un objeto JSON antes del JOIN |
Valores de cardinalidad [tool-verified: provisa/core/models.py Cardinality enum, lines 79–81]:
many-to-one— cada fila de origen se mapea a una fila de destino (FK a PK)one-to-many— cada fila de origen se mapea a varias filas de destino (inverso de la anterior)
Reglas de seguridad de nivel de fila¶
Las reglas RLS inyectan cláusulas WHERE en el momento de la consulta, con alcance a un rol y opcionalmente a una tabla o dominio. [tool-verified: provisa/core/models.py RLSRule class lines 391–395; config/provisa.yaml lines 128–131] (REQ-041)
rls_rules:
- table_id: orders # applies to orders table only
role_id: analyst
filter: "region = current_setting('provisa.user_region')"
- domain_id: sales-analytics # applies to every table in domain (REQ-402)
role_id: analyst
filter: "tenant_id = current_setting('provisa.tenant_id')"
Cuando existen tanto una regla de nivel de dominio como una de nivel de tabla para el mismo rol, la regla de nivel de tabla tiene prioridad (REQ-403).
| Campo | Obligatorio | Descripción |
|---|---|---|
table_id |
Condicional | Tabla a la que se aplica la regla; mutuamente excluyente con domain_id |
domain_id |
Condicional | Dominio al que se aplica la regla; se aplica a todas las tablas del dominio (REQ-402) |
role_id |
Sí | Rol al que se aplica esta regla |
filter |
Sí | Predicado SQL inyectado en WHERE; puede referenciar variables de sesión (REQ-041) |
Funciones y webhooks¶
Funciones de base de datos¶
Registra una función de base de datos y la expone como consulta o mutación GraphQL. [tool-verified: provisa/core/models.py Function class lines 423–438; config/provisa.yaml lines 152–164] (REQ-205)
Los orígenes de base de datos también pueden autodescubrir sus procedimientos almacenados y funciones a partir del catálogo del proveedor (pg_proc, information_schema.routines, o equivalentes del proveedor), eliminando la necesidad de registrar cada uno manualmente. La detección lee prokind y provolatile: las funciones inmutables/estables se registran como relaciones parametrizadas (los argumentos del procedimiento se convierten en parámetros de consulta, con la misma forma que las tablas OpenAPI GET), y los procedimientos volátiles se registran como mutaciones/funciones rastreadas. Las rutinas descubiertas pasan por el gobierno de Etapa 2 de forma idéntica a las registradas manualmente. [tool-verified: provisa/api/admin/introspect.py:541, provisa/api/admin/introspect.py:593] (REQ-887)
functions:
- name: get_customers_by_region
source_id: sales-pg
schema: public
function_name: get_customers_by_region
returns: customers
domain_id: sales-analytics
description: "Returns customers filtered by region"
visible_to: [admin, analyst]
kind: query
arguments:
- name: p_region
type: String
| Campo | Obligatorio | Predeterminado | Descripción |
|---|---|---|---|
name |
Sí | — | Nombre del campo GraphQL |
source_id |
Sí | — | Origen que contiene la función |
schema |
No | public |
Esquema de base de datos |
function_name |
Sí | — | Nombre real de la función de base de datos |
returns |
Sí | — | ID de la tabla registrada que devuelve la función (REQ-207) |
arguments |
No | [] |
Lista de definiciones de argumento {name, type} (REQ-211) |
visible_to |
No | [] |
Roles que pueden llamar a esta función |
writable_by |
No | [] |
Roles que pueden llamarla como mutación |
domain_id |
No | "" |
Dominio al que pertenece esta función |
description |
No | null |
Descripción del campo GraphQL |
kind |
No | mutation |
"query" o "mutation" (REQ-205) |
Webhooks¶
Expone un endpoint HTTP externo como consulta o mutación GraphQL. [tool-verified: provisa/core/models.py Webhook class lines 441–455; config/provisa.yaml lines 166–178] (REQ-209)
webhooks:
- name: notify_support
url: http://localhost:9999/notify
method: POST
timeout_ms: 3000
domain_id: sales-analytics
description: "Send a support notification"
visible_to: [admin]
kind: mutation
arguments:
- name: message
type: String
| Campo | Obligatorio | Predeterminado | Descripción |
|---|---|---|---|
name |
Sí | — | Nombre del campo GraphQL |
url |
Sí | — | URL del endpoint del webhook |
method |
No | POST |
Método HTTP |
timeout_ms |
No | 5000 |
Tiempo límite de la solicitud en milisegundos |
returns |
No | null |
ID de tabla registrada, o null para tipo en línea |
inline_return_type |
No | [] |
Lista de campos {name, type} para formas de retorno personalizadas (REQ-210) |
arguments |
No | [] |
Lista de definiciones de argumento {name, type} |
visible_to |
No | [] |
Roles que pueden llamar a este webhook |
domain_id |
No | "" |
Dominio al que pertenece este webhook |
description |
No | null |
Descripción del campo GraphQL |
kind |
No | mutation |
"query" o "mutation" |
Autenticación¶
La autenticación se configura bajo la clave auth. [tool-verified: provisa/core/models.py AuthConfig class lines 467–477] (REQ-120)
| Proveedor | Descripción |
|---|---|
none |
Sin autenticación; todas las solicitudes se tratan como el default_role |
firebase |
Firebase Authentication; requiere project_id y service_account_key (REQ-121) |
keycloak |
Keycloak OIDC (REQ-122) |
oauth |
OAuth 2.0 genérico (REQ-123) |
simple |
Usuario/contraseña sin proveedor externo (REQ-124) |
auth:
provider: firebase
assignments_source: provisa # "claims" or "provisa"
default_role: analyst
default_assignments:
- role_id: analyst
domain_id: "*"
firebase:
project_id: ${env:FIREBASE_PROJECT_ID}
service_account_key: ${env:FIREBASE_SERVICE_ACCOUNT_KEY}
assignments_source: claims lee las asignaciones de rol desde los claims del JWT. assignments_source: provisa las lee desde el almacén de asignaciones propio de Provisa. [tool-verified: provisa/core/models.py line 476] (REQ-551)
Enrutamiento de ejecución¶
Ejecución directa — Las consultas RDBMS de un solo origen se enrutan al controlador nativo para lograr una latencia menor a 100 ms (REQ-027). Los orígenes requieren tanto una entrada en SOURCE_TO_DIALECT como una en SOURCE_TO_CONNECTOR para soportar esta ruta (REQ-229).
Ejecución federada — Las consultas de varios orígenes y los orígenes sin controlador directo se enrutan a través del motor de federación (REQ-028). Provisa incluye un motor de federación embebido; apunte a su propio clúster compatible para despliegues a gran escala (REQ-226).
Estadísticas — Al registrar, Provisa ejecuta ANALYZE contra cada tabla publicada para preparar el optimizador basado en costos (conteo de filas, fracción de nulos, valores distintos, mínimo/máximo). Los fallos se registran en el log y no bloquean el registro (REQ-275).
Orígenes de grafo y semántica¶
Neo4j¶
Registre una base de datos de grafos Neo4j como un origen consultable. Los stewards escriben consultas Cypher que proyectan valores escalares; Provisa almacena en caché los resultados y los expone como tipos GraphQL (REQ-295).
Las consultas Cypher deben usar accesores de propiedad en la cláusula RETURN (RETURN n.id AS id, n.name AS name) — devolver objetos de nodo se rechaza en el momento del registro (REQ-296).
# Register via admin API (no YAML config required)
POST /admin/sources/neo4j
{
"source_id": "graph",
"host": "neo4j",
"port": 7474,
"database": "neo4j"
}
# Register a table (preview + validate before persisting)
POST /admin/sources/neo4j/graph/tables
{
"table_name": "person_skills",
"cypher": "MATCH (p:Person)-[:HAS_SKILL]->(s:Skill) RETURN p.name AS name, s.skill AS skill, p.experience AS years",
"ttl": 300
}
El endpoint de vista previa (POST /admin/sources/neo4j/{id}/preview) devuelve filas de muestra y bloquea el registro si el Cypher devuelve objetos de nodo (REQ-296).
SPARQL¶
Registre cualquier triplestore compatible con SPARQL 1.1 (Apache Jena Fuseki, Virtuoso, Stardog, etc.) como un origen consultable (REQ-297).
Las consultas deben ser consultas SELECT. Los nombres de variable en la cláusula SELECT se convierten automáticamente en nombres de columna (REQ-297).
# Register via admin API
POST /admin/sources/sparql
{
"source_id": "knowledge-graph",
"endpoint_url": "http://fuseki:3030/ds/sparql",
"default_graph_uri": "http://example.org/graph"
}
# Register a table (executes LIMIT 5 probe to validate and infer columns)
POST /admin/sources/sparql/knowledge-graph/tables
{
"table_name": "product_categories",
"sparql_query": "SELECT ?product ?label ?category WHERE { ?product a :Product ; rdfs:label ?label ; :hasCategory ?category . }",
"ttl": 600
}
Ambos conectores usan el pipeline de caché de origen de API — los resultados se almacenan en PostgreSQL con TTL configurable, lo que los hace disponibles para JOIN federados entre orígenes (REQ-295, REQ-297, REQ-299).
Ejemplos de conexión¶
PostgreSQL¶
- id: sales-pg
type: postgresql
host: postgres
port: 5432
database: provisa
username: provisa
password: ${env:PG_PASSWORD}
Snowflake¶
- id: analytics-sf
type: snowflake
host: org.snowflakecomputing.com
port: 443
database: ANALYTICS
username: svc_provisa
password: ${env:SNOWFLAKE_PASSWORD}
federation_hints:
account: myorg-myaccount
warehouse: COMPUTE_WH
Databricks¶
- id: lakehouse-db
type: databricks
host: my-workspace.azuredatabricks.net
password: ${env:DATABRICKS_TOKEN}
federation_hints:
http_path: /sql/1.0/warehouses/xxxx
MongoDB¶
- id: reviews-mongo
type: mongodb
host: mongodb
port: 27017
database: provisa
username: ""
password: ""
Consulta entre orígenes¶
{
orders(where: {region: {eq: "us"}}) {
id
amount
customers { # PostgreSQL
name
email
}
productReviews { # MongoDB (federated)
rating
comment
}
}
}
Las porciones de un solo origen se enrutan directamente (REQ-027). Los JOIN entre orígenes se federan con coerción de tipos automática (REQ-028, REQ-552).