sql-dialect-master 1.1.8__tar.gz → 1.1.9__tar.gz
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.
- {sql_dialect_master-1.1.8/sql_dialect_master.egg-info → sql_dialect_master-1.1.9}/PKG-INFO +29 -3
- {sql_dialect_master-1.1.8 → sql_dialect_master-1.1.9}/README.md +28 -2
- {sql_dialect_master-1.1.8 → sql_dialect_master-1.1.9}/backend/api/main.py +96 -2
- {sql_dialect_master-1.1.8 → sql_dialect_master-1.1.9}/backend/api/metrics.py +33 -0
- {sql_dialect_master-1.1.8 → sql_dialect_master-1.1.9}/backend/core/metadata.py +2 -2
- {sql_dialect_master-1.1.8 → sql_dialect_master-1.1.9}/pyproject.toml +1 -1
- {sql_dialect_master-1.1.8 → sql_dialect_master-1.1.9/sql_dialect_master.egg-info}/PKG-INFO +29 -3
- {sql_dialect_master-1.1.8 → sql_dialect_master-1.1.9}/LICENSE +0 -0
- {sql_dialect_master-1.1.8 → sql_dialect_master-1.1.9}/backend/__init__.py +0 -0
- {sql_dialect_master-1.1.8 → sql_dialect_master-1.1.9}/backend/api/__init__.py +0 -0
- {sql_dialect_master-1.1.8 → sql_dialect_master-1.1.9}/backend/api/auth.py +0 -0
- {sql_dialect_master-1.1.8 → sql_dialect_master-1.1.9}/backend/api/client_identity.py +0 -0
- {sql_dialect_master-1.1.8 → sql_dialect_master-1.1.9}/backend/api/middleware.py +0 -0
- {sql_dialect_master-1.1.8 → sql_dialect_master-1.1.9}/backend/api/rate_limit_store.py +0 -0
- {sql_dialect_master-1.1.8 → sql_dialect_master-1.1.9}/backend/api/readiness.py +0 -0
- {sql_dialect_master-1.1.8 → sql_dialect_master-1.1.9}/backend/api/workers.py +0 -0
- {sql_dialect_master-1.1.8 → sql_dialect_master-1.1.9}/backend/core/__init__.py +0 -0
- {sql_dialect_master-1.1.8 → sql_dialect_master-1.1.9}/backend/core/cache.py +0 -0
- {sql_dialect_master-1.1.8 → sql_dialect_master-1.1.9}/backend/core/column_hint_validation.py +0 -0
- {sql_dialect_master-1.1.8 → sql_dialect_master-1.1.9}/backend/core/config.py +0 -0
- {sql_dialect_master-1.1.8 → sql_dialect_master-1.1.9}/backend/core/constants.py +0 -0
- {sql_dialect_master-1.1.8 → sql_dialect_master-1.1.9}/backend/core/exceptions.py +0 -0
- {sql_dialect_master-1.1.8 → sql_dialect_master-1.1.9}/backend/core/function_call_scanner.py +0 -0
- {sql_dialect_master-1.1.8 → sql_dialect_master-1.1.9}/backend/core/function_semantics.py +0 -0
- {sql_dialect_master-1.1.8 → sql_dialect_master-1.1.9}/backend/core/functions_db.json +0 -0
- {sql_dialect_master-1.1.8 → sql_dialect_master-1.1.9}/backend/core/functions_lookup.py +0 -0
- {sql_dialect_master-1.1.8 → sql_dialect_master-1.1.9}/backend/core/nl2sql.py +0 -0
- {sql_dialect_master-1.1.8 → sql_dialect_master-1.1.9}/backend/core/nl2sql_components/__init__.py +0 -0
- {sql_dialect_master-1.1.8 → sql_dialect_master-1.1.9}/backend/core/nl2sql_components/aggregations.py +0 -0
- {sql_dialect_master-1.1.8 → sql_dialect_master-1.1.9}/backend/core/nl2sql_components/boolean_conditions.py +0 -0
- {sql_dialect_master-1.1.8 → sql_dialect_master-1.1.9}/backend/core/nl2sql_components/core_extract.py +0 -0
- {sql_dialect_master-1.1.8 → sql_dialect_master-1.1.9}/backend/core/nl2sql_components/evidence.py +0 -0
- {sql_dialect_master-1.1.8 → sql_dialect_master-1.1.9}/backend/core/nl2sql_components/mappings.py +0 -0
- {sql_dialect_master-1.1.8 → sql_dialect_master-1.1.9}/backend/core/nl2sql_components/relations.py +0 -0
- {sql_dialect_master-1.1.8 → sql_dialect_master-1.1.9}/backend/core/nl2sql_components/templates.py +0 -0
- {sql_dialect_master-1.1.8 → sql_dialect_master-1.1.9}/backend/core/nl2sql_components/tokenizer.py +0 -0
- {sql_dialect_master-1.1.8 → sql_dialect_master-1.1.9}/backend/core/nl2sql_legacy.py +0 -0
- {sql_dialect_master-1.1.8 → sql_dialect_master-1.1.9}/backend/core/nl2sql_pipeline/__init__.py +0 -0
- {sql_dialect_master-1.1.8 → sql_dialect_master-1.1.9}/backend/core/nl2sql_pipeline/aggregations.py +0 -0
- {sql_dialect_master-1.1.8 → sql_dialect_master-1.1.9}/backend/core/nl2sql_pipeline/clause_extract.py +0 -0
- {sql_dialect_master-1.1.8 → sql_dialect_master-1.1.9}/backend/core/nl2sql_pipeline/dialect.py +0 -0
- {sql_dialect_master-1.1.8 → sql_dialect_master-1.1.9}/backend/core/nl2sql_pipeline/intent.py +0 -0
- {sql_dialect_master-1.1.8 → sql_dialect_master-1.1.9}/backend/core/nl2sql_pipeline/ir.py +0 -0
- {sql_dialect_master-1.1.8 → sql_dialect_master-1.1.9}/backend/core/nl2sql_pipeline/models.py +0 -0
- {sql_dialect_master-1.1.8 → sql_dialect_master-1.1.9}/backend/core/nl2sql_pipeline/orchestrator.py +0 -0
- {sql_dialect_master-1.1.8 → sql_dialect_master-1.1.9}/backend/core/nl2sql_pipeline/predicates.py +0 -0
- {sql_dialect_master-1.1.8 → sql_dialect_master-1.1.9}/backend/core/nl2sql_pipeline/renderer.py +0 -0
- {sql_dialect_master-1.1.8 → sql_dialect_master-1.1.9}/backend/core/nl2sql_pipeline/resolution.py +0 -0
- {sql_dialect_master-1.1.8 → sql_dialect_master-1.1.9}/backend/core/nl2sql_pipeline/suggestions.py +0 -0
- {sql_dialect_master-1.1.8 → sql_dialect_master-1.1.9}/backend/core/nl2sql_pipeline/templates.py +0 -0
- {sql_dialect_master-1.1.8 → sql_dialect_master-1.1.9}/backend/core/nl2sql_pipeline/validation.py +0 -0
- {sql_dialect_master-1.1.8 → sql_dialect_master-1.1.9}/backend/core/p1_sql_scanner.py +0 -0
- {sql_dialect_master-1.1.8 → sql_dialect_master-1.1.9}/backend/core/p2_data_validation.py +0 -0
- {sql_dialect_master-1.1.8 → sql_dialect_master-1.1.9}/backend/core/parser.py +0 -0
- {sql_dialect_master-1.1.8 → sql_dialect_master-1.1.9}/backend/core/post_processor.py +0 -0
- {sql_dialect_master-1.1.8 → sql_dialect_master-1.1.9}/backend/core/rules.py +0 -0
- {sql_dialect_master-1.1.8 → sql_dialect_master-1.1.9}/backend/core/semantic_diff.py +0 -0
- {sql_dialect_master-1.1.8 → sql_dialect_master-1.1.9}/backend/core/sql_statements.py +0 -0
- {sql_dialect_master-1.1.8 → sql_dialect_master-1.1.9}/backend/core/transpiler.py +0 -0
- {sql_dialect_master-1.1.8 → sql_dialect_master-1.1.9}/backend/core/type_mapping.json +0 -0
- {sql_dialect_master-1.1.8 → sql_dialect_master-1.1.9}/backend/core/type_mapping.py +0 -0
- {sql_dialect_master-1.1.8 → sql_dialect_master-1.1.9}/backend/utils/__init__.py +0 -0
- {sql_dialect_master-1.1.8 → sql_dialect_master-1.1.9}/backend/utils/validators.py +0 -0
- {sql_dialect_master-1.1.8 → sql_dialect_master-1.1.9}/setup.cfg +0 -0
- {sql_dialect_master-1.1.8 → sql_dialect_master-1.1.9}/sql_dialect_master.egg-info/SOURCES.txt +0 -0
- {sql_dialect_master-1.1.8 → sql_dialect_master-1.1.9}/sql_dialect_master.egg-info/dependency_links.txt +0 -0
- {sql_dialect_master-1.1.8 → sql_dialect_master-1.1.9}/sql_dialect_master.egg-info/requires.txt +0 -0
- {sql_dialect_master-1.1.8 → sql_dialect_master-1.1.9}/sql_dialect_master.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: sql-dialect-master
|
|
3
|
-
Version: 1.1.
|
|
3
|
+
Version: 1.1.9
|
|
4
4
|
Summary: SQL Dialect Master - Multi-database SQL conversion engine
|
|
5
5
|
Requires-Python: >=3.11
|
|
6
6
|
Description-Content-Type: text/markdown
|
|
@@ -36,7 +36,7 @@ Dynamic: license-file
|
|
|
36
36
|
|
|
37
37
|
Enterprise-grade multi-database SQL conversion engine supporting 12 database dialects.
|
|
38
38
|
|
|
39
|
-
Current release: 1.1.
|
|
39
|
+
Current release: 1.1.9
|
|
40
40
|
|
|
41
41
|
[](https://www.python.org/downloads/)
|
|
42
42
|
[](https://opensource.org/licenses/MIT)
|
|
@@ -294,6 +294,7 @@ sql-dialect-master/
|
|
|
294
294
|
| Endpoint | Method | Description |
|
|
295
295
|
|----------|--------|-------------|
|
|
296
296
|
| `/api/convert` | POST | Convert SQL between dialects; response includes `error_code` on failure |
|
|
297
|
+
| `/api/convert/batch` | POST | Convert an ordered batch with one dialect pair and per-item results |
|
|
297
298
|
| `/api/parse` | POST | Parse SQL and extract structural elements |
|
|
298
299
|
| `/api/nl2sql` | POST | Generate SQL from natural language |
|
|
299
300
|
| `/api/functions` | GET | Search SQL functions |
|
|
@@ -305,6 +306,24 @@ sql-dialect-master/
|
|
|
305
306
|
| `/health/deep` | GET | Deep health check |
|
|
306
307
|
| `/api/stats` | GET | Service and dataset statistics |
|
|
307
308
|
|
|
309
|
+
For example, send this JSON body to `POST /api/convert/batch`:
|
|
310
|
+
|
|
311
|
+
```json
|
|
312
|
+
{
|
|
313
|
+
"statements": ["SELECT id FROM users", "SELECT user_id FROM orders"],
|
|
314
|
+
"source_dialect": "postgres",
|
|
315
|
+
"target_dialect": "mysql",
|
|
316
|
+
"pretty": true
|
|
317
|
+
}
|
|
318
|
+
```
|
|
319
|
+
|
|
320
|
+
Results retain input order and include a zero-based `index` alongside the
|
|
321
|
+
single-conversion response fields. The summary includes `count`, `succeeded`,
|
|
322
|
+
and `failed`; top-level `success` is true only when every item succeeds.
|
|
323
|
+
Ordinary item failures, including a batch where every item fails, return HTTP
|
|
324
|
+
200 with per-item `error` and `error_code`. Request-level errors use the
|
|
325
|
+
existing error envelope; 503/504 responses do not include partial results.
|
|
326
|
+
|
|
308
327
|
## 🧪 Quality, Validation & Performance
|
|
309
328
|
|
|
310
329
|
The project maintains a 12 × 12 source-to-target dialect regression matrix, semantic regression tests, post-processing safety regressions, security boundary checks, deterministic rule-engine tests, cache-versioning tests, async concurrency tests, and stable error-code tests.
|
|
@@ -317,7 +336,14 @@ The semantic CI gate executes representative conversions against PostgreSQL and
|
|
|
317
336
|
|
|
318
337
|
Security validation structurally detects stacked SQL statements using the parser when available, with configurable policy controlling whether dangerous input is blocked or only warned about.
|
|
319
338
|
|
|
320
|
-
The
|
|
339
|
+
The SDK's `batch_transpile_async` bounds concurrent work and preserves input
|
|
340
|
+
order. REST batch conversion runs sequentially in one API worker slot, and the
|
|
341
|
+
entire batch shares the default 30-second queue-plus-execution budget
|
|
342
|
+
(`SDM_REQUEST_TIMEOUT`). HTTP 504 does not cancel the background batch. See
|
|
343
|
+
the [deployment limits](docs/deployment.md#1-deployment-model) for capacity
|
|
344
|
+
and timeout behavior.
|
|
345
|
+
|
|
346
|
+
A reproducible transpiler benchmark is available under `backend/benchmarks/` and is also executed in CI for performance observability. The benchmark intentionally reports measurements without failing the build on a fixed latency threshold because hosted CI timing is variable.
|
|
321
347
|
|
|
322
348
|
README source-of-truth checks run in CI and verify the release version, Python requirement, supported dialect list, and benchmark references against repository sources.
|
|
323
349
|
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
Enterprise-grade multi-database SQL conversion engine supporting 12 database dialects.
|
|
4
4
|
|
|
5
|
-
Current release: 1.1.
|
|
5
|
+
Current release: 1.1.9
|
|
6
6
|
|
|
7
7
|
[](https://www.python.org/downloads/)
|
|
8
8
|
[](https://opensource.org/licenses/MIT)
|
|
@@ -260,6 +260,7 @@ sql-dialect-master/
|
|
|
260
260
|
| Endpoint | Method | Description |
|
|
261
261
|
|----------|--------|-------------|
|
|
262
262
|
| `/api/convert` | POST | Convert SQL between dialects; response includes `error_code` on failure |
|
|
263
|
+
| `/api/convert/batch` | POST | Convert an ordered batch with one dialect pair and per-item results |
|
|
263
264
|
| `/api/parse` | POST | Parse SQL and extract structural elements |
|
|
264
265
|
| `/api/nl2sql` | POST | Generate SQL from natural language |
|
|
265
266
|
| `/api/functions` | GET | Search SQL functions |
|
|
@@ -271,6 +272,24 @@ sql-dialect-master/
|
|
|
271
272
|
| `/health/deep` | GET | Deep health check |
|
|
272
273
|
| `/api/stats` | GET | Service and dataset statistics |
|
|
273
274
|
|
|
275
|
+
For example, send this JSON body to `POST /api/convert/batch`:
|
|
276
|
+
|
|
277
|
+
```json
|
|
278
|
+
{
|
|
279
|
+
"statements": ["SELECT id FROM users", "SELECT user_id FROM orders"],
|
|
280
|
+
"source_dialect": "postgres",
|
|
281
|
+
"target_dialect": "mysql",
|
|
282
|
+
"pretty": true
|
|
283
|
+
}
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
Results retain input order and include a zero-based `index` alongside the
|
|
287
|
+
single-conversion response fields. The summary includes `count`, `succeeded`,
|
|
288
|
+
and `failed`; top-level `success` is true only when every item succeeds.
|
|
289
|
+
Ordinary item failures, including a batch where every item fails, return HTTP
|
|
290
|
+
200 with per-item `error` and `error_code`. Request-level errors use the
|
|
291
|
+
existing error envelope; 503/504 responses do not include partial results.
|
|
292
|
+
|
|
274
293
|
## 🧪 Quality, Validation & Performance
|
|
275
294
|
|
|
276
295
|
The project maintains a 12 × 12 source-to-target dialect regression matrix, semantic regression tests, post-processing safety regressions, security boundary checks, deterministic rule-engine tests, cache-versioning tests, async concurrency tests, and stable error-code tests.
|
|
@@ -283,7 +302,14 @@ The semantic CI gate executes representative conversions against PostgreSQL and
|
|
|
283
302
|
|
|
284
303
|
Security validation structurally detects stacked SQL statements using the parser when available, with configurable policy controlling whether dangerous input is blocked or only warned about.
|
|
285
304
|
|
|
286
|
-
The
|
|
305
|
+
The SDK's `batch_transpile_async` bounds concurrent work and preserves input
|
|
306
|
+
order. REST batch conversion runs sequentially in one API worker slot, and the
|
|
307
|
+
entire batch shares the default 30-second queue-plus-execution budget
|
|
308
|
+
(`SDM_REQUEST_TIMEOUT`). HTTP 504 does not cancel the background batch. See
|
|
309
|
+
the [deployment limits](docs/deployment.md#1-deployment-model) for capacity
|
|
310
|
+
and timeout behavior.
|
|
311
|
+
|
|
312
|
+
A reproducible transpiler benchmark is available under `backend/benchmarks/` and is also executed in CI for performance observability. The benchmark intentionally reports measurements without failing the build on a fixed latency threshold because hosted CI timing is variable.
|
|
287
313
|
|
|
288
314
|
README source-of-truth checks run in CI and verify the release version, Python requirement, supported dialect list, and benchmark references against repository sources.
|
|
289
315
|
|
|
@@ -27,10 +27,18 @@ from fastapi import Depends, FastAPI, HTTPException, Query, Request
|
|
|
27
27
|
from fastapi.middleware.cors import CORSMiddleware
|
|
28
28
|
from fastapi.middleware.gzip import GZipMiddleware
|
|
29
29
|
from fastapi.responses import JSONResponse
|
|
30
|
-
from pydantic import BaseModel, ConfigDict, Field
|
|
30
|
+
from pydantic import BaseModel, ConfigDict, Field, StrictStr
|
|
31
31
|
|
|
32
32
|
from backend.api.auth import require_api_access
|
|
33
|
-
from backend.api.metrics import
|
|
33
|
+
from backend.api.metrics import (
|
|
34
|
+
MetricsMiddleware,
|
|
35
|
+
configure_runtime_metrics,
|
|
36
|
+
metrics_response,
|
|
37
|
+
observe_transpile_batch_size,
|
|
38
|
+
record_transpile_batch_items,
|
|
39
|
+
record_transpile_batch_request,
|
|
40
|
+
record_transpile_request,
|
|
41
|
+
)
|
|
34
42
|
from backend.api.rate_limit_store import InMemoryRateLimitStore
|
|
35
43
|
from backend.api.readiness import health_probe_response
|
|
36
44
|
from backend.api.workers import BoundedWorkerPool, WorkerCapacityError
|
|
@@ -392,6 +400,38 @@ class ConvertResponse(BaseModel):
|
|
|
392
400
|
)
|
|
393
401
|
timestamp: str = Field(default_factory=lambda: datetime.now().isoformat(), description="Response timestamp")
|
|
394
402
|
|
|
403
|
+
|
|
404
|
+
class BatchConvertRequest(BaseModel):
|
|
405
|
+
"""Convert an ordered, bounded list using one dialect pair."""
|
|
406
|
+
|
|
407
|
+
statements: List[StrictStr] = Field(
|
|
408
|
+
...,
|
|
409
|
+
min_length=1,
|
|
410
|
+
max_length=settings.max_batch_size,
|
|
411
|
+
description="SQL statements in input order; each item is converted independently",
|
|
412
|
+
)
|
|
413
|
+
source_dialect: str
|
|
414
|
+
target_dialect: str
|
|
415
|
+
pretty: bool = settings.transpiler_pretty_default
|
|
416
|
+
|
|
417
|
+
|
|
418
|
+
class BatchConvertItemResponse(ConvertResponse):
|
|
419
|
+
"""A conversion result associated with its original input position."""
|
|
420
|
+
|
|
421
|
+
index: int = Field(..., ge=0, description="Zero-based index in the input statements")
|
|
422
|
+
|
|
423
|
+
|
|
424
|
+
class BatchConvertResponse(BaseModel):
|
|
425
|
+
"""Ordered conversion results, including ordinary per-item failures."""
|
|
426
|
+
|
|
427
|
+
success: bool
|
|
428
|
+
results: List[BatchConvertItemResponse]
|
|
429
|
+
count: int
|
|
430
|
+
succeeded: int
|
|
431
|
+
failed: int
|
|
432
|
+
timestamp: str = Field(default_factory=lambda: datetime.now().isoformat())
|
|
433
|
+
|
|
434
|
+
|
|
395
435
|
class NL2SQLRequest(BaseModel):
|
|
396
436
|
"""Natural language to SQL request model."""
|
|
397
437
|
text: str = Field(..., description="Natural language query (Chinese or English)")
|
|
@@ -620,6 +660,60 @@ async def convert_sql(request: ConvertRequest):
|
|
|
620
660
|
target_validation_state=result.target_validation_state,
|
|
621
661
|
)
|
|
622
662
|
|
|
663
|
+
@app.post("/api/convert/batch", response_model=BatchConvertResponse, tags=["conversion"])
|
|
664
|
+
async def convert_sql_batch(request: BatchConvertRequest):
|
|
665
|
+
"""Convert statements sequentially in one worker slot, preserving input order.
|
|
666
|
+
|
|
667
|
+
Ordinary item failures, including a batch where every item fails, return
|
|
668
|
+
HTTP 200 with per-item errors. Request-level failures use the existing
|
|
669
|
+
error envelope. A 504 ends the wait but does not cancel the worker batch.
|
|
670
|
+
"""
|
|
671
|
+
source_dialect = target_dialect = "unknown"
|
|
672
|
+
try:
|
|
673
|
+
source_dialect = normalize_dialect(request.source_dialect, "source dialect")
|
|
674
|
+
target_dialect = normalize_dialect(request.target_dialect, "target dialect")
|
|
675
|
+
observe_transpile_batch_size(len(request.statements))
|
|
676
|
+
batch_results = await _run_cpu_bound(
|
|
677
|
+
transpiler.batch_transpile,
|
|
678
|
+
list(request.statements),
|
|
679
|
+
source_dialect,
|
|
680
|
+
target_dialect,
|
|
681
|
+
request.pretty,
|
|
682
|
+
)
|
|
683
|
+
results = [
|
|
684
|
+
BatchConvertItemResponse(index=index, **result.to_dict())
|
|
685
|
+
for index, result in enumerate(batch_results)
|
|
686
|
+
]
|
|
687
|
+
count = len(results)
|
|
688
|
+
succeeded = sum(item.success for item in results)
|
|
689
|
+
failed = count - succeeded
|
|
690
|
+
response = BatchConvertResponse(
|
|
691
|
+
success=failed == 0,
|
|
692
|
+
results=results,
|
|
693
|
+
count=count,
|
|
694
|
+
succeeded=succeeded,
|
|
695
|
+
failed=failed,
|
|
696
|
+
)
|
|
697
|
+
except HTTPException as exc:
|
|
698
|
+
record_transpile_batch_request(
|
|
699
|
+
source_dialect,
|
|
700
|
+
target_dialect,
|
|
701
|
+
"validation_error" if exc.status_code == 400 else "error",
|
|
702
|
+
)
|
|
703
|
+
raise
|
|
704
|
+
except Exception:
|
|
705
|
+
record_transpile_batch_request(source_dialect, target_dialect, "error")
|
|
706
|
+
raise
|
|
707
|
+
|
|
708
|
+
record_transpile_batch_items(source_dialect, target_dialect, succeeded, failed)
|
|
709
|
+
record_transpile_batch_request(
|
|
710
|
+
source_dialect,
|
|
711
|
+
target_dialect,
|
|
712
|
+
"success" if failed == 0 else "partial_failure" if succeeded else "error",
|
|
713
|
+
)
|
|
714
|
+
return response
|
|
715
|
+
|
|
716
|
+
|
|
623
717
|
@app.post("/api/parse", tags=["conversion"])
|
|
624
718
|
async def parse_sql(request: ParseRequest):
|
|
625
719
|
"""
|
|
@@ -48,6 +48,24 @@ TRANSPILE_REQUESTS = Counter(
|
|
|
48
48
|
["source", "target", "result"],
|
|
49
49
|
registry=REGISTRY,
|
|
50
50
|
)
|
|
51
|
+
TRANSPILE_BATCH_REQUESTS = Counter(
|
|
52
|
+
"sdm_transpile_batch_requests_total",
|
|
53
|
+
"Batch conversion handler outcomes by dialect pair and result",
|
|
54
|
+
["source", "target", "result"],
|
|
55
|
+
registry=REGISTRY,
|
|
56
|
+
)
|
|
57
|
+
TRANSPILE_BATCH_ITEMS = Counter(
|
|
58
|
+
"sdm_transpile_batch_items_total",
|
|
59
|
+
"Items in complete batch results received by the API handler",
|
|
60
|
+
["source", "target", "result"],
|
|
61
|
+
registry=REGISTRY,
|
|
62
|
+
)
|
|
63
|
+
TRANSPILE_BATCH_SIZE = Histogram(
|
|
64
|
+
"sdm_transpile_batch_size",
|
|
65
|
+
"Statement count of validated batches before worker admission",
|
|
66
|
+
buckets=(1, 2, 5, 10, 20, 50, 100),
|
|
67
|
+
registry=REGISTRY,
|
|
68
|
+
)
|
|
51
69
|
|
|
52
70
|
_transpiler_provider: Callable[[], object] | None = None
|
|
53
71
|
_worker_provider: Callable[[], object] | None = None
|
|
@@ -130,6 +148,21 @@ def record_transpile_request(source: str, target: str, result: str) -> None:
|
|
|
130
148
|
TRANSPILE_REQUESTS.labels(source=source, target=target, result=result).inc()
|
|
131
149
|
|
|
132
150
|
|
|
151
|
+
def record_transpile_batch_request(source: str, target: str, result: str) -> None:
|
|
152
|
+
TRANSPILE_BATCH_REQUESTS.labels(source=source, target=target, result=result).inc()
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
def record_transpile_batch_items(source: str, target: str, succeeded: int, failed: int) -> None:
|
|
156
|
+
if succeeded:
|
|
157
|
+
TRANSPILE_BATCH_ITEMS.labels(source=source, target=target, result="success").inc(succeeded)
|
|
158
|
+
if failed:
|
|
159
|
+
TRANSPILE_BATCH_ITEMS.labels(source=source, target=target, result="error").inc(failed)
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
def observe_transpile_batch_size(size: int) -> None:
|
|
163
|
+
TRANSPILE_BATCH_SIZE.observe(size)
|
|
164
|
+
|
|
165
|
+
|
|
133
166
|
def _authorized(request: Request) -> bool:
|
|
134
167
|
configured = settings.metrics_token
|
|
135
168
|
expected = configured.get_secret_value().strip() if configured else ""
|
|
@@ -17,8 +17,8 @@ Design rules:
|
|
|
17
17
|
from __future__ import annotations
|
|
18
18
|
|
|
19
19
|
# ── Release version facts (sole source of truth) ────────────────────────
|
|
20
|
-
PROJECT_VERSION = "1.1.
|
|
21
|
-
API_VERSION = "1.1.
|
|
20
|
+
PROJECT_VERSION = "1.1.9"
|
|
21
|
+
API_VERSION = "1.1.9"
|
|
22
22
|
# Frontend v2 architecture — independent of the product release version.
|
|
23
23
|
FRONTEND_ARCHITECTURE_VERSION = 2
|
|
24
24
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: sql-dialect-master
|
|
3
|
-
Version: 1.1.
|
|
3
|
+
Version: 1.1.9
|
|
4
4
|
Summary: SQL Dialect Master - Multi-database SQL conversion engine
|
|
5
5
|
Requires-Python: >=3.11
|
|
6
6
|
Description-Content-Type: text/markdown
|
|
@@ -36,7 +36,7 @@ Dynamic: license-file
|
|
|
36
36
|
|
|
37
37
|
Enterprise-grade multi-database SQL conversion engine supporting 12 database dialects.
|
|
38
38
|
|
|
39
|
-
Current release: 1.1.
|
|
39
|
+
Current release: 1.1.9
|
|
40
40
|
|
|
41
41
|
[](https://www.python.org/downloads/)
|
|
42
42
|
[](https://opensource.org/licenses/MIT)
|
|
@@ -294,6 +294,7 @@ sql-dialect-master/
|
|
|
294
294
|
| Endpoint | Method | Description |
|
|
295
295
|
|----------|--------|-------------|
|
|
296
296
|
| `/api/convert` | POST | Convert SQL between dialects; response includes `error_code` on failure |
|
|
297
|
+
| `/api/convert/batch` | POST | Convert an ordered batch with one dialect pair and per-item results |
|
|
297
298
|
| `/api/parse` | POST | Parse SQL and extract structural elements |
|
|
298
299
|
| `/api/nl2sql` | POST | Generate SQL from natural language |
|
|
299
300
|
| `/api/functions` | GET | Search SQL functions |
|
|
@@ -305,6 +306,24 @@ sql-dialect-master/
|
|
|
305
306
|
| `/health/deep` | GET | Deep health check |
|
|
306
307
|
| `/api/stats` | GET | Service and dataset statistics |
|
|
307
308
|
|
|
309
|
+
For example, send this JSON body to `POST /api/convert/batch`:
|
|
310
|
+
|
|
311
|
+
```json
|
|
312
|
+
{
|
|
313
|
+
"statements": ["SELECT id FROM users", "SELECT user_id FROM orders"],
|
|
314
|
+
"source_dialect": "postgres",
|
|
315
|
+
"target_dialect": "mysql",
|
|
316
|
+
"pretty": true
|
|
317
|
+
}
|
|
318
|
+
```
|
|
319
|
+
|
|
320
|
+
Results retain input order and include a zero-based `index` alongside the
|
|
321
|
+
single-conversion response fields. The summary includes `count`, `succeeded`,
|
|
322
|
+
and `failed`; top-level `success` is true only when every item succeeds.
|
|
323
|
+
Ordinary item failures, including a batch where every item fails, return HTTP
|
|
324
|
+
200 with per-item `error` and `error_code`. Request-level errors use the
|
|
325
|
+
existing error envelope; 503/504 responses do not include partial results.
|
|
326
|
+
|
|
308
327
|
## 🧪 Quality, Validation & Performance
|
|
309
328
|
|
|
310
329
|
The project maintains a 12 × 12 source-to-target dialect regression matrix, semantic regression tests, post-processing safety regressions, security boundary checks, deterministic rule-engine tests, cache-versioning tests, async concurrency tests, and stable error-code tests.
|
|
@@ -317,7 +336,14 @@ The semantic CI gate executes representative conversions against PostgreSQL and
|
|
|
317
336
|
|
|
318
337
|
Security validation structurally detects stacked SQL statements using the parser when available, with configurable policy controlling whether dangerous input is blocked or only warned about.
|
|
319
338
|
|
|
320
|
-
The
|
|
339
|
+
The SDK's `batch_transpile_async` bounds concurrent work and preserves input
|
|
340
|
+
order. REST batch conversion runs sequentially in one API worker slot, and the
|
|
341
|
+
entire batch shares the default 30-second queue-plus-execution budget
|
|
342
|
+
(`SDM_REQUEST_TIMEOUT`). HTTP 504 does not cancel the background batch. See
|
|
343
|
+
the [deployment limits](docs/deployment.md#1-deployment-model) for capacity
|
|
344
|
+
and timeout behavior.
|
|
345
|
+
|
|
346
|
+
A reproducible transpiler benchmark is available under `backend/benchmarks/` and is also executed in CI for performance observability. The benchmark intentionally reports measurements without failing the build on a fixed latency threshold because hosted CI timing is variable.
|
|
321
347
|
|
|
322
348
|
README source-of-truth checks run in CI and verify the release version, Python requirement, supported dialect list, and benchmark references against repository sources.
|
|
323
349
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{sql_dialect_master-1.1.8 → sql_dialect_master-1.1.9}/backend/core/column_hint_validation.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{sql_dialect_master-1.1.8 → sql_dialect_master-1.1.9}/backend/core/nl2sql_components/__init__.py
RENAMED
|
File without changes
|
{sql_dialect_master-1.1.8 → sql_dialect_master-1.1.9}/backend/core/nl2sql_components/aggregations.py
RENAMED
|
File without changes
|
|
File without changes
|
{sql_dialect_master-1.1.8 → sql_dialect_master-1.1.9}/backend/core/nl2sql_components/core_extract.py
RENAMED
|
File without changes
|
{sql_dialect_master-1.1.8 → sql_dialect_master-1.1.9}/backend/core/nl2sql_components/evidence.py
RENAMED
|
File without changes
|
{sql_dialect_master-1.1.8 → sql_dialect_master-1.1.9}/backend/core/nl2sql_components/mappings.py
RENAMED
|
File without changes
|
{sql_dialect_master-1.1.8 → sql_dialect_master-1.1.9}/backend/core/nl2sql_components/relations.py
RENAMED
|
File without changes
|
{sql_dialect_master-1.1.8 → sql_dialect_master-1.1.9}/backend/core/nl2sql_components/templates.py
RENAMED
|
File without changes
|
{sql_dialect_master-1.1.8 → sql_dialect_master-1.1.9}/backend/core/nl2sql_components/tokenizer.py
RENAMED
|
File without changes
|
|
File without changes
|
{sql_dialect_master-1.1.8 → sql_dialect_master-1.1.9}/backend/core/nl2sql_pipeline/__init__.py
RENAMED
|
File without changes
|
{sql_dialect_master-1.1.8 → sql_dialect_master-1.1.9}/backend/core/nl2sql_pipeline/aggregations.py
RENAMED
|
File without changes
|
{sql_dialect_master-1.1.8 → sql_dialect_master-1.1.9}/backend/core/nl2sql_pipeline/clause_extract.py
RENAMED
|
File without changes
|
{sql_dialect_master-1.1.8 → sql_dialect_master-1.1.9}/backend/core/nl2sql_pipeline/dialect.py
RENAMED
|
File without changes
|
{sql_dialect_master-1.1.8 → sql_dialect_master-1.1.9}/backend/core/nl2sql_pipeline/intent.py
RENAMED
|
File without changes
|
|
File without changes
|
{sql_dialect_master-1.1.8 → sql_dialect_master-1.1.9}/backend/core/nl2sql_pipeline/models.py
RENAMED
|
File without changes
|
{sql_dialect_master-1.1.8 → sql_dialect_master-1.1.9}/backend/core/nl2sql_pipeline/orchestrator.py
RENAMED
|
File without changes
|
{sql_dialect_master-1.1.8 → sql_dialect_master-1.1.9}/backend/core/nl2sql_pipeline/predicates.py
RENAMED
|
File without changes
|
{sql_dialect_master-1.1.8 → sql_dialect_master-1.1.9}/backend/core/nl2sql_pipeline/renderer.py
RENAMED
|
File without changes
|
{sql_dialect_master-1.1.8 → sql_dialect_master-1.1.9}/backend/core/nl2sql_pipeline/resolution.py
RENAMED
|
File without changes
|
{sql_dialect_master-1.1.8 → sql_dialect_master-1.1.9}/backend/core/nl2sql_pipeline/suggestions.py
RENAMED
|
File without changes
|
{sql_dialect_master-1.1.8 → sql_dialect_master-1.1.9}/backend/core/nl2sql_pipeline/templates.py
RENAMED
|
File without changes
|
{sql_dialect_master-1.1.8 → sql_dialect_master-1.1.9}/backend/core/nl2sql_pipeline/validation.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{sql_dialect_master-1.1.8 → sql_dialect_master-1.1.9}/sql_dialect_master.egg-info/SOURCES.txt
RENAMED
|
File without changes
|
|
File without changes
|
{sql_dialect_master-1.1.8 → sql_dialect_master-1.1.9}/sql_dialect_master.egg-info/requires.txt
RENAMED
|
File without changes
|
{sql_dialect_master-1.1.8 → sql_dialect_master-1.1.9}/sql_dialect_master.egg-info/top_level.txt
RENAMED
|
File without changes
|