Skip to content

Commit 03a31b9

Browse files
authored
FEAT: Using Row Objects in MacOS Cursor (#81)
### Summary This pull request refactors the `Cursor` class in `mssql_python/cursor_mac.py` to improve data handling by introducing a `Row` object for query results. The changes enhance type safety and make the interface more consistent by replacing raw sequences (e.g., tuples) with `Row` objects. Additionally, the implementation of `fetchone`, `fetchmany`, and `fetchall` methods has been updated to reflect this new design. ### Refactoring for Improved Data Handling: * **Introduction of `Row` Object**: Added an import for the `Row` class and updated the `fetchone`, `fetchmany`, and `fetchall` methods to return `Row` objects instead of raw sequences like tuples. This change improves type safety and encapsulates row data with metadata (`mssql_python/cursor_mac.py`, [[1]](diffhunk://#diff-4b626c1fe80240df798a2254710c9d104782e717f6c23e1268fc369906bf8c46R15) [[2]](diffhunk://#diff-4b626c1fe80240df798a2254710c9d104782e717f6c23e1268fc369906bf8c46L36-R39) [[3]](diffhunk://#diff-4b626c1fe80240df798a2254710c9d104782e717f6c23e1268fc369906bf8c46L654-R722). ### Method Updates: * **`fetchone` Method**: Refactored to fetch raw data, check for no data, and return a `Row` object constructed with the row data and description. * **`fetchmany` Method**: Updated to fetch a specified number of rows, validate input size, and return a list of `Row` objects. * **`fetchall` Method**: Modified to fetch all remaining rows and return them as a list of `Row` objects. ### Issue Reference Fixes [AB#37748](https://sqlclientdrivers.visualstudio.com/c6d89619-62de-46a0-8b46-70b92a84d85e/_workitems/edit/37748) ### Checklist - [x] **Tests Passed** (if applicable) - [x] **Code is formatted** - [x] **Docs Updated** (if necessary) ### Testing Performed <!-- How was this fix tested? --> - [x] Unit Tests
1 parent 1d5f970 commit 03a31b9

File tree

1 file changed

+40
-33
lines changed

1 file changed

+40
-33
lines changed

mssql_python/cursor_mac.py

Lines changed: 40 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
from mssql_python.helpers import check_error
1313
from mssql_python.logging_config import get_logger, ENABLE_LOGGING
1414
from mssql_python import ddbc_bindings
15+
from .row import Row
1516

1617
logger = get_logger()
1718

@@ -33,9 +34,9 @@ class Cursor:
3334
close() -> None.
3435
execute(operation, parameters=None) -> None.
3536
executemany(operation, seq_of_parameters) -> None.
36-
fetchone() -> Single sequence or None if no more data is available.
37-
fetchmany(size=None) -> Sequence of sequences (e.g. list of tuples).
38-
fetchall() -> Sequence of sequences (e.g. list of tuples).
37+
fetchone() -> Single Row object or None if no more data is available.
38+
fetchmany(size=None) -> List of Row objects.
39+
fetchall() -> List of Row objects.
3940
nextset() -> True if there is another result set, None otherwise.
4041
setinputsizes(sizes) -> None.
4142
setoutputsize(size, column=None) -> None.
@@ -651,68 +652,74 @@ def executemany(self, operation: str, seq_of_parameters: list) -> None:
651652
total_rowcount = -1
652653
self.rowcount = total_rowcount
653654

654-
def fetchone(self) -> Union[None, tuple]:
655+
def fetchone(self) -> Union[None, Row]:
655656
"""
656657
Fetch the next row of a query result set.
657-
658+
658659
Returns:
659-
Single sequence or None if no more data is available.
660-
661-
Raises:
662-
Error: If the previous call to execute did not produce any result set.
660+
Single Row object or None if no more data is available.
663661
"""
664662
self._check_closed() # Check if the cursor is closed
665663

666-
row = []
667-
ret = ddbc_bindings.DDBCSQLFetchOne(self.hstmt.value, row)
664+
# Fetch raw data
665+
row_data = []
666+
ret = ddbc_bindings.DDBCSQLFetchOne(self.hstmt.value, row_data)
668667
check_error(ddbc_sql_const.SQL_HANDLE_STMT.value, self.hstmt.value, ret)
669-
return list(row)
668+
669+
if ret == ddbc_sql_const.SQL_NO_DATA.value:
670+
return None
671+
672+
# Create and return a Row object
673+
return Row(row_data, self.description)
670674

671-
def fetchmany(self, size: int = None) -> List[tuple]:
675+
def fetchmany(self, size: int = None) -> List[Row]:
672676
"""
673677
Fetch the next set of rows of a query result.
674-
678+
675679
Args:
676680
size: Number of rows to fetch at a time.
677-
681+
678682
Returns:
679-
Sequence of sequences (e.g. list of tuples).
680-
681-
Raises:
682-
Error: If the previous call to execute did not produce any result set.
683+
List of Row objects.
683684
"""
684685
self._check_closed() # Check if the cursor is closed
685686

686687
if size is None:
687688
size = self.arraysize
688689

689-
# Fetch the next set of rows
690-
rows = []
691-
ret = ddbc_bindings.DDBCSQLFetchMany(self.hstmt.value, rows, size)
690+
if size <= 0:
691+
return []
692+
693+
# Fetch raw data
694+
rows_data = []
695+
ret = ddbc_bindings.DDBCSQLFetchMany(self.hstmt.value, rows_data, size)
692696
check_error(ddbc_sql_const.SQL_HANDLE_STMT.value, self.hstmt.value, ret)
697+
693698
if ret == ddbc_sql_const.SQL_NO_DATA.value:
694699
return []
695-
return rows
700+
701+
# Convert raw data to Row objects
702+
return [Row(row_data, self.description) for row_data in rows_data]
696703

697-
def fetchall(self) -> List[tuple]:
704+
def fetchall(self) -> List[Row]:
698705
"""
699706
Fetch all (remaining) rows of a query result.
700-
707+
701708
Returns:
702-
Sequence of sequences (e.g. list of tuples).
703-
704-
Raises:
705-
Error: If the previous call to execute did not produce any result set.
709+
List of Row objects.
706710
"""
707711
self._check_closed() # Check if the cursor is closed
708712

709-
# Fetch all remaining rows
710-
rows = []
711-
ret = ddbc_bindings.DDBCSQLFetchAll(self.hstmt.value, rows)
713+
# Fetch raw data
714+
rows_data = []
715+
ret = ddbc_bindings.DDBCSQLFetchAll(self.hstmt.value, rows_data)
712716
check_error(ddbc_sql_const.SQL_HANDLE_STMT.value, self.hstmt.value, ret)
717+
713718
if ret != ddbc_sql_const.SQL_NO_DATA.value:
714719
return []
715-
return list(rows)
720+
721+
# Convert raw data to Row objects
722+
return [Row(row_data, self.description) for row_data in rows_data]
716723

717724
def nextset(self) -> Union[bool, None]:
718725
"""

0 commit comments

Comments
 (0)