Skip to content

Commit 206fbc2

Browse files
asg017claude
andcommitted
Add Python regression tests for existing insert/delete paths
Baseline tests protecting non-DiskANN chunk-based insert and delete behavior: vector round-trips, auto rowids, text primary keys, delete validity, reinsert after delete, dimension/type validation, and v_info snapshot. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 0bca960 commit 206fbc2

2 files changed

Lines changed: 236 additions & 0 deletions

File tree

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
# serializer version: 1
2+
# name: test_info_table_contents
3+
OrderedDict({
4+
'sql': 'select key, value from v_info order by key',
5+
'rows': list([
6+
OrderedDict({
7+
'key': 'CREATE_VERSION',
8+
'value': 'v0.1.7-alpha.10',
9+
}),
10+
OrderedDict({
11+
'key': 'CREATE_VERSION_MAJOR',
12+
'value': 0,
13+
}),
14+
OrderedDict({
15+
'key': 'CREATE_VERSION_MINOR',
16+
'value': 1,
17+
}),
18+
OrderedDict({
19+
'key': 'CREATE_VERSION_PATCH',
20+
'value': 7,
21+
}),
22+
]),
23+
})
24+
# ---
25+
# name: test_insert_creates_chunks_and_vectors[rowids_count]
26+
OrderedDict({
27+
'sql': 'select count(*) as cnt from v_rowids',
28+
'rows': list([
29+
OrderedDict({
30+
'cnt': 5,
31+
}),
32+
]),
33+
})
34+
# ---
35+
# name: test_insert_creates_chunks_and_vectors[vector_chunks_count]
36+
OrderedDict({
37+
'sql': 'select count(*) as cnt from v_vector_chunks00',
38+
'rows': list([
39+
OrderedDict({
40+
'cnt': 1,
41+
}),
42+
]),
43+
})
44+
# ---
45+
# name: test_insert_text_primary_key[rowids]
46+
OrderedDict({
47+
'sql': 'select rowid, id, chunk_id, chunk_offset from v_rowids order by rowid',
48+
'rows': list([
49+
OrderedDict({
50+
'rowid': 1,
51+
'id': 'doc_a',
52+
'chunk_id': 1,
53+
'chunk_offset': 0,
54+
}),
55+
OrderedDict({
56+
'rowid': 2,
57+
'id': 'doc_b',
58+
'chunk_id': 1,
59+
'chunk_offset': 1,
60+
}),
61+
]),
62+
})
63+
# ---

tests/test-insert-delete.py

