diff --git a/sqliter/exceptions.py b/sqliter/exceptions.py index cf49652..f248a94 100644 --- a/sqliter/exceptions.py +++ b/sqliter/exceptions.py @@ -114,7 +114,7 @@ class RecordUpdateError(SqliterError): class RecordNotFoundError(SqliterError): """Exception raised when a requested record is not found in the database.""" - message_template = "Failed to find a record for key '{}' " + message_template = "Failed to find that record in the table (key '{}') " class RecordFetchError(SqliterError): diff --git a/sqliter/query/query.py b/sqliter/query/query.py index 175a439..a4ba9de 100644 --- a/sqliter/query/query.py +++ b/sqliter/query/query.py @@ -184,7 +184,7 @@ def exclude(self, fields: Optional[list[str]] = None) -> QueryBuilder: self._fields = list(all_fields - set(fields)) # Explicit check: raise an error if no fields remain - if not self._fields: + if self._fields == ["pk"]: err = "Exclusion results in no fields being selected." raise ValueError(err) diff --git a/sqliter/sqliter.py b/sqliter/sqliter.py index 6b10468..23f82c1 100644 --- a/sqliter/sqliter.py +++ b/sqliter/sqliter.py @@ -397,8 +397,8 @@ def update(self, model_instance: BaseDBModel) -> None: model_instance: An instance of a Pydantic model to be updated. Raises: - RecordUpdateError: If there's an error updating the record. - RecordNotFoundError: If the record to update is not found. + RecordUpdateError: If there's an error updating the record or if it + is not found. """ model_class = type(model_instance) table_name = model_class.get_table_name() diff --git a/tests/conftest.py b/tests/conftest.py index 4145c45..82719eb 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -39,8 +39,6 @@ class ExampleModel(BaseDBModel): class Meta: """Configuration for the model.""" - create_pk: bool = False - primary_key: str = "slug" table_name: str = "test_table" @@ -53,9 +51,7 @@ class PersonModel(BaseDBModel): class Meta: """Configuration for the model.""" - create_pk = False table_name = "person_table" - primary_key = "name" class DetailedPersonModel(BaseDBModel): @@ -72,14 +68,11 @@ class Meta: """Configuration for the model.""" table_name = "detailed_person_table" - primary_key = "name" - create_pk = False class ComplexModel(BaseDBModel): """Model to test complex field types.""" - id: int name: str age: float is_active: bool @@ -90,8 +83,6 @@ class Meta: """Configuration for the model.""" table_name = "complex_model" - primary_key = "id" - create_pk = False @pytest.fixture diff --git a/tests/test_debug_logging.py b/tests/test_debug_logging.py index 1176cfe..f4a7eb6 100644 --- a/tests/test_debug_logging.py +++ b/tests/test_debug_logging.py @@ -39,7 +39,7 @@ def test_debug_sql_output_basic_query( # Assert the SQL query was printed assert ( - 'Executing SQL: SELECT "id", "name", "age", "is_active", "score", ' + 'Executing SQL: SELECT "pk", "name", "age", "is_active", "score", ' '"nullable_field" FROM "complex_model" WHERE age = 30.5' in caplog.text ) @@ -55,7 +55,7 @@ def test_debug_sql_output_string_values( # Assert the SQL query was printed with the string properly quoted assert ( - 'Executing SQL: SELECT "id", "name", "age", "is_active", "score", ' + 'Executing SQL: SELECT "pk", "name", "age", "is_active", "score", ' '"nullable_field" FROM "complex_model" WHERE name = \'Alice\'' in caplog.text ) @@ -71,7 +71,7 @@ def test_debug_sql_output_multiple_conditions( # Assert the SQL query was printed with multiple conditions assert ( - 'Executing SQL: SELECT "id", "name", "age", "is_active", "score", ' + 'Executing SQL: SELECT "pk", "name", "age", "is_active", "score", ' '"nullable_field" FROM "complex_model" WHERE name = \'Alice\' AND ' "age = 30.5" in caplog.text ) @@ -87,7 +87,7 @@ def test_debug_sql_output_order_and_limit( # Assert the SQL query was printed with ORDER and LIMIT assert ( - 'Executing SQL: SELECT "id", "name", "age", "is_active", "score", ' + 'Executing SQL: SELECT "pk", "name", "age", "is_active", "score", ' '"nullable_field" FROM "complex_model" ORDER BY "age" DESC LIMIT 1' in caplog.text ) @@ -99,7 +99,7 @@ def test_debug_sql_output_with_null_value( with caplog.at_level(logging.DEBUG): db_mock_complex_debug.insert( ComplexModel( - id=4, + pk=4, name="David", age=40.0, is_active=True, @@ -114,7 +114,7 @@ def test_debug_sql_output_with_null_value( # Assert the SQL query was printed with IS NULL assert ( - 'Executing SQL: SELECT "id", "name", "age", "is_active", "score", ' + 'Executing SQL: SELECT "pk", "name", "age", "is_active", "score", ' '"nullable_field" FROM "complex_model" WHERE age IS NULL' in caplog.text ) @@ -130,7 +130,8 @@ def test_debug_sql_output_with_fields_single( # Assert the SQL query only selects the 'name' field assert ( - 'Executing SQL: SELECT "name" FROM "complex_model"' in caplog.text + 'Executing SQL: SELECT "name", "pk" FROM "complex_model"' + in caplog.text ) def test_debug_sql_output_with_fields_multiple( @@ -144,7 +145,7 @@ def test_debug_sql_output_with_fields_multiple( # Assert the SQL query only selects the 'name' and 'age' fields assert ( - 'Executing SQL: SELECT "name", "age" FROM "complex_model"' + 'Executing SQL: SELECT "name", "age", "pk" FROM "complex_model"' in caplog.text ) @@ -159,7 +160,7 @@ def test_debug_sql_output_with_fields_and_filter( # Assert the SQL query selects 'name' and 'score' and applies the filter assert ( - 'Executing SQL: SELECT "name", "score" FROM "complex_model" ' + 'Executing SQL: SELECT "name", "score", "pk" FROM "complex_model" ' "WHERE score > 85" in caplog.text ) @@ -198,7 +199,7 @@ def test_manual_logger_respects_debug_flag(self, caplog) -> None: # Assert that log output was captured with the manually passed logger assert ( - 'Executing SQL: SELECT "id", "name", "age", "is_active", "score", ' + 'Executing SQL: SELECT "pk", "name", "age", "is_active", "score", ' in caplog.text ) @@ -227,7 +228,7 @@ def test_debug_sql_output_no_matching_records( # Assert that the SQL query was logged despite no matching records assert ( - 'Executing SQL: SELECT "id", "name", "age", "is_active", "score", ' + 'Executing SQL: SELECT "pk", "name", "age", "is_active", "score", ' '"nullable_field" FROM "complex_model" WHERE age = 100' in caplog.text ) @@ -241,7 +242,7 @@ def test_debug_sql_output_empty_query( # Assert that the SQL query was logged for a full table scan assert ( - 'Executing SQL: SELECT "id", "name", "age", "is_active", "score", ' + 'Executing SQL: SELECT "pk", "name", "age", "is_active", "score", ' '"nullable_field" FROM "complex_model"' in caplog.text ) diff --git a/tests/test_execeptions.py b/tests/test_execeptions.py index cfd4eb5..69faf8c 100644 --- a/tests/test_execeptions.py +++ b/tests/test_execeptions.py @@ -55,6 +55,7 @@ def test_database_connection_error(self, mocker) -> None: exc_info.value ) + @pytest.mark.skip(reason="This is no longer a valid test case.") def test_insert_duplicate_primary_key(self, db_mock) -> None: """Test that exception raised when inserting duplicate primary key.""" # Create a model instance with a unique primary key @@ -98,7 +99,9 @@ def test_update_not_found_error(self, db_mock) -> None: db_mock.update(example_model) # Verify that the exception message contains the table name - assert "Failed to find a record for key 'test'" in str(exc_info.value) + assert "Failed to find that record in the table (key 'None')" in str( + exc_info.value + ) def test_update_exception_error(self, db_mock, mocker) -> None: """Test an exception is raised when updating a record with an error.""" diff --git a/tests/test_optional_fields_complex_model.py b/tests/test_optional_fields_complex_model.py index 3349390..260c0c7 100644 --- a/tests/test_optional_fields_complex_model.py +++ b/tests/test_optional_fields_complex_model.py @@ -8,11 +8,11 @@ @pytest.fixture def db_mock_complex(db_mock: SqliterDB) -> SqliterDB: - """Ficture for a mock database with a complex model.""" + """Fixture for a mock database with a complex model.""" db_mock.create_table(ComplexModel) db_mock.insert( ComplexModel( - id=1, + pk=1, name="Alice", age=30.5, is_active=True, @@ -22,7 +22,7 @@ def db_mock_complex(db_mock: SqliterDB) -> SqliterDB: ) db_mock.insert( ComplexModel( - id=2, + pk=2, name="Bob", age=25.0, is_active=False, @@ -41,7 +41,7 @@ def test_select_all_fields(self, db_mock_complex: SqliterDB) -> None: results = db_mock_complex.select(ComplexModel).fetch_all() assert len(results) == 2 for result in results: - assert isinstance(result.id, int) + assert isinstance(result.pk, int) assert isinstance(result.name, str) assert isinstance(result.age, float) assert isinstance(result.is_active, bool) @@ -53,13 +53,13 @@ def test_select_all_fields(self, db_mock_complex: SqliterDB) -> None: def test_select_subset_of_fields(self, db_mock_complex: SqliterDB) -> None: """Select a subset of fields and ensure their types are correct.""" - fields = ["id", "name", "age", "is_active", "score"] + fields = ["pk", "name", "age", "is_active", "score"] results = db_mock_complex.select( ComplexModel, fields=fields ).fetch_all() assert len(results) == 2 for result in results: - assert isinstance(result.id, int) + assert isinstance(result.pk, int) assert isinstance(result.name, str) assert isinstance(result.age, float) assert isinstance(result.is_active, bool) @@ -71,13 +71,13 @@ def test_select_with_type_conversion( self, db_mock_complex: SqliterDB ) -> None: """Select a subset of fields and ensure their types are correct.""" - fields = ["id", "age", "is_active", "score"] + fields = ["pk", "age", "is_active", "score"] results = db_mock_complex.select( ComplexModel, fields=fields ).fetch_all() assert len(results) == 2 for result in results: - assert isinstance(result.id, int) + assert isinstance(result.pk, int) assert isinstance(result.age, float) assert isinstance(result.is_active, bool) assert isinstance(result.score, (int, float)) @@ -107,7 +107,7 @@ def test_select_with_union_field(self, db_mock_complex: SqliterDB) -> None: def test_select_with_filtering(self, db_mock_complex: SqliterDB) -> None: """Select fields with a filter.""" - fields = ["id", "name", "age"] + fields = ["pk", "name", "age"] results = ( db_mock_complex.select(ComplexModel, fields=fields) .filter(age__gt=28) @@ -119,7 +119,7 @@ def test_select_with_filtering(self, db_mock_complex: SqliterDB) -> None: def test_select_with_ordering(self, db_mock_complex: SqliterDB) -> None: """Select fields with ordering.""" - fields = ["id", "name", "age"] + fields = ["pk", "name", "age"] results = ( db_mock_complex.select(ComplexModel, fields=fields) .order("age", direction="DESC") diff --git a/tests/test_query.py b/tests/test_query.py index 756c993..53a721a 100644 --- a/tests/test_query.py +++ b/tests/test_query.py @@ -565,8 +565,8 @@ def test_fetch_result_with_list_of_tuples(self, mocker) -> None: # Create some mock tuples (mimicking database rows) mock_result = [ - ("john", "John", "content"), - ("jane", "Jane", "content"), + ("1", "john", "John", "content"), + ("2", "jane", "Jane", "content"), ] # Mock the _execute_query method on the QueryBuilder instance @@ -581,5 +581,5 @@ def test_fetch_result_with_list_of_tuples(self, mocker) -> None: assert not isinstance(result, list) assert isinstance(result, ExampleModel) assert result == ExampleModel( - slug="john", name="John", content="content" + pk=1, slug="john", name="John", content="content" )