@memberjunction/sqlglot-ts 0.0.1 → 5.5.0

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.
package/README.md CHANGED
@@ -1,45 +1,89 @@
1
1
  # @memberjunction/sqlglot-ts
2
2
 
3
- ## ⚠️ IMPORTANT NOTICE ⚠️
3
+ A TypeScript wrapper for Python's [sqlglot](https://github.com/tobymao/sqlglot) SQL transpiler. Provides deterministic, verifiable SQL dialect conversion via a managed local Python FastAPI microservice.
4
4
 
5
- **This package is created solely for the purpose of setting up OIDC (OpenID Connect) trusted publishing with npm.**
5
+ ## Features
6
6
 
7
- This is **NOT** a functional package and contains **NO** code or functionality beyond the OIDC setup configuration.
7
+ - **31 SQL dialects** supported (T-SQL, PostgreSQL, MySQL, Snowflake, BigQuery, etc.)
8
+ - **Deterministic conversion** — no LLM randomness, reproducible results
9
+ - **Zero MemberJunction dependencies** — standalone community package
10
+ - **Ephemeral port binding** — microservice runs on `127.0.0.1` with auto-assigned port
11
+ - **Managed lifecycle** — automatic startup/shutdown of the Python process
12
+ - **Statement-by-statement mode** — individual statement tracking, one failure doesn't block others
8
13
 
9
- ## Purpose
14
+ ## Prerequisites
10
15
 
11
- This package exists to:
12
- 1. Configure OIDC trusted publishing for the package name `@memberjunction/sqlglot-ts`
13
- 2. Enable secure, token-less publishing from CI/CD workflows
14
- 3. Establish provenance for packages published under this name
16
+ - **Python 3.9+** with `sqlglot`, `fastapi`, and `uvicorn` installed:
15
17
 
16
- ## What is OIDC Trusted Publishing?
18
+ ```bash
19
+ pip install sqlglot fastapi uvicorn
20
+ ```
17
21
 
18
- OIDC trusted publishing allows package maintainers to publish packages directly from their CI/CD workflows without needing to manage npm access tokens. Instead, it uses OpenID Connect to establish trust between the CI/CD provider (like GitHub Actions) and npm.
22
+ ## Usage
19
23
 
20
- ## Setup Instructions
24
+ ```typescript
25
+ import { SqlGlotClient } from '@memberjunction/sqlglot-ts';
21
26
 
22
- To properly configure OIDC trusted publishing for this package:
27
+ const client = new SqlGlotClient();
28
+ await client.start();
23
29
 
24
- 1. Go to [npmjs.com](https://www.npmjs.com/) and navigate to your package settings
25
- 2. Configure the trusted publisher (e.g., GitHub Actions)
26
- 3. Specify the repository and workflow that should be allowed to publish
27
- 4. Use the configured workflow to publish your actual package
30
+ // Transpile T-SQL to PostgreSQL
31
+ const result = await client.transpile(
32
+ "SELECT ISNULL(col, 0) FROM [dbo].[MyTable]",
33
+ { fromDialect: 'tsql', toDialect: 'postgres' }
34
+ );
35
+ console.log(result.sql);
36
+ // Output: SELECT COALESCE(col, 0) FROM "dbo"."MyTable";
28
37
 
29
- ## DO NOT USE THIS PACKAGE
38
+ // Statement-by-statement mode
39
+ const stmtResult = await client.transpileStatements(
40
+ "SELECT TOP 10 * FROM Users; SELECT GETDATE();",
41
+ { fromDialect: 'tsql', toDialect: 'postgres' }
42
+ );
43
+ console.log(stmtResult.statements);
30
44
 
31
- This package is a placeholder for OIDC configuration only. It:
32
- - Contains no executable code
33
- - Provides no functionality
34
- - Should not be installed as a dependency
35
- - Exists only for administrative purposes
45
+ // Parse SQL to AST
46
+ const ast = await client.parse(
47
+ "SELECT 1",
48
+ { dialect: 'postgres' }
49
+ );
36
50
 
37
- ## More Information
51
+ // List supported dialects
52
+ const dialects = await client.getDialects();
38
53
 
39
- For more details about npm's trusted publishing feature, see:
40
- - [npm Trusted Publishing Documentation](https://docs.npmjs.com/generating-provenance-statements)
41
- - [GitHub Actions OIDC Documentation](https://docs.github.com/en/actions/deployment/security-hardening-your-deployments/about-security-hardening-with-openid-connect)
54
+ // Health check
55
+ const health = await client.health();
42
56
 
43
- ---
57
+ await client.stop();
58
+ ```
44
59
 
