structured2graph 0.1.1__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.
- __init__.py +47 -0
- core/__init__.py +23 -0
- core/hygm/__init__.py +74 -0
- core/hygm/hygm.py +2351 -0
- core/hygm/models/__init__.py +82 -0
- core/hygm/models/graph_models.py +667 -0
- core/hygm/models/llm_models.py +229 -0
- core/hygm/models/operations.py +176 -0
- core/hygm/models/sources.py +68 -0
- core/hygm/models/user_operations.py +139 -0
- core/hygm/strategies/__init__.py +17 -0
- core/hygm/strategies/base.py +36 -0
- core/hygm/strategies/deterministic.py +262 -0
- core/hygm/strategies/llm.py +904 -0
- core/hygm/validation/__init__.py +38 -0
- core/hygm/validation/base.py +194 -0
- core/hygm/validation/graph_schema_validator.py +687 -0
- core/hygm/validation/memgraph_data_validator.py +991 -0
- core/migration_agent.py +1369 -0
- core/schema/spec.json +155 -0
- core/utils/meta_graph.py +108 -0
- database/__init__.py +36 -0
- database/adapters/__init__.py +11 -0
- database/adapters/memgraph.py +318 -0
- database/adapters/mysql.py +311 -0
- database/adapters/postgresql.py +335 -0
- database/analyzer.py +396 -0
- database/factory.py +219 -0
- database/models.py +209 -0
- main.py +518 -0
- query_generation/__init__.py +20 -0
- query_generation/cypher_generator.py +129 -0
- query_generation/schema_utilities.py +88 -0
- structured2graph-0.1.1.dist-info/METADATA +197 -0
- structured2graph-0.1.1.dist-info/RECORD +41 -0
- structured2graph-0.1.1.dist-info/WHEEL +4 -0
- structured2graph-0.1.1.dist-info/entry_points.txt +2 -0
- structured2graph-0.1.1.dist-info/licenses/LICENSE +21 -0
- utils/__init__.py +57 -0
- utils/config.py +235 -0
- utils/environment.py +404 -0
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Validation module for HyGM graph models and Memgraph schemas.
|
|
3
|
+
|
|
4
|
+
This module provides comprehensive validation capabilities including:
|
|
5
|
+
- Pre-migration validation (Graph Schema Validation)
|
|
6
|
+
- Post-migration validation (Memgraph Data Validation)
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from .base import (
|
|
10
|
+
ValidationSeverity,
|
|
11
|
+
ValidationCategory,
|
|
12
|
+
ValidationIssue,
|
|
13
|
+
ValidationMetrics,
|
|
14
|
+
ValidationResult,
|
|
15
|
+
BaseValidator,
|
|
16
|
+
create_validation_issue,
|
|
17
|
+
)
|
|
18
|
+
from .graph_schema_validator import GraphSchemaValidator
|
|
19
|
+
from .memgraph_data_validator import (
|
|
20
|
+
MemgraphDataValidator,
|
|
21
|
+
validate_memgraph_data,
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
__all__ = [
|
|
25
|
+
# Base classes and types
|
|
26
|
+
"ValidationSeverity",
|
|
27
|
+
"ValidationCategory",
|
|
28
|
+
"ValidationIssue",
|
|
29
|
+
"ValidationMetrics",
|
|
30
|
+
"ValidationResult",
|
|
31
|
+
"BaseValidator",
|
|
32
|
+
"create_validation_issue",
|
|
33
|
+
# Pre-migration validation
|
|
34
|
+
"GraphSchemaValidator",
|
|
35
|
+
# Post-migration validation
|
|
36
|
+
"MemgraphDataValidator",
|
|
37
|
+
"validate_memgraph_data",
|
|
38
|
+
]
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Base validation interfaces and common types for HyGM validation system.
|
|
3
|
+
|
|
4
|
+
This module provides common validation interfaces, result types, and utilities
|
|
5
|
+
that are shared between pre-migration and post-migration validation.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import logging
|
|
9
|
+
from abc import ABC, abstractmethod
|
|
10
|
+
from dataclasses import dataclass, field
|
|
11
|
+
from enum import Enum
|
|
12
|
+
from typing import Dict, List, Any, Optional, Union
|
|
13
|
+
|
|
14
|
+
logger = logging.getLogger(__name__)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class ValidationSeverity(Enum):
|
|
18
|
+
"""Severity levels for validation issues."""
|
|
19
|
+
|
|
20
|
+
CRITICAL = "CRITICAL"
|
|
21
|
+
WARNING = "WARNING"
|
|
22
|
+
INFO = "INFO"
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class ValidationCategory(Enum):
|
|
26
|
+
"""Categories of validation issues."""
|
|
27
|
+
|
|
28
|
+
COVERAGE = "coverage"
|
|
29
|
+
STRUCTURE = "structure"
|
|
30
|
+
CONSISTENCY = "consistency"
|
|
31
|
+
PERFORMANCE = "performance"
|
|
32
|
+
DATA_INTEGRITY = "data_integrity"
|
|
33
|
+
SCHEMA_MISMATCH = "schema_mismatch"
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
@dataclass
|
|
37
|
+
class ValidationIssue:
|
|
38
|
+
"""Represents a validation issue found during schema validation."""
|
|
39
|
+
|
|
40
|
+
severity: ValidationSeverity
|
|
41
|
+
category: ValidationCategory
|
|
42
|
+
message: str
|
|
43
|
+
expected: Any = None
|
|
44
|
+
actual: Any = None
|
|
45
|
+
recommendation: Optional[str] = None
|
|
46
|
+
details: Dict[str, Any] = field(default_factory=dict)
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
@dataclass
|
|
50
|
+
class ValidationMetrics:
|
|
51
|
+
"""Metrics collected during validation."""
|
|
52
|
+
|
|
53
|
+
tables_covered: int = 0
|
|
54
|
+
tables_total: int = 0
|
|
55
|
+
properties_covered: int = 0
|
|
56
|
+
properties_total: int = 0
|
|
57
|
+
relationships_covered: int = 0
|
|
58
|
+
relationships_total: int = 0
|
|
59
|
+
indexes_covered: int = 0
|
|
60
|
+
indexes_total: int = 0
|
|
61
|
+
constraints_covered: int = 0
|
|
62
|
+
constraints_total: int = 0
|
|
63
|
+
coverage_percentage: float = 0.0
|
|
64
|
+
|
|
65
|
+
def calculate_coverage(self):
|
|
66
|
+
"""Calculate overall coverage percentage."""
|
|
67
|
+
if self.tables_total == 0:
|
|
68
|
+
self.coverage_percentage = 0.0
|
|
69
|
+
else:
|
|
70
|
+
self.coverage_percentage = (self.tables_covered / self.tables_total) * 100
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
@dataclass
|
|
74
|
+
class ValidationResult:
|
|
75
|
+
"""Base result class for all validation types."""
|
|
76
|
+
|
|
77
|
+
validation_type: str
|
|
78
|
+
success: bool
|
|
79
|
+
summary: str
|
|
80
|
+
issues: List[ValidationIssue] = field(default_factory=list)
|
|
81
|
+
metrics: ValidationMetrics = field(default_factory=ValidationMetrics)
|
|
82
|
+
details: Dict[str, Any] = field(default_factory=dict)
|
|
83
|
+
|
|
84
|
+
@property
|
|
85
|
+
def critical_issues(self) -> List[ValidationIssue]:
|
|
86
|
+
"""Get only critical issues."""
|
|
87
|
+
return [
|
|
88
|
+
issue
|
|
89
|
+
for issue in self.issues
|
|
90
|
+
if issue.severity == ValidationSeverity.CRITICAL
|
|
91
|
+
]
|
|
92
|
+
|
|
93
|
+
@property
|
|
94
|
+
def warnings(self) -> List[ValidationIssue]:
|
|
95
|
+
"""Get only warning issues."""
|
|
96
|
+
return [
|
|
97
|
+
issue
|
|
98
|
+
for issue in self.issues
|
|
99
|
+
if issue.severity == ValidationSeverity.WARNING
|
|
100
|
+
]
|
|
101
|
+
|
|
102
|
+
@property
|
|
103
|
+
def info_issues(self) -> List[ValidationIssue]:
|
|
104
|
+
"""Get only info issues."""
|
|
105
|
+
return [
|
|
106
|
+
issue for issue in self.issues if issue.severity == ValidationSeverity.INFO
|
|
107
|
+
]
|
|
108
|
+
|
|
109
|
+
def add_issue(self, issue: ValidationIssue):
|
|
110
|
+
"""Add a validation issue."""
|
|
111
|
+
self.issues.append(issue)
|
|
112
|
+
|
|
113
|
+
# Update success status based on critical issues
|
|
114
|
+
if issue.severity == ValidationSeverity.CRITICAL:
|
|
115
|
+
self.success = False
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
class BaseValidator(ABC):
|
|
119
|
+
"""Abstract base class for all validators."""
|
|
120
|
+
|
|
121
|
+
def __init__(self):
|
|
122
|
+
self.issues: List[ValidationIssue] = []
|
|
123
|
+
self.metrics = ValidationMetrics()
|
|
124
|
+
|
|
125
|
+
@abstractmethod
|
|
126
|
+
def validate(self, *args, **kwargs) -> ValidationResult:
|
|
127
|
+
"""Perform validation and return results."""
|
|
128
|
+
pass
|
|
129
|
+
|
|
130
|
+
def add_issue(
|
|
131
|
+
self,
|
|
132
|
+
severity: ValidationSeverity,
|
|
133
|
+
category: ValidationCategory,
|
|
134
|
+
message: str,
|
|
135
|
+
expected: Any = None,
|
|
136
|
+
actual: Any = None,
|
|
137
|
+
recommendation: Optional[str] = None,
|
|
138
|
+
details: Optional[Dict[str, Any]] = None,
|
|
139
|
+
):
|
|
140
|
+
"""Helper method to add validation issues."""
|
|
141
|
+
issue = ValidationIssue(
|
|
142
|
+
severity=severity,
|
|
143
|
+
category=category,
|
|
144
|
+
message=message,
|
|
145
|
+
expected=expected,
|
|
146
|
+
actual=actual,
|
|
147
|
+
recommendation=recommendation,
|
|
148
|
+
details=details or {},
|
|
149
|
+
)
|
|
150
|
+
self.issues.append(issue)
|
|
151
|
+
logger.debug("Added %s issue: %s", severity.value, message)
|
|
152
|
+
|
|
153
|
+
def reset(self):
|
|
154
|
+
"""Reset validator state for new validation."""
|
|
155
|
+
self.issues = []
|
|
156
|
+
self.metrics = ValidationMetrics()
|
|
157
|
+
|
|
158
|
+
def _generate_summary(self) -> str:
|
|
159
|
+
"""Generate a summary of validation results."""
|
|
160
|
+
critical_count = len(
|
|
161
|
+
[i for i in self.issues if i.severity == ValidationSeverity.CRITICAL]
|
|
162
|
+
)
|
|
163
|
+
warning_count = len(
|
|
164
|
+
[i for i in self.issues if i.severity == ValidationSeverity.WARNING]
|
|
165
|
+
)
|
|
166
|
+
|
|
167
|
+
if critical_count > 0:
|
|
168
|
+
return (
|
|
169
|
+
f"Validation FAILED: {critical_count} critical issues, "
|
|
170
|
+
f"{warning_count} warnings"
|
|
171
|
+
)
|
|
172
|
+
elif warning_count > 0:
|
|
173
|
+
return f"Validation PASSED with {warning_count} warnings"
|
|
174
|
+
else:
|
|
175
|
+
return "Validation PASSED: No issues found"
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
def create_validation_issue(
|
|
179
|
+
severity: Union[str, ValidationSeverity],
|
|
180
|
+
category: Union[str, ValidationCategory],
|
|
181
|
+
message: str,
|
|
182
|
+
**kwargs,
|
|
183
|
+
) -> ValidationIssue:
|
|
184
|
+
"""
|
|
185
|
+
Helper function to create validation issues with string or enum inputs.
|
|
186
|
+
"""
|
|
187
|
+
if isinstance(severity, str):
|
|
188
|
+
severity = ValidationSeverity(severity.upper())
|
|
189
|
+
if isinstance(category, str):
|
|
190
|
+
category = ValidationCategory(category.lower())
|
|
191
|
+
|
|
192
|
+
return ValidationIssue(
|
|
193
|
+
severity=severity, category=category, message=message, **kwargs
|
|
194
|
+
)
|