1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
//! Per-column vector model metadata for embedding tracking and migration.
//!
//! Stored in the system catalog keyed by `(tenant_id, collection, column)`.
//! Informational by default; optional strict dimension enforcement.
use serde::{Deserialize, Serialize};
/// Metadata about the embedding model that produced vectors in a column.
///
/// Stored in the system catalog via `ALTER COLLECTION x SET VECTOR METADATA ON column (...)`.
/// Retrieved via `SELECT VECTOR_METADATA('collection', 'column')` or `SHOW VECTOR MODELS`.
#[derive(
Debug, Clone, Serialize, Deserialize, zerompk::ToMessagePack, zerompk::FromMessagePack,
)]
pub struct VectorModelMetadata {
/// Embedding model identifier (e.g. "text-embedding-3-large", "all-MiniLM-L6-v2").
pub model: String,
/// Expected vector dimensionality for this model.
pub dimensions: usize,
/// ISO-8601 date when the metadata was set (informational).
pub created_at: String,
/// If true, INSERT rejects vectors whose dimension doesn't match `dimensions`.
/// Default: false (no enforcement — metadata only).
#[serde(default)]
pub strict_dimensions: bool,
}
/// Catalog entry for vector model metadata.
///
/// Wraps `VectorModelMetadata` with the key fields needed for catalog storage
/// and the `_system.vector_models` view.
#[derive(
Debug, Clone, Serialize, Deserialize, zerompk::ToMessagePack, zerompk::FromMessagePack,
)]
pub struct VectorModelEntry {
/// Tenant that owns this collection.
pub tenant_id: u32,
/// Collection name.
pub collection: String,
/// Vector column name.
pub column: String,
/// The model metadata.
pub metadata: VectorModelMetadata,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn serde_roundtrip() {
let entry = VectorModelEntry {
tenant_id: 1,
collection: "chunks".into(),
column: "embedding".into(),
metadata: VectorModelMetadata {
model: "text-embedding-3-large".into(),
dimensions: 1536,
created_at: "2026-03-01".into(),
strict_dimensions: false,
},
};
let bytes = zerompk::to_msgpack_vec(&entry).unwrap();
let restored: VectorModelEntry = zerompk::from_msgpack(&bytes).unwrap();
assert_eq!(restored.metadata.model, "text-embedding-3-large");
assert_eq!(restored.metadata.dimensions, 1536);
assert!(!restored.metadata.strict_dimensions);
}
#[test]
fn strict_dimensions_default_false() {
// Deserialize without strict_dimensions field → defaults to false.
let meta = VectorModelMetadata {
model: "test".into(),
dimensions: 128,
created_at: "2026-01-01".into(),
strict_dimensions: false,
};
let bytes = zerompk::to_msgpack_vec(&meta).unwrap();
let restored: VectorModelMetadata = zerompk::from_msgpack(&bytes).unwrap();
assert!(!restored.strict_dimensions);
}
}