diff --git a/airbyte/caches/base.py b/airbyte/caches/base.py index 07abe365..cc168c71 100644 --- a/airbyte/caches/base.py +++ b/airbyte/caches/base.py @@ -103,8 +103,11 @@ def __init__(self, **data: Any) -> None: # noqa: ANN401 @property def config_hash(self) -> str | None: - """Return a hash of the cache configuration.""" - pass + """Return a hash of the cache configuration. + + This is the same as the SQLConfig hash from the superclass. + """ + return super(SqlConfig, self).config_hash @final @property diff --git a/airbyte/shared/sql_processor.py b/airbyte/shared/sql_processor.py index 39cd9b51..52e58f50 100644 --- a/airbyte/shared/sql_processor.py +++ b/airbyte/shared/sql_processor.py @@ -41,6 +41,7 @@ ) from airbyte import exceptions as exc +from airbyte._util.hashing import one_way_hash from airbyte._util.name_normalizers import LowerCaseNormalizer from airbyte.constants import ( AB_EXTRACTED_AT_COLUMN, @@ -101,6 +102,28 @@ def get_database_name(self) -> str: """Return the name of the database.""" ... + @property + def config_hash(self) -> str | None: + """Return a unique one-way hash of the configuration. + + The generic implementation uses the SQL Alchemy URL, schema name, and table prefix. Some + inputs may be redundant with the SQL Alchemy URL, but this does not hurt the hash + uniqueness. + + In most cases, subclasses do not need to override this method. + """ + return one_way_hash( + SecretString( + ":".join( + [ + str(self.get_sql_alchemy_url()), + self.schema_name or "", + self.table_prefix or "", + ] + ) + ) + ) + def get_sql_engine(self) -> Engine: """Return a new SQL engine to use.""" return create_engine(