Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion src/arcadedb/_native/database.py
Original file line number Diff line number Diff line change
Expand Up @@ -1319,7 +1319,9 @@ def exists_type(self, name):
return bool(rows)

def drop_type(self, name):
self._run(f"DROP TYPE `{name}`")
# UNSAFE: the engine's dropType, which the JPype build calls, drops a type with its records; plain DROP TYPE refuses
# a vertex or edge type that still holds records
self._run(f"DROP TYPE `{name}` UNSAFE")

def create_property(self, type_name, property_name, property_type, of_type=None):
t = getattr(property_type, "value", property_type)
Expand Down
19 changes: 14 additions & 5 deletions src/arcadedb/_native/schema_objects.py
Original file line number Diff line number Diff line change
Expand Up @@ -300,11 +300,20 @@ def _lookup_query_vector_by_key(self, key):
)
return row.get("query_vector")

def _live_info(self):
# read afresh, the native side of the JPype wrapper's _check_live: a dropped index raises here (the glue names it),
# REBUILD INDEX builds new bucket indexes, and a re-created index has its own configuration; a memoized read
# answered all three from the old index
self._shim.__dict__.pop("_engine_info", None)
return self._shim.engine_info()

def get_size(self):
self._live_info()
return super().get_size()

def get_stats(self):
"""The engine's live counters of the primary bucket index, from its ``schema:index:<name>`` row (the row's own columns left out)."""
# read afresh: REBUILD INDEX builds new bucket indexes, so the name a memoized read holds can be gone
self._shim.__dict__.pop("_engine_info", None)
bucket = self._shim.engine_info()["bucket"]
bucket = self._live_info()["bucket"]
rows = self._database.query(
"sql",
f"SELECT FROM schema:index:`{bucket}`", # nosec B608 - a backtick-quoted index name the engine reported
Expand All @@ -317,7 +326,7 @@ def get_stats(self):

def get_metadata(self):
"""The engine's configuration of the index: what this session created and what an index opened from disk carries, defaults included."""
info = self._shim.engine_info()
info = self._live_info()
return {
"index_name": self._shim._name,
"bucket_index_name": info["bucket"],
Expand All @@ -329,7 +338,7 @@ def get_metadata(self):
}

def get_quantization(self):
return str(self._shim.engine_info()["quantization"] or "NONE")
return str(self._live_info()["quantization"] or "NONE")


# the descriptive columns of a schema:index row; every other column is a counter of IndexInternal.getStats()
Expand Down
25 changes: 25 additions & 0 deletions tests/test_schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,31 @@ def test_drop_type(self, test_db):
schema.drop_type("TempType")
assert not schema.exists_type("TempType")

@pytest.mark.parametrize("kind", ["vertex", "edge"])
def test_drop_type_drops_a_populated_graph_type(self, test_db, kind):
"""``drop_type`` drops a type and all its data, records included, on both builds.

The native build ran SQL ``DROP TYPE``, which refuses a vertex or edge type that holds records unless
``UNSAFE`` is given; the JVM build calls the engine's ``dropType``, which does not check for records.
"""
schema = test_db.schema
schema.create_vertex_type("Person")
schema.create_edge_type("Knows")
with test_db.transaction():
test_db.command("sql", "CREATE VERTEX Person SET name = 'a'")
test_db.command("sql", "CREATE VERTEX Person SET name = 'b'")
test_db.command(
"sql",
"CREATE EDGE Knows FROM (SELECT FROM Person WHERE name = 'a') "
"TO (SELECT FROM Person WHERE name = 'b')",
)
name = "Person" if kind == "vertex" else "Knows"
assert test_db.count_type(name) > 0

schema.drop_type(name)

assert not schema.exists_type(name)

def test_drop_non_existent_type_fails(self, test_db):
"""Test dropping non-existent type raises error."""
schema = test_db.schema
Expand Down
27 changes: 24 additions & 3 deletions tests/test_vector_index_introspection.py
Original file line number Diff line number Diff line change
Expand Up @@ -369,7 +369,28 @@ def test_dropped_index_raises_and_never_answers_empty(self, temp_db):
if arcadedb.__backend__ == "jvm":
# the JVM wrapper names the index itself; the native one passes the engine's own error on
assert "Doc[embedding]" in str(excinfo.value)
# every read raises on both builds: the native wrapper answered get_size() with the row count and
# get_metadata()/get_quantization() from a memoized read of the dropped index
for read in (
index.get_stats,
index.get_size,
index.get_metadata,
index.get_quantization,
):
with pytest.raises(arcadedb.ArcadeDBError, match=r"Doc\[embedding\]"):
index.get_stats()
with pytest.raises(arcadedb.ArcadeDBError, match=r"Doc\[embedding\]"):
index.get_size()
read()

def test_a_recreated_index_reports_its_own_configuration(self, temp_db):
index = self._held_index(temp_db)
assert (
index.get_quantization() != "NONE"
) # create_vector_index defaults to INT8

temp_db.command("sql", "DROP INDEX `Doc[embedding]`")
temp_db.create_vector_index(
"Doc", "embedding", dimensions=3, quantization="NONE"
)

assert index.get_quantization() == "NONE"
assert index.get_metadata()["quantization"] == "NONE"
assert index.get_size() == len(self.ROWS)
Loading