quantum-framework 0.18.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- quantum/__init__.py +1 -0
- quantum/cli/__init__.py +2 -0
- quantum/cli/admin.py +131 -0
- quantum/cli/check.py +223 -0
- quantum/cli/commands/__init__.py +15 -0
- quantum/cli/commands/build.py +414 -0
- quantum/cli/commands/dev.py +185 -0
- quantum/cli/commands/docs.py +329 -0
- quantum/cli/commands/lint.py +523 -0
- quantum/cli/commands/migrate.py +548 -0
- quantum/cli/commands/new.py +622 -0
- quantum/cli/commands/serve.py +190 -0
- quantum/cli/commands/test.py +193 -0
- quantum/cli/deploy.py +810 -0
- quantum/cli/hot_reload.py +951 -0
- quantum/cli/jobs.py +356 -0
- quantum/cli/mq.py +582 -0
- quantum/cli/pkg.py +390 -0
- quantum/cli/runner.py +565 -0
- quantum/cli/server_process.py +159 -0
- quantum/cli/utils.py +334 -0
- quantum/compiler/__init__.py +30 -0
- quantum/compiler/base_generator.py +367 -0
- quantum/compiler/cli.py +295 -0
- quantum/compiler/expression_transformer.py +444 -0
- quantum/compiler/javascript/__init__.py +10 -0
- quantum/compiler/javascript/generator.py +659 -0
- quantum/compiler/optimizer.py +270 -0
- quantum/compiler/python/__init__.py +10 -0
- quantum/compiler/python/generator.py +883 -0
- quantum/compiler/python/runtime.py +863 -0
- quantum/compiler/transpiler.py +330 -0
- quantum/core/__init__.py +3 -0
- quantum/core/ast_nodes.py +2619 -0
- quantum/core/config_env.py +54 -0
- quantum/core/docs_links.py +8 -0
- quantum/core/expression_diagnostics.py +87 -0
- quantum/core/expression_stdlib.py +208 -0
- quantum/core/expressions.py +677 -0
- quantum/core/features/agents/src/__init__.py +30 -0
- quantum/core/features/agents/src/ast_node.py +540 -0
- quantum/core/features/conditionals/src/__init__.py +8 -0
- quantum/core/features/conditionals/src/ast_node.py +68 -0
- quantum/core/features/data_import/src/__init__.py +0 -0
- quantum/core/features/data_import/src/ast_node.py +292 -0
- quantum/core/features/data_import/src/runtime.py +533 -0
- quantum/core/features/dump/src/__init__.py +12 -0
- quantum/core/features/dump/src/ast_node.py +106 -0
- quantum/core/features/dump/src/parser.py +61 -0
- quantum/core/features/dump/src/runtime.py +246 -0
- quantum/core/features/functions/src/__init__.py +8 -0
- quantum/core/features/functions/src/ast_node.py +149 -0
- quantum/core/features/game_engine_2d/src/__init__.py +19 -0
- quantum/core/features/game_engine_2d/src/ast_nodes.py +1719 -0
- quantum/core/features/game_engine_2d/src/parser.py +983 -0
- quantum/core/features/invocation/src/__init__.py +0 -0
- quantum/core/features/invocation/src/ast_node.py +147 -0
- quantum/core/features/invocation/src/runtime.py +332 -0
- quantum/core/features/knowledge_base/src/__init__.py +6 -0
- quantum/core/features/knowledge_base/src/ast_node.py +113 -0
- quantum/core/features/knowledge_base/src/parser.py +82 -0
- quantum/core/features/logging/src/__init__.py +12 -0
- quantum/core/features/logging/src/ast_node.py +111 -0
- quantum/core/features/logging/src/parser.py +50 -0
- quantum/core/features/logging/src/runtime.py +190 -0
- quantum/core/features/loops/src/__init__.py +8 -0
- quantum/core/features/loops/src/ast_node.py +60 -0
- quantum/core/features/query/src/__init__.py +0 -0
- quantum/core/features/query/src/query_validators.py +20 -0
- quantum/core/features/state_management/src/__init__.py +11 -0
- quantum/core/features/state_management/src/ast_node.py +121 -0
- quantum/core/features/terminal_engine/src/__init__.py +21 -0
- quantum/core/features/terminal_engine/src/ast_nodes.py +560 -0
- quantum/core/features/terminal_engine/src/parser.py +361 -0
- quantum/core/features/testing_engine/src/__init__.py +41 -0
- quantum/core/features/testing_engine/src/ast_nodes.py +1212 -0
- quantum/core/features/testing_engine/src/parser.py +604 -0
- quantum/core/features/theming/src/__init__.py +48 -0
- quantum/core/features/theming/src/ast_node.py +137 -0
- quantum/core/features/theming/src/presets.py +405 -0
- quantum/core/features/ui_engine/src/__init__.py +20 -0
- quantum/core/features/ui_engine/src/ast_nodes.py +1913 -0
- quantum/core/features/ui_engine/src/parser.py +1192 -0
- quantum/core/features/websocket/src/__init__.py +24 -0
- quantum/core/features/websocket/src/ast_node.py +247 -0
- quantum/core/guards.py +53 -0
- quantum/core/html_compat.py +299 -0
- quantum/core/parser.py +1551 -0
- quantum/core/parser_registry.py +213 -0
- quantum/core/parsers/__init__.py +76 -0
- quantum/core/parsers/ai/__init__.py +12 -0
- quantum/core/parsers/ai/agent_parser.py +106 -0
- quantum/core/parsers/ai/knowledge_parser.py +86 -0
- quantum/core/parsers/ai/llm_parser.py +78 -0
- quantum/core/parsers/ai/team_parser.py +88 -0
- quantum/core/parsers/base.py +322 -0
- quantum/core/parsers/composition/__init__.py +10 -0
- quantum/core/parsers/composition/import_parser.py +50 -0
- quantum/core/parsers/composition/slot_parser.py +48 -0
- quantum/core/parsers/control_flow/__init__.py +11 -0
- quantum/core/parsers/control_flow/if_parser.py +71 -0
- quantum/core/parsers/control_flow/loop_parser.py +105 -0
- quantum/core/parsers/control_flow/set_parser.py +93 -0
- quantum/core/parsers/data/__init__.py +12 -0
- quantum/core/parsers/data/data_parser.py +229 -0
- quantum/core/parsers/data/invoke_parser.py +133 -0
- quantum/core/parsers/data/query_parser.py +213 -0
- quantum/core/parsers/data/transaction_parser.py +86 -0
- quantum/core/parsers/events/__init__.py +9 -0
- quantum/core/parsers/events/dispatch_event_parser.py +44 -0
- quantum/core/parsers/forms/__init__.py +11 -0
- quantum/core/parsers/forms/action_parser.py +79 -0
- quantum/core/parsers/forms/flash_parser.py +34 -0
- quantum/core/parsers/forms/redirect_parser.py +33 -0
- quantum/core/parsers/functions/__init__.py +11 -0
- quantum/core/parsers/functions/function_parser.py +98 -0
- quantum/core/parsers/functions/param_parser.py +73 -0
- quantum/core/parsers/functions/return_parser.py +31 -0
- quantum/core/parsers/html/__init__.py +10 -0
- quantum/core/parsers/html/component_call_parser.py +130 -0
- quantum/core/parsers/html/html_parser.py +115 -0
- quantum/core/parsers/jobs/__init__.py +11 -0
- quantum/core/parsers/jobs/job_parser.py +71 -0
- quantum/core/parsers/jobs/schedule_parser.py +62 -0
- quantum/core/parsers/jobs/thread_parser.py +57 -0
- quantum/core/parsers/messaging/__init__.py +17 -0
- quantum/core/parsers/messaging/message_ack_parser.py +30 -0
- quantum/core/parsers/messaging/message_nack_parser.py +30 -0
- quantum/core/parsers/messaging/message_parser.py +114 -0
- quantum/core/parsers/messaging/queue_parser.py +61 -0
- quantum/core/parsers/messaging/websocket_parser.py +121 -0
- quantum/core/parsers/routing/__init__.py +9 -0
- quantum/core/parsers/routing/route_parser.py +41 -0
- quantum/core/parsers/scripting/__init__.py +12 -0
- quantum/core/parsers/scripting/pyclass_parser.py +62 -0
- quantum/core/parsers/scripting/pydecorator_parser.py +68 -0
- quantum/core/parsers/scripting/pyimport_parser.py +52 -0
- quantum/core/parsers/scripting/python_parser.py +49 -0
- quantum/core/parsers/services/__init__.py +12 -0
- quantum/core/parsers/services/dump_parser.py +52 -0
- quantum/core/parsers/services/file_parser.py +48 -0
- quantum/core/parsers/services/log_parser.py +46 -0
- quantum/core/parsers/services/mail_parser.py +65 -0
- quantum/core/tiers.py +164 -0
- quantum/core/xml_lines.py +81 -0
- quantum/packages/__init__.py +28 -0
- quantum/packages/manager.py +413 -0
- quantum/packages/manifest.py +351 -0
- quantum/packages/registry.py +399 -0
- quantum/packages/resolver.py +336 -0
- quantum/plugins/__init__.py +33 -0
- quantum/plugins/hooks.py +329 -0
- quantum/plugins/loader.py +479 -0
- quantum/plugins/manifest.py +336 -0
- quantum/plugins/registry.py +371 -0
- quantum/runtime/__init__.py +25 -0
- quantum/runtime/action_handler.py +532 -0
- quantum/runtime/adapters/__init__.py +88 -0
- quantum/runtime/adapters/memory_adapter.py +690 -0
- quantum/runtime/adapters/rabbitmq_adapter.py +715 -0
- quantum/runtime/adapters/redis_adapter.py +582 -0
- quantum/runtime/adapters/sqlite_adapter.py +414 -0
- quantum/runtime/agent_service.py +1133 -0
- quantum/runtime/ast_cache.py +506 -0
- quantum/runtime/auth_service.py +267 -0
- quantum/runtime/component.py +1048 -0
- quantum/runtime/component_composer.py +133 -0
- quantum/runtime/component_resolver.py +174 -0
- quantum/runtime/conditions.py +54 -0
- quantum/runtime/database_service.py +595 -0
- quantum/runtime/db_schema.py +100 -0
- quantum/runtime/dev_panel.py +178 -0
- quantum/runtime/email_service.py +162 -0
- quantum/runtime/error_handler.py +295 -0
- quantum/runtime/execution_context.py +283 -0
- quantum/runtime/executor_registry.py +178 -0
- quantum/runtime/executors/__init__.py +71 -0
- quantum/runtime/executors/ai/__init__.py +12 -0
- quantum/runtime/executors/ai/agent_executor.py +217 -0
- quantum/runtime/executors/ai/knowledge_executor.py +114 -0
- quantum/runtime/executors/ai/llm_executor.py +153 -0
- quantum/runtime/executors/ai/team_executor.py +171 -0
- quantum/runtime/executors/base.py +264 -0
- quantum/runtime/executors/control_flow/__init__.py +12 -0
- quantum/runtime/executors/control_flow/if_executor.py +98 -0
- quantum/runtime/executors/control_flow/loop_executor.py +308 -0
- quantum/runtime/executors/control_flow/redirect_executor.py +43 -0
- quantum/runtime/executors/control_flow/set_executor.py +464 -0
- quantum/runtime/executors/data/__init__.py +12 -0
- quantum/runtime/executors/data/data_executor.py +156 -0
- quantum/runtime/executors/data/invoke_executor.py +228 -0
- quantum/runtime/executors/data/query_executor.py +290 -0
- quantum/runtime/executors/data/transaction_executor.py +91 -0
- quantum/runtime/executors/jobs/__init__.py +11 -0
- quantum/runtime/executors/jobs/job_executor.py +190 -0
- quantum/runtime/executors/jobs/schedule_executor.py +132 -0
- quantum/runtime/executors/jobs/thread_executor.py +127 -0
- quantum/runtime/executors/messaging/__init__.py +17 -0
- quantum/runtime/executors/messaging/message_ack_executor.py +51 -0
- quantum/runtime/executors/messaging/message_executor.py +174 -0
- quantum/runtime/executors/messaging/queue_executor.py +103 -0
- quantum/runtime/executors/messaging/websocket_executor.py +197 -0
- quantum/runtime/executors/scripting/__init__.py +11 -0
- quantum/runtime/executors/scripting/pyclass_executor.py +90 -0
- quantum/runtime/executors/scripting/pyimport_executor.py +81 -0
- quantum/runtime/executors/scripting/python_executor.py +249 -0
- quantum/runtime/executors/services/__init__.py +12 -0
- quantum/runtime/executors/services/dump_executor.py +72 -0
- quantum/runtime/executors/services/file_executor.py +89 -0
- quantum/runtime/executors/services/log_executor.py +77 -0
- quantum/runtime/executors/services/mail_executor.py +81 -0
- quantum/runtime/expression_cache.py +498 -0
- quantum/runtime/file_upload_service.py +326 -0
- quantum/runtime/function_registry.py +118 -0
- quantum/runtime/game_builder.py +166 -0
- quantum/runtime/game_code_generator.py +2371 -0
- quantum/runtime/game_templates.py +2006 -0
- quantum/runtime/godot_code_generator.py +4681 -0
- quantum/runtime/godot_templates.py +1449 -0
- quantum/runtime/job_executor.py +1599 -0
- quantum/runtime/knowledge_service.py +546 -0
- quantum/runtime/llm_cache.py +100 -0
- quantum/runtime/llm_providers.py +704 -0
- quantum/runtime/llm_service.py +287 -0
- quantum/runtime/local_server.py +28 -0
- quantum/runtime/logging_setup.py +141 -0
- quantum/runtime/message_broker.py +364 -0
- quantum/runtime/message_queue_service.py +571 -0
- quantum/runtime/param_validation.py +218 -0
- quantum/runtime/pypy_compat.py +317 -0
- quantum/runtime/python_bridge.py +698 -0
- quantum/runtime/query_validators.py +304 -0
- quantum/runtime/renderer.py +734 -0
- quantum/runtime/service_container.py +470 -0
- quantum/runtime/table_params.py +163 -0
- quantum/runtime/terminal_builder.py +76 -0
- quantum/runtime/terminal_code_generator.py +607 -0
- quantum/runtime/terminal_templates.py +243 -0
- quantum/runtime/testing_builder.py +77 -0
- quantum/runtime/testing_code_generator.py +833 -0
- quantum/runtime/testing_templates.py +85 -0
- quantum/runtime/ui_builder.py +222 -0
- quantum/runtime/ui_console.py +405 -0
- quantum/runtime/ui_desktop.py +56 -0
- quantum/runtime/ui_form_rules.py +193 -0
- quantum/runtime/ui_html_adapter.py +2567 -0
- quantum/runtime/ui_html_templates.py +2106 -0
- quantum/runtime/ui_mobile_adapter.py +1832 -0
- quantum/runtime/ui_mobile_templates.py +1003 -0
- quantum/runtime/ui_page_renderer.py +392 -0
- quantum/runtime/ui_pager.py +73 -0
- quantum/runtime/ui_table_edit.py +139 -0
- quantum/runtime/ui_textual_adapter.py +1866 -0
- quantum/runtime/ui_textual_templates.py +45 -0
- quantum/runtime/ui_tokens.py +465 -0
- quantum/runtime/ui_validator.py +365 -0
- quantum/runtime/ui_view.py +221 -0
- quantum/runtime/validators.py +256 -0
- quantum/runtime/web_server.py +2131 -0
- quantum/runtime/websocket_adapter.py +501 -0
- quantum/runtime/websocket_service.py +585 -0
- quantum/runtime/websocket_transport.py +289 -0
- quantum/runtime/wsgi.py +101 -0
- quantum/services.py +109 -0
- quantum/utils/__init__.py +1 -0
- quantum_admin/__init__.py +4 -0
- quantum_admin/assets/quantum-admin-connectors.js +123 -0
- quantum_admin/assets/quantum-admin.css +2058 -0
- quantum_admin/assets/quantum-source-highlight.js +106 -0
- quantum_admin/backend/__init__.py +4 -0
- quantum_admin/backend/audit_service.py +346 -0
- quantum_admin/backend/auth_service.py +394 -0
- quantum_admin/backend/component_discovery.py +766 -0
- quantum_admin/backend/config_generator.py +586 -0
- quantum_admin/backend/connector_service.py +1016 -0
- quantum_admin/backend/crud.py +557 -0
- quantum_admin/backend/database.py +226 -0
- quantum_admin/backend/db_setup_service.py +193 -0
- quantum_admin/backend/deploy_service.py +698 -0
- quantum_admin/backend/docker_service.py +422 -0
- quantum_admin/backend/environment_service.py +418 -0
- quantum_admin/backend/git_service.py +370 -0
- quantum_admin/backend/health_service.py +390 -0
- quantum_admin/backend/job_service.py +347 -0
- quantum_admin/backend/log_service.py +331 -0
- quantum_admin/backend/main.py +14426 -0
- quantum_admin/backend/models.py +986 -0
- quantum_admin/backend/pipeline_service.py +812 -0
- quantum_admin/backend/resource_manager.py +1118 -0
- quantum_admin/backend/schemas.py +419 -0
- quantum_admin/backend/secret_manager.py +277 -0
- quantum_admin/backend/settings_service.py +488 -0
- quantum_admin/backend/template_service.py +710 -0
- quantum_admin/backend/test_execution_service.py +364 -0
- quantum_admin/backend/test_generator.py +782 -0
- quantum_admin/backend/webhook_service.py +454 -0
- quantum_admin/backend/websocket_manager.py +360 -0
- quantum_admin/components/admin/_layout/AdminShell.q +121 -0
- quantum_admin/components/admin/agents.q +107 -0
- quantum_admin/components/admin/app/[name].q +558 -0
- quantum_admin/components/admin/applications.q +160 -0
- quantum_admin/components/admin/component/[...path].q +205 -0
- quantum_admin/components/admin/components.q +59 -0
- quantum_admin/components/admin/connectors.q +283 -0
- quantum_admin/components/admin/dashboard.q +86 -0
- quantum_admin/components/admin/database.q +95 -0
- quantum_admin/components/admin/features.q +69 -0
- quantum_admin/components/admin/index.q +12 -0
- quantum_admin/components/admin/jobs.q +75 -0
- quantum_admin/components/admin/login.q +65 -0
- quantum_admin/components/admin/logout.q +11 -0
- quantum_admin/components/admin/settings.q +174 -0
- quantum_admin/components/admin/source.q +45 -0
- quantum_admin/components/admin/tests.q +73 -0
- quantum_admin/run.py +13 -0
- quantum_admin/services/__init__.py +16 -0
- quantum_admin/services/_base.py +84 -0
- quantum_admin/services/_component_test_generator.py +205 -0
- quantum_admin/services/_yaml_editor.py +82 -0
- quantum_admin/services/apps.py +330 -0
- quantum_admin/services/auth.py +61 -0
- quantum_admin/services/components.py +210 -0
- quantum_admin/services/connectors.py +164 -0
- quantum_admin/services/projects.py +189 -0
- quantum_admin/services/repository.py +223 -0
- quantum_admin/services/settings.py +150 -0
- quantum_admin/services/yaml_import.py +118 -0
- quantum_framework-0.18.0.dist-info/METADATA +281 -0
- quantum_framework-0.18.0.dist-info/RECORD +333 -0
- quantum_framework-0.18.0.dist-info/WHEEL +5 -0
- quantum_framework-0.18.0.dist-info/entry_points.txt +2 -0
- quantum_framework-0.18.0.dist-info/licenses/LICENSE +21 -0
- quantum_framework-0.18.0.dist-info/top_level.txt +2 -0
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Database configuration and session management
|
|
3
|
+
"""
|
|
4
|
+
import os
|
|
5
|
+
from datetime import datetime
|
|
6
|
+
from sqlalchemy import create_engine
|
|
7
|
+
from sqlalchemy.orm import sessionmaker
|
|
8
|
+
from .models import Base
|
|
9
|
+
|
|
10
|
+
# SQLite database file location - use absolute path relative to quantum_admin folder
|
|
11
|
+
_QUANTUM_ADMIN_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
|
12
|
+
_DB_PATH = os.path.join(_QUANTUM_ADMIN_DIR, "quantum_admin.db")
|
|
13
|
+
|
|
14
|
+
# QUANTUM_ADMIN_DATABASE_URL overrides the location. The path used to be fixed,
|
|
15
|
+
# so the admin test suite created and deleted rows in the same database the
|
|
16
|
+
# admin serves — every `pytest` run wrote into the developer's real data.
|
|
17
|
+
DATABASE_URL = os.environ.get("QUANTUM_ADMIN_DATABASE_URL") or f"sqlite:///{_DB_PATH}"
|
|
18
|
+
|
|
19
|
+
# Create engine with SQLite-specific settings
|
|
20
|
+
engine = create_engine(
|
|
21
|
+
DATABASE_URL,
|
|
22
|
+
connect_args={"check_same_thread": False} if DATABASE_URL.startswith("sqlite") else {},
|
|
23
|
+
echo=False # Set to True for SQL query logging during development
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
# Create session factory
|
|
27
|
+
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def init_db():
|
|
31
|
+
"""
|
|
32
|
+
Initialize database - create all tables
|
|
33
|
+
Call this on application startup
|
|
34
|
+
"""
|
|
35
|
+
Base.metadata.create_all(bind=engine)
|
|
36
|
+
print("[OK] Database initialized successfully")
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def seed_db():
|
|
40
|
+
"""
|
|
41
|
+
Seed database with sample data if empty
|
|
42
|
+
"""
|
|
43
|
+
from . import models
|
|
44
|
+
import uuid
|
|
45
|
+
|
|
46
|
+
db = SessionLocal()
|
|
47
|
+
try:
|
|
48
|
+
# Check if we already have data
|
|
49
|
+
existing_projects = db.query(models.Project).first()
|
|
50
|
+
if existing_projects:
|
|
51
|
+
print("[OK] Database already has data, skipping seed")
|
|
52
|
+
return
|
|
53
|
+
|
|
54
|
+
print("[INFO] Seeding database with sample data...")
|
|
55
|
+
|
|
56
|
+
# Create sample projects
|
|
57
|
+
projects = [
|
|
58
|
+
models.Project(
|
|
59
|
+
name="Blog Application",
|
|
60
|
+
description="A full-featured blog with posts, comments, and user authentication",
|
|
61
|
+
status="active"
|
|
62
|
+
),
|
|
63
|
+
models.Project(
|
|
64
|
+
name="E-Commerce API",
|
|
65
|
+
description="REST API for an e-commerce platform with products, orders, and payments",
|
|
66
|
+
status="active"
|
|
67
|
+
),
|
|
68
|
+
models.Project(
|
|
69
|
+
name="Dashboard App",
|
|
70
|
+
description="Real-time analytics dashboard with charts and data visualization",
|
|
71
|
+
status="inactive"
|
|
72
|
+
),
|
|
73
|
+
]
|
|
74
|
+
for p in projects:
|
|
75
|
+
db.add(p)
|
|
76
|
+
db.flush()
|
|
77
|
+
|
|
78
|
+
# Create sample connectors (id is String, required)
|
|
79
|
+
connectors = [
|
|
80
|
+
models.Connector(
|
|
81
|
+
id="postgres-prod",
|
|
82
|
+
name="PostgreSQL Production",
|
|
83
|
+
type="database",
|
|
84
|
+
provider="postgres",
|
|
85
|
+
host="db.example.com",
|
|
86
|
+
port=5432,
|
|
87
|
+
database="production",
|
|
88
|
+
status="connected"
|
|
89
|
+
),
|
|
90
|
+
models.Connector(
|
|
91
|
+
id="redis-cache",
|
|
92
|
+
name="Redis Cache",
|
|
93
|
+
type="cache",
|
|
94
|
+
provider="redis",
|
|
95
|
+
host="redis.example.com",
|
|
96
|
+
port=6379,
|
|
97
|
+
status="connected"
|
|
98
|
+
),
|
|
99
|
+
models.Connector(
|
|
100
|
+
id="s3-storage",
|
|
101
|
+
name="AWS S3 Storage",
|
|
102
|
+
type="storage",
|
|
103
|
+
provider="s3",
|
|
104
|
+
database="my-app-files",
|
|
105
|
+
status="disconnected"
|
|
106
|
+
),
|
|
107
|
+
]
|
|
108
|
+
for c in connectors:
|
|
109
|
+
db.add(c)
|
|
110
|
+
|
|
111
|
+
# Create sample environments for first project
|
|
112
|
+
environments = [
|
|
113
|
+
models.Environment(
|
|
114
|
+
name="dev",
|
|
115
|
+
display_name="Development",
|
|
116
|
+
project_id=1,
|
|
117
|
+
order=1,
|
|
118
|
+
branch="develop",
|
|
119
|
+
is_active=True
|
|
120
|
+
),
|
|
121
|
+
models.Environment(
|
|
122
|
+
name="staging",
|
|
123
|
+
display_name="Staging",
|
|
124
|
+
project_id=1,
|
|
125
|
+
order=2,
|
|
126
|
+
branch="staging",
|
|
127
|
+
is_active=True
|
|
128
|
+
),
|
|
129
|
+
models.Environment(
|
|
130
|
+
name="production",
|
|
131
|
+
display_name="Production",
|
|
132
|
+
project_id=1,
|
|
133
|
+
order=3,
|
|
134
|
+
branch="main",
|
|
135
|
+
requires_approval=True,
|
|
136
|
+
is_active=True
|
|
137
|
+
),
|
|
138
|
+
]
|
|
139
|
+
for e in environments:
|
|
140
|
+
db.add(e)
|
|
141
|
+
|
|
142
|
+
# Create sample application logs
|
|
143
|
+
from datetime import timedelta
|
|
144
|
+
sample_logs = [
|
|
145
|
+
models.ApplicationLog(
|
|
146
|
+
project_id=1,
|
|
147
|
+
timestamp=datetime.utcnow() - timedelta(minutes=5),
|
|
148
|
+
level="INFO",
|
|
149
|
+
source="app",
|
|
150
|
+
message="Application started successfully",
|
|
151
|
+
component_name="main"
|
|
152
|
+
),
|
|
153
|
+
models.ApplicationLog(
|
|
154
|
+
project_id=1,
|
|
155
|
+
timestamp=datetime.utcnow() - timedelta(minutes=4),
|
|
156
|
+
level="INFO",
|
|
157
|
+
source="database",
|
|
158
|
+
message="Database connection established",
|
|
159
|
+
response_time_ms=45
|
|
160
|
+
),
|
|
161
|
+
models.ApplicationLog(
|
|
162
|
+
project_id=1,
|
|
163
|
+
timestamp=datetime.utcnow() - timedelta(minutes=3),
|
|
164
|
+
level="INFO",
|
|
165
|
+
source="access",
|
|
166
|
+
message="GET /api/posts 200",
|
|
167
|
+
request_method="GET",
|
|
168
|
+
request_path="/api/posts",
|
|
169
|
+
response_status=200,
|
|
170
|
+
response_time_ms=120
|
|
171
|
+
),
|
|
172
|
+
models.ApplicationLog(
|
|
173
|
+
project_id=1,
|
|
174
|
+
timestamp=datetime.utcnow() - timedelta(minutes=2),
|
|
175
|
+
level="WARNING",
|
|
176
|
+
source="api",
|
|
177
|
+
message="External API rate limit approaching",
|
|
178
|
+
component_name="oauth_service"
|
|
179
|
+
),
|
|
180
|
+
models.ApplicationLog(
|
|
181
|
+
project_id=1,
|
|
182
|
+
timestamp=datetime.utcnow() - timedelta(minutes=1),
|
|
183
|
+
level="INFO",
|
|
184
|
+
source="security",
|
|
185
|
+
message="User login successful: admin@example.com",
|
|
186
|
+
component_name="auth"
|
|
187
|
+
),
|
|
188
|
+
models.ApplicationLog(
|
|
189
|
+
project_id=1,
|
|
190
|
+
timestamp=datetime.utcnow(),
|
|
191
|
+
level="INFO",
|
|
192
|
+
source="deploy",
|
|
193
|
+
message="Deployment completed: v1.2.3",
|
|
194
|
+
component_name="deployer"
|
|
195
|
+
),
|
|
196
|
+
]
|
|
197
|
+
for log in sample_logs:
|
|
198
|
+
db.add(log)
|
|
199
|
+
|
|
200
|
+
db.commit()
|
|
201
|
+
print("[OK] Database seeded with sample data")
|
|
202
|
+
|
|
203
|
+
except Exception as e:
|
|
204
|
+
db.rollback()
|
|
205
|
+
print(f"[ERROR] Failed to seed database: {e}")
|
|
206
|
+
import traceback
|
|
207
|
+
traceback.print_exc()
|
|
208
|
+
finally:
|
|
209
|
+
db.close()
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+
def get_db():
|
|
213
|
+
"""
|
|
214
|
+
Dependency for FastAPI endpoints
|
|
215
|
+
Provides a database session and ensures cleanup
|
|
216
|
+
|
|
217
|
+
Usage:
|
|
218
|
+
@app.get("/items")
|
|
219
|
+
def get_items(db: Session = Depends(get_db)):
|
|
220
|
+
return db.query(Item).all()
|
|
221
|
+
"""
|
|
222
|
+
db = SessionLocal()
|
|
223
|
+
try:
|
|
224
|
+
yield db
|
|
225
|
+
finally:
|
|
226
|
+
db.close()
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Database Setup Service
|
|
3
|
+
Handles initial configuration of database containers
|
|
4
|
+
"""
|
|
5
|
+
import logging
|
|
6
|
+
import time
|
|
7
|
+
import psycopg2
|
|
8
|
+
import pymysql
|
|
9
|
+
from pymongo import MongoClient
|
|
10
|
+
|
|
11
|
+
logger = logging.getLogger(__name__)
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class DatabaseSetupService:
|
|
15
|
+
"""Service for setting up databases in containers"""
|
|
16
|
+
|
|
17
|
+
@staticmethod
|
|
18
|
+
def setup_database(datasource) -> tuple[bool, str]:
|
|
19
|
+
"""
|
|
20
|
+
Setup database based on type
|
|
21
|
+
|
|
22
|
+
Returns:
|
|
23
|
+
tuple: (success: bool, message: str)
|
|
24
|
+
"""
|
|
25
|
+
try:
|
|
26
|
+
db_type = datasource.type.lower()
|
|
27
|
+
|
|
28
|
+
if db_type == 'postgres':
|
|
29
|
+
return DatabaseSetupService._setup_postgres(datasource)
|
|
30
|
+
elif db_type in ['mysql', 'mariadb']:
|
|
31
|
+
return DatabaseSetupService._setup_mysql(datasource)
|
|
32
|
+
elif db_type == 'mongodb':
|
|
33
|
+
return DatabaseSetupService._setup_mongodb(datasource)
|
|
34
|
+
elif db_type == 'redis':
|
|
35
|
+
# Redis doesn't need setup
|
|
36
|
+
return True, "Redis is ready to use"
|
|
37
|
+
else:
|
|
38
|
+
return False, f"Unsupported database type: {db_type}"
|
|
39
|
+
|
|
40
|
+
except Exception as e:
|
|
41
|
+
logger.error(f"Database setup failed: {e}")
|
|
42
|
+
return False, str(e)
|
|
43
|
+
|
|
44
|
+
@staticmethod
|
|
45
|
+
def _setup_postgres(datasource) -> tuple[bool, str]:
|
|
46
|
+
"""Setup PostgreSQL database"""
|
|
47
|
+
max_retries = 30
|
|
48
|
+
retry_delay = 2
|
|
49
|
+
|
|
50
|
+
for attempt in range(max_retries):
|
|
51
|
+
try:
|
|
52
|
+
# Connect to default postgres database
|
|
53
|
+
conn = psycopg2.connect(
|
|
54
|
+
host=datasource.host,
|
|
55
|
+
port=datasource.port,
|
|
56
|
+
database='postgres',
|
|
57
|
+
user=datasource.username,
|
|
58
|
+
password=datasource.password_encrypted,
|
|
59
|
+
connect_timeout=5
|
|
60
|
+
)
|
|
61
|
+
conn.autocommit = True
|
|
62
|
+
cursor = conn.cursor()
|
|
63
|
+
|
|
64
|
+
# Check if database exists
|
|
65
|
+
cursor.execute(
|
|
66
|
+
"SELECT 1 FROM pg_database WHERE datname = %s",
|
|
67
|
+
(datasource.database_name,)
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
if not cursor.fetchone():
|
|
71
|
+
# Create database
|
|
72
|
+
cursor.execute(
|
|
73
|
+
f'CREATE DATABASE "{datasource.database_name}" '
|
|
74
|
+
f'OWNER "{datasource.username}"'
|
|
75
|
+
)
|
|
76
|
+
logger.info(f"Created database: {datasource.database_name}")
|
|
77
|
+
|
|
78
|
+
cursor.close()
|
|
79
|
+
conn.close()
|
|
80
|
+
|
|
81
|
+
# Test connection to new database
|
|
82
|
+
test_conn = psycopg2.connect(
|
|
83
|
+
host=datasource.host,
|
|
84
|
+
port=datasource.port,
|
|
85
|
+
database=datasource.database_name,
|
|
86
|
+
user=datasource.username,
|
|
87
|
+
password=datasource.password_encrypted,
|
|
88
|
+
connect_timeout=5
|
|
89
|
+
)
|
|
90
|
+
test_conn.close()
|
|
91
|
+
|
|
92
|
+
return True, f"PostgreSQL database '{datasource.database_name}' is ready"
|
|
93
|
+
|
|
94
|
+
except psycopg2.OperationalError as e:
|
|
95
|
+
if attempt < max_retries - 1:
|
|
96
|
+
logger.info(f"Waiting for PostgreSQL to be ready... (attempt {attempt + 1}/{max_retries})")
|
|
97
|
+
time.sleep(retry_delay)
|
|
98
|
+
else:
|
|
99
|
+
return False, f"PostgreSQL failed to start: {str(e)}"
|
|
100
|
+
except Exception as e:
|
|
101
|
+
return False, f"PostgreSQL setup error: {str(e)}"
|
|
102
|
+
|
|
103
|
+
@staticmethod
|
|
104
|
+
def _setup_mysql(datasource) -> tuple[bool, str]:
|
|
105
|
+
"""Setup MySQL/MariaDB database"""
|
|
106
|
+
max_retries = 30
|
|
107
|
+
retry_delay = 2
|
|
108
|
+
|
|
109
|
+
for attempt in range(max_retries):
|
|
110
|
+
try:
|
|
111
|
+
# Connect to MySQL server
|
|
112
|
+
conn = pymysql.connect(
|
|
113
|
+
host=datasource.host,
|
|
114
|
+
port=datasource.port,
|
|
115
|
+
user=datasource.username,
|
|
116
|
+
password=datasource.password_encrypted,
|
|
117
|
+
connect_timeout=5
|
|
118
|
+
)
|
|
119
|
+
cursor = conn.cursor()
|
|
120
|
+
|
|
121
|
+
# Create database if not exists
|
|
122
|
+
cursor.execute(f"CREATE DATABASE IF NOT EXISTS `{datasource.database_name}`")
|
|
123
|
+
|
|
124
|
+
# Grant privileges
|
|
125
|
+
cursor.execute(
|
|
126
|
+
f"GRANT ALL PRIVILEGES ON `{datasource.database_name}`.* "
|
|
127
|
+
f"TO '{datasource.username}'@'%'"
|
|
128
|
+
)
|
|
129
|
+
cursor.execute("FLUSH PRIVILEGES")
|
|
130
|
+
|
|
131
|
+
cursor.close()
|
|
132
|
+
conn.close()
|
|
133
|
+
|
|
134
|
+
# Test connection to new database
|
|
135
|
+
test_conn = pymysql.connect(
|
|
136
|
+
host=datasource.host,
|
|
137
|
+
port=datasource.port,
|
|
138
|
+
database=datasource.database_name,
|
|
139
|
+
user=datasource.username,
|
|
140
|
+
password=datasource.password_encrypted,
|
|
141
|
+
connect_timeout=5
|
|
142
|
+
)
|
|
143
|
+
test_conn.close()
|
|
144
|
+
|
|
145
|
+
db_type = 'MariaDB' if datasource.type == 'mariadb' else 'MySQL'
|
|
146
|
+
return True, f"{db_type} database '{datasource.database_name}' is ready"
|
|
147
|
+
|
|
148
|
+
except pymysql.OperationalError as e:
|
|
149
|
+
if attempt < max_retries - 1:
|
|
150
|
+
logger.info(f"Waiting for MySQL/MariaDB to be ready... (attempt {attempt + 1}/{max_retries})")
|
|
151
|
+
time.sleep(retry_delay)
|
|
152
|
+
else:
|
|
153
|
+
return False, f"MySQL/MariaDB failed to start: {str(e)}"
|
|
154
|
+
except Exception as e:
|
|
155
|
+
return False, f"MySQL/MariaDB setup error: {str(e)}"
|
|
156
|
+
|
|
157
|
+
@staticmethod
|
|
158
|
+
def _setup_mongodb(datasource) -> tuple[bool, str]:
|
|
159
|
+
"""Setup MongoDB database"""
|
|
160
|
+
max_retries = 30
|
|
161
|
+
retry_delay = 2
|
|
162
|
+
|
|
163
|
+
for attempt in range(max_retries):
|
|
164
|
+
try:
|
|
165
|
+
# Connect to MongoDB
|
|
166
|
+
client = MongoClient(
|
|
167
|
+
host=datasource.host,
|
|
168
|
+
port=datasource.port,
|
|
169
|
+
username=datasource.username,
|
|
170
|
+
password=datasource.password_encrypted,
|
|
171
|
+
serverSelectionTimeoutMS=5000
|
|
172
|
+
)
|
|
173
|
+
|
|
174
|
+
# Test connection
|
|
175
|
+
client.server_info()
|
|
176
|
+
|
|
177
|
+
# Create database (MongoDB creates it on first write)
|
|
178
|
+
db = client[datasource.database_name]
|
|
179
|
+
|
|
180
|
+
# Create a test collection to initialize the database
|
|
181
|
+
db.create_collection('_quantum_init')
|
|
182
|
+
db['_quantum_init'].insert_one({'initialized': True})
|
|
183
|
+
|
|
184
|
+
client.close()
|
|
185
|
+
|
|
186
|
+
return True, f"MongoDB database '{datasource.database_name}' is ready"
|
|
187
|
+
|
|
188
|
+
except Exception as e:
|
|
189
|
+
if attempt < max_retries - 1:
|
|
190
|
+
logger.info(f"Waiting for MongoDB to be ready... (attempt {attempt + 1}/{max_retries})")
|
|
191
|
+
time.sleep(retry_delay)
|
|
192
|
+
else:
|
|
193
|
+
return False, f"MongoDB failed to start: {str(e)}"
|