chore: import upstream snapshot with attribution
Integ / changes (push) Has been skipped
Pre-commit / pre-commit (push) Failing after 1s
CLI exit codes / changes (push) Has been skipped
Test (Install) / changes (push) Has been skipped
Test (Python) / changes (push) Has been skipped
Test (TypeScript) / changes (push) Has been skipped
CLI exit codes / cli-gate (push) Has been cancelled
Test (Install) / test-install-gate (push) Has been cancelled
Integ / integ-gate (push) Has been cancelled
Test (Python) / test-python-gate (push) Has been cancelled
Test (TypeScript) / test-typescript-gate (push) Has been cancelled
Test (Install) / python-minimal (3.12) (push) Has been cancelled
Test (Install) / python-minimal (3.11) (push) Has been cancelled
Test (Install) / python-extra (agno, mirage.agents.agno) (push) Has been cancelled
Test (Install) / python-extra (chroma, mirage.resource.chroma) (push) Has been cancelled
Test (Install) / python-extra (pdf, mirage.core.filetype.pdf) (push) Has been cancelled
Integ / integ (push) Has been cancelled
Integ / integ-database (push) Has been cancelled
Integ / integ-database-ts (push) Has been cancelled
Integ / integ-data (push) Has been cancelled
Integ / integ-ssh (push) Has been cancelled
Integ / integ-ssh-ts (push) Has been cancelled
Test (Python) / audit (push) Has been cancelled
Test (TypeScript) / test (push) Has been cancelled
Test (TypeScript) / python-fs-shim (push) Has been cancelled
CLI exit codes / Python CLI (push) Has been cancelled
CLI exit codes / TypeScript CLI (push) Has been cancelled
CLI exit codes / Cross-language snapshot interop (push) Has been cancelled
Test (Python) / test (push) Has been cancelled
Test (Python) / import-isolation (deepagents, openai, mirage.agents.openai_agents) (push) Has been cancelled
Test (Python) / import-isolation (deepagents, pydantic-ai, mirage.agents.pydantic_ai) (push) Has been cancelled
Integ / integ-ts (push) Has been cancelled
Integ / integ-fuse (push) Has been cancelled
Test (Install) / python-extra (databricks, mirage.resource.databricks_volume) (push) Has been cancelled
Test (Install) / python-extra (deepagents, mirage.agents.langchain) (push) Has been cancelled
Test (Install) / python-extra (email, mirage.resource.email) (push) Has been cancelled
Test (Install) / python-extra (fuse, mirage.fuse.mount) (push) Has been cancelled
Test (Install) / python-extra (hdf5, mirage.core.filetype.hdf5) (push) Has been cancelled
Test (Install) / python-extra (hf, mirage.resource.hf_buckets) (push) Has been cancelled
Test (Install) / python-extra (lancedb, mirage.resource.lancedb) (push) Has been cancelled
Test (Install) / python-extra (langfuse, mirage.resource.langfuse) (push) Has been cancelled
Test (Install) / python-extra (mongodb, mirage.resource.mongodb) (push) Has been cancelled
Test (Install) / python-extra (nextcloud, mirage.resource.nextcloud) (push) Has been cancelled
Test (Install) / python-extra (openai, mirage.agents.openai_agents) (push) Has been cancelled
Test (Install) / python-extra (openhands, mirage.agents.openhands, 3.12) (push) Has been cancelled
Test (Install) / python-extra (parquet, mirage.core.filetype.parquet) (push) Has been cancelled
Test (Install) / python-extra (postgres, mirage.resource.postgres) (push) Has been cancelled
Test (Install) / python-extra (pydantic-ai, mirage.agents.pydantic_ai) (push) Has been cancelled
Test (Install) / python-extra (qdrant, mirage.resource.qdrant) (push) Has been cancelled
Test (Install) / python-extra (redis, mirage.resource.redis) (push) Has been cancelled
Test (Install) / python-extra (s3, mirage.resource.s3) (push) Has been cancelled
Test (Install) / python-extra (ssh, mirage.resource.ssh) (push) Has been cancelled
Test (Install) / ts-minimal (push) Has been cancelled

