Skip to content

Commit

Permalink
feat(adapters): support to __conform__() method
Browse files Browse the repository at this point in the history
  • Loading branch information
Daniele Briggi committed Aug 14, 2024
1 parent 6fae45b commit f872db6
Show file tree
Hide file tree
Showing 2 changed files with 71 additions and 2 deletions.
9 changes: 7 additions & 2 deletions src/sqlitecloud/dbapi2.py
Original file line number Diff line number Diff line change
Expand Up @@ -275,17 +275,22 @@ def cursor(self):

def _apply_adapter(self, value: object) -> SQLiteTypes:
"""
Applies the adapter to convert the Python type into a SQLite supported type.
Applies the registered adapter to convert the Python type into a SQLite supported type.
In the case there is no registered adapter, it calls the __conform__() method when the value object implements it.
Args:
value (object): The Python type to convert.
Returns:
SQLiteTypes: The SQLite supported type.
SQLiteTypes: The SQLite supported type or the given value when no adapter is found.
"""
if type(value) in adapters:
return adapters[type(value)](value)

if hasattr(value, "__conform__"):
# we don't support sqlite3.PrepareProtocol
return value.__conform__(None)

return value

def __del__(self) -> None:
Expand Down
64 changes: 64 additions & 0 deletions src/tests/integration/test_sqlite3_parity.py
Original file line number Diff line number Diff line change
Expand Up @@ -477,6 +477,70 @@ def adapt_datetime(ts):

assert result[0] == adapt_datetime(now)

@pytest.mark.parametrize(
"connection",
[
"sqlitecloud_dbapi2_connection",
"sqlite3_connection",
],
)
def test_conform_object(self, connection, request):
connection = request.getfixturevalue(connection)

class Point:
def __init__(self, x, y):
self.x, self.y = x, y

def __conform__(self, protocol):
if isinstance(connection, sqlitecloud.Connection):
assert protocol is None
elif isinstance(connection, sqlite3.Connection):
assert protocol is sqlite3.PrepareProtocol
else:
pytest.fail("Unknown connection type")

return f"{self.x};{self.y}"

p = Point(4.0, -3.2)
cursor = connection.execute("SELECT ?", (p,))

result = cursor.fetchone()

assert result[0] == "4.0;-3.2"

@pytest.mark.parametrize(
"connection, module",
[
("sqlitecloud_dbapi2_connection", sqlitecloud),
("sqlite3_connection", sqlite3),
],
)
def test_adapters_to_have_precedence_over_conform_object(
self, connection, module, request
):
connection = request.getfixturevalue(connection)

class Point:
def __init__(self, x, y):
self.x, self.y = x, y

def __conform__(self, protocol):
# 4.0;1.1
return f"{self.x};{self.y}"

def adapt_point(point):
# 4.0, 1.1
return f"{point.x}, {point.y}"

module.register_adapter(Point, adapt_point)

p = Point(4.0, -3.2)
cursor = connection.execute("SELECT ?", (p,))

result = cursor.fetchone()

assert result[0] == "4.0, -3.2"

# def test_datatypes(self, sqlite3_connection):
# class Point:
# def __init__(self, x, y):
Expand Down

0 comments on commit f872db6

Please sign in to comment.