Skip to content

Commit ff19012

Browse files
committed
fix for the issue#42
1 parent c4a6301 commit ff19012

1 file changed

Lines changed: 40 additions & 18 deletions

File tree

src/qql/executor.py

Lines changed: 40 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,18 @@ class CollectionTopology:
131131
has_unnamed_dense: bool = False
132132
dense_names: tuple[str, ...] = ()
133133
sparse_names: tuple[str, ...] = ()
134+
# Sizes fetched once in _resolve_topology() so _ensure_collection() never
135+
# needs a second get_collection() call.
136+
dense_sizes: tuple[tuple[str, int], ...] = ()
137+
138+
def dense_size_map(self) -> dict[str, int]:
139+
"""Return {vector_name: size} for every dense vector whose size was fetched.
140+
141+
Unnamed single-vector collections appear under the ``""`` key, matching
142+
``dense_config_key()``. Returns an empty dict when ``exists`` is False or
143+
sizes were not available (e.g. when a mock omits the size attribute).
144+
"""
145+
return dict(self.dense_sizes)
134146

135147
@property
136148
def has_dense(self) -> bool:
@@ -239,14 +251,23 @@ def _resolve_topology(self, name: str) -> CollectionTopology:
239251

240252
if isinstance(vectors, dict):
241253
dense_names = tuple(vectors.keys())
254+
dense_sizes: tuple[tuple[str, int], ...] = tuple(
255+
(k, v.size)
256+
for k, v in vectors.items()
257+
if getattr(v, "size", None) is not None
258+
)
242259
has_unnamed_dense = False
243260
is_named_dense = True
244261
elif vectors is None:
245262
dense_names = ()
263+
dense_sizes = ()
246264
has_unnamed_dense = False
247265
is_named_dense = False
248266
else:
267+
# Single unnamed dense vector
249268
dense_names = ()
269+
unnamed_size = getattr(vectors, "size", None)
270+
dense_sizes = (("", unnamed_size),) if unnamed_size is not None else ()
250271
has_unnamed_dense = True
251272
is_named_dense = False
252273

@@ -259,6 +280,7 @@ def _resolve_topology(self, name: str) -> CollectionTopology:
259280
has_unnamed_dense=has_unnamed_dense,
260281
dense_names=dense_names,
261282
sparse_names=sparse_names,
283+
dense_sizes=dense_sizes,
262284
)
263285

264286
def _default_dense_vector_name(self) -> str:
@@ -565,9 +587,9 @@ def _execute_create(self, node: CreateCollectionStmt) -> ExecutionResult:
565587
)
566588

567589
def _execute_alter_collection(self, node: AlterCollectionStmt) -> ExecutionResult:
568-
if not self._client.collection_exists(node.collection):
569-
raise QQLRuntimeError(f"Collection '{node.collection}' does not exist")
570590
topology = self._resolve_topology(node.collection)
591+
if not topology.exists:
592+
raise QQLRuntimeError(f"Collection '{node.collection}' does not exist")
571593

572594
update_kwargs: dict[str, Any] = {"collection_name": node.collection}
573595
vectors_config = self._build_vectors_config_diff(topology, node.config)
@@ -828,9 +850,9 @@ def _execute_select(self, node: SelectStmt) -> ExecutionResult:
828850
)
829851

830852
def _execute_search(self, node: SearchStmt) -> ExecutionResult:
831-
if not self._client.collection_exists(node.collection):
832-
raise QQLRuntimeError(f"Collection '{node.collection}' does not exist")
833853
topology = self._resolve_topology(node.collection)
854+
if not topology.exists:
855+
raise QQLRuntimeError(f"Collection '{node.collection}' does not exist")
834856

835857
# Build WHERE filter (shared by both hybrid and dense-only paths)
836858
qdrant_filter: Filter | None = None
@@ -1711,9 +1733,9 @@ def _execute_search_groups(
17111733

17121734
def _execute_update_vector(self, node: UpdateVectorStmt) -> ExecutionResult:
17131735
"""Execute UPDATE ... SET VECTOR using update_vectors()."""
1714-
if not self._client.collection_exists(node.collection):
1715-
raise QQLRuntimeError(f"Collection '{node.collection}' does not exist")
17161736
topology = self._resolve_topology(node.collection)
1737+
if not topology.exists:
1738+
raise QQLRuntimeError(f"Collection '{node.collection}' does not exist")
17171739
vector_name = topology.dense_payload_name(node.vector_name)
17181740
vector_struct: Any = (
17191741
{vector_name: list(node.vector)} if vector_name else list(node.vector)
@@ -1915,33 +1937,33 @@ def _ensure_collection(
19151937
topology: CollectionTopology,
19161938
explicit_vector: str | None,
19171939
) -> None:
1918-
"""Create the collection if it doesn't exist. Raises on dimension mismatch.
1940+
"""Create the collection if needed, or validate dimension compatibility.
19191941
19201942
QQL-created dense collections use the configured dense vector name.
19211943
Externally created unnamed collections still accept plain dense vectors.
1944+
All validation is done against pre-fetched ``topology`` data; no extra
1945+
Qdrant API calls are made.
19221946
"""
19231947
if topology.exists:
1924-
info = self._client.get_collection(name)
1925-
vectors = info.config.params.vectors # type: ignore[union-attr]
1926-
if isinstance(vectors, dict):
1948+
sizes = topology.dense_size_map()
1949+
if topology.is_named_dense:
1950+
# dense_using() raises QQLRuntimeError on bad/ambiguous names,
1951+
# and always returns a non-None string in the named-dense branch.
19271952
vector_name = topology.dense_using(explicit_vector)
1928-
if vector_name is None:
1929-
raise QQLRuntimeError("Collection has no dense vector")
1930-
vector_config = vectors[vector_name]
1931-
expected_size = getattr(vector_config, "size", None)
1953+
expected_size = sizes.get(vector_name) # type: ignore[arg-type]
19321954
if expected_size is not None and expected_size != vector_size:
19331955
raise QQLRuntimeError(
19341956
f"Vector dimension mismatch: collection '{name}' vector "
19351957
f"'{vector_name}' expects {expected_size} dims, but "
19361958
f"model produces {vector_size} dims. Specify a compatible "
19371959
"model with USING MODEL '<model>'."
19381960
)
1939-
elif vectors is not None:
1940-
# Unnamed single-vector collection: validate dimensions
1941-
if vectors.size != vector_size:
1961+
elif topology.has_unnamed_dense:
1962+
expected_size = sizes.get("")
1963+
if expected_size is not None and expected_size != vector_size:
19421964
raise QQLRuntimeError(
19431965
f"Vector dimension mismatch: collection '{name}' expects "
1944-
f"{vectors.size} dims, but model produces {vector_size} dims. "
1966+
f"{expected_size} dims, but model produces {vector_size} dims. "
19451967
f"Specify a compatible model with USING MODEL '<model>'."
19461968
)
19471969
else:

0 commit comments

Comments
 (0)