This commit is contained in:
wehub-resource-sync
2026-07-13 12:30:44 +08:00
commit bcbd1bdb22
5748 changed files with 562488 additions and 0 deletions
+13
View File
@@ -0,0 +1,13 @@
# ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========
+338
View File
@@ -0,0 +1,338 @@
# ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========
from unittest.mock import AsyncMock, MagicMock
import pytest
from mirage.core.postgres import _client
@pytest.fixture
def mock_conn():
conn = MagicMock()
conn.fetch = AsyncMock()
conn.fetchval = AsyncMock()
conn.fetchrow = AsyncMock()
return conn
@pytest.mark.asyncio
async def test_list_schemas(mock_conn):
mock_conn.fetch.return_value = [
{
"schema_name": "analytics"
},
{
"schema_name": "public"
},
]
result = await _client.list_schemas(mock_conn, None)
assert result == ["analytics", "public"]
@pytest.mark.asyncio
async def test_list_schemas_allowlist(mock_conn):
mock_conn.fetch.return_value = [
{
"schema_name": "public"
},
{
"schema_name": "analytics"
},
]
result = await _client.list_schemas(mock_conn, ["public"])
assert result == ["public"]
@pytest.mark.asyncio
async def test_list_tables(mock_conn):
mock_conn.fetch.return_value = [
{
"table_name": "v1"
},
{
"table_name": "v2"
},
]
result = await _client.list_tables(mock_conn, "public")
assert result == ["v1", "v2"]
@pytest.mark.asyncio
async def test_list_views(mock_conn):
mock_conn.fetch.return_value = [
{
"table_name": "v1"
},
{
"table_name": "v2"
},
]
result = await _client.list_views(mock_conn, "public")
assert result == ["v1", "v2"]
@pytest.mark.asyncio
async def test_list_matviews(mock_conn):
mock_conn.fetch.return_value = [{"name": "mv1"}]
result = await _client.list_matviews(mock_conn, "public")
assert result == ["mv1"]
@pytest.mark.asyncio
async def test_count_rows(mock_conn):
mock_conn.fetchval.return_value = 42
result = await _client.count_rows(mock_conn, "public", "users")
assert result == 42
@pytest.mark.asyncio
async def test_estimate_size(mock_conn):
mock_conn.fetchval.return_value = [{
"Plan": {
"Plan Rows": 1234,
"Plan Width": 80
}
}]
result = await _client.estimate_size(mock_conn, "public", "users")
assert result == (1234, 80)
@pytest.mark.asyncio
async def test_estimate_size_json_string(mock_conn):
mock_conn.fetchval.return_value = (
'[{"Plan": {"Plan Rows": 500, "Plan Width": 64}}]')
rows, width = await _client.estimate_size(mock_conn, "public", "v1")
assert rows == 500
assert width == 64
@pytest.mark.asyncio
async def test_estimated_row_count(mock_conn):
mock_conn.fetchval.return_value = 9999
result = await _client.estimated_row_count(mock_conn, "public", "users")
assert result == 9999
@pytest.mark.asyncio
async def test_estimated_row_count_none(mock_conn):
mock_conn.fetchval.return_value = None
result = await _client.estimated_row_count(mock_conn, "public", "users")
assert result == 0
@pytest.mark.asyncio
async def test_table_size_bytes(mock_conn):
mock_conn.fetchval.return_value = 2_097_152
result = await _client.table_size_bytes(mock_conn, "public", "users")
assert result == 2097152
@pytest.mark.asyncio
async def test_fetch_rows(mock_conn):
mock_conn.fetch.return_value = [
{
"id": 1,
"name": "a"
},
{
"id": 2,
"name": "b"
},
]
result = await _client.fetch_rows(mock_conn,
"public",
"users",
limit=10,
offset=0)
assert len(result) == 2
assert result[0]["name"] == "a"
@pytest.mark.asyncio
async def test_fetch_columns(mock_conn):
mock_conn.fetch.return_value = [
{
"column_name": "id",
"data_type": "uuid",
"is_nullable": "NO"
},
{
"column_name": "team_id",
"data_type": "uuid",
"is_nullable": "YES",
},
]
result = await _client.fetch_columns(mock_conn, "public", "users")
assert result == [
{
"name": "id",
"type": "uuid",
"nullable": False
},
{
"name": "team_id",
"type": "uuid",
"nullable": True
},
]
@pytest.mark.asyncio
async def test_fetch_primary_key(mock_conn):
mock_conn.fetch.return_value = [{"column_name": "id"}]
result = await _client.fetch_primary_key(mock_conn, "public", "users")
assert result == ["id"]
@pytest.mark.asyncio
async def test_fetch_foreign_keys(mock_conn):
mock_conn.fetch.return_value = [{
"constraint_name": "fk1",
"from_column": "team_id",
"ordinal_position": 1,
"to_schema": "public",
"to_table": "teams",
"to_column": "id",
}]
result = await _client.fetch_foreign_keys(mock_conn, "public", "users")
assert result == [{
"columns": ["team_id"],
"references": {
"schema": "public",
"table": "teams",
"columns": ["id"],
},
}]
@pytest.mark.asyncio
async def test_fetch_foreign_keys_multi_column(mock_conn):
mock_conn.fetch.return_value = [
{
"constraint_name": "fk_compound",
"from_column": "tenant_id",
"to_column": "tenant_id",
"ord": 1,
"to_schema": "public",
"to_table": "accounts",
},
{
"constraint_name": "fk_compound",
"from_column": "user_id",
"to_column": "id",
"ord": 2,
"to_schema": "public",
"to_table": "accounts",
},
]
result = await _client.fetch_foreign_keys(mock_conn, "public",
"memberships")
assert result == [{
"columns": ["tenant_id", "user_id"],
"references": {
"schema": "public",
"table": "accounts",
"columns": ["tenant_id", "id"],
},
}]
@pytest.mark.asyncio
async def test_fetch_indexes(mock_conn):
mock_conn.fetch.return_value = [{
"name": "users_email_idx",
"unique": True,
"columns": ["email"],
}]
result = await _client.fetch_indexes(mock_conn, "public", "users")
assert result == [{
"name": "users_email_idx",
"columns": ["email"],
"unique": True,
}]
@pytest.mark.asyncio
async def test_fetch_all_relationships(mock_conn):
mock_conn.fetch.return_value = [{
"constraint_name": "fk1",
"from_schema": "public",
"from_table": "users",
"from_column": "team_id",
"ordinal_position": 1,
"to_schema": "public",
"to_table": "teams",
"to_column": "id",
}]
result = await _client.fetch_all_relationships(mock_conn, ["public"])
assert len(result) == 1
assert result[0]["kind"] == "many_to_one"
assert result[0]["from"] == {
"schema": "public",
"table": "users",
"columns": ["team_id"],
}
assert result[0]["to"] == {
"schema": "public",
"table": "teams",
"columns": ["id"],
}
@pytest.mark.asyncio
async def test_fetch_all_relationships_multi_column(mock_conn):
mock_conn.fetch.return_value = [
{
"constraint_name": "fk_compound",
"from_schema": "public",
"from_table": "memberships",
"from_column": "tenant_id",
"to_column": "tenant_id",
"ord": 1,
"to_schema": "public",
"to_table": "accounts",
},
{
"constraint_name": "fk_compound",
"from_schema": "public",
"from_table": "memberships",
"from_column": "user_id",
"to_column": "id",
"ord": 2,
"to_schema": "public",
"to_table": "accounts",
},
]
result = await _client.fetch_all_relationships(mock_conn, ["public"])
assert len(result) == 1
assert result[0]["kind"] == "many_to_one"
assert result[0]["from"] == {
"schema": "public",
"table": "memberships",
"columns": ["tenant_id", "user_id"],
}
assert result[0]["to"] == {
"schema": "public",
"table": "accounts",
"columns": ["tenant_id", "id"],
}
@pytest.mark.asyncio
async def test_fetch_all_relationships_empty_schemas(mock_conn):
result = await _client.fetch_all_relationships(mock_conn, [])
assert result == []
mock_conn.fetch.assert_not_called()
+79
View File
@@ -0,0 +1,79 @@
# ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========
from unittest.mock import AsyncMock, patch
import pytest
from mirage.accessor.postgres import PostgresAccessor
from mirage.cache.index.ram import RAMIndexCacheStore
from mirage.core.postgres.glob import resolve_glob
from mirage.resource.postgres.config import PostgresConfig
from mirage.types import PathSpec
@pytest.fixture
def index():
return RAMIndexCacheStore()
@pytest.fixture
def accessor():
return PostgresAccessor(PostgresConfig(dsn="postgres://localhost/db"))
@pytest.mark.asyncio
async def test_resolve_glob_str_path(accessor, index):
result = await resolve_glob(accessor, ["/public/tables/users"], index)
assert len(result) == 1
assert result[0].virtual == "/public/tables/users"
@pytest.mark.asyncio
async def test_resolve_glob_resolved_pathspec(accessor, index):
p = PathSpec(resource_path="public/tables/users",
virtual="/public/tables/users",
directory="/public/tables",
resolved=True)
result = await resolve_glob(accessor, [p], index)
assert result == [p]
@pytest.mark.asyncio
async def test_resolve_glob_pattern_match(accessor, index):
with patch("mirage.core.postgres.glob.readdir",
new_callable=AsyncMock,
return_value=[
"/public/tables/users", "/public/tables/orders",
"/public/tables/teams"
]):
p = PathSpec(resource_path="public/tables/u*",
virtual="/public/tables/u*",
directory="/public/tables",
pattern="u*",
resolved=False)
result = await resolve_glob(accessor, [p], index)
assert len(result) == 1
assert result[0].virtual == "/public/tables/users"
@pytest.mark.asyncio
async def test_resolve_glob_unresolved_no_pattern(accessor, index):
p = PathSpec(resource_path="public/tables",
virtual="/public/tables",
directory="/public",
resolved=False,
pattern=None)
result = await resolve_glob(accessor, [p], index)
assert result == [p]
+217
View File
@@ -0,0 +1,217 @@
# ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========
import json
from contextlib import asynccontextmanager
from unittest.mock import AsyncMock, MagicMock, patch
import pytest
from mirage.accessor.postgres import PostgresAccessor
from mirage.cache.index.ram import RAMIndexCacheStore
from mirage.core.postgres.read import read
from mirage.resource.postgres.config import PostgresConfig
from mirage.types import PathSpec
@asynccontextmanager
async def _fake_acquire():
yield MagicMock()
def _accessor(max_read_rows: int = 10_000,
max_read_bytes: int = 10 * 1024 * 1024,
default_row_limit: int = 1000) -> PostgresAccessor:
a = PostgresAccessor(
PostgresConfig(dsn="postgres://localhost/db",
max_read_rows=max_read_rows,
max_read_bytes=max_read_bytes,
default_row_limit=default_row_limit))
pool = MagicMock()
pool.acquire = lambda: _fake_acquire()
a.pool = AsyncMock(return_value=pool)
return a
@pytest.fixture
def index():
return RAMIndexCacheStore()
@pytest.mark.asyncio
async def test_read_database_json():
accessor = _accessor()
fake_doc = {
"database": "db",
"schemas": ["public"],
"tables": [],
"views": [],
"relationships": []
}
with patch("mirage.core.postgres.read.build_database_json",
new_callable=AsyncMock,
return_value=fake_doc):
out = await read(
accessor,
PathSpec(resource_path="database.json",
virtual="/database.json",
directory="/database.json"))
parsed = json.loads(out)
assert parsed == fake_doc
@pytest.mark.asyncio
async def test_read_entity_schema_json_table():
accessor = _accessor()
fake_doc = {"schema": "public", "name": "users", "kind": "table"}
with patch("mirage.core.postgres.read.build_entity_schema_json",
new_callable=AsyncMock,
return_value=fake_doc) as mock_fn:
out = await read(
accessor,
PathSpec(resource_path="public/tables/users/schema.json",
virtual="/public/tables/users/schema.json",
directory="/public/tables/users/schema.json"))
parsed = json.loads(out)
assert parsed == fake_doc
mock_fn.assert_awaited_once_with(accessor, "public", "users", "table")
@pytest.mark.asyncio
async def test_read_entity_schema_json_view_kind():
accessor = _accessor()
fake_doc = {"schema": "public", "name": "v1", "kind": "view"}
with patch("mirage.core.postgres.read.build_entity_schema_json",
new_callable=AsyncMock,
return_value=fake_doc) as mock_fn:
await read(
accessor,
PathSpec(resource_path="public/views/v1/schema.json",
virtual="/public/views/v1/schema.json",
directory="/public/views/v1/schema.json"))
mock_fn.assert_awaited_once_with(accessor, "public", "v1", "view")
@pytest.mark.asyncio
async def test_read_rows_returns_jsonl():
accessor = _accessor()
rows = [{"id": 1, "name": "a"}, {"id": 2, "name": "b"}]
with patch("mirage.core.postgres.read._client") as mc:
mc.estimate_size = AsyncMock(return_value=(2, 80))
mc.fetch_rows = AsyncMock(return_value=rows)
out = await read(
accessor,
PathSpec(resource_path="public/tables/users/rows.jsonl",
virtual="/public/tables/users/rows.jsonl",
directory="/public/tables/users/rows.jsonl"))
lines = out.decode().strip().split("\n")
assert len(lines) == 2
assert json.loads(lines[0]) == {"id": 1, "name": "a"}
@pytest.mark.asyncio
async def test_read_rows_too_many_rows_raises():
accessor = _accessor(max_read_rows=100)
with patch("mirage.core.postgres.read._client") as mc:
mc.estimate_size = AsyncMock(return_value=(1_000_000, 50))
with pytest.raises(ValueError, match="too large"):
await read(
accessor,
PathSpec(resource_path="public/tables/users/rows.jsonl",
virtual="/public/tables/users/rows.jsonl",
directory="/public/tables/users/rows.jsonl"))
@pytest.mark.asyncio
async def test_read_rows_too_many_bytes_raises():
accessor = _accessor(max_read_rows=10_000_000, max_read_bytes=1024)
with patch("mirage.core.postgres.read._client") as mc:
mc.estimate_size = AsyncMock(return_value=(100, 100))
with pytest.raises(ValueError, match="too large"):
await read(
accessor,
PathSpec(resource_path="public/tables/users/rows.jsonl",
virtual="/public/tables/users/rows.jsonl",
directory="/public/tables/users/rows.jsonl"))
@pytest.mark.asyncio
async def test_read_rows_with_explicit_limit_bypasses_guard():
accessor = _accessor(max_read_rows=10)
rows = [{"id": i} for i in range(5)]
with patch("mirage.core.postgres.read._client") as mc:
mc.fetch_rows = AsyncMock(return_value=rows)
out = await read(accessor,
PathSpec(
resource_path="public/tables/users/rows.jsonl",
virtual="/public/tables/users/rows.jsonl",
directory="/public/tables/users/rows.jsonl"),
limit=5,
offset=0)
mc.estimate_size.assert_not_called()
lines = out.decode().strip().split("\n")
assert len(lines) == 5
@pytest.mark.asyncio
async def test_read_rows_with_only_offset_bypasses_guard():
accessor = _accessor(max_read_rows=10)
rows = [{"id": i} for i in range(3)]
with patch("mirage.core.postgres.read._client") as mc:
mc.fetch_rows = AsyncMock(return_value=rows)
await read(accessor,
PathSpec(resource_path="public/tables/users/rows.jsonl",
virtual="/public/tables/users/rows.jsonl",
directory="/public/tables/users/rows.jsonl"),
offset=10)
mc.estimate_size.assert_not_called()
@pytest.mark.asyncio
async def test_read_rows_empty_returns_empty_bytes():
accessor = _accessor()
with patch("mirage.core.postgres.read._client") as mc:
mc.estimate_size = AsyncMock(return_value=(0, 50))
mc.fetch_rows = AsyncMock(return_value=[])
out = await read(
accessor,
PathSpec(resource_path="public/tables/users/rows.jsonl",
virtual="/public/tables/users/rows.jsonl",
directory="/public/tables/users/rows.jsonl"))
assert out == b""
@pytest.mark.asyncio
async def test_read_invalid_path_raises():
accessor = _accessor()
with pytest.raises(FileNotFoundError):
await read(
accessor,
PathSpec(resource_path="public/tables",
virtual="/public/tables",
directory="/public/tables"))
@pytest.mark.asyncio
async def test_read_view_rows_uses_view_kind_in_error():
"""Error message references views/, not tables/, for a view path."""
accessor = _accessor(max_read_rows=10)
with patch("mirage.core.postgres.read._client") as mc:
mc.estimate_size = AsyncMock(return_value=(10000, 100))
with pytest.raises(ValueError, match="views/v1"):
await read(
accessor,
PathSpec(resource_path="public/views/v1/rows.jsonl",
virtual="/public/views/v1/rows.jsonl",
directory="/public/views/v1/rows.jsonl"))
+154
View File
@@ -0,0 +1,154 @@
# ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========
from contextlib import asynccontextmanager
from unittest.mock import AsyncMock, MagicMock, patch
import pytest
from mirage.accessor.postgres import PostgresAccessor
from mirage.cache.index.ram import RAMIndexCacheStore
from mirage.core.postgres.readdir import is_dir_name, readdir
from mirage.resource.postgres.config import PostgresConfig
from mirage.types import PathSpec
@asynccontextmanager
async def _fake_acquire():
yield MagicMock()
def _accessor(schemas=None) -> PostgresAccessor:
a = PostgresAccessor(
PostgresConfig(dsn="postgres://localhost/db", schemas=schemas))
pool = MagicMock()
pool.acquire = lambda: _fake_acquire()
a.pool = AsyncMock(return_value=pool)
return a
@pytest.fixture
def index():
return RAMIndexCacheStore()
@pytest.fixture
def accessor():
return _accessor()
@pytest.mark.asyncio
async def test_readdir_root_lists_database_json_and_schemas(accessor, index):
with patch("mirage.core.postgres.readdir._client") as mc:
mc.list_schemas = AsyncMock(return_value=["public", "analytics"])
result = await readdir(
accessor, PathSpec(resource_path="", virtual="/", directory="/"),
index)
assert "/database.json" in result
assert "/public" in result
assert "/analytics" in result
@pytest.mark.asyncio
async def test_readdir_schema_lists_kinds(accessor, index):
result = await readdir(
accessor,
PathSpec(resource_path="public",
virtual="/public",
directory="/public"), index)
assert result == ["/public/tables", "/public/views"]
@pytest.mark.asyncio
async def test_readdir_tables_kind_lists_tables(accessor, index):
with patch("mirage.core.postgres.readdir._client") as mc:
mc.list_tables = AsyncMock(return_value=["users", "orders"])
result = await readdir(
accessor,
PathSpec(resource_path="public/tables",
virtual="/public/tables",
directory="/public/tables"), index)
assert "/public/tables/users" in result
assert "/public/tables/orders" in result
@pytest.mark.asyncio
async def test_readdir_views_kind_unions_views_and_matviews(accessor, index):
with patch("mirage.core.postgres.readdir._client") as mc:
mc.list_views = AsyncMock(return_value=["customer_360"])
mc.list_matviews = AsyncMock(return_value=["daily_revenue"])
result = await readdir(
accessor,
PathSpec(resource_path="public/views",
virtual="/public/views",
directory="/public/views"), index)
assert "/public/views/customer_360" in result
assert "/public/views/daily_revenue" in result
@pytest.mark.asyncio
async def test_readdir_entity_lists_schema_and_rows(accessor, index):
result = await readdir(
accessor,
PathSpec(resource_path="public/tables/users",
virtual="/public/tables/users",
directory="/public/tables/users"), index)
assert result == [
"/public/tables/users/schema.json",
"/public/tables/users/rows.jsonl",
]
@pytest.mark.asyncio
async def test_readdir_view_entity_lists_schema_and_rows(accessor, index):
result = await readdir(
accessor,
PathSpec(resource_path="analytics/views/daily_revenue",
virtual="/analytics/views/daily_revenue",
directory="/analytics/views/daily_revenue"), index)
assert result == [
"/analytics/views/daily_revenue/schema.json",
"/analytics/views/daily_revenue/rows.jsonl",
]
@pytest.mark.asyncio
async def test_readdir_invalid_path_raises(accessor, index):
with pytest.raises(FileNotFoundError):
await readdir(
accessor,
PathSpec(resource_path="public/tables/users/extra/foo",
virtual="/public/tables/users/extra/foo",
directory="/public/tables/users/extra/foo"), index)
@pytest.mark.asyncio
async def test_readdir_caches_root_listing(accessor, index):
mock_list_schemas = AsyncMock(return_value=["public"])
with patch("mirage.core.postgres.readdir._client") as mc:
mc.list_schemas = mock_list_schemas
first = await readdir(
accessor, PathSpec(resource_path="", virtual="/", directory="/"),
index)
second = await readdir(
accessor, PathSpec(resource_path="", virtual="/", directory="/"),
index)
assert first == second
assert mock_list_schemas.call_count == 1
def test_is_dir_name_classifies_by_extension():
assert is_dir_name("/public/tables") is True
assert is_dir_name("/database.json") is False
assert is_dir_name("/public/tables/users/rows.jsonl") is False
@@ -0,0 +1,261 @@
# ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========
from contextlib import asynccontextmanager
from unittest.mock import AsyncMock, MagicMock, patch
import pytest
from mirage.accessor.postgres import PostgresAccessor
from mirage.core.postgres._schema_json import (_db_name_from_dsn,
build_database_json,
build_entity_schema_json)
from mirage.resource.postgres.config import PostgresConfig
@asynccontextmanager
async def _fake_acquire():
yield MagicMock()
def _accessor(dsn: str = "postgres://localhost/acme_prod",
schemas=None) -> PostgresAccessor:
a = PostgresAccessor(PostgresConfig(dsn=dsn, schemas=schemas))
pool = MagicMock()
pool.acquire = lambda: _fake_acquire()
a.pool = AsyncMock(return_value=pool)
return a
@pytest.mark.asyncio
async def test_build_database_json_basic():
accessor = _accessor()
with patch("mirage.core.postgres._schema_json._client") as mc:
mc.list_schemas = AsyncMock(return_value=["public"])
mc.list_tables = AsyncMock(return_value=["users", "orders"])
mc.list_views = AsyncMock(return_value=["customer_360"])
mc.list_matviews = AsyncMock(return_value=["daily_revenue"])
mc.estimated_row_count = AsyncMock(side_effect=[100, 200])
mc.table_size_bytes = AsyncMock(side_effect=[1024, 2048])
mc.fetch_all_relationships = AsyncMock(return_value=[
{
"from": {
"schema": "public",
"table": "orders",
"columns": ["user_id"]
},
"to": {
"schema": "public",
"table": "users",
"columns": ["id"]
},
"kind": "many_to_one",
},
])
result = await build_database_json(accessor)
assert result["database"] == "acme_prod"
assert result["schemas"] == ["public"]
assert result["tables"] == [
{
"schema": "public",
"name": "users",
"row_count_estimate": 100,
"size_bytes_estimate": 1024,
},
{
"schema": "public",
"name": "orders",
"row_count_estimate": 200,
"size_bytes_estimate": 2048,
},
]
assert result["views"] == [
{
"schema": "public",
"name": "customer_360",
"kind": "view"
},
{
"schema": "public",
"name": "daily_revenue",
"kind": "materialized"
},
]
assert len(result["relationships"]) == 1
@pytest.mark.asyncio
async def test_build_database_json_empty():
accessor = _accessor()
with patch("mirage.core.postgres._schema_json._client") as mc:
mc.list_schemas = AsyncMock(return_value=[])
mc.fetch_all_relationships = AsyncMock(return_value=[])
result = await build_database_json(accessor)
assert result["schemas"] == []
assert result["tables"] == []
assert result["views"] == []
assert result["relationships"] == []
@pytest.mark.asyncio
async def test_build_entity_schema_json_table_with_pk_and_fk():
accessor = _accessor()
with patch("mirage.core.postgres._schema_json._client") as mc:
mc.fetch_columns = AsyncMock(return_value=[
{
"name": "id",
"type": "uuid",
"nullable": False
},
{
"name": "team_id",
"type": "uuid",
"nullable": True
},
{
"name": "email",
"type": "text",
"nullable": False
},
])
mc.fetch_primary_key = AsyncMock(return_value=["id"])
mc.fetch_foreign_keys = AsyncMock(return_value=[
{
"columns": ["team_id"],
"references": {
"schema": "public",
"table": "teams",
"columns": ["id"],
},
},
])
mc.fetch_indexes = AsyncMock(return_value=[
{
"name": "users_email_idx",
"columns": ["email"],
"unique": True
},
])
mc.estimated_row_count = AsyncMock(return_value=42)
mc.table_size_bytes = AsyncMock(return_value=4096)
result = await build_entity_schema_json(accessor, "public", "users",
"table")
assert result["schema"] == "public"
assert result["name"] == "users"
assert result["kind"] == "table"
assert result["row_count_estimate"] == 42
assert result["size_bytes_estimate"] == 4096
assert result["primary_key"] == ["id"]
cols_by_name = {c["name"]: c for c in result["columns"]}
assert cols_by_name["id"].get("primary_key") is True
assert "primary_key" not in cols_by_name["team_id"]
assert cols_by_name["team_id"]["references"] == {
"schema": "public",
"table": "teams",
"column": "id",
}
assert "references" not in cols_by_name["email"]
assert result["foreign_keys"][0]["columns"] == ["team_id"]
@pytest.mark.asyncio
async def test_build_entity_schema_json_view_kind():
accessor = _accessor()
with patch("mirage.core.postgres._schema_json._client") as mc:
mc.fetch_columns = AsyncMock(return_value=[
{
"name": "team",
"type": "text",
"nullable": True
},
])
mc.fetch_primary_key = AsyncMock(return_value=[])
mc.fetch_foreign_keys = AsyncMock(return_value=[])
mc.fetch_indexes = AsyncMock(return_value=[])
mc.estimated_row_count = AsyncMock(return_value=0)
mc.table_size_bytes = AsyncMock(return_value=0)
result = await build_entity_schema_json(accessor, "public",
"user_summary", "view")
assert result["kind"] == "view"
assert result["primary_key"] == []
assert result["columns"][0] == {
"name": "team",
"type": "text",
"nullable": True,
}
@pytest.mark.asyncio
async def test_build_entity_schema_json_multi_column_fk():
accessor = _accessor()
with patch("mirage.core.postgres._schema_json._client") as mc:
mc.fetch_columns = AsyncMock(return_value=[
{
"name": "tenant_id",
"type": "uuid",
"nullable": False
},
{
"name": "user_id",
"type": "uuid",
"nullable": False
},
])
mc.fetch_primary_key = AsyncMock(return_value=["tenant_id", "user_id"])
mc.fetch_foreign_keys = AsyncMock(return_value=[
{
"columns": ["tenant_id", "user_id"],
"references": {
"schema": "public",
"table": "accounts",
"columns": ["tenant_id", "id"],
},
},
])
mc.fetch_indexes = AsyncMock(return_value=[])
mc.estimated_row_count = AsyncMock(return_value=0)
mc.table_size_bytes = AsyncMock(return_value=0)
result = await build_entity_schema_json(accessor, "public",
"memberships", "table")
cols = {c["name"]: c for c in result["columns"]}
assert cols["tenant_id"]["references"] == {
"schema": "public",
"table": "accounts",
"column": "tenant_id",
}
assert cols["user_id"]["references"] == {
"schema": "public",
"table": "accounts",
"column": "id",
}
def test_db_name_from_dsn_simple():
assert _db_name_from_dsn("postgres://localhost/acme_prod") == "acme_prod"
def test_db_name_from_dsn_with_query():
assert _db_name_from_dsn(
"postgres://localhost/acme?sslmode=require") == "acme"
def test_db_name_from_dsn_with_user_pass():
assert _db_name_from_dsn(
"postgres://u:p@db.example.com:5432/myapp") == "myapp"
def test_db_name_from_dsn_no_db_returns_default():
assert _db_name_from_dsn("postgres://localhost") == "localhost"
+122
View File
@@ -0,0 +1,122 @@
# ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========
from mirage.core.postgres.scope import detect_scope
from mirage.types import PathSpec
def _ps(p: str) -> PathSpec:
return PathSpec(virtual=p, directory=p, resource_path=p.strip("/"))
def test_root():
s = detect_scope(_ps("/"))
assert s.level == "root"
assert s.schema is None
assert s.resource_path == "/"
def test_root_empty_path():
s = detect_scope(_ps(""))
assert s.level == "root"
def test_database_json():
s = detect_scope(_ps("/database.json"))
assert s.level == "database_json"
assert s.file == "database.json"
def test_schema():
s = detect_scope(_ps("/public"))
assert s.level == "schema"
assert s.schema == "public"
def test_schema_with_trailing_slash():
s = detect_scope(_ps("/public/"))
assert s.level == "schema"
assert s.schema == "public"
def test_kind_tables():
s = detect_scope(_ps("/public/tables"))
assert s.level == "kind"
assert s.schema == "public"
assert s.kind == "tables"
def test_kind_views():
s = detect_scope(_ps("/analytics/views"))
assert s.level == "kind"
assert s.schema == "analytics"
assert s.kind == "views"
def test_entity_table():
s = detect_scope(_ps("/public/tables/users"))
assert s.level == "entity"
assert s.schema == "public"
assert s.kind == "tables"
assert s.entity == "users"
def test_entity_view():
s = detect_scope(_ps("/analytics/views/daily_revenue"))
assert s.level == "entity"
assert s.kind == "views"
assert s.entity == "daily_revenue"
def test_entity_schema_file():
s = detect_scope(_ps("/public/tables/users/schema.json"))
assert s.level == "entity_schema"
assert s.schema == "public"
assert s.kind == "tables"
assert s.entity == "users"
assert s.file == "schema.json"
def test_entity_rows_file():
s = detect_scope(_ps("/public/tables/users/rows.jsonl"))
assert s.level == "entity_rows"
assert s.schema == "public"
assert s.entity == "users"
assert s.file == "rows.jsonl"
def test_view_entity_schema_file():
s = detect_scope(_ps("/analytics/views/daily_revenue/schema.json"))
assert s.level == "entity_schema"
assert s.kind == "views"
def test_invalid_kind_segment():
s = detect_scope(_ps("/public/sequences"))
assert s.level == "invalid"
def test_invalid_too_deep():
s = detect_scope(_ps("/public/tables/users/extra/foo"))
assert s.level == "invalid"
def test_invalid_unknown_file():
s = detect_scope(_ps("/public/tables/users/data.jsonl"))
assert s.level == "invalid"
def test_invalid_kind_in_third_position():
s = detect_scope(_ps("/public/wrong_kind/foo"))
assert s.level == "invalid"
+219
View File
@@ -0,0 +1,219 @@
# ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========
from contextlib import asynccontextmanager
from unittest.mock import AsyncMock, MagicMock, patch
import pytest
from mirage.accessor.postgres import PostgresAccessor
from mirage.core.postgres.search import (format_grep_results, search_database,
search_entity, search_kind,
search_schema)
from mirage.resource.postgres.config import PostgresConfig
@asynccontextmanager
async def _fake_acquire(conn=None):
yield conn or MagicMock()
def _accessor(schemas=None) -> PostgresAccessor:
a = PostgresAccessor(
PostgresConfig(dsn="postgres://localhost/db", schemas=schemas))
pool = MagicMock()
pool.acquire = lambda: _fake_acquire()
a.pool = AsyncMock(return_value=pool)
return a
def _accessor_with_conn(conn) -> PostgresAccessor:
a = PostgresAccessor(PostgresConfig(dsn="postgres://localhost/db"))
pool = MagicMock()
pool.acquire = lambda: _fake_acquire(conn)
a.pool = AsyncMock(return_value=pool)
return a
@pytest.mark.asyncio
async def test_search_entity_returns_matching_rows():
conn = MagicMock()
conn.fetch = AsyncMock(side_effect=[
# _text_columns response
[{
"column_name": "name"
}, {
"column_name": "email"
}],
# final query response
[{
"id": 1,
"name": "alice"
}, {
"id": 2,
"name": "alex"
}],
])
accessor = _accessor_with_conn(conn)
rows = await search_entity(accessor,
"public",
"tables",
"users",
"al",
limit=100)
assert len(rows) == 2
assert rows[0]["name"] == "alice"
@pytest.mark.asyncio
async def test_search_entity_no_text_columns_returns_empty():
conn = MagicMock()
conn.fetch = AsyncMock(return_value=[])
accessor = _accessor_with_conn(conn)
rows = await search_entity(accessor,
"public",
"tables",
"ints",
"x",
limit=10)
assert rows == []
@pytest.mark.asyncio
async def test_search_entity_builds_or_clause():
conn = MagicMock()
conn.fetch = AsyncMock(side_effect=[
[{
"column_name": "a"
}, {
"column_name": "b"
}, {
"column_name": "c"
}],
[],
])
accessor = _accessor_with_conn(conn)
await search_entity(accessor, "public", "tables", "t1", "pat", limit=5)
final_call_sql = conn.fetch.await_args_list[1].args[0]
assert "ILIKE" in final_call_sql
assert final_call_sql.count("ILIKE") == 3
assert "$1" in final_call_sql
assert "LIMIT $2" in final_call_sql
@pytest.mark.asyncio
async def test_search_kind_iterates_tables():
accessor = _accessor()
with patch("mirage.core.postgres.search._client") as mc, \
patch("mirage.core.postgres.search.search_entity",
new_callable=AsyncMock) as mock_entity:
mc.list_tables = AsyncMock(return_value=["t1", "t2", "t3"])
mock_entity.side_effect = [
[{
"id": 1
}], # t1 has matches
[], # t2 empty
[{
"id": 9
}], # t3 has matches
]
result = await search_kind(accessor, "public", "tables", "x", limit=10)
assert len(result) == 2
assert result[0] == ("public", "tables", "t1", [{"id": 1}])
assert result[1] == ("public", "tables", "t3", [{"id": 9}])
@pytest.mark.asyncio
async def test_search_kind_views_unions_views_and_matviews():
accessor = _accessor()
with patch("mirage.core.postgres.search._client") as mc, \
patch("mirage.core.postgres.search.search_entity",
new_callable=AsyncMock, return_value=[]) as mock_entity:
mc.list_views = AsyncMock(return_value=["v1"])
mc.list_matviews = AsyncMock(return_value=["mv1"])
await search_kind(accessor, "public", "views", "x", limit=10)
called_entities = sorted(c.args[3] for c in mock_entity.await_args_list)
assert called_entities == ["mv1", "v1"]
@pytest.mark.asyncio
async def test_search_schema_visits_both_kinds():
accessor = _accessor()
with patch("mirage.core.postgres.search.search_kind",
new_callable=AsyncMock,
side_effect=[
[("public", "tables", "t1", [{
"id": 1
}])],
[("public", "views", "v1", [{
"id": 2
}])],
]) as mock_kind:
result = await search_schema(accessor, "public", "x", limit=10)
assert len(result) == 2
assert mock_kind.await_args_list[0].args == (accessor, "public", "tables",
"x", 10)
assert mock_kind.await_args_list[1].args == (accessor, "public", "views",
"x", 10)
@pytest.mark.asyncio
async def test_search_database_iterates_schemas():
accessor = _accessor()
with patch("mirage.core.postgres.search._client") as mc, \
patch("mirage.core.postgres.search.search_schema",
new_callable=AsyncMock,
side_effect=[
[("public", "tables", "t1", [{"id": 1}])],
[("analytics", "tables", "t2", [{"id": 2}])],
]) as mock_schema:
mc.list_schemas = AsyncMock(return_value=["public", "analytics"])
result = await search_database(accessor, "x", limit=10)
assert len(result) == 2
assert mock_schema.await_count == 2
def test_format_grep_results():
results = [
("public", "tables", "users", [{
"id": 1,
"name": "a"
}]),
("public", "views", "v1", [{
"x": 9
}]),
]
lines = format_grep_results(results)
assert len(lines) == 2
assert lines[0].startswith("public/tables/users/rows.jsonl:")
assert "{\"id\":1,\"name\":\"a\"}" in lines[0]
assert lines[1].startswith("public/views/v1/rows.jsonl:")
def test_format_grep_results_empty():
assert format_grep_results([]) == []
def test_format_grep_results_multiple_rows_per_entity():
results = [
("s", "tables", "t", [{
"x": 1
}, {
"x": 2
}, {
"x": 3
}]),
]
lines = format_grep_results(results)
assert len(lines) == 3
+258
View File
@@ -0,0 +1,258 @@
# ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========
from contextlib import asynccontextmanager
from unittest.mock import AsyncMock, MagicMock, patch
import pytest
from mirage.accessor.postgres import PostgresAccessor
from mirage.cache.index.ram import RAMIndexCacheStore
from mirage.core.postgres.stat import stat
from mirage.resource.postgres.config import PostgresConfig
from mirage.types import FileType, PathSpec
from mirage.utils.key_prefix import mount_key
@asynccontextmanager
async def _fake_acquire():
yield MagicMock()
def _accessor() -> PostgresAccessor:
a = PostgresAccessor(PostgresConfig(dsn="postgres://localhost/db"))
pool = MagicMock()
pool.acquire = lambda: _fake_acquire()
a.pool = AsyncMock(return_value=pool)
return a
@pytest.fixture
def index():
return RAMIndexCacheStore()
@pytest.fixture
def accessor():
return _accessor()
@pytest.fixture(autouse=True)
def _exists(monkeypatch):
monkeypatch.setattr("mirage.core.postgres.stat._schema_exists",
AsyncMock(return_value=True))
monkeypatch.setattr("mirage.core.postgres.stat._entity_exists",
AsyncMock(return_value=True))
@pytest.mark.asyncio
async def test_stat_root(accessor, index):
result = await stat(accessor,
PathSpec(resource_path="", virtual="/", directory="/"),
index)
assert result.type == FileType.DIRECTORY
assert result.name == "/"
@pytest.mark.asyncio
async def test_stat_database_json(accessor, index):
result = await stat(
accessor,
PathSpec(resource_path="database.json",
virtual="/database.json",
directory="/database.json"), index)
assert result.type == FileType.JSON
assert result.name == "database.json"
@pytest.mark.asyncio
async def test_stat_schema(accessor, index):
result = await stat(
accessor,
PathSpec(resource_path="public",
virtual="/public",
directory="/public"), index)
assert result.type == FileType.DIRECTORY
assert result.extra["schema"] == "public"
@pytest.mark.asyncio
async def test_stat_kind_tables(accessor, index):
result = await stat(
accessor,
PathSpec(resource_path="public/tables",
virtual="/public/tables",
directory="/public/tables"), index)
assert result.type == FileType.DIRECTORY
assert result.extra == {"schema": "public", "kind": "tables"}
@pytest.mark.asyncio
async def test_stat_kind_views(accessor, index):
result = await stat(
accessor,
PathSpec(resource_path="analytics/views",
virtual="/analytics/views",
directory="/analytics/views"), index)
assert result.type == FileType.DIRECTORY
assert result.extra == {"schema": "analytics", "kind": "views"}
@pytest.mark.asyncio
async def test_stat_entity_table(accessor, index):
result = await stat(
accessor,
PathSpec(resource_path="public/tables/users",
virtual="/public/tables/users",
directory="/public/tables/users"), index)
assert result.type == FileType.DIRECTORY
assert result.name == "users"
assert result.extra == {
"schema": "public",
"kind": "tables",
"name": "users"
}
@pytest.mark.asyncio
async def test_stat_entity_schema_json(accessor, index):
result = await stat(
accessor,
PathSpec(resource_path="public/tables/users/schema.json",
virtual="/public/tables/users/schema.json",
directory="/public/tables/users/schema.json"), index)
assert result.type == FileType.JSON
assert result.name == "schema.json"
assert result.extra == {
"schema": "public",
"kind": "tables",
"name": "users"
}
@pytest.mark.asyncio
async def test_stat_entity_rows_jsonl(accessor, index):
with patch("mirage.core.postgres.stat._client") as mc:
mc.fetch_columns = AsyncMock(return_value=[
{
"name": "id",
"type": "uuid",
"nullable": False
},
{
"name": "email",
"type": "text",
"nullable": False
},
])
mc.estimated_row_count = AsyncMock(return_value=42)
mc.table_size_bytes = AsyncMock(return_value=4096)
result = await stat(
accessor,
PathSpec(resource_path="public/tables/users/rows.jsonl",
virtual="/public/tables/users/rows.jsonl",
directory="/public/tables/users/rows.jsonl"), index)
assert result.type == FileType.TEXT
assert result.name == "rows.jsonl"
assert result.size == 4096
assert result.fingerprint is not None
assert len(result.fingerprint) == 64
assert result.extra["row_count"] == 42
assert result.extra["size_bytes"] == 4096
assert result.extra["schema"] == "public"
assert result.extra["kind"] == "tables"
assert result.extra["name"] == "users"
@pytest.mark.asyncio
async def test_stat_view_entity_rows(accessor, index):
with patch("mirage.core.postgres.stat._client") as mc:
mc.fetch_columns = AsyncMock(return_value=[
{
"name": "team",
"type": "text",
"nullable": True
},
])
mc.estimated_row_count = AsyncMock(return_value=2)
mc.table_size_bytes = AsyncMock(return_value=128)
result = await stat(
accessor,
PathSpec(resource_path="analytics/views/daily_revenue/rows.jsonl",
virtual="/analytics/views/daily_revenue/rows.jsonl",
directory="/analytics/views/daily_revenue/rows.jsonl"),
index)
assert result.type == FileType.TEXT
assert result.extra["kind"] == "views"
@pytest.mark.asyncio
async def test_stat_fingerprint_changes_with_row_count(accessor, index):
with patch("mirage.core.postgres.stat._client") as mc:
mc.fetch_columns = AsyncMock(return_value=[
{
"name": "id",
"type": "uuid",
"nullable": False
},
])
mc.table_size_bytes = AsyncMock(return_value=100)
mc.estimated_row_count = AsyncMock(return_value=10)
first = await stat(
accessor,
PathSpec(resource_path="public/tables/users/rows.jsonl",
virtual="/public/tables/users/rows.jsonl",
directory="/public/tables/users/rows.jsonl"), index)
mc.estimated_row_count = AsyncMock(return_value=20)
second = await stat(
accessor,
PathSpec(resource_path="public/tables/users/rows.jsonl",
virtual="/public/tables/users/rows.jsonl",
directory="/public/tables/users/rows.jsonl"), index)
assert first.fingerprint != second.fingerprint
@pytest.mark.asyncio
async def test_stat_invalid_raises(accessor, index):
with pytest.raises(FileNotFoundError):
await stat(
accessor,
PathSpec(resource_path="public/tables/users/extra/foo",
virtual="/public/tables/users/extra/foo",
directory="/public/tables/users/extra/foo"), index)
@pytest.mark.asyncio
async def test_stat_missing_schema_raises(accessor, index):
with patch("mirage.core.postgres.stat._schema_exists",
AsyncMock(return_value=False)):
with pytest.raises(FileNotFoundError):
await stat(
accessor,
PathSpec(resource_path=mount_key("/pg/__nf_missing__.txt",
"/pg"),
virtual="/pg/__nf_missing__.txt",
directory="/pg/__nf_missing__.txt"), index)
@pytest.mark.asyncio
async def test_stat_missing_entity_raises(accessor, index):
with patch("mirage.core.postgres.stat._entity_exists",
AsyncMock(return_value=False)):
with pytest.raises(FileNotFoundError):
await stat(
accessor,
PathSpec(resource_path="public/tables/nope",
virtual="/public/tables/nope",
directory="/public/tables/nope"), index)