zova 0.17.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- zova-0.17.0/Cargo.lock +148 -0
- zova-0.17.0/Cargo.toml +17 -0
- zova-0.17.0/LICENSE +21 -0
- zova-0.17.0/PKG-INFO +319 -0
- zova-0.17.0/README.md +292 -0
- zova-0.17.0/examples/basic.py +13 -0
- zova-0.17.0/examples/objects.py +42 -0
- zova-0.17.0/examples/vectors.py +78 -0
- zova-0.17.0/pyproject.toml +39 -0
- zova-0.17.0/python/zova/__init__.py +71 -0
- zova-0.17.0/python/zova/py.typed +1 -0
- zova-0.17.0/src/database.rs +525 -0
- zova-0.17.0/src/error.rs +33 -0
- zova-0.17.0/src/lib.rs +43 -0
- zova-0.17.0/src/object.rs +378 -0
- zova-0.17.0/src/statement.rs +141 -0
- zova-0.17.0/src/vector.rs +256 -0
- zova-0.17.0/tests/test_lifecycle.py +301 -0
- zova-0.17.0/tests/test_objects.py +199 -0
- zova-0.17.0/tests/test_vectors.py +245 -0
zova-0.17.0/Cargo.lock
ADDED
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
# This file is automatically @generated by Cargo.
|
|
2
|
+
# It is not intended for manual editing.
|
|
3
|
+
version = 4
|
|
4
|
+
|
|
5
|
+
[[package]]
|
|
6
|
+
name = "heck"
|
|
7
|
+
version = "0.5.0"
|
|
8
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
9
|
+
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
|
|
10
|
+
|
|
11
|
+
[[package]]
|
|
12
|
+
name = "libc"
|
|
13
|
+
version = "0.2.186"
|
|
14
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
15
|
+
checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66"
|
|
16
|
+
|
|
17
|
+
[[package]]
|
|
18
|
+
name = "once_cell"
|
|
19
|
+
version = "1.21.4"
|
|
20
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
21
|
+
checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50"
|
|
22
|
+
|
|
23
|
+
[[package]]
|
|
24
|
+
name = "portable-atomic"
|
|
25
|
+
version = "1.13.1"
|
|
26
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
27
|
+
checksum = "c33a9471896f1c69cecef8d20cbe2f7accd12527ce60845ff44c153bb2a21b49"
|
|
28
|
+
|
|
29
|
+
[[package]]
|
|
30
|
+
name = "proc-macro2"
|
|
31
|
+
version = "1.0.106"
|
|
32
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
33
|
+
checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934"
|
|
34
|
+
dependencies = [
|
|
35
|
+
"unicode-ident",
|
|
36
|
+
]
|
|
37
|
+
|
|
38
|
+
[[package]]
|
|
39
|
+
name = "pyo3"
|
|
40
|
+
version = "0.29.0"
|
|
41
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
42
|
+
checksum = "cd274650b21d4bfc26a0a47587962c1edb425f69287324355cd040c3ea66071c"
|
|
43
|
+
dependencies = [
|
|
44
|
+
"libc",
|
|
45
|
+
"once_cell",
|
|
46
|
+
"portable-atomic",
|
|
47
|
+
"pyo3-build-config",
|
|
48
|
+
"pyo3-ffi",
|
|
49
|
+
"pyo3-macros",
|
|
50
|
+
]
|
|
51
|
+
|
|
52
|
+
[[package]]
|
|
53
|
+
name = "pyo3-build-config"
|
|
54
|
+
version = "0.29.0"
|
|
55
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
56
|
+
checksum = "c5e2a7d2f0d013342f295c048ad19237add5154a55b1c5a254c0ec93d4109078"
|
|
57
|
+
dependencies = [
|
|
58
|
+
"target-lexicon",
|
|
59
|
+
]
|
|
60
|
+
|
|
61
|
+
[[package]]
|
|
62
|
+
name = "pyo3-ffi"
|
|
63
|
+
version = "0.29.0"
|
|
64
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
65
|
+
checksum = "ca85c467da1bbc8d866eea5deff9cf29ea5f7785054a17da36e65bda9c05845b"
|
|
66
|
+
dependencies = [
|
|
67
|
+
"libc",
|
|
68
|
+
"pyo3-build-config",
|
|
69
|
+
]
|
|
70
|
+
|
|
71
|
+
[[package]]
|
|
72
|
+
name = "pyo3-macros"
|
|
73
|
+
version = "0.29.0"
|
|
74
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
75
|
+
checksum = "9ac53762fd065daa3194dd09337a38bd793a188100fd1a9304c4ab312d901771"
|
|
76
|
+
dependencies = [
|
|
77
|
+
"proc-macro2",
|
|
78
|
+
"pyo3-macros-backend",
|
|
79
|
+
"quote",
|
|
80
|
+
"syn",
|
|
81
|
+
]
|
|
82
|
+
|
|
83
|
+
[[package]]
|
|
84
|
+
name = "pyo3-macros-backend"
|
|
85
|
+
version = "0.29.0"
|
|
86
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
87
|
+
checksum = "4ca3a1557399783172dc5bf39cfca835157732532cba56b71d2292161e53b362"
|
|
88
|
+
dependencies = [
|
|
89
|
+
"heck",
|
|
90
|
+
"proc-macro2",
|
|
91
|
+
"quote",
|
|
92
|
+
"syn",
|
|
93
|
+
]
|
|
94
|
+
|
|
95
|
+
[[package]]
|
|
96
|
+
name = "quote"
|
|
97
|
+
version = "1.0.46"
|
|
98
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
99
|
+
checksum = "dfbc457d0c7a0759a614551b11a6409e5951f6c7537be1f1b7682b9ae9230368"
|
|
100
|
+
dependencies = [
|
|
101
|
+
"proc-macro2",
|
|
102
|
+
]
|
|
103
|
+
|
|
104
|
+
[[package]]
|
|
105
|
+
name = "syn"
|
|
106
|
+
version = "2.0.118"
|
|
107
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
108
|
+
checksum = "1b9ae57f904213ebb649ce6895b8a66c66f0203b9319718f69a5612a065b1422"
|
|
109
|
+
dependencies = [
|
|
110
|
+
"proc-macro2",
|
|
111
|
+
"quote",
|
|
112
|
+
"unicode-ident",
|
|
113
|
+
]
|
|
114
|
+
|
|
115
|
+
[[package]]
|
|
116
|
+
name = "target-lexicon"
|
|
117
|
+
version = "0.13.5"
|
|
118
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
119
|
+
checksum = "adb6935a6f5c20170eeceb1a3835a49e12e19d792f6dd344ccc76a985ca5a6ca"
|
|
120
|
+
|
|
121
|
+
[[package]]
|
|
122
|
+
name = "unicode-ident"
|
|
123
|
+
version = "1.0.24"
|
|
124
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
125
|
+
checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75"
|
|
126
|
+
|
|
127
|
+
[[package]]
|
|
128
|
+
name = "zova"
|
|
129
|
+
version = "0.17.0"
|
|
130
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
131
|
+
checksum = "4a8fb0a3a7ca0fef420a4c4e1bd31bb519e7bc697553f541e249163cf866ef56"
|
|
132
|
+
dependencies = [
|
|
133
|
+
"zova-sys",
|
|
134
|
+
]
|
|
135
|
+
|
|
136
|
+
[[package]]
|
|
137
|
+
name = "zova-python"
|
|
138
|
+
version = "0.17.0"
|
|
139
|
+
dependencies = [
|
|
140
|
+
"pyo3",
|
|
141
|
+
"zova",
|
|
142
|
+
]
|
|
143
|
+
|
|
144
|
+
[[package]]
|
|
145
|
+
name = "zova-sys"
|
|
146
|
+
version = "0.17.0"
|
|
147
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
148
|
+
checksum = "4c11b4d0622a9a16ef3f75518face4a6425c70bd5c4e872612c8c231a0f915bf"
|
zova-0.17.0/Cargo.toml
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
[package]
|
|
2
|
+
name = "zova-python"
|
|
3
|
+
version = "0.17.0"
|
|
4
|
+
edition = "2021"
|
|
5
|
+
license = "MIT"
|
|
6
|
+
description = "PyO3 extension for the Zova Python package."
|
|
7
|
+
repository = "https://github.com/atasesli/zova"
|
|
8
|
+
homepage = "https://github.com/atasesli/zova"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
|
|
11
|
+
[lib]
|
|
12
|
+
name = "zova_python"
|
|
13
|
+
crate-type = ["cdylib"]
|
|
14
|
+
|
|
15
|
+
[dependencies]
|
|
16
|
+
pyo3 = { version = "0.29.0", features = ["extension-module"] }
|
|
17
|
+
zova_rust = { package = "zova", version = "0.17.0" }
|
zova-0.17.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Ata Sesli
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
zova-0.17.0/PKG-INFO
ADDED
|
@@ -0,0 +1,319 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: zova
|
|
3
|
+
Version: 0.17.0
|
|
4
|
+
Classifier: Development Status :: 3 - Alpha
|
|
5
|
+
Classifier: Intended Audience :: Developers
|
|
6
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
7
|
+
Classifier: Operating System :: OS Independent
|
|
8
|
+
Classifier: Programming Language :: Python :: 3
|
|
9
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
10
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
13
|
+
Classifier: Programming Language :: Rust
|
|
14
|
+
Classifier: Topic :: Database
|
|
15
|
+
License-File: LICENSE
|
|
16
|
+
Summary: SQLite-backed embedded database for records, objects, and vectors in one local file.
|
|
17
|
+
Keywords: zova,sqlite,database,objects,vectors
|
|
18
|
+
Home-Page: https://github.com/atasesli/zova
|
|
19
|
+
Author: Ata Sesli
|
|
20
|
+
License-Expression: MIT
|
|
21
|
+
Requires-Python: >=3.10
|
|
22
|
+
Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM
|
|
23
|
+
Project-URL: Homepage, https://github.com/atasesli/zova
|
|
24
|
+
Project-URL: Issues, https://github.com/atasesli/zova/issues
|
|
25
|
+
Project-URL: Repository, https://github.com/atasesli/zova
|
|
26
|
+
|
|
27
|
+
# Zova Python Bindings
|
|
28
|
+
|
|
29
|
+
This package contains the source-first Python bindings for Zova.
|
|
30
|
+
|
|
31
|
+
It is a PyO3/maturin extension backed by the safe Rust `zova` binding. It does
|
|
32
|
+
not wrap the C ABI directly with `ctypes` or cffi. The native build still uses
|
|
33
|
+
Zova's C ABI underneath through the Rust `zova-sys` crate, so Python gets the
|
|
34
|
+
same records/objects/vectors foundation without reimplementing the ABI ownership
|
|
35
|
+
rules.
|
|
36
|
+
|
|
37
|
+
## Contents
|
|
38
|
+
|
|
39
|
+
1. [How It Fits](#how-it-fits)
|
|
40
|
+
2. [Install](#install)
|
|
41
|
+
3. [Local Development](#local-development)
|
|
42
|
+
4. [What It Covers](#what-it-covers)
|
|
43
|
+
5. [Savepoints](#savepoints)
|
|
44
|
+
6. [Operational Safety](#operational-safety)
|
|
45
|
+
7. [Objects](#objects)
|
|
46
|
+
8. [Vectors](#vectors)
|
|
47
|
+
9. [SQL-Native Vector Search](#sql-native-vector-search)
|
|
48
|
+
|
|
49
|
+
## How It Fits
|
|
50
|
+
|
|
51
|
+
Python users import `zova`. The extension is built with PyO3 and reuses the
|
|
52
|
+
safe Rust binding, which in turn links Zova's C ABI.
|
|
53
|
+
|
|
54
|
+
```mermaid
|
|
55
|
+
flowchart LR
|
|
56
|
+
App["Python app"]
|
|
57
|
+
PyPkg["zova Python package"]
|
|
58
|
+
PyO3["PyO3 extension"]
|
|
59
|
+
Rust["Rust zova crate"]
|
|
60
|
+
CABI["libzova_c.a"]
|
|
61
|
+
File["local .zova file"]
|
|
62
|
+
|
|
63
|
+
App --> PyPkg
|
|
64
|
+
PyPkg --> PyO3
|
|
65
|
+
PyO3 --> Rust
|
|
66
|
+
Rust --> CABI
|
|
67
|
+
CABI --> File
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## Install
|
|
71
|
+
|
|
72
|
+
After the Python package is published to PyPI:
|
|
73
|
+
|
|
74
|
+
```sh
|
|
75
|
+
python -m pip install zova
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
The v0.17 Python package is source-first. It builds the PyO3 extension locally
|
|
79
|
+
through maturin and Cargo, and the Rust crates `zova` and `zova-sys` must be
|
|
80
|
+
available on crates.io first. Users need Python 3.10 or newer, Rust/Cargo, Zig
|
|
81
|
+
0.16.0 or newer, and a working C compiler/linker.
|
|
82
|
+
|
|
83
|
+
No official platform wheel matrix is promised in v0.17.
|
|
84
|
+
|
|
85
|
+
## Local Development
|
|
86
|
+
|
|
87
|
+
From `bindings/python`:
|
|
88
|
+
|
|
89
|
+
```sh
|
|
90
|
+
uv run --isolated --with maturin --with pytest maturin develop
|
|
91
|
+
uv run --isolated --with pytest python -m pytest
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
The native build uses maturin, Cargo, Zig, and the Rust `zova` crate. Users do
|
|
95
|
+
not need to locate a shared C library manually.
|
|
96
|
+
|
|
97
|
+
The Python API is pre-1.0 and may still change alongside the Rust binding.
|
|
98
|
+
|
|
99
|
+
## What It Covers
|
|
100
|
+
|
|
101
|
+
The Python package exposes database lifecycle, conversion, prepared SQL
|
|
102
|
+
statements, transactions, explicit vacuum, backup/compact/restore, objects,
|
|
103
|
+
streaming object writes, vectors, SQL-native vector search, context managers,
|
|
104
|
+
and Zova status exceptions.
|
|
105
|
+
|
|
106
|
+
One Python `Database` object owns one native handle. The native C ABI serializes
|
|
107
|
+
calls on that handle, so one handle is safe but not parallel. Open additional
|
|
108
|
+
database handles when an application needs independent concurrent connections;
|
|
109
|
+
SQLite locking rules still apply across handles. PyO3 classes remain unsendable
|
|
110
|
+
in this release even though the native C ABI serializes its own calls.
|
|
111
|
+
|
|
112
|
+
Use `Database.open(path, read_only=True)` for read-only handles, and
|
|
113
|
+
`Database.set_busy_timeout(milliseconds)` when an application wants SQLite to
|
|
114
|
+
wait briefly on cross-handle contention. No nonzero timeout is installed by
|
|
115
|
+
default.
|
|
116
|
+
|
|
117
|
+
Use `Database.last_insert_rowid()`, `Database.changes()`,
|
|
118
|
+
`Database.total_changes()`, and `Statement.column_name(index)` for normal
|
|
119
|
+
application SQL record helpers. They do not expose or stabilize Zova's private
|
|
120
|
+
`_zova_*` tables.
|
|
121
|
+
|
|
122
|
+
## Savepoints
|
|
123
|
+
|
|
124
|
+
Use explicit savepoints for partial rollback inside one database connection:
|
|
125
|
+
|
|
126
|
+
```python
|
|
127
|
+
with zova.Database.open("app.zova") as db:
|
|
128
|
+
db.begin_immediate()
|
|
129
|
+
db.savepoint("attach_file")
|
|
130
|
+
db.exec("insert into attachments(filename) values ('draft.txt')")
|
|
131
|
+
db.rollback_to_savepoint("attach_file")
|
|
132
|
+
db.release_savepoint("attach_file")
|
|
133
|
+
db.commit()
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
Savepoint names are strict ASCII identifiers: 1-64 bytes, first byte
|
|
137
|
+
`[A-Za-z_]`, remaining bytes `[A-Za-z0-9_]`, and no case-insensitive `_zova_`
|
|
138
|
+
prefix. `rollback_to_savepoint()` keeps the savepoint active;
|
|
139
|
+
`release_savepoint()` removes it.
|
|
140
|
+
An inner released savepoint can still be undone by rolling back an outer
|
|
141
|
+
transaction or savepoint.
|
|
142
|
+
|
|
143
|
+
Use `savepoint_context()` when you want rollback cleanup tied to a `with` block:
|
|
144
|
+
|
|
145
|
+
```python
|
|
146
|
+
with db.savepoint_context("attach_file") as scoped_db:
|
|
147
|
+
scoped_db.exec("insert into attachments(filename) values ('draft.txt')")
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
On normal exit the context releases the savepoint. On exception it rolls back,
|
|
151
|
+
releases, and then re-raises the original exception when cleanup succeeds.
|
|
152
|
+
|
|
153
|
+
## Operational Safety
|
|
154
|
+
|
|
155
|
+
Use `backup_to()` for a faithful snapshot, `compact_to()` for a
|
|
156
|
+
space-reclaiming copy, and `restore_backup()` to copy a backup into a new
|
|
157
|
+
destination file. Destinations must be `.zova` paths and are never overwritten.
|
|
158
|
+
|
|
159
|
+
```python
|
|
160
|
+
with zova.Database.open("app.zova") as db:
|
|
161
|
+
db.backup_to("app.backup.zova")
|
|
162
|
+
db.compact_to("app.compact.zova")
|
|
163
|
+
|
|
164
|
+
zova.restore_backup("app.backup.zova", "app.restored.zova")
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
By default, each operation verifies the destination after copying. Pass
|
|
168
|
+
`verify=False` only when you will verify separately, for example with
|
|
169
|
+
`zova check --deep`.
|
|
170
|
+
|
|
171
|
+
Diagnostic recovery commands such as `zova doctor`, `zova salvage --dry-run`,
|
|
172
|
+
and `zova salvage <source> <destination>` are CLI-first in the v0.16 line. The
|
|
173
|
+
Python package does not expose typed doctor/salvage report APIs yet, and library
|
|
174
|
+
code should not parse the human text output as a stable binding contract.
|
|
175
|
+
|
|
176
|
+
## Objects
|
|
177
|
+
|
|
178
|
+
The Python binding exposes Zova objects as content-addressed byte values while
|
|
179
|
+
keeping application metadata in normal SQL tables.
|
|
180
|
+
|
|
181
|
+
```python
|
|
182
|
+
import zova
|
|
183
|
+
|
|
184
|
+
with zova.Database.create("app.zova") as db:
|
|
185
|
+
db.exec(
|
|
186
|
+
"create table attachments("
|
|
187
|
+
"id integer primary key, "
|
|
188
|
+
"filename text not null, "
|
|
189
|
+
"object_id blob not null)"
|
|
190
|
+
)
|
|
191
|
+
|
|
192
|
+
object_id = db.put_object(b"hello from Zova")
|
|
193
|
+
|
|
194
|
+
with db.prepare("insert into attachments(filename, object_id) values (?1, ?2)") as stmt:
|
|
195
|
+
stmt.bind_text(1, "hello.txt")
|
|
196
|
+
stmt.bind_blob(2, bytes(object_id))
|
|
197
|
+
stmt.step()
|
|
198
|
+
|
|
199
|
+
assert db.read_object_range(object_id, 0, 5) == b"hello"
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
For large inputs, use `ObjectWriter` so the full object does not have to be held
|
|
203
|
+
in memory by the caller:
|
|
204
|
+
|
|
205
|
+
```python
|
|
206
|
+
with db.object_writer() as writer:
|
|
207
|
+
writer.write(b"chunk one")
|
|
208
|
+
writer.write(b"chunk two")
|
|
209
|
+
object_id = writer.finish()
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
If a writer leaves the context without `finish()`, it is cancelled and any
|
|
213
|
+
unreferenced chunks written by that writer are cleaned up. Writer operations
|
|
214
|
+
follow Zova's object transaction policy and reject active user transactions.
|
|
215
|
+
|
|
216
|
+
Loose chunks and assembly are also exposed for receive-side workflows:
|
|
217
|
+
applications track transfer state in their own SQL tables, call
|
|
218
|
+
`put_object_chunk()` for verified chunks, then call
|
|
219
|
+
`assemble_object_from_chunks()` when the manifest is complete.
|
|
220
|
+
|
|
221
|
+
## Vectors
|
|
222
|
+
|
|
223
|
+
The Python binding exposes Zova vectors with the same model as the Rust binding:
|
|
224
|
+
Zova stores numeric vectors in named collections, while application metadata
|
|
225
|
+
stays in normal SQL tables.
|
|
226
|
+
|
|
227
|
+
```python
|
|
228
|
+
import zova
|
|
229
|
+
|
|
230
|
+
with zova.Database.create("vectors.zova") as db:
|
|
231
|
+
db.exec(
|
|
232
|
+
"create table chunks("
|
|
233
|
+
"id text primary key, "
|
|
234
|
+
"document_id text not null, "
|
|
235
|
+
"text text not null, "
|
|
236
|
+
"vector_id text not null)"
|
|
237
|
+
)
|
|
238
|
+
|
|
239
|
+
db.create_vector_collection(
|
|
240
|
+
"chunks",
|
|
241
|
+
zova.VectorCollectionOptions(2, zova.VectorMetric.L2),
|
|
242
|
+
)
|
|
243
|
+
db.put_vectors(
|
|
244
|
+
"chunks",
|
|
245
|
+
[
|
|
246
|
+
zova.VectorInput("chunk:1", [0.0, 0.0]),
|
|
247
|
+
zova.VectorInput("chunk:2", [1.0, 0.0]),
|
|
248
|
+
],
|
|
249
|
+
)
|
|
250
|
+
|
|
251
|
+
db.exec(
|
|
252
|
+
"insert into chunks(id, document_id, text, vector_id) values "
|
|
253
|
+
"('c1', 'doc-a', 'first chunk', 'chunk:1'), "
|
|
254
|
+
"('c2', 'doc-a', 'near chunk', 'chunk:2')"
|
|
255
|
+
)
|
|
256
|
+
|
|
257
|
+
results = db.search_vectors_in(
|
|
258
|
+
"chunks",
|
|
259
|
+
[0.0, 0.0],
|
|
260
|
+
["chunk:1", "chunk:2"],
|
|
261
|
+
2,
|
|
262
|
+
)
|
|
263
|
+
for result in results:
|
|
264
|
+
with db.prepare("select text from chunks where vector_id = ?1") as stmt:
|
|
265
|
+
stmt.bind_text(1, result.id)
|
|
266
|
+
stmt.step()
|
|
267
|
+
print(result.id, result.distance, stmt.column_text(0))
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
Search is exact and lower distance is better. Candidate-filtered searches skip
|
|
271
|
+
missing ids and deduplicate duplicate candidates. Search-by-id excludes the
|
|
272
|
+
source vector. Threshold variants are inclusive, and dot-product thresholds may
|
|
273
|
+
be negative because dot distance is `-dot_product`.
|
|
274
|
+
|
|
275
|
+
Deleting a vector collection removes Zova's private vector rows only. User SQL
|
|
276
|
+
metadata rows that reference vector ids are application-owned and remain in
|
|
277
|
+
place.
|
|
278
|
+
|
|
279
|
+
## SQL-Native Vector Search
|
|
280
|
+
|
|
281
|
+
Zova registers SQL vector functions and the `zova_vector_search` virtual table
|
|
282
|
+
on Zova database connections. Bind query vectors as little-endian `f32` blobs
|
|
283
|
+
with `encode_f32_le()`:
|
|
284
|
+
|
|
285
|
+
```python
|
|
286
|
+
query = zova.encode_f32_le([0.0, 0.0])
|
|
287
|
+
|
|
288
|
+
with db.prepare(
|
|
289
|
+
"select c.id, zova_vector_distance('chunks', c.vector_id, ?1) as distance "
|
|
290
|
+
"from chunks as c "
|
|
291
|
+
"where c.document_id = 'doc-a' "
|
|
292
|
+
"order by distance "
|
|
293
|
+
"limit 10"
|
|
294
|
+
) as stmt:
|
|
295
|
+
stmt.bind_blob(1, query)
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
Row-to-row distances use `zova_vector_distance_by_id(collection, vector_id,
|
|
299
|
+
source_vector_id)`. Collection-wide SQL search uses `zova_vector_search`:
|
|
300
|
+
|
|
301
|
+
```python
|
|
302
|
+
with db.prepare(
|
|
303
|
+
"select c.text, s.distance "
|
|
304
|
+
"from zova_vector_search as s "
|
|
305
|
+
"join chunks as c on c.vector_id = s.vector_id "
|
|
306
|
+
"where s.collection = 'chunks' "
|
|
307
|
+
"and s.query_vector = ?1 "
|
|
308
|
+
"and s.top_k = 10 "
|
|
309
|
+
"order by s.rank"
|
|
310
|
+
) as stmt:
|
|
311
|
+
stmt.bind_blob(1, query)
|
|
312
|
+
```
|
|
313
|
+
|
|
314
|
+
Python's built-in `sqlite3` module opens an ordinary SQLite connection and does
|
|
315
|
+
not automatically register Zova's SQL functions or virtual table. Use
|
|
316
|
+
`zova.Database` for SQL-native vector search in this binding. A future SQLite
|
|
317
|
+
loadable extension may make the SQL surface available to external SQLite
|
|
318
|
+
connections.
|
|
319
|
+
|