Skip to content
This repository was archived by the owner on Jun 5, 2025. It is now read-only.

Commit fd757dd

Browse files
authored
Add instance table along with init code. (#1234)
This change adds an `instance` table containing the minimum set of details about codegate. We might want to add more details in the future. The table must contain only a single record at any time. To guarantee that, a trigger is added that prevents inserts beyond the first record. Finally, code performing the initialization is added to the `serve` command.
1 parent 39ea5bf commit fd757dd

File tree

4 files changed

+118
-3
lines changed

4 files changed

+118
-3
lines changed
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
"""add installation table
2+
3+
Revision ID: e4c05d7591a8
4+
Revises: 3ec2b4ab569c
5+
Create Date: 2025-03-05 21:26:19.034319+00:00
6+
7+
"""
8+
9+
from typing import Sequence, Union
10+
11+
from alembic import op
12+
import sqlalchemy as sa
13+
14+
15+
# revision identifiers, used by Alembic.
16+
revision: str = "e4c05d7591a8"
17+
down_revision: Union[str, None] = "3ec2b4ab569c"
18+
branch_labels: Union[str, Sequence[str], None] = None
19+
depends_on: Union[str, Sequence[str], None] = None
20+
21+
22+
def upgrade() -> None:
23+
op.execute("BEGIN TRANSACTION;")
24+
25+
op.execute(
26+
"""
27+
CREATE TABLE IF NOT EXISTS instance (
28+
id TEXT PRIMARY KEY, -- UUID stored as TEXT
29+
created_at DATETIME NOT NULL
30+
);
31+
"""
32+
)
33+
34+
op.execute(
35+
"""
36+
-- The following trigger prevents multiple insertions in the
37+
-- instance table. It is safe since the dimension of the table
38+
-- is fixed.
39+
40+
CREATE TRIGGER single_instance
41+
BEFORE INSERT ON instance
42+
WHEN (SELECT COUNT(*) FROM instance) >= 1
43+
BEGIN
44+
SELECT RAISE(FAIL, 'only one instance!');
45+
END;
46+
"""
47+
)
48+
49+
# Finish transaction
50+
op.execute("COMMIT;")
51+
52+
53+
def downgrade() -> None:
54+
op.execute("BEGIN TRANSACTION;")
55+
56+
op.execute(
57+
"""
58+
DROP TABLE instance;
59+
"""
60+
)
61+
62+
# Finish transaction
63+
op.execute("COMMIT;")

src/codegate/cli.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,11 @@
1414
from codegate.ca.codegate_ca import CertificateAuthority
1515
from codegate.codegate_logging import LogFormat, LogLevel, setup_logging
1616
from codegate.config import Config, ConfigurationError
17-
from codegate.db.connection import init_db_sync, init_session_if_not_exists
17+
from codegate.db.connection import (
18+
init_db_sync,
19+
init_session_if_not_exists,
20+
init_instance,
21+
)
1822
from codegate.pipeline.factory import PipelineFactory
1923
from codegate.pipeline.sensitive_data.manager import SensitiveDataManager
2024
from codegate.providers import crud as provendcrud
@@ -318,6 +322,7 @@ def serve( # noqa: C901
318322
logger = structlog.get_logger("codegate").bind(origin="cli")
319323

320324
init_db_sync(cfg.db_path)
325+
init_instance(cfg.db_path)
321326
init_session_if_not_exists(cfg.db_path)
322327

323328
# Check certificates and create CA if necessary

src/codegate/db/connection.py

Lines changed: 44 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import asyncio
2+
import datetime
23
import json
34
import sqlite3
45
import uuid
@@ -23,6 +24,7 @@
2324
Alert,
2425
GetPromptWithOutputsRow,
2526
GetWorkspaceByNameConditions,
27+
Instance,
2628
IntermediatePromptWithOutputUsageAlerts,
2729
MuxRule,
2830
Output,
@@ -596,6 +598,27 @@ async def delete_persona(self, persona_id: str) -> None:
596598
conditions = {"id": persona_id}
597599
await self._execute_with_no_return(sql, conditions)
598600

601+
async def init_instance(self) -> None:
602+
"""
603+
Initializes instance details in the database.
604+
"""
605+
sql = text(
606+
"""
607+
INSERT INTO instance (id, created_at)
608+
VALUES (:id, :created_at)
609+
"""
610+
)
611+
612+
try:
613+
instance = Instance(
614+
id=str(uuid.uuid4()),
615+
created_at=datetime.datetime.now(datetime.timezone.utc),
616+
)
617+
await self._execute_with_no_return(sql, instance.model_dump())
618+
except IntegrityError as e:
619+
logger.debug(f"Exception type: {type(e)}")
620+
raise AlreadyExistsError(f"Instance already initialized.")
621+
599622

600623
class DbReader(DbCodeGate):
601624
def __init__(self, sqlite_path: Optional[str] = None, *args, **kwargs):
@@ -1098,6 +1121,13 @@ async def get_all_personas(self) -> List[Persona]:
10981121
personas = await self._execute_select_pydantic_model(Persona, sql, should_raise=True)
10991122
return personas
11001123

1124+
async def get_instance(self) -> Instance:
1125+
"""
1126+
Get the details of the instance.
1127+
"""
1128+
sql = text("SELECT id, created_at FROM instance")
1129+
return await self._execute_select_pydantic_model(Instance, sql)
1130+
11011131

11021132
class DbTransaction:
11031133
def __init__(self):
@@ -1148,8 +1178,6 @@ def init_db_sync(db_path: Optional[str] = None):
11481178

11491179

11501180
def init_session_if_not_exists(db_path: Optional[str] = None):
1151-
import datetime
1152-
11531181
db_reader = DbReader(db_path)
11541182
sessions = asyncio.run(db_reader.get_sessions())
11551183
# If there are no sessions, create a new one
@@ -1169,5 +1197,19 @@ def init_session_if_not_exists(db_path: Optional[str] = None):
11691197
logger.info("Session in DB initialized successfully.")
11701198

11711199

1200+
def init_instance(db_path: Optional[str] = None):
1201+
db_reader = DbReader(db_path)
1202+
instance = asyncio.run(db_reader.get_instance())
1203+
# Initialize instance if not already initialized.
1204+
if not instance:
1205+
db_recorder = DbRecorder(db_path)
1206+
try:
1207+
asyncio.run(db_recorder.init_instance())
1208+
except Exception as e:
1209+
logger.error(f"Failed to initialize instance in DB: {e}")
1210+
raise
1211+
logger.info("Instance initialized successfully.")
1212+
1213+
11721214
if __name__ == "__main__":
11731215
init_db_sync()

src/codegate/db/models.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,11 @@ class Session(BaseModel):
128128
last_update: datetime.datetime
129129

130130

131+
class Instance(BaseModel):
132+
id: str
133+
created_at: datetime.datetime
134+
135+
131136
# Models for select queries
132137

133138

0 commit comments

Comments
 (0)