45
- **Maintained for OIDC setup purposes only**
60
+ ## API
61
+
62
+ ### `SqlGlotClient`
63
+
64
+ #### Constructor Options
65
+
66
+ | Option | Type | Default | Description |
67
+ |--------|------|---------|-------------|
68
+ | `pythonPath` | `string` | `'python3'` | Path to Python executable |
69
+ | `serverPath` | `string` | auto-detected | Path to `server.py` |
70
+ | `startupTimeoutMs` | `number` | `30000` | Max ms to wait for server startup |
71
+ | `requestTimeoutMs` | `number` | `60000` | Max ms per HTTP request |
72
+
73
+ #### Methods
74
+
75
+ - `start()` — Start the Python microservice
76
+ - `stop()` — Stop the Python microservice
77
+ - `transpile(sql, options)` — Transpile SQL between dialects (batch)
78
+ - `transpileStatements(sql, options)` — Transpile statement-by-statement
79
+ - `parse(sql, options)` — Parse SQL to AST (JSON)
80
+ - `getDialects()` — List all supported dialects
81
+ - `health()` — Server health check
82
+
83
+ ## Attribution
84
+
85
+ This package wraps the excellent [sqlglot](https://github.com/tobymao/sqlglot) Python library by Toby Mao and contributors. sqlglot provides a comprehensive SQL parser, transpiler, and optimizer supporting 31 SQL dialects with 8,900+ stars and 7,000+ commits.
86
+
87
+ ## License
88
+
89
+ ISC
@@ -0,0 +1,80 @@
1
+ import type { SqlGlotClientOptions, TranspileOptions, TranspileResult, ParseOptions, ParseResult, HealthStatus } from './types.js';
2
+ /**
3
+ * TypeScript client for the sqlglot Python microservice.
4
+ *
5
+ * Spawns a Python FastAPI process on 127.0.0.1 with an ephemeral port,
6
+ * then communicates via HTTP. The lifecycle methods `start()` and `stop()`
7
+ * manage the child process. Cleanup handlers are registered for SIGINT/SIGTERM.
8
+ *
9
+ * @example
10
+ * ```ts
11
+ * const client = new SqlGlotClient();
12
+ * await client.start();
13
+ *
14
+ * const result = await client.transpile({
15
+ * sql: "SELECT ISNULL(col, 0) FROM [dbo].[MyTable]",
16
+ * fromDialect: 'tsql',
17
+ * toDialect: 'postgres',
18
+ * });
19
+ * console.log(result.sql);
20
+ *
21
+ * await client.stop();
22
+ * ```
23
+ */
24
+ export declare class SqlGlotClient {
25
+ private process;
26
+ private port;
27
+ private readonly pythonPath;
28
+ private readonly serverPath;
29
+ private readonly startupTimeoutMs;
30
+ private readonly requestTimeoutMs;
31
+ private stopping;
32
+ private cleanupRegistered;
33
+ constructor(options?: SqlGlotClientOptions);
34
+ /** Whether the Python microservice is currently running */
35
+ get IsRunning(): boolean;
36
+ /** The port the Python microservice is listening on, or null if not running */
37
+ get Port(): number | null;
38
+ /**
39
+ * Start the Python microservice. Resolves once the server is ready.
40
+ * If already running, this is a no-op.
41
+ */
42
+ start(): Promise<void>;
43
+ /**
44
+ * Stop the Python microservice. Resolves once the process has exited.
45
+ * If not running, this is a no-op.
46
+ */
47
+ stop(): Promise<void>;
48
+ /**
49
+ * Transpile SQL from one dialect to another.
50
+ * All statements are transpiled together as a batch.
51
+ */
52
+ transpile(sql: string, options: TranspileOptions): Promise<TranspileResult>;
53
+ /**
54
+ * Transpile SQL statement-by-statement.
55
+ * Each statement is transpiled individually, so one failure doesn't block others.
56
+ */
57
+ transpileStatements(sql: string, options: TranspileOptions): Promise<TranspileResult>;
58
+ /**
59
+ * Parse SQL and return the AST as JSON.
60
+ */
61
+ parse(sql: string, options: ParseOptions): Promise<ParseResult>;
62
+ /**
63
+ * List all supported SQL dialects.
64
+ */
65
+ getDialects(): Promise<string[]>;
66
+ /**
67
+ * Check server health and return status information.
68
+ */
69
+ health(): Promise<HealthStatus>;
70
+ private assertRunning;
71
+ /**
72
+ * Poll the health endpoint until the server is accepting requests.
73
+ * Uses short intervals with an overall timeout from startupTimeoutMs.
74
+ */
75
+ private waitForReady;
76
+ private registerCleanup;
77
+ private httpPost;
78
+ private httpGet;
79
+ }
80
+ //# sourceMappingURL=SqlGlotClient.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SqlGlotClient.d.ts","sourceRoot":"","sources":["../src/SqlGlotClient.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EACV,oBAAoB,EACpB,gBAAgB,EAChB,eAAe,EACf,YAAY,EACZ,WAAW,EACX,YAAY,EACb,MAAM,YAAY,CAAC;AAyBpB;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,qBAAa,aAAa;IACxB,OAAO,CAAC,OAAO,CAA6B;IAC5C,OAAO,CAAC,IAAI,CAAuB;IACnC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;IACpC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;IACpC,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAS;IAC1C,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAS;IAC1C,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,iBAAiB,CAAS;gBAEtB,OAAO,CAAC,EAAE,oBAAoB;IAO1C,2DAA2D;IAC3D,IAAI,SAAS,IAAI,OAAO,CAEvB;IAED,+EAA+E;IAC/E,IAAI,IAAI,IAAI,MAAM,GAAG,IAAI,CAExB;IAED;;;OAGG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAyE5B;;;OAGG;IACG,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAwB3B;;;OAGG;IACG,SAAS,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,eAAe,CAAC;IAWjF;;;OAGG;IACG,mBAAmB,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,eAAe,CAAC;IAW3F;;OAEG;IACG,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,WAAW,CAAC;IAQrE;;OAEG;IACG,WAAW,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;IAMtC;;OAEG;IACG,MAAM,IAAI,OAAO,CAAC,YAAY,CAAC;IAerC,OAAO,CAAC,aAAa;IAQrB;;;OAGG;YACW,YAAY;IAc1B,OAAO,CAAC,eAAe;IAuBvB,OAAO,CAAC,QAAQ;IA6ChB,OAAO,CAAC,OAAO;CAsChB"}
@@ -0,0 +1,332 @@
1
+ import { spawn } from 'node:child_process';
2
+ import { existsSync } from 'node:fs';
3
+ import http from 'node:http';
4
+ import path from 'node:path';
5
+ import { fileURLToPath } from 'node:url';
6
+ const __filename = fileURLToPath(import.meta.url);
7
+ const __dirname = path.dirname(__filename);
8
+ /**
9
+ * Resolve the Python server script path.
10
+ * When running from dist/ the path is ../src/python/server.py
11
+ * When running from src/ (e.g. vitest) the path is ./python/server.py
12
+ */
13
+ function resolveServerPath() {
14
+ const candidates = [
15
+ path.resolve(__dirname, '..', 'src', 'python', 'server.py'), // from dist/
16
+ path.resolve(__dirname, 'python', 'server.py'), // from src/ (vitest)
17
+ ];
18
+ for (const candidate of candidates) {
19
+ if (existsSync(candidate)) {
20
+ return candidate;
21
+ }
22
+ }
23
+ return candidates[0]; // fallback; will fail at spawn time with a clear error
24
+ }
25
+ const DEFAULT_SERVER_PATH = resolveServerPath();
26
+ /**
27
+ * TypeScript client for the sqlglot Python microservice.
28
+ *
29
+ * Spawns a Python FastAPI process on 127.0.0.1 with an ephemeral port,
30
+ * then communicates via HTTP. The lifecycle methods `start()` and `stop()`
31
+ * manage the child process. Cleanup handlers are registered for SIGINT/SIGTERM.
32
+ *
33
+ * @example
34
+ * ```ts
35
+ * const client = new SqlGlotClient();
36
+ * await client.start();
37
+ *
38
+ * const result = await client.transpile({
39
+ * sql: "SELECT ISNULL(col, 0) FROM [dbo].[MyTable]",
40
+ * fromDialect: 'tsql',
41
+ * toDialect: 'postgres',
42
+ * });
43
+ * console.log(result.sql);
44
+ *
45
+ * await client.stop();
46
+ * ```
47
+ */
48
+ export class SqlGlotClient {
49
+ constructor(options) {
50
+ this.process = null;
51
+ this.port = null;
52
+ this.stopping = false;
53
+ this.cleanupRegistered = false;
54
+ this.pythonPath = options?.pythonPath ?? 'python3';
55
+ this.serverPath = options?.serverPath ?? DEFAULT_SERVER_PATH;
56
+ this.startupTimeoutMs = options?.startupTimeoutMs ?? 30000;
57
+ this.requestTimeoutMs = options?.requestTimeoutMs ?? 60000;
58
+ }
59
+ /** Whether the Python microservice is currently running */
60
+ get IsRunning() {
61
+ return this.process !== null && this.port !== null && !this.stopping;
62
+ }
63
+ /** The port the Python microservice is listening on, or null if not running */
64
+ get Port() {
65
+ return this.port;
66
+ }
67
+ /**
68
+ * Start the Python microservice. Resolves once the server is ready.
69
+ * If already running, this is a no-op.
70
+ */
71
+ async start() {
72
+ if (this.IsRunning) {
73
+ return;
74
+ }
75
+ this.stopping = false;
76
+ await new Promise((resolve, reject) => {
77
+ const proc = spawn(this.pythonPath, [this.serverPath, '0'], {
78
+ stdio: ['ignore', 'pipe', 'pipe'],
79
+ env: { ...process.env },
80
+ });
81
+ let stdoutBuffer = '';
82
+ let stderrBuffer = '';
83
+ let resolved = false;
84
+ const timeout = setTimeout(() => {
85
+ if (!resolved) {
86
+ resolved = true;
87
+ proc.kill('SIGKILL');
88
+ reject(new Error(`sqlglot-ts server failed to start within ${this.startupTimeoutMs}ms. ` +
89
+ `stderr: ${stderrBuffer.slice(0, 500)}`));
90
+ }
91
+ }, this.startupTimeoutMs);
92
+ proc.stdout.on('data', (chunk) => {
93
+ stdoutBuffer += chunk.toString();
94
+ const match = stdoutBuffer.match(/SQLGLOT_PORT=(\d+)/);
95
+ if (match && !resolved) {
96
+ resolved = true;
97
+ clearTimeout(timeout);
98
+ this.port = parseInt(match[1], 10);
99
+ this.process = proc;
100
+ this.registerCleanup();
101
+ // Wait for the server to be ready before resolving
102
+ this.waitForReady()
103
+ .then(() => resolve())
104
+ .catch((err) => reject(err));
105
+ }
106
+ });
107
+ proc.stderr.on('data', (chunk) => {
108
+ stderrBuffer += chunk.toString();
109
+ });
110
+ proc.on('error', (err) => {
111
+ if (!resolved) {
112
+ resolved = true;
113
+ clearTimeout(timeout);
114
+ reject(new Error(`Failed to spawn Python process: ${err.message}`));
115
+ }
116
+ });
117
+ proc.on('exit', (code) => {
118
+ if (!resolved) {
119
+ resolved = true;
120
+ clearTimeout(timeout);
121
+ reject(new Error(`Python process exited with code ${code} before becoming ready. ` +
122
+ `stderr: ${stderrBuffer.slice(0, 500)}`));
123
+ }
124
+ // If we were running and the process dies unexpectedly, clean up
125
+ if (this.process === proc) {
126
+ this.process = null;
127
+ this.port = null;
128
+ }
129
+ });
130
+ });
131
+ }
132
+ /**
133
+ * Stop the Python microservice. Resolves once the process has exited.
134
+ * If not running, this is a no-op.
135
+ */
136
+ async stop() {
137
+ if (!this.process) {
138
+ return;
139
+ }
140
+ this.stopping = true;
141
+ const proc = this.process;
142
+ this.process = null;
143
+ this.port = null;
144
+ return new Promise((resolve) => {
145
+ const timeout = setTimeout(() => {
146
+ proc.kill('SIGKILL');
147
+ resolve();
148
+ }, 5000);
149
+ proc.on('exit', () => {
150
+ clearTimeout(timeout);
151
+ resolve();
152
+ });
153
+ proc.kill('SIGTERM');
154
+ });
155
+ }
156
+ /**
157
+ * Transpile SQL from one dialect to another.
158
+ * All statements are transpiled together as a batch.
159
+ */
160
+ async transpile(sql, options) {
161
+ this.assertRunning();
162
+ return this.httpPost('/transpile', {
163
+ sql,
164
+ from_dialect: options.fromDialect,
165
+ to_dialect: options.toDialect,
166
+ pretty: options.pretty ?? true,
167
+ error_level: options.errorLevel ?? 'WARN',
168
+ });
169
+ }
170
+ /**
171
+ * Transpile SQL statement-by-statement.
172
+ * Each statement is transpiled individually, so one failure doesn't block others.
173
+ */
174
+ async transpileStatements(sql, options) {
175
+ this.assertRunning();
176
+ return this.httpPost('/transpile-statements', {
177
+ sql,
178
+ from_dialect: options.fromDialect,
179
+ to_dialect: options.toDialect,
180
+ pretty: options.pretty ?? true,
181
+ error_level: options.errorLevel ?? 'WARN',
182
+ });
183
+ }
184
+ /**
185
+ * Parse SQL and return the AST as JSON.
186
+ */
187
+ async parse(sql, options) {
188
+ this.assertRunning();
189
+ return this.httpPost('/parse', {
190
+ sql,
191
+ dialect: options.dialect,
192
+ });
193
+ }
194
+ /**
195
+ * List all supported SQL dialects.
196
+ */
197
+ async getDialects() {
198
+ this.assertRunning();
199
+ const result = await this.httpGet('/dialects');
200
+ return result.dialects;
201
+ }
202
+ /**
203
+ * Check server health and return status information.
204
+ */
205
+ async health() {
206
+ this.assertRunning();
207
+ const result = await this.httpGet('/health');
208
+ return {
209
+ status: result.status,
210
+ sqlglotVersion: result.sqlglot_version,
211
+ service: result.service,
212
+ port: this.port,
213
+ };
214
+ }
215
+ assertRunning() {
216
+ if (!this.IsRunning) {
217
+ throw new Error('SqlGlotClient is not running. Call start() first.');
218
+ }
219
+ }
220
+ /**
221
+ * Poll the health endpoint until the server is accepting requests.
222
+ * Uses short intervals with an overall timeout from startupTimeoutMs.
223
+ */
224
+ async waitForReady() {
225
+ const deadline = Date.now() + this.startupTimeoutMs;
226
+ const interval = 50;
227
+ while (Date.now() < deadline) {
228
+ try {
229
+ await this.httpGet('/health');
230
+ return; // Server is ready
231
+ }
232
+ catch {
233
+ await new Promise((r) => setTimeout(r, interval));
234
+ }
235
+ }
236
+ throw new Error(`sqlglot-ts server did not become ready within ${this.startupTimeoutMs}ms`);
237
+ }
238
+ registerCleanup() {
239
+ if (this.cleanupRegistered)
240
+ return;
241
+ this.cleanupRegistered = true;
242
+ const cleanup = () => {
243
+ if (this.process) {
244
+ this.process.kill('SIGTERM');
245
+ this.process = null;
246
+ this.port = null;
247
+ }
248
+ };
249
+ process.on('exit', cleanup);
250
+ process.on('SIGINT', () => {
251
+ cleanup();
252
+ process.exit(0);
253
+ });
254
+ process.on('SIGTERM', () => {
255
+ cleanup();
256
+ process.exit(0);
257
+ });
258
+ }
259
+ httpPost(path, body) {
260
+ return new Promise((resolve, reject) => {
261
+ const data = JSON.stringify(body);
262
+ const req = http.request({
263
+ hostname: '127.0.0.1',
264
+ port: this.port,
265
+ path,
266
+ method: 'POST',
267
+ headers: {
268
+ 'Content-Type': 'application/json',
269
+ 'Content-Length': Buffer.byteLength(data),
270
+ },
271
+ timeout: this.requestTimeoutMs,
272
+ }, (res) => {
273
+ let responseBody = '';
274
+ res.on('data', (chunk) => {
275
+ responseBody += chunk.toString();
276
+ });
277
+ res.on('end', () => {
278
+ try {
279
+ const parsed = JSON.parse(responseBody);
280
+ resolve(parsed);
281
+ }
282
+ catch {
283
+ reject(new Error(`Failed to parse response: ${responseBody.slice(0, 200)}`));
284
+ }
285
+ });
286
+ });
287
+ req.on('error', (err) => {
288
+ reject(new Error(`HTTP request to sqlglot server failed: ${err.message}`));
289
+ });
290
+ req.on('timeout', () => {
291
+ req.destroy();
292
+ reject(new Error(`Request to ${path} timed out after ${this.requestTimeoutMs}ms`));
293
+ });
294
+ req.write(data);
295
+ req.end();
296
+ });
297
+ }
298
+ httpGet(path) {
299
+ return new Promise((resolve, reject) => {
300
+ const req = http.request({
301
+ hostname: '127.0.0.1',
302
+ port: this.port,
303
+ path,
304
+ method: 'GET',
305
+ timeout: this.requestTimeoutMs,
306
+ }, (res) => {
307
+ let responseBody = '';
308
+ res.on('data', (chunk) => {
309
+ responseBody += chunk.toString();
310
+ });
311
+ res.on('end', () => {
312
+ try {
313
+ const parsed = JSON.parse(responseBody);
314
+ resolve(parsed);
315
+ }
316
+ catch {
317
+ reject(new Error(`Failed to parse response: ${responseBody.slice(0, 200)}`));
318
+ }
319
+ });
320
+ });
321
+ req.on('error', (err) => {
322
+ reject(new Error(`HTTP request to sqlglot server failed: ${err.message}`));
323
+ });
324
+ req.on('timeout', () => {
325
+ req.destroy();
326
+ reject(new Error(`Request to ${path} timed out after ${this.requestTimeoutMs}ms`));
327
+ });
328
+ req.end();
329
+ });
330
+ }
331
+ }
332
+ //# sourceMappingURL=SqlGlotClient.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SqlGlotClient.js","sourceRoot":"","sources":["../src/SqlGlotClient.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ export { SqlGlotClient } from './SqlGlotClient.js';
2
+ export type { SQLDialect, ErrorLevel, TranspileOptions, TranspileResult, ParseOptions, ParseResult, SqlGlotClientOptions, HealthStatus, } from './types.js';
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,YAAY,EACV,UAAU,EACV,UAAU,EACV,gBAAgB,EAChB,eAAe,EACf,YAAY,EACZ,WAAW,EACX,oBAAoB,EACpB,YAAY,GACb,MAAM,YAAY,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,2 @@
1
+ export { SqlGlotClient } from './SqlGlotClient.js';
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC"}
@@ -0,0 +1,54 @@
1
+ /** Supported SQL dialects (subset of sqlglot's 31 dialects) */
2
+ export type SQLDialect = 'tsql' | 'postgres' | 'mysql' | 'sqlite' | 'bigquery' | 'snowflake' | 'redshift' | 'spark' | 'duckdb' | 'oracle' | 'hive' | 'trino' | 'clickhouse' | 'databricks' | string;
3
+ export type ErrorLevel = 'IGNORE' | 'WARN' | 'RAISE' | 'IMMEDIATE';
4
+ export interface TranspileOptions {
5
+ /** Source SQL dialect */
6
+ fromDialect: SQLDialect;
7
+ /** Target SQL dialect */
8
+ toDialect: SQLDialect;
9
+ /** Pretty-print output (default: true) */
10
+ pretty?: boolean;
11
+ /** Error handling level (default: 'WARN') */
12
+ errorLevel?: ErrorLevel;
13
+ }
14
+ export interface TranspileResult {
15
+ /** Whether transpilation succeeded without errors */
16
+ success: boolean;
17
+ /** Combined SQL output (all statements joined with ;\n) */
18
+ sql: string;
19
+ /** Individual transpiled statements */
20
+ statements: string[];
21
+ /** Error messages */
22
+ errors: string[];
23
+ /** Warning messages */
24
+ warnings: string[];
25
+ }
26
+ export interface ParseOptions {
27
+ /** SQL dialect to parse as */
28
+ dialect: SQLDialect;
29
+ }
30
+ export interface ParseResult {
31
+ /** Whether parsing succeeded */
32
+ success: boolean;
33
+ /** AST as JSON string */
34
+ ast: string;
35
+ /** Error messages */
36
+ errors: string[];
37
+ }
38
+ export interface SqlGlotClientOptions {
39
+ /** Path to Python executable (default: 'python3') */
40
+ pythonPath?: string;
41
+ /** Path to the server.py file (default: auto-detected from package) */
42
+ serverPath?: string;
43
+ /** Startup timeout in ms (default: 30000) */
44
+ startupTimeoutMs?: number;
45
+ /** Request timeout in ms (default: 60000) */
46
+ requestTimeoutMs?: number;
47
+ }
48
+ export interface HealthStatus {
49
+ status: string;
50
+ sqlglotVersion: string;
51
+ service: string;
52
+ port: number;
53
+ }
54
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,+DAA+D;AAC/D,MAAM,MAAM,UAAU,GAClB,MAAM,GACN,UAAU,GACV,OAAO,GACP,QAAQ,GACR,UAAU,GACV,WAAW,GACX,UAAU,GACV,OAAO,GACP,QAAQ,GACR,QAAQ,GACR,MAAM,GACN,OAAO,GACP,YAAY,GACZ,YAAY,GACZ,MAAM,CAAC;AAEX,MAAM,MAAM,UAAU,GAAG,QAAQ,GAAG,MAAM,GAAG,OAAO,GAAG,WAAW,CAAC;AAEnE,MAAM,WAAW,gBAAgB;IAC/B,yBAAyB;IACzB,WAAW,EAAE,UAAU,CAAC;IACxB,yBAAyB;IACzB,SAAS,EAAE,UAAU,CAAC;IACtB,0CAA0C;IAC1C,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,6CAA6C;IAC7C,UAAU,CAAC,EAAE,UAAU,CAAC;CACzB;AAED,MAAM,WAAW,eAAe;IAC9B,qDAAqD;IACrD,OAAO,EAAE,OAAO,CAAC;IACjB,2DAA2D;IAC3D,GAAG,EAAE,MAAM,CAAC;IACZ,uCAAuC;IACvC,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,qBAAqB;IACrB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,uBAAuB;IACvB,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AAED,MAAM,WAAW,YAAY;IAC3B,8BAA8B;IAC9B,OAAO,EAAE,UAAU,CAAC;CACrB;AAED,MAAM,WAAW,WAAW;IAC1B,gCAAgC;IAChC,OAAO,EAAE,OAAO,CAAC;IACjB,yBAAyB;IACzB,GAAG,EAAE,MAAM,CAAC;IACZ,qBAAqB;IACrB,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB;AAED,MAAM,WAAW,oBAAoB;IACnC,qDAAqD;IACrD,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,uEAAuE;IACvE,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,6CAA6C;IAC7C,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,6CAA6C;IAC7C,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,cAAc,EAAE,MAAM,CAAC;IACvB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;CACd"}
package/dist/types.js ADDED
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
package/package.json CHANGED
@@ -1,10 +1,37 @@
1
1
  {
2
2
  "name": "@memberjunction/sqlglot-ts",
3
- "version": "0.0.1",
4
- "description": "OIDC trusted publishing setup package for @memberjunction/sqlglot-ts",
3
+ "version": "5.5.0",
4
+ "description": "TypeScript wrapper for Python's sqlglot SQL transpiler. Manages a local Python FastAPI microservice to provide deterministic SQL dialect conversion.",
5
+ "type": "module",
6
+ "main": "dist/index.js",
7
+ "types": "dist/index.d.ts",
8
+ "files": [
9
+ "/dist",
10
+ "/src/python"
11
+ ],
12
+ "scripts": {
13
+ "build": "tsc && tsc-alias -f",
14
+ "test": "vitest run",
15
+ "test:watch": "vitest"
16
+ },
5
17
  "keywords": [
6
- "oidc",
7
- "trusted-publishing",
8
- "setup"
9
- ]
18
+ "sql",
19
+ "transpiler",
20
+ "sqlglot",
21
+ "tsql",
22
+ "postgresql",
23
+ "mysql",
24
+ "dialect",
25
+ "conversion"
26
+ ],
27
+ "repository": {
28
+ "type": "git",
29
+ "url": "https://github.com/MemberJunction/MJ"
30
+ },
31
+ "license": "ISC",
32
+ "dependencies": {},
33
+ "devDependencies": {
34
+ "typescript": "^5.9.3",
35
+ "vitest": "^4.0.18"
36
+ }
10
37
  }
