mirror of
https://github.com/johndoe6345789/metabuilder.git
synced 2026-04-26 14:54:55 +00:00
README.md
LICENSE
AGENTS.md
api/ # Language-agnostic contract (source of truth)
schema/
entities/ # Entity definitions (conceptual models)
user.yaml
session.yaml
...
operations/ # CRUD + domain operations (semantic, not SQL)
user.ops.yaml
...
errors.yaml # Standard error codes (conflict, not_found, etc.)
capabilities.yaml # Feature flags per backend (tx, joins, ttl, etc.)
idl/
dbal.proto # Optional: RPC/IPC contract if needed
dbal.fbs # Optional: FlatBuffers schema if you prefer
versioning/
compat.md # Compatibility rules across TS/C++
common/ # Shared test vectors + fixtures + golden results
fixtures/
seed/
datasets/
golden/
query_results/
contracts/
conformance_cases.yaml
ts/ # Development implementation in TypeScript
package.json
tsconfig.json
src/
index.ts # Public entrypoint (creates client)
core/
client.ts # DBAL client facade
types.ts # TS types mirroring api/schema
errors.ts # Error mapping to api/errors.yaml
validation/ # Runtime validation (zod/io-ts/etc.)
input.ts
output.ts
capabilities.ts # Capability negotiation
telemetry/
logger.ts
metrics.ts
tracing.ts
adapters/ # Backend implementations (TS)
prisma/
index.ts
prisma_client.ts # Wraps Prisma client (server-side only)
mapping.ts # DB <-> entity mapping, select shaping
migrations/ # Optional: Prisma migration helpers
sqlite/
index.ts
sqlite_driver.ts
schema.ts
migrations/
mongodb/
index.ts
mongo_driver.ts
schema.ts
query/ # Query builder / AST (no backend leakage)
ast.ts
builder.ts
normalize.ts
optimize.ts
runtime/
config.ts # DBAL config (env, URLs, pool sizes)
secrets.ts # Secret loading boundary (server-only)
util/
assert.ts
retry.ts
backoff.ts
time.ts
tests/
unit/
integration/
conformance/ # Runs common/contract vectors on TS adapters
harness/
setup.ts
cpp/ # Production implementation in C++
CMakeLists.txt
include/
dbal/
dbal.hpp # Public API
client.hpp # Facade
types.hpp # Entity/DTO types
errors.hpp
capabilities.hpp
telemetry.hpp
query/
ast.hpp
builder.hpp
normalize.hpp
adapters/
adapter.hpp # Adapter interface
sqlite/
sqlite_adapter.hpp
mongodb/
mongodb_adapter.hpp
prisma/
prisma_adapter.hpp # Usually NOT direct; see note below
util/
expected.hpp
result.hpp
uuid.hpp
src/
client.cpp
errors.cpp
capabilities.cpp
telemetry.cpp
query/
ast.cpp
builder.cpp
normalize.cpp
adapters/
sqlite/
sqlite_adapter.cpp
sqlite_pool.cpp
sqlite_migrations.cpp
mongodb/
mongodb_adapter.cpp
mongo_pool.cpp
prisma/
prisma_adapter.cpp # See note below (often an RPC bridge)
util/
uuid.cpp
backoff.cpp
tests/
unit/
integration/
conformance/ # Runs common/contract vectors on C++ adapters
harness/
main.cpp
backends/ # Backend-specific assets not tied to one lang
sqlite/
schema.sql
migrations/
mongodb/
indexes.json
prisma/
schema.prisma
migrations/
tools/ # Codegen + build helpers (prefer Python)
codegen/
gen_types.py # api/schema -> ts/core/types.ts and cpp/types.hpp
gen_errors.py
gen_capabilities.py
conformance/
run_all.py # runs TS + C++ conformance suites
dev/
lint.py
format.py
scripts/ # Cross-platform entrypoints (Python per your pref)
build.py
test.py
conformance.py
package.py
dist/ # Build outputs (gitignored)
.github/
workflows/
ci.yml
.gitignore
.editorconfig
168 lines
5.5 KiB
Python
168 lines
5.5 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
Conformance test runner
|
|
Runs the same test vectors against both TypeScript and C++ implementations
|
|
"""
|
|
|
|
import subprocess
|
|
import json
|
|
import yaml
|
|
from pathlib import Path
|
|
from typing import Dict, Any, List
|
|
import sys
|
|
|
|
|
|
class ConformanceRunner:
|
|
def __init__(self, root_dir: Path):
|
|
self.root_dir = root_dir
|
|
self.test_dir = root_dir / 'common' / 'contracts'
|
|
self.results = {'ts': {}, 'cpp': {}}
|
|
|
|
def load_test_cases(self) -> List[Dict[str, Any]]:
|
|
"""Load all conformance test cases"""
|
|
test_cases = []
|
|
for yaml_file in self.test_dir.glob('*_tests.yaml'):
|
|
with open(yaml_file) as f:
|
|
cases = yaml.safe_load(f)
|
|
if isinstance(cases, list):
|
|
test_cases.extend(cases)
|
|
return test_cases
|
|
|
|
def run_typescript_tests(self) -> bool:
|
|
"""Run TypeScript conformance tests"""
|
|
print("\n=== Running TypeScript Conformance Tests ===")
|
|
ts_dir = self.root_dir / 'ts'
|
|
|
|
try:
|
|
result = subprocess.run(
|
|
['npm', 'run', 'test:conformance'],
|
|
cwd=ts_dir,
|
|
capture_output=True,
|
|
text=True,
|
|
timeout=300
|
|
)
|
|
|
|
print(result.stdout)
|
|
if result.returncode != 0:
|
|
print(f"TypeScript tests failed:\n{result.stderr}", file=sys.stderr)
|
|
return False
|
|
|
|
self.results['ts'] = self.parse_test_output(result.stdout)
|
|
return True
|
|
|
|
except subprocess.TimeoutExpired:
|
|
print("TypeScript tests timed out", file=sys.stderr)
|
|
return False
|
|
except Exception as e:
|
|
print(f"Error running TypeScript tests: {e}", file=sys.stderr)
|
|
return False
|
|
|
|
def run_cpp_tests(self) -> bool:
|
|
"""Run C++ conformance tests"""
|
|
print("\n=== Running C++ Conformance Tests ===")
|
|
cpp_build_dir = self.root_dir / 'cpp' / 'build'
|
|
|
|
if not cpp_build_dir.exists():
|
|
print("C++ build directory not found. Run: cd cpp && cmake -B build && make",
|
|
file=sys.stderr)
|
|
return False
|
|
|
|
try:
|
|
result = subprocess.run(
|
|
['./conformance_tests'],
|
|
cwd=cpp_build_dir,
|
|
capture_output=True,
|
|
text=True,
|
|
timeout=300
|
|
)
|
|
|
|
print(result.stdout)
|
|
if result.returncode != 0:
|
|
print(f"C++ tests failed:\n{result.stderr}", file=sys.stderr)
|
|
return False
|
|
|
|
self.results['cpp'] = self.parse_test_output(result.stdout)
|
|
return True
|
|
|
|
except subprocess.TimeoutExpired:
|
|
print("C++ tests timed out", file=sys.stderr)
|
|
return False
|
|
except Exception as e:
|
|
print(f"Error running C++ tests: {e}", file=sys.stderr)
|
|
return False
|
|
|
|
def parse_test_output(self, output: str) -> Dict[str, Any]:
|
|
"""Parse test output to structured results"""
|
|
results = {}
|
|
for line in output.split('\n'):
|
|
if 'PASS' in line or 'FAIL' in line:
|
|
parts = line.split()
|
|
if len(parts) >= 2:
|
|
test_name = parts[0]
|
|
status = 'pass' if 'PASS' in line else 'fail'
|
|
results[test_name] = status
|
|
return results
|
|
|
|
def compare_results(self) -> bool:
|
|
"""Compare TypeScript and C++ test results"""
|
|
print("\n=== Comparing Results ===")
|
|
|
|
ts_results = self.results['ts']
|
|
cpp_results = self.results['cpp']
|
|
|
|
all_tests = set(ts_results.keys()) | set(cpp_results.keys())
|
|
|
|
mismatches = []
|
|
for test_name in sorted(all_tests):
|
|
ts_status = ts_results.get(test_name, 'missing')
|
|
cpp_status = cpp_results.get(test_name, 'missing')
|
|
|
|
if ts_status != cpp_status:
|
|
mismatches.append({
|
|
'test': test_name,
|
|
'ts': ts_status,
|
|
'cpp': cpp_status
|
|
})
|
|
|
|
if mismatches:
|
|
print("\n❌ Implementation Mismatch Detected!")
|
|
print(f"Found {len(mismatches)} test(s) with different results:\n")
|
|
for mismatch in mismatches:
|
|
print(f" {mismatch['test']}:")
|
|
print(f" TypeScript: {mismatch['ts']}")
|
|
print(f" C++: {mismatch['cpp']}")
|
|
return False
|
|
else:
|
|
print("\n✓ All tests passed consistently across both implementations!")
|
|
print(f" Total tests: {len(all_tests)}")
|
|
return True
|
|
|
|
def run_all(self) -> bool:
|
|
"""Run all conformance tests"""
|
|
print("DBAL Conformance Test Runner")
|
|
print("=" * 60)
|
|
|
|
test_cases = self.load_test_cases()
|
|
print(f"Loaded {len(test_cases)} test cases")
|
|
|
|
ts_success = self.run_typescript_tests()
|
|
cpp_success = self.run_cpp_tests()
|
|
|
|
if not (ts_success and cpp_success):
|
|
print("\n❌ Conformance tests failed", file=sys.stderr)
|
|
return False
|
|
|
|
return self.compare_results()
|
|
|
|
|
|
def main():
|
|
root_dir = Path(__file__).parent.parent.parent
|
|
runner = ConformanceRunner(root_dir)
|
|
|
|
success = runner.run_all()
|
|
sys.exit(0 if success else 1)
|
|
|
|
|
|
if __name__ == '__main__':
|
|
main()
|