Lines changed: 173 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,173 @@
1+
import sqlite3
2+
import struct
3+
from collections import OrderedDict
4+
import pytest
5+
6+
7+
def _f32(list):
8+
return struct.pack("%sf" % len(list), *list)
9+
10+
11+
def exec(db, sql, parameters=[]):
12+
try:
13+
rows = db.execute(sql, parameters).fetchall()
14+
except (sqlite3.OperationalError, sqlite3.DatabaseError) as e:
15+
return {
16+
"error": e.__class__.__name__,
17+
"message": str(e),
18+
}
19+
a = []
20+
for row in rows:
21+
o = OrderedDict()
22+
for k in row.keys():
23+
o[k] = row[k]
24+
a.append(o)
25+
result = OrderedDict()
26+
result["sql"] = sql
27+
result["rows"] = a
28+
return result
29+
30+
31+
def test_insert_creates_chunks_and_vectors(db, snapshot):
32+
db.execute("create virtual table v using vec0(emb float[4], chunk_size=8)")
33+
34+
vecs = [
35+
[1.0, 2.0, 3.0, 4.0],
36+
[5.0, 6.0, 7.0, 8.0],
37+
[0.1, 0.2, 0.3, 0.4],
38+
[10.0, 20.0, 30.0, 40.0],
39+
[0.5, 0.5, 0.5, 0.5],
40+
]
41+
for i, v in enumerate(vecs, start=1):
42+
db.execute("insert into v(rowid, emb) values (?, ?)", [i, _f32(v)])
43+
44+
assert exec(db, "select count(*) as cnt from v_rowids") == snapshot(
45+
name="rowids_count"
46+
)
47+
assert exec(db, "select count(*) as cnt from v_vector_chunks00") == snapshot(
48+
name="vector_chunks_count"
49+
)
50+
51+
# Verify round-trip: each inserted vector comes back identical
52+
for i, v in enumerate(vecs, start=1):
53+
rows = db.execute("select emb from v where rowid = ?", [i]).fetchall()
54+
assert len(rows) == 1
55+
assert rows[0][0] == _f32(v)
56+
57+
58+
def test_insert_auto_rowid(db):
59+
db.execute("create virtual table v using vec0(emb float[4], chunk_size=8)")
60+
61+
vecs = [[1.0, 0.0, 0.0, 0.0], [0.0, 1.0, 0.0, 0.0], [0.0, 0.0, 1.0, 0.0]]
62+
for v in vecs:
63+
db.execute("insert into v(emb) values (?)", [_f32(v)])
64+
65+
rows = db.execute("select rowid from v order by rowid").fetchall()
66+
rowids = [r[0] for r in rows]
67+
assert rowids == [1, 2, 3]
68+
69+
for i, v in enumerate(vecs, start=1):
70+
row = db.execute("select emb from v where rowid = ?", [i]).fetchone()
71+
assert row[0] == _f32(v)
72+
73+
74+
def test_insert_text_primary_key(db, snapshot):
75+
db.execute(
76+
"create virtual table v using vec0(id text primary key, emb float[4], chunk_size=8)"
77+
)
78+
79+
db.execute(
80+
"insert into v(id, emb) values ('doc_a', ?)", [_f32([1.0, 2.0, 3.0, 4.0])]
81+
)
82+
db.execute(
83+
"insert into v(id, emb) values ('doc_b', ?)", [_f32([5.0, 6.0, 7.0, 8.0])]
84+
)
85+
86+
assert exec(db, "select rowid, id, chunk_id, chunk_offset from v_rowids order by rowid") == snapshot(
87+
name="rowids"
88+
)
89+
90+
row = db.execute("select emb from v where id = 'doc_a'").fetchone()
91+
assert row[0] == _f32([1.0, 2.0, 3.0, 4.0])
92+
93+
row = db.execute("select emb from v where id = 'doc_b'").fetchone()
94+
assert row[0] == _f32([5.0, 6.0, 7.0, 8.0])
95+
96+
97+
def test_delete_clears_validity(db):
98+
db.execute("create virtual table v using vec0(emb float[4], chunk_size=8)")
99+
100+
for i, v in enumerate(
101+
[[1.0, 0.0, 0.0, 0.0], [0.0, 1.0, 0.0, 0.0], [0.0, 0.0, 1.0, 0.0]],
102+
start=1,
103+
):
104+
db.execute("insert into v(rowid, emb) values (?, ?)", [i, _f32(v)])
105+
106+
db.execute("delete from v where rowid = 2")
107+
108+
rows = db.execute("select rowid from v order by rowid").fetchall()
109+
assert [r[0] for r in rows] == [1, 3]
110+
111+
rowid_rows = db.execute("select rowid from v_rowids order by rowid").fetchall()
112+
assert 2 not in [r[0] for r in rowid_rows]
113+
114+
# Inserting a new vector after deletion still works
115+
db.execute("insert into v(rowid, emb) values (4, ?)", [_f32([0.0, 0.0, 0.0, 1.0])])
116+
row = db.execute("select emb from v where rowid = 4").fetchone()
117+
assert row[0] == _f32([0.0, 0.0, 0.0, 1.0])
118+
119+
120+
def test_insert_delete_reinsert(db):
121+
db.execute("create virtual table v using vec0(emb float[4], chunk_size=8)")
122+
123+
db.execute("insert into v(rowid, emb) values (1, ?)", [_f32([1.0, 1.0, 1.0, 1.0])])
124+
db.execute("delete from v where rowid = 1")
125+
db.execute("insert into v(rowid, emb) values (2, ?)", [_f32([2.0, 2.0, 2.0, 2.0])])
126+
127+
rows = db.execute("select rowid from v order by rowid").fetchall()
128+
assert [r[0] for r in rows] == [2]
129+
130+
# KNN query works and returns rowid 2
131+
knn = db.execute(
132+
"select rowid, distance from v where emb match ? and k = 1",
133+
[_f32([2.0, 2.0, 2.0, 2.0])],
134+
).fetchall()
135+
assert len(knn) == 1
136+
assert knn[0][0] == 2
137+
138+
139+
def test_insert_validates_dimensions(db):
140+
db.execute("create virtual table v using vec0(emb float[4], chunk_size=8)")
141+
142+
result = exec(db, "insert into v(rowid, emb) values (1, ?)", [_f32([1.0, 2.0, 3.0])])
143+
assert result["error"] == "OperationalError"
144+
assert "Dimension mismatch" in result["message"]
145+
assert "Expected 4" in result["message"]
146+
assert "3" in result["message"]
147+
148+
result = exec(
149+
db, "insert into v(rowid, emb) values (1, ?)", [_f32([1.0, 2.0, 3.0, 4.0, 5.0])]
150+
)
151+
assert result["error"] == "OperationalError"
152+
assert "Dimension mismatch" in result["message"]
153+
assert "Expected 4" in result["message"]
154+
assert "5" in result["message"]
155+
156+
157+
def test_insert_validates_type(db):
158+
db.execute("create virtual table v using vec0(emb float[4], chunk_size=8)")
159+
160+
int8_vec = struct.pack("4b", 1, 2, 3, 4)
161+
result = exec(
162+
db,
163+
"insert into v(rowid, emb) values (1, vec_int8(?))",
164+
[int8_vec],
165+
)
166+
assert "error" in result
167+
assert "float32" in result["message"]
168+
assert "int8" in result["message"]
169+
170+
171+
def test_info_table_contents(db, snapshot):
172+
db.execute("create virtual table v using vec0(emb float[4], chunk_size=8)")
173+
assert exec(db, "select key, value from v_info order by key") == snapshot()

0 commit comments

Comments
 (0)