@@ -0,0 +1,188 @@
1
+ """
2
+ sqlglot-ts Python microservice.
3
+ Thin FastAPI wrapper around Python's sqlglot library (https://github.com/tobymao/sqlglot).
4
+ Runs on 127.0.0.1 with an ephemeral port for security.
5
+ """
6
+ from fastapi import FastAPI
7
+ from pydantic import BaseModel
8
+ import sqlglot
9
+ import sqlglot.errors
10
+ import uvicorn
11
+ import sys
12
+ import json
13
+
14
+ app = FastAPI(title="sqlglot-ts", version="1.0.0")
15
+
16
+
17
+ class TranspileRequest(BaseModel):
18
+ sql: str
19
+ from_dialect: str
20
+ to_dialect: str
21
+ pretty: bool = True
22
+ error_level: str = "WARN" # IGNORE, WARN, RAISE, IMMEDIATE
23
+
24
+
25
+ class TranspileResponse(BaseModel):
26
+ success: bool
27
+ sql: str = ""
28
+ statements: list[str] = []
29
+ errors: list[str] = []
30
+ warnings: list[str] = []
31
+
32
+
33
+ class ParseRequest(BaseModel):
34
+ sql: str
35
+ dialect: str
36
+
37
+
38
+ class ParseResponse(BaseModel):
39
+ success: bool
40
+ ast: str = ""
41
+ errors: list[str] = []
42
+
43
+
44
+ class DialectsResponse(BaseModel):
45
+ dialects: list[str]
46
+
47
+
48
+ @app.post("/transpile", response_model=TranspileResponse)
49
+ def transpile(req: TranspileRequest):
50
+ """Transpile SQL from one dialect to another."""
51
+ try:
52
+ error_level = getattr(
53
+ sqlglot.errors.ErrorLevel,
54
+ req.error_level,
55
+ sqlglot.errors.ErrorLevel.WARN,
56
+ )
57
+ results = sqlglot.transpile(
58
+ req.sql,
59
+ read=req.from_dialect,
60
+ write=req.to_dialect,
61
+ pretty=req.pretty,
62
+ error_level=error_level,
63
+ )
64
+ return TranspileResponse(
65
+ success=True,
66
+ sql=";\n".join(results) + (";" if results else ""),
67
+ statements=results,
68
+ errors=[],
69
+ warnings=[],
70
+ )
71
+ except sqlglot.errors.SqlglotError as e:
72
+ return TranspileResponse(
73
+ success=False,
74
+ sql="",
75
+ statements=[],
76
+ errors=[str(e)],
77
+ warnings=[],
78
+ )
79
+ except Exception as e:
80
+ return TranspileResponse(
81
+ success=False,
82
+ sql="",
83
+ statements=[],
84
+ errors=[f"Unexpected error: {str(e)}"],
85
+ warnings=[],
86
+ )
87
+
88
+
89
+ @app.post("/transpile-statements", response_model=TranspileResponse)
90
+ def transpile_statements(req: TranspileRequest):
91
+ """
92
+ Transpile SQL statement-by-statement.
93
+ Returns individual results for each statement, useful for
94
+ identifying which specific statements fail conversion.
95
+ """
96
+ try:
97
+ error_level = getattr(
98
+ sqlglot.errors.ErrorLevel,
99
+ req.error_level,
100
+ sqlglot.errors.ErrorLevel.WARN,
101
+ )
102
+ # Parse into individual statements first
103
+ parsed = sqlglot.parse(
104
+ req.sql, read=req.from_dialect, error_level=error_level
105
+ )
106
+
107
+ results: list[str] = []
108
+ errors: list[str] = []
109
+ warnings: list[str] = []
110
+
111
+ for i, stmt in enumerate(parsed):
112
+ if stmt is None:
113
+ continue
114
+ try:
115
+ transpiled = stmt.sql(dialect=req.to_dialect, pretty=req.pretty)
116
+ results.append(transpiled)
117
+ except Exception as e:
118
+ original = stmt.sql(dialect=req.from_dialect)
119
+ errors.append(
120
+ f"Statement {i+1} failed: {str(e)} | Original: {original[:200]}"
121
+ )
122
+ results.append(f"-- FAILED: {original}")
123
+
124
+ return TranspileResponse(
125
+ success=len(errors) == 0,
126
+ sql=";\n".join(results) + (";" if results else ""),
127
+ statements=results,
128
+ errors=errors,
129
+ warnings=warnings,
130
+ )
131
+ except Exception as e:
132
+ return TranspileResponse(
133
+ success=False,
134
+ sql="",
135
+ statements=[],
136
+ errors=[str(e)],
137
+ warnings=[],
138
+ )
139
+
140
+
141
+ @app.post("/parse", response_model=ParseResponse)
142
+ def parse(req: ParseRequest):
143
+ """Parse SQL and return the AST as JSON."""
144
+ try:
145
+ parsed = sqlglot.parse(req.sql, read=req.dialect)
146
+ ast_json = [stmt.dump() if stmt else None for stmt in parsed]
147
+ return ParseResponse(success=True, ast=json.dumps(ast_json, indent=2))
148
+ except Exception as e:
149
+ return ParseResponse(success=False, errors=[str(e)])
150
+
151
+
152
+ @app.get("/dialects", response_model=DialectsResponse)
153
+ def dialects():
154
+ """List all supported SQL dialects."""
155
+ actual = sorted(sqlglot.Dialect.classes.keys())
156
+ return DialectsResponse(dialects=actual)
157
+
158
+
159
+ @app.get("/health")
160
+ def health():
161
+ """Health check endpoint."""
162
+ return {
163
+ "status": "ok",
164
+ "sqlglot_version": sqlglot.__version__,
165
+ "service": "sqlglot-ts",
166
+ }
167
+
168
+
169
+ if __name__ == "__main__":
170
+ import socket
171
+
172
+ requested_port = int(sys.argv[1]) if len(sys.argv) > 1 else 0
173
+
174
+ # Bind a socket to discover the ephemeral port, then close it and
175
+ # pass that port to uvicorn. There is a tiny race window but it is
176
+ # acceptable for a local-only dev tool.
177
+ if requested_port == 0:
178
+ sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
179
+ sock.bind(("127.0.0.1", 0))
180
+ actual_port = sock.getsockname()[1]
181
+ sock.close()
182
+ else:
183
+ actual_port = requested_port
184
+
185
+ # Print the port BEFORE uvicorn starts so the TS client can read it.
186
+ print(f"SQLGLOT_PORT={actual_port}", flush=True)
187
+
188
+ uvicorn.run(app, host="127.0.0.1", port=actual_port, log_level="warning")