264 lines
7.6 KiB
Python
Raw Normal View History

2025-11-04 05:17:27 +01:00
import json
import sqlite3
import time
from typing import List, Optional
2025-11-04 08:09:12 +01:00
2025-11-04 05:17:27 +01:00
from .workflow_definition import Workflow
2025-11-04 08:09:12 +01:00
2025-11-04 05:17:27 +01:00
class WorkflowStorage:
def __init__(self, db_path: str):
self.db_path = db_path
self._initialize_storage()
def _initialize_storage(self):
conn = sqlite3.connect(self.db_path, check_same_thread=False)
cursor = conn.cursor()
2025-11-04 08:09:12 +01:00
cursor.execute(
"""
2025-11-04 05:17:27 +01:00
CREATE TABLE IF NOT EXISTS workflows (
workflow_id TEXT PRIMARY KEY,
name TEXT NOT NULL,
description TEXT,
workflow_data TEXT NOT NULL,
created_at INTEGER NOT NULL,
updated_at INTEGER NOT NULL,
execution_count INTEGER DEFAULT 0,
last_execution_at INTEGER,
tags TEXT
)
2025-11-04 08:09:12 +01:00
"""
)
2025-11-04 05:17:27 +01:00
2025-11-04 08:09:12 +01:00
cursor.execute(
"""
2025-11-04 05:17:27 +01:00
CREATE TABLE IF NOT EXISTS workflow_executions (
execution_id TEXT PRIMARY KEY,
workflow_id TEXT NOT NULL,
started_at INTEGER NOT NULL,
completed_at INTEGER,
status TEXT NOT NULL,
execution_log TEXT,
variables TEXT,
step_results TEXT,
FOREIGN KEY (workflow_id) REFERENCES workflows(workflow_id)
)
2025-11-04 08:09:12 +01:00
"""
)
2025-11-04 05:17:27 +01:00
2025-11-04 08:09:12 +01:00
cursor.execute(
"""
2025-11-04 05:17:27 +01:00
CREATE INDEX IF NOT EXISTS idx_workflow_name ON workflows(name)
2025-11-04 08:09:12 +01:00
"""
)
cursor.execute(
"""
2025-11-04 05:17:27 +01:00
CREATE INDEX IF NOT EXISTS idx_execution_workflow ON workflow_executions(workflow_id)
2025-11-04 08:09:12 +01:00
"""
)
cursor.execute(
"""
2025-11-04 05:17:27 +01:00
CREATE INDEX IF NOT EXISTS idx_execution_started ON workflow_executions(started_at)
2025-11-04 08:09:12 +01:00
"""
)
2025-11-04 05:17:27 +01:00
conn.commit()
conn.close()
def save_workflow(self, workflow: Workflow) -> str:
import hashlib
workflow_data = json.dumps(workflow.to_dict())
workflow_id = hashlib.sha256(workflow.name.encode()).hexdigest()[:16]
conn = sqlite3.connect(self.db_path, check_same_thread=False)
cursor = conn.cursor()
current_time = int(time.time())
tags_json = json.dumps(workflow.tags)
2025-11-04 08:09:12 +01:00
cursor.execute(
"""
2025-11-04 05:17:27 +01:00
INSERT OR REPLACE INTO workflows
(workflow_id, name, description, workflow_data, created_at, updated_at, tags)
VALUES (?, ?, ?, ?, ?, ?, ?)
2025-11-04 08:09:12 +01:00
""",
(
workflow_id,
workflow.name,
workflow.description,
workflow_data,
current_time,
current_time,
tags_json,
),
)
2025-11-04 05:17:27 +01:00
conn.commit()
conn.close()
return workflow_id
def load_workflow(self, workflow_id: str) -> Optional[Workflow]:
conn = sqlite3.connect(self.db_path, check_same_thread=False)
cursor = conn.cursor()
2025-11-04 08:09:12 +01:00
cursor.execute(
"SELECT workflow_data FROM workflows WHERE workflow_id = ?", (workflow_id,)
)
2025-11-04 05:17:27 +01:00
row = cursor.fetchone()
conn.close()
if row:
workflow_dict = json.loads(row[0])
return Workflow.from_dict(workflow_dict)
return None
def load_workflow_by_name(self, name: str) -> Optional[Workflow]:
conn = sqlite3.connect(self.db_path, check_same_thread=False)
cursor = conn.cursor()
2025-11-04 08:09:12 +01:00
cursor.execute("SELECT workflow_data FROM workflows WHERE name = ?", (name,))
2025-11-04 05:17:27 +01:00
row = cursor.fetchone()
conn.close()
if row:
workflow_dict = json.loads(row[0])
return Workflow.from_dict(workflow_dict)
return None
def list_workflows(self, tag: Optional[str] = None) -> List[dict]:
conn = sqlite3.connect(self.db_path, check_same_thread=False)
cursor = conn.cursor()
if tag:
2025-11-04 08:09:12 +01:00
cursor.execute(
"""
2025-11-04 05:17:27 +01:00
SELECT workflow_id, name, description, execution_count, last_execution_at, tags
FROM workflows
WHERE tags LIKE ?
ORDER BY name
2025-11-04 08:09:12 +01:00
""",
(f'%"{tag}"%',),
)
2025-11-04 05:17:27 +01:00
else:
2025-11-04 08:09:12 +01:00
cursor.execute(
"""
2025-11-04 05:17:27 +01:00
SELECT workflow_id, name, description, execution_count, last_execution_at, tags
FROM workflows
ORDER BY name
2025-11-04 08:09:12 +01:00
"""
)
2025-11-04 05:17:27 +01:00
workflows = []
for row in cursor.fetchall():
2025-11-04 08:09:12 +01:00
workflows.append(
{
"workflow_id": row[0],
"name": row[1],
"description": row[2],
"execution_count": row[3],
"last_execution_at": row[4],
"tags": json.loads(row[5]) if row[5] else [],
}
)
2025-11-04 05:17:27 +01:00
conn.close()
return workflows
def delete_workflow(self, workflow_id: str) -> bool:
conn = sqlite3.connect(self.db_path, check_same_thread=False)
cursor = conn.cursor()
2025-11-04 08:09:12 +01:00
cursor.execute("DELETE FROM workflows WHERE workflow_id = ?", (workflow_id,))
2025-11-04 05:17:27 +01:00
deleted = cursor.rowcount > 0
2025-11-04 08:09:12 +01:00
cursor.execute(
"DELETE FROM workflow_executions WHERE workflow_id = ?", (workflow_id,)
)
2025-11-04 05:17:27 +01:00
conn.commit()
conn.close()
return deleted
2025-11-04 08:09:12 +01:00
def save_execution(
self, workflow_id: str, execution_context: "WorkflowExecutionContext"
) -> str:
2025-11-04 05:17:27 +01:00
import uuid
execution_id = str(uuid.uuid4())[:16]
conn = sqlite3.connect(self.db_path, check_same_thread=False)
cursor = conn.cursor()
2025-11-04 08:09:12 +01:00
started_at = (
int(execution_context.execution_log[0]["timestamp"])
if execution_context.execution_log
else int(time.time())
)
2025-11-04 05:17:27 +01:00
completed_at = int(time.time())
2025-11-04 08:09:12 +01:00
cursor.execute(
"""
2025-11-04 05:17:27 +01:00
INSERT INTO workflow_executions
(execution_id, workflow_id, started_at, completed_at, status, execution_log, variables, step_results)
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
2025-11-04 08:09:12 +01:00
""",
(
execution_id,
workflow_id,
started_at,
completed_at,
"completed",
json.dumps(execution_context.execution_log),
json.dumps(execution_context.variables),
json.dumps(execution_context.step_results),
),
)
cursor.execute(
"""
2025-11-04 05:17:27 +01:00
UPDATE workflows
SET execution_count = execution_count + 1,
last_execution_at = ?
WHERE workflow_id = ?
2025-11-04 08:09:12 +01:00
""",
(completed_at, workflow_id),
)
2025-11-04 05:17:27 +01:00
conn.commit()
conn.close()
return execution_id
def get_execution_history(self, workflow_id: str, limit: int = 10) -> List[dict]:
conn = sqlite3.connect(self.db_path, check_same_thread=False)
cursor = conn.cursor()
2025-11-04 08:09:12 +01:00
cursor.execute(
"""
2025-11-04 05:17:27 +01:00
SELECT execution_id, started_at, completed_at, status
FROM workflow_executions
WHERE workflow_id = ?
ORDER BY started_at DESC
LIMIT ?
2025-11-04 08:09:12 +01:00
""",
(workflow_id, limit),
)
2025-11-04 05:17:27 +01:00
executions = []
for row in cursor.fetchall():
2025-11-04 08:09:12 +01:00
executions.append(
{
"execution_id": row[0],
"started_at": row[1],
"completed_at": row[2],
"status": row[3],
}
)
2025-11-04 05:17:27 +01:00
conn.close()
return executions