Test Update Operations

Setup

from fastlite import *
from dataclasses import is_dataclass

Note: Make sure to use fastlite’s database() here

db = database(':memory:')
class People: id: int; name: str
people = db.create(People, pk='id')

Test Single Updates

Here we test update()

Test Cases for update() Where Nothing Is Updated

Test that calling insert() without any parameters doesn’t change anything, and returns nothing

people.update()
{}

Test None doesn’t change anything.

count = people.count
assert people.update(None) == {}
assert people.count == count

Test empty dict doesn’t change anything

count = people.count
assert people.update({}) == {}
assert people.count == count
# Test empty dataclass doesn't change anything
PersonDC = people.dataclass()
count = people.count
assert people.update(PersonDC()) == {}
assert people.count == count
# Test empty class instance doesn't change anything
class EmptyPerson: pass
count = people.count
assert people.update(EmptyPerson()) == {}
assert people.count == count

Single Update Types

Test update with dict. Result should include the Updated value

person = people.insert(name='Alice')
adict = dict(id=person.id, name='Bob')
assert people.update(adict).name == 'Bob'
assert people[person.id].name == 'Bob'

Fetch record from database to confirm it has changed

assert people[person.id].name == 'Bob'

Test update with dataclass

dc = People(id=person.id, name='Bobby')
assert is_dataclass(dc) is True
assert people.update(dc).name == 'Bobby'
assert people[person.id].name == 'Bobby'

Test with regular class

class Student: pass
student = Student()
student.name = 'Charlo'
student.id = person.id

assert people.update(student).name == 'Charlo'
assert people[student.id].name == 'Charlo'

None and Empty String Handling

SQLite makes a clear distinction between NULL (represented as None in Python) and an empty string (’’). Unlike some popular Python ORMs, fastlite preserves this distinction because:

  1. NULL represents “unknown” or “missing” data
  2. Empty string represents “known to be empty”

These are semantically different concepts, and maintaining this distinction allows users to make appropriate queries (e.g. WHERE name IS NULL vs WHERE name = ''). The fact that fastlite preserves this distinction in both directions (Python->SQLite and SQLite->Python) is good database design.

Test updating a record with name set to None

result = people.update(dict(id=person.id, name=None))
assert result.name is None
assert people[person.id].name == None

Test with empty string

result = people.update(dict(id=person.id, name=''))
assert result.name == ''
assert people[person.id].name == ''

Other Cases

Test with special characters

assert people.update(dict(id=person.id, name='O\'Connor')).name == "O'Connor"
assert people[person.id].name == "O'Connor"
assert people.update(dict(id=person.id, name='José')).name == "José"
assert people[person.id].name == "José"

Test that extra fields raise sqlite3.OperationalError

from sqlite3 import OperationalError
try:
    p = people.update(dict(id=person.id, name='Extra', age=25, title='Dr'))
except OperationalError as e:
    assert e.args[0] == 'no such column: age'