Learn how to build SQL applications that extract metadata from databases
The Application SDK provides a robust framework for building SQL applications that interact with databases to extract, process, and store metadata. This guide demonstrates how to leverage the SDK’s default implementations while maintaining the flexibility to customize behavior for your specific needs.
An SQL application built with the SDK follows a “batteries included but swappable” philosophy - it provides sensible defaults for common tasks while allowing customization at every level.
1
Connect
Securely connects to SQL databases using various authentication methods (basic, IAM user, IAM role).
The SDK’s SQL metadata extraction workflow relies on three main customizable components:
SQL Client
BaseSQLClientHandles database connectivity and query execution.Extend to support different SQL dialects, connection string formats, or custom authentication logic.
Activities
BaseSQLMetadataExtractionActivitiesDefines SQL queries for extracting metadata (databases, schemas, tables, columns, etc.).Override specific query attributes to tailor metadata extraction for your database.
Handler
BaseSQLHandlerManages database-specific validation logic and helper methods.Extend to implement custom validation checks or database-specific logic.
These components work together within the BaseSQLMetadataExtractionWorkflow, orchestrated by a Worker.
Extend BaseSQLMetadataExtractionActivities to provide custom SQL queries for metadata extraction:
class SampleSQLActivities(BaseSQLMetadataExtractionActivities): # Customize database metadata query for PostgreSQL fetch_database_sql = """ SELECT datname as database_name FROM pg_database WHERE datname = current_database(); """
The queries use template variables like {normalized_exclude_regex} and {normalized_include_regex} which are filled at runtime from the workflow configuration.
Extend BaseSQLHandler to implement custom validation logic:
from application_sdk.handlers.sql import BaseSQLHandlerclass SampleSQLWorkflowHandler(BaseSQLHandler): # Customize query to check table count (used in preflight checks) tables_check_sql = """ SELECT count(*) FROM INFORMATION_SCHEMA.TABLES t WHERE concat(TABLE_CATALOG, concat('.', TABLE_SCHEMA)) !~ '{normalized_exclude_regex}' AND concat(TABLE_CATALOG, concat('.', TABLE_SCHEMA)) ~ '{normalized_include_regex}' AND TABLE_SCHEMA NOT IN ('performance_schema', 'information_schema', 'pg_catalog', 'pg_internal') {temp_table_regex_sql}; """ temp_table_regex_sql = "AND t.table_name !~ '{exclude_table_regex}'" # Customize query to fetch basic schema/catalog info metadata_sql = """ SELECT schema_name, catalog_name FROM INFORMATION_SCHEMA.SCHEMATA WHERE schema_name NOT LIKE 'pg_%' AND schema_name != 'information_schema' """
Load sensitive credentials from environment variables or secure stores, not directly in code. Use the constants defined in application_sdk.constants.
Error Handling
Implement try...except blocks in custom code (especially within Activities or Handlers) to handle potential database errors or unexpected data.
Logging
Use the SDK’s logger (application_sdk.observability.logger_adaptor.get_logger) for consistent and structured logging integrated with Temporal.
Idempotency
Design activities to be idempotent where possible, meaning they can be run multiple times with the same result. Temporal handles retries, but idempotent activities simplify recovery.
Testing
Write unit tests for your custom Client, Activities, and Handler classes. The SDK provides testing utilities in application_sdk.test_utils.
Resource Management
Ensure database connections are properly closed. The SDK’s client and workflow management generally handle this, but be mindful in custom extensions.