amaslyaev / noorm

NoORM (Not only ORM) - Python library that makes your database operations convenient and natural
MIT License
16 stars 0 forks source link

Conflict with SQLite PARSE_DECLTYPES #7

Closed LecronRu closed 1 month ago

LecronRu commented 1 month ago

В существующем проекте сохраняется пользовательский класс в колонку таблицы (как скаляр), используя встроенные механизмы sqlite3. Таким же образом сохраняется дата. Пример на базе документации sqlite3

import sqlite3
from datetime import date
import noorm.sqlite3 as nm

class Point:
    def __init__(self, x, y):
        self.x, self.y = x, y
    def __repr__(self):
        return f"Point({self.x},{self.y})"
    def __conform__(self, protocol):
        if protocol is sqlite3.PrepareProtocol:
            return f"{self.x};{self.y}"

def convert_point(s):
    coord = map(float, s.split(b";"))
    return Point(*coord)
sqlite3.register_converter("point", convert_point)

con = sqlite3.connect(":memory:", detect_types=sqlite3.PARSE_DECLTYPES)
cur = con.execute("CREATE TABLE test(p point, p_date date)")

p = Point(4.0, -3.2)
p_date = date.today()
cur.execute("INSERT INTO test(p, p_date) VALUES(?, ?)", (p, p_date))
cur.execute("SELECT p, p_date FROM test")
print("with declared types:", cur.fetchone())

#>> with declared types: (Point(4.0,-3.2), datetime.date(2024, 8, 4))

Решив использовать noorm, при вызове

@nm.sql_fetch_scalars(date, "SELECT p_date FROM test")
def all_date():
    ...

print(all_date(con))

получу ошибку TypeError: fromisoformat: argument must be str из-за дополнительного преобразования уже преобразованной драйвером в дату строки. Если выключить конвертацию драйвером, даты будут преобразованы библиотекой, но она ничего не знает про восстановление пользовательского объекта — вернёт строку '4.0;-3.2'

Можно использовать PARSE_COLNAMES, но а) запрос выглядит некрасиво p AS "p [point]" и б) это надо не забывать дублировать в каждом запросе, где участвует поле point.

P.S. Хороший аргумент для issue #6 Discussion of using type hints for return data. Возможность задать параметр `scalar=True' действительно нужна, для перекрытия автоматики.

amaslyaev commented 1 month ago

Fixed in version 0.1.5