feat(db): add projects and project links tables
CI / lint (pull_request) Successful in 14s
CI / typecheck (pull_request) Successful in 27s
CI / security (pull_request) Successful in 23s
CI / quality (pull_request) Successful in 16s
CI / integration_tests (pull_request) Failing after 3m31s
CI / build (pull_request) Successful in 15s
CI / lint (push) Successful in 13s
CI / typecheck (push) Successful in 28s
CI / security (push) Successful in 23s
CI / quality (push) Successful in 15s
CI / unit_tests (pull_request) Failing after 9m45s
CI / docker (pull_request) Has been skipped
CI / integration_tests (push) Failing after 3m30s
CI / build (push) Successful in 15s
CI / unit_tests (push) Failing after 9m42s
CI / docker (push) Has been skipped
CI / coverage (pull_request) Failing after 3m29s
CI / coverage (push) Failing after 3m28s
CI / lint (pull_request) Successful in 14s
CI / typecheck (pull_request) Successful in 27s
CI / security (pull_request) Successful in 23s
CI / quality (pull_request) Successful in 16s
CI / integration_tests (pull_request) Failing after 3m31s
CI / build (pull_request) Successful in 15s
CI / lint (push) Successful in 13s
CI / typecheck (push) Successful in 28s
CI / security (push) Successful in 23s
CI / quality (push) Successful in 15s
CI / unit_tests (pull_request) Failing after 9m45s
CI / docker (pull_request) Has been skipped
CI / integration_tests (push) Failing after 3m30s
CI / build (push) Successful in 15s
CI / unit_tests (push) Failing after 9m42s
CI / docker (push) Has been skipped
CI / coverage (pull_request) Failing after 3m29s
CI / coverage (push) Failing after 3m28s
This commit was merged in pull request #75.
This commit is contained in:
@@ -0,0 +1,249 @@
|
||||
"""ASV benchmarks for project migration and ORM operations.
|
||||
|
||||
Measures:
|
||||
- NamespacedProjectModel insert throughput
|
||||
- ProjectResourceLinkModel insert throughput
|
||||
- Project-to-domain conversion performance
|
||||
- Link query performance (by project name)
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
from datetime import UTC, datetime
|
||||
|
||||
from sqlalchemy import create_engine, event, text
|
||||
from sqlalchemy.orm import sessionmaker
|
||||
|
||||
from cleveragents.infrastructure.database.models import (
|
||||
Base,
|
||||
NamespacedProjectModel,
|
||||
ProjectResourceLinkModel,
|
||||
ResourceModel,
|
||||
ResourceTypeModel,
|
||||
)
|
||||
|
||||
|
||||
def _now_iso() -> str:
|
||||
return datetime.now(tz=UTC).isoformat()
|
||||
|
||||
|
||||
def _make_ulid(n: int) -> str:
|
||||
return str(n).zfill(26)
|
||||
|
||||
|
||||
def _set_sqlite_pragma(dbapi_conn: object, _connection_record: object) -> None:
|
||||
cursor = dbapi_conn.cursor() # type: ignore[union-attr]
|
||||
cursor.execute("PRAGMA foreign_keys = ON")
|
||||
cursor.close()
|
||||
|
||||
|
||||
class ProjectInsert:
|
||||
"""Benchmark inserting project records."""
|
||||
|
||||
def setup(self) -> None:
|
||||
self.engine = create_engine("sqlite:///:memory:")
|
||||
event.listen(self.engine, "connect", _set_sqlite_pragma)
|
||||
with self.engine.connect() as conn:
|
||||
conn.execute(text("PRAGMA foreign_keys = ON"))
|
||||
conn.commit()
|
||||
Base.metadata.create_all(self.engine)
|
||||
self.session_factory = sessionmaker(bind=self.engine)
|
||||
|
||||
def teardown(self) -> None:
|
||||
self.engine.dispose()
|
||||
|
||||
def time_insert_single_project(self) -> None:
|
||||
session = self.session_factory()
|
||||
proj = NamespacedProjectModel(
|
||||
namespaced_name="bench/single-project",
|
||||
namespace="bench",
|
||||
tags_json="[]",
|
||||
created_at=_now_iso(),
|
||||
updated_at=_now_iso(),
|
||||
)
|
||||
session.add(proj)
|
||||
session.commit()
|
||||
session.close()
|
||||
|
||||
def time_insert_100_projects(self) -> None:
|
||||
session = self.session_factory()
|
||||
for i in range(100):
|
||||
proj = NamespacedProjectModel(
|
||||
namespaced_name=f"bench/project-{i}",
|
||||
namespace="bench",
|
||||
description=f"Project {i}",
|
||||
tags_json=json.dumps([f"tag-{i}"]),
|
||||
created_at=_now_iso(),
|
||||
updated_at=_now_iso(),
|
||||
)
|
||||
session.add(proj)
|
||||
session.commit()
|
||||
session.close()
|
||||
|
||||
|
||||
class ProjectLinkInsert:
|
||||
"""Benchmark inserting project resource link records."""
|
||||
|
||||
def setup(self) -> None:
|
||||
self.engine = create_engine("sqlite:///:memory:")
|
||||
event.listen(self.engine, "connect", _set_sqlite_pragma)
|
||||
with self.engine.connect() as conn:
|
||||
conn.execute(text("PRAGMA foreign_keys = ON"))
|
||||
conn.commit()
|
||||
Base.metadata.create_all(self.engine)
|
||||
self.session_factory = sessionmaker(bind=self.engine)
|
||||
|
||||
session = self.session_factory()
|
||||
# Create resource type
|
||||
rt = ResourceTypeModel()
|
||||
rt.name = "bench/git-checkout"
|
||||
rt.namespace = "bench"
|
||||
rt.resource_kind = "physical"
|
||||
rt.user_addable = True
|
||||
rt.created_at = _now_iso()
|
||||
rt.updated_at = _now_iso()
|
||||
session.add(rt)
|
||||
|
||||
# Create project
|
||||
proj = NamespacedProjectModel(
|
||||
namespaced_name="bench/link-project",
|
||||
namespace="bench",
|
||||
tags_json="[]",
|
||||
created_at=_now_iso(),
|
||||
updated_at=_now_iso(),
|
||||
)
|
||||
session.add(proj)
|
||||
|
||||
# Create 50 resources
|
||||
for i in range(50):
|
||||
r = ResourceModel()
|
||||
r.resource_id = _make_ulid(i)
|
||||
r.type_name = "bench/git-checkout"
|
||||
r.resource_kind = "physical"
|
||||
r.created_at = _now_iso()
|
||||
r.updated_at = _now_iso()
|
||||
session.add(r)
|
||||
|
||||
session.commit()
|
||||
session.close()
|
||||
|
||||
def teardown(self) -> None:
|
||||
self.engine.dispose()
|
||||
|
||||
def time_insert_50_links(self) -> None:
|
||||
session = self.session_factory()
|
||||
for i in range(50):
|
||||
link = ProjectResourceLinkModel(
|
||||
link_id=_make_ulid(1000 + i),
|
||||
project_name="bench/link-project",
|
||||
resource_id=_make_ulid(i),
|
||||
read_only=i % 2 == 0,
|
||||
created_at=_now_iso(),
|
||||
)
|
||||
session.add(link)
|
||||
session.commit()
|
||||
session.close()
|
||||
|
||||
|
||||
class ProjectDomainConversion:
|
||||
"""Benchmark domain model conversion."""
|
||||
|
||||
def setup(self) -> None:
|
||||
self.engine = create_engine("sqlite:///:memory:")
|
||||
event.listen(self.engine, "connect", _set_sqlite_pragma)
|
||||
with self.engine.connect() as conn:
|
||||
conn.execute(text("PRAGMA foreign_keys = ON"))
|
||||
conn.commit()
|
||||
Base.metadata.create_all(self.engine)
|
||||
self.session_factory = sessionmaker(bind=self.engine)
|
||||
|
||||
session = self.session_factory()
|
||||
proj = NamespacedProjectModel(
|
||||
namespaced_name="bench/domain-project",
|
||||
namespace="bench",
|
||||
description="Domain conversion bench",
|
||||
invariants_json=json.dumps(["inv-1", "inv-2", "inv-3"]),
|
||||
tags_json=json.dumps(["tag-a", "tag-b"]),
|
||||
created_at=_now_iso(),
|
||||
updated_at=_now_iso(),
|
||||
)
|
||||
session.add(proj)
|
||||
session.commit()
|
||||
session.close()
|
||||
|
||||
def teardown(self) -> None:
|
||||
self.engine.dispose()
|
||||
|
||||
def time_to_domain_conversion(self) -> None:
|
||||
session = self.session_factory()
|
||||
proj = session.get(NamespacedProjectModel, "bench/domain-project")
|
||||
assert proj is not None
|
||||
proj.to_domain()
|
||||
session.close()
|
||||
|
||||
|
||||
class ProjectLinkQuery:
|
||||
"""Benchmark link queries by project name."""
|
||||
|
||||
def setup(self) -> None:
|
||||
self.engine = create_engine("sqlite:///:memory:")
|
||||
event.listen(self.engine, "connect", _set_sqlite_pragma)
|
||||
with self.engine.connect() as conn:
|
||||
conn.execute(text("PRAGMA foreign_keys = ON"))
|
||||
conn.commit()
|
||||
Base.metadata.create_all(self.engine)
|
||||
self.session_factory = sessionmaker(bind=self.engine)
|
||||
|
||||
session = self.session_factory()
|
||||
rt = ResourceTypeModel()
|
||||
rt.name = "bench/git-checkout"
|
||||
rt.namespace = "bench"
|
||||
rt.resource_kind = "physical"
|
||||
rt.user_addable = True
|
||||
rt.created_at = _now_iso()
|
||||
rt.updated_at = _now_iso()
|
||||
session.add(rt)
|
||||
|
||||
proj = NamespacedProjectModel(
|
||||
namespaced_name="bench/query-project",
|
||||
namespace="bench",
|
||||
tags_json="[]",
|
||||
created_at=_now_iso(),
|
||||
updated_at=_now_iso(),
|
||||
)
|
||||
session.add(proj)
|
||||
|
||||
for i in range(30):
|
||||
r = ResourceModel()
|
||||
r.resource_id = _make_ulid(i + 2000)
|
||||
r.type_name = "bench/git-checkout"
|
||||
r.resource_kind = "physical"
|
||||
r.created_at = _now_iso()
|
||||
r.updated_at = _now_iso()
|
||||
session.add(r)
|
||||
|
||||
link = ProjectResourceLinkModel(
|
||||
link_id=_make_ulid(i + 3000),
|
||||
project_name="bench/query-project",
|
||||
resource_id=_make_ulid(i + 2000),
|
||||
read_only=False,
|
||||
created_at=_now_iso(),
|
||||
)
|
||||
session.add(link)
|
||||
|
||||
session.commit()
|
||||
session.close()
|
||||
|
||||
def teardown(self) -> None:
|
||||
self.engine.dispose()
|
||||
|
||||
def time_query_30_links_by_project(self) -> None:
|
||||
session = self.session_factory()
|
||||
links = (
|
||||
session.query(ProjectResourceLinkModel)
|
||||
.filter(ProjectResourceLinkModel.project_name == "bench/query-project")
|
||||
.all()
|
||||
)
|
||||
assert len(links) == 30
|
||||
session.close()
|
||||
Reference in New Issue
Block a user