@sqg/sqg 0.5.0 → 0.7.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 +6 -1
- package/dist/sqg.mjs +864 -482
- package/dist/templates/libsql.hbs +101 -0
- package/dist/templates/node-sqlite.hbs +108 -0
- package/dist/templates/turso.hbs +112 -0
- package/package.json +5 -2
package/dist/sqg.mjs
CHANGED
|
@@ -2,11 +2,15 @@
|
|
|
2
2
|
import { exit } from "node:process";
|
|
3
3
|
import { Command } from "commander";
|
|
4
4
|
import consola, { LogLevels } from "consola";
|
|
5
|
-
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
6
|
-
import {
|
|
5
|
+
import { existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
|
6
|
+
import { randomUUID } from "node:crypto";
|
|
7
|
+
import { homedir, tmpdir } from "node:os";
|
|
7
8
|
import { basename, dirname, extname, join, resolve } from "node:path";
|
|
8
|
-
import
|
|
9
|
+
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
10
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
11
|
+
import { CallToolRequestSchema, ListResourcesRequestSchema, ListToolsRequestSchema, ReadResourceRequestSchema } from "@modelcontextprotocol/sdk/types.js";
|
|
9
12
|
import YAML from "yaml";
|
|
13
|
+
import Handlebars from "handlebars";
|
|
10
14
|
import { z } from "zod";
|
|
11
15
|
import { DuckDBEnumType, DuckDBInstance, DuckDBListType, DuckDBMapType, DuckDBStructType } from "@duckdb/node-api";
|
|
12
16
|
import { LRParser } from "@lezer/lr";
|
|
@@ -21,6 +25,18 @@ import typescriptPlugin from "prettier/parser-typescript";
|
|
|
21
25
|
import estree from "prettier/plugins/estree";
|
|
22
26
|
|
|
23
27
|
//#region src/constants.ts
|
|
28
|
+
/**
|
|
29
|
+
* SQG Constants - Centralized definitions for supported generators
|
|
30
|
+
*
|
|
31
|
+
* Generator format: <language>/<engine>/<driver>
|
|
32
|
+
* Short format: <language>/<engine> (uses default driver)
|
|
33
|
+
*/
|
|
34
|
+
/** Supported database engines */
|
|
35
|
+
const DB_ENGINES = [
|
|
36
|
+
"sqlite",
|
|
37
|
+
"duckdb",
|
|
38
|
+
"postgres"
|
|
39
|
+
];
|
|
24
40
|
/** All supported generators with their full specification */
|
|
25
41
|
const GENERATORS = {
|
|
26
42
|
"typescript/sqlite/better-sqlite3": {
|
|
@@ -31,6 +47,30 @@ const GENERATORS = {
|
|
|
31
47
|
extension: ".ts",
|
|
32
48
|
template: "better-sqlite3.hbs"
|
|
33
49
|
},
|
|
50
|
+
"typescript/sqlite/node": {
|
|
51
|
+
language: "typescript",
|
|
52
|
+
engine: "sqlite",
|
|
53
|
+
driver: "node",
|
|
54
|
+
description: "TypeScript with Node.js built-in SQLite",
|
|
55
|
+
extension: ".ts",
|
|
56
|
+
template: "node-sqlite.hbs"
|
|
57
|
+
},
|
|
58
|
+
"typescript/sqlite/libsql": {
|
|
59
|
+
language: "typescript",
|
|
60
|
+
engine: "sqlite",
|
|
61
|
+
driver: "libsql",
|
|
62
|
+
description: "TypeScript with @libsql/client (Turso)",
|
|
63
|
+
extension: ".ts",
|
|
64
|
+
template: "libsql.hbs"
|
|
65
|
+
},
|
|
66
|
+
"typescript/sqlite/turso": {
|
|
67
|
+
language: "typescript",
|
|
68
|
+
engine: "sqlite",
|
|
69
|
+
driver: "turso",
|
|
70
|
+
description: "TypeScript with Turso (limbo) native driver",
|
|
71
|
+
extension: ".ts",
|
|
72
|
+
template: "turso.hbs"
|
|
73
|
+
},
|
|
34
74
|
"typescript/duckdb/node-api": {
|
|
35
75
|
language: "typescript",
|
|
36
76
|
engine: "duckdb",
|
|
@@ -315,246 +355,513 @@ function formatErrorForOutput(err) {
|
|
|
315
355
|
}
|
|
316
356
|
|
|
317
357
|
//#endregion
|
|
318
|
-
//#region src/
|
|
319
|
-
const parser = LRParser.deserialize({
|
|
320
|
-
version: 14,
|
|
321
|
-
states: "&SOVQPOOO_QPO'#CwOdQPO'#CzOiQPO'#CvO!SQQO'#C^OOQO'#Cn'#CnQVQPOOO!aQSO,59cO!lQPO,59fOOQO'#Cp'#CpO!tQQO,59bOOQO'#C}'#C}O#iQQO'#CiOOQO,58x,58xOOQO-E6l-E6lOOQO'#Co'#CoO!aQSO1G.}O!dQSO1G.}OOQO'#Cb'#CbOOQO1G.}1G.}O#yQPO1G/QOOQO-E6n-E6nO$RQPO'#CdOOQO'#Cq'#CqO$WQQO1G.|OOQO'#Cm'#CmOOQO'#Cr'#CrO$xQQO,59TOOQO-E6m-E6mO!dQSO7+$iOOQO7+$i7+$iO%YQPO,59OOOQO-E6o-E6oOOQO-E6p-E6pOOQO<<HT<<HTO%_QQO1G.jOOQO'#Ce'#CeOiQPO7+$UO%jQQO<<Gp",
|
|
322
|
-
stateData: "&l~OiOS~ORPOVQO~OSVO~OSWO~OlXO~OYZOZZO[ZO^ZO_ZO`ZO~OR]PV]Pg]P~PnOT_OlXOmbO~OT_Olna~OlXOofORjaVjaYjaZja[ja^ja_ja`jagja~OliOR]XV]Xg]X~PnOT_Olni~OSoO~OofORjiVjiYjiZji[ji^ji_ji`jigji~OliOR]aV]ag]a~PnOpsO~OYtOZtO[tO~OlXORWyVWyYWyZWy[Wy^Wy_Wy`WygWyoWy~OR`o^iZTmYV_[~",
|
|
323
|
-
goto: "#prPPsPPPwP!R!VPPP!YPPP!]!a!g!q#T#ZPPP#a#ePP#ePP#iTTOUQcVSn`aRrmTgYhRusR]STj[kQUOR^UQ`VQdWTl`dQYRQaVWeYamvQm`RvuQhYRphQk[RqkTSOUTROUQ[STj[k",
|
|
324
|
-
nodeNames: "⚠ File QueryBlock BlockCommentStartSpecial Name Modifiers Config LineCommentStartSpecial SetVarLine Value StringLiteral StringLiteralSingle SQLText SQLBlock BlockComment LineComment VarRef BR",
|
|
325
|
-
maxTerm: 33,
|
|
326
|
-
skippedNodes: [0],
|
|
327
|
-
repeatNodeCount: 5,
|
|
328
|
-
tokenData: "$3b~RqOX#YXY'wYZ(iZ]#Y]^$W^p#Ypq'wqr#Yrs(}st#Ytu6^uw#Ywx9[xz#Yz{%_{}#Y}!OKi!O!P#Y!P!Q#%p!Q![$)l![!]$+U!]!_#Y!_!`$.U!`!b#Y!b!c$/U!c!}$)l!}#R#Y#R#S$)l#S#T#Y#T#o$)l#o;'S#Y;'S;=`'q<%lO#YU#_][QOX#YXZ$WZ]#Y]^$W^p#Ypq$Wqt#Ytu$Wuz#Yz{%_{;'S#Y;'S;=`'q<%lO#YS$ZTOz$Wz{$j{;'S$W;'S;=`%X<%lO$WS$mVOz$Wz{$j{!P$W!P!Q%S!Q;'S$W;'S;=`%X<%lO$WS%XOmSS%[P;=`<%l$WU%d_[QOX#YXZ$WZ]#Y]^$W^p#Ypq$Wqt#Ytu$Wuz#Yz{%_{!P#Y!P!Q&c!Q;'S#Y;'S;=`'q<%lO#YU&jVmS[QOX'PZ]'P^p'Pqt'Pu;'S'P;'S;=`'k<%lO'PQ'UV[QOX'PZ]'P^p'Pqt'Pu;'S'P;'S;=`'k<%lO'PQ'nP;=`<%l'PU'tP;=`<%l#Y~'|Xi~OX$WXY'wYp$Wpq'wqz$Wz{$j{;'S$W;'S;=`%X<%lO$W~(nTl~Oz$Wz{$j{;'S$W;'S;=`%X<%lO$WU)Sb[QOX(}XY*[YZ$WZ](}]^*[^p(}pq*[qr(}rs.yst(}tu*[uz(}z{/y{#O(}#O#P5V#P;'S(};'S;=`6W<%lO(}U*_ZOY*[YZ$WZr*[rs+Qsz*[z{+f{#O*[#O#P.Z#P;'S*[;'S;=`.s<%lO*[U+VTYQOz$Wz{$j{;'S$W;'S;=`%X<%lO$WU+i]OY*[YZ$WZr*[rs+Qsz*[z{+f{!P*[!P!Q,b!Q#O*[#O#P.Z#P;'S*[;'S;=`.s<%lO*[U,gWmSOY-PZr-Prs-ls#O-P#O#P-q#P;'S-P;'S;=`.T<%lO-PQ-SWOY-PZr-Prs-ls#O-P#O#P-q#P;'S-P;'S;=`.T<%lO-PQ-qOYQQ-tTOY-PYZ-PZ;'S-P;'S;=`.T<%lO-PQ.WP;=`<%l-PU.^VOY*[YZ*[Zz*[z{+f{;'S*[;'S;=`.s<%lO*[U.vP;=`<%l*[U/Q]YQ[QOX#YXZ$WZ]#Y]^$W^p#Ypq$Wqt#Ytu$Wuz#Yz{%_{;'S#Y;'S;=`'q<%lO#YU0Od[QOX(}XY*[YZ$WZ](}]^*[^p(}pq*[qr(}rs.yst(}tu*[uz(}z{/y{!P(}!P!Q1^!Q#O(}#O#P5V#P;'S(};'S;=`6W<%lO(}U1e_mS[QOX2dXY-PZ]2d]^-P^p2dpq-Pqr2drs3hst2dtu-Pu#O2d#O#P4U#P;'S2d;'S;=`5P<%lO2dQ2i_[QOX2dXY-PZ]2d]^-P^p2dpq-Pqr2drs3hst2dtu-Pu#O2d#O#P4U#P;'S2d;'S;=`5P<%lO2dQ3oVYQ[QOX'PZ]'P^p'Pqt'Pu;'S'P;'S;=`'k<%lO'PQ4Z[[QOX2dXY-PYZ-PZ]2d]^-P^p2dpq-Pqt2dtu-Pu;'S2d;'S;=`5P<%lO2dQ5SP;=`<%l2dU5[^[QOX(}XY*[YZ*[Z](}]^*[^p(}pq*[qt(}tu*[uz(}z{/y{;'S(};'S;=`6W<%lO(}U6ZP;=`<%l(}U6cV[QOz$Wz{$j{#o$W#o#p6x#p;'S$W;'S;=`%X<%lO$WU6{]Oz$Wz{$j{!Q$W!Q![7t![!c$W!c!}7t!}#R$W#R#S7t#S#T$W#T#o7t#o;'S$W;'S;=`%X<%lO$WU7w_Oz$Wz{$j{!Q$W!Q![7t![!c$W!c!}7t!}#R$W#R#S7t#S#T$W#T#o7t#o#q$W#q#r8v#r;'S$W;'S;=`%X<%lO$WU8{T`QOz$Wz{$j{;'S$W;'S;=`%X<%lO$WU9ab[QOX9[XY:iYZ$WZ]9[]^:i^p9[pq:iqt9[tu:iuw9[wxAVxz9[z{BV{#O9[#O#PHu#P;'S9[;'S;=`Kc<%lO9[U:lZOY:iYZ$WZw:iwx;_xz:iz{;s{#O:i#O#P?c#P;'S:i;'S;=`AP<%lO:iU;dTZQOz$Wz{$j{;'S$W;'S;=`%X<%lO$WU;v]OY:iYZ$WZw:iwx;_xz:iz{;s{!P:i!P!Q<o!Q#O:i#O#P?c#P;'S:i;'S;=`AP<%lO:iU<tWmSOY=^Zw=^wx=yx#O=^#O#P>O#P;'S=^;'S;=`?]<%lO=^Q=aWOY=^Zw=^wx=yx#O=^#O#P>O#P;'S=^;'S;=`?]<%lO=^Q>OOZQQ>RXOY=^YZ=^Zw=^wx>nx#O=^#O#P>O#P;'S=^;'S;=`?]<%lO=^Q>sWZQOY=^Zw=^wx=yx#O=^#O#P>O#P;'S=^;'S;=`?]<%lO=^Q?`P;=`<%l=^U?fZOY:iYZ:iZw:iwx@Xxz:iz{;s{#O:i#O#P?c#P;'S:i;'S;=`AP<%lO:iU@^ZZQOY:iYZ$WZw:iwx;_xz:iz{;s{#O:i#O#P?c#P;'S:i;'S;=`AP<%lO:iUASP;=`<%l:iUA^]ZQ[QOX#YXZ$WZ]#Y]^$W^p#Ypq$Wqt#Ytu$Wuz#Yz{%_{;'S#Y;'S;=`'q<%lO#YUB[d[QOX9[XY:iYZ$WZ]9[]^:i^p9[pq:iqt9[tu:iuw9[wxAVxz9[z{BV{!P9[!P!QCj!Q#O9[#O#PHu#P;'S9[;'S;=`Kc<%lO9[UCq_mS[QOXDpXY=^Z]Dp]^=^^pDppq=^qtDptu=^uwDpwxEtx#ODp#O#PFb#P;'SDp;'S;=`Ho<%lODpQDu_[QOXDpXY=^Z]Dp]^=^^pDppq=^qtDptu=^uwDpwxEtx#ODp#O#PFb#P;'SDp;'S;=`Ho<%lODpQE{VZQ[QOX'PZ]'P^p'Pqt'Pu;'S'P;'S;=`'k<%lO'PQFg`[QOXDpXY=^YZ=^Z]Dp]^=^^pDppq=^qtDptu=^uwDpwxGix#ODp#O#PFb#P;'SDp;'S;=`Ho<%lODpQGp_ZQ[QOXDpXY=^Z]Dp]^=^^pDppq=^qtDptu=^uwDpwxEtx#ODp#O#PFb#P;'SDp;'S;=`Ho<%lODpQHrP;=`<%lDpUHzb[QOX9[XY:iYZ:iZ]9[]^:i^p9[pq:iqt9[tu:iuw9[wxJSxz9[z{BV{#O9[#O#PHu#P;'S9[;'S;=`Kc<%lO9[UJZbZQ[QOX9[XY:iYZ$WZ]9[]^:i^p9[pq:iqt9[tu:iuw9[wxAVxz9[z{BV{#O9[#O#PHu#P;'S9[;'S;=`Kc<%lO9[UKfP;=`<%l9[VKn_[QOX#YXZ$WZ]#Y]^$W^p#Ypq$Wqt#Ytu$Wuz#Yz{%_{}#Y}!OLm!O;'S#Y;'S;=`'q<%lO#YVLtf_Q[QOXNYXY!&vYZ$WZ]NY]^! ]^pNYpq!&vqtNYtu! ]uzNYz{!#k{!gNY!g!h!8V!h!oNY!o!p!<w!p!sNY!s!t!DP!t!vNY!v!w!Hu!w;'SNY;'S;=`!&p<%lONYUNa^_Q[QOXNYXY! ]YZ$WZ]NY]^! ]^pNYpq! ]qtNYtu! ]uzNYz{!#k{;'SNY;'S;=`!&p<%lONYU! bV_QOY! ]YZ$WZz! ]z{! w{;'S! ];'S;=`!#e<%lO! ]U! |X_QOY! ]YZ$WZz! ]z{! w{!P! ]!P!Q!!i!Q;'S! ];'S;=`!#e<%lO! ]U!!pSmS_QOY!!|Z;'S!!|;'S;=`!#_<%lO!!|Q!#RS_QOY!!|Z;'S!!|;'S;=`!#_<%lO!!|Q!#bP;=`<%l!!|U!#hP;=`<%l! ]U!#r`_Q[QOXNYXY! ]YZ$WZ]NY]^! ]^pNYpq! ]qtNYtu! ]uzNYz{!#k{!PNY!P!Q!$t!Q;'SNY;'S;=`!&p<%lONYU!$}ZmS_Q[QOX!%pXY!!|Z]!%p]^!!|^p!%ppq!!|qt!%ptu!!|u;'S!%p;'S;=`!&j<%lO!%pQ!%wZ_Q[QOX!%pXY!!|Z]!%p]^!!|^p!%ppq!!|qt!%ptu!!|u;'S!%p;'S;=`!&j<%lO!%pQ!&mP;=`<%l!%pU!&sP;=`<%lNYV!&{b_QOX! ]XY!&vYZ$WZp! ]pq!&vqz! ]z{! w{!g! ]!g!h!(T!h!o! ]!o!p!*u!p!s! ]!s!t!.}!t!v! ]!v!w!1s!w;'S! ];'S;=`!#e<%lO! ]V!(YX_QOY! ]YZ$WZz! ]z{! w{!z! ]!z!{!(u!{;'S! ];'S;=`!#e<%lO! ]V!(zX_QOY! ]YZ$WZz! ]z{! w{!g! ]!g!h!)g!h;'S! ];'S;=`!#e<%lO! ]V!)lX_QOY! ]YZ$WZz! ]z{! w{!e! ]!e!f!*X!f;'S! ];'S;=`!#e<%lO! ]V!*`VVR_QOY! ]YZ$WZz! ]z{! w{;'S! ];'S;=`!#e<%lO! ]V!*zX_QOY! ]YZ$WZz! ]z{! w{!k! ]!k!l!+g!l;'S! ];'S;=`!#e<%lO! ]V!+lX_QOY! ]YZ$WZz! ]z{! w{!i! ]!i!j!,X!j;'S! ];'S;=`!#e<%lO! ]V!,^X_QOY! ]YZ$WZz! ]z{! w{!t! ]!t!u!,y!u;'S! ];'S;=`!#e<%lO! ]V!-OX_QOY! ]YZ$WZz! ]z{! w{!c! ]!c!d!-k!d;'S! ];'S;=`!#e<%lO! ]V!-pX_QOY! ]YZ$WZz! ]z{! w{!v! ]!v!w!.]!w;'S! ];'S;=`!#e<%lO! ]V!.bX_QOY! ]YZ$WZz! ]z{! w{!g! ]!g!h!*X!h;'S! ];'S;=`!#e<%lO! ]V!/SX_QOY! ]YZ$WZz! ]z{! w{!w! ]!w!x!/o!x;'S! ];'S;=`!#e<%lO! ]V!/tX_QOY! ]YZ$WZz! ]z{! w{!g! ]!g!h!0a!h;'S! ];'S;=`!#e<%lO! ]V!0fX_QOY! ]YZ$WZz! ]z{! w{!t! ]!t!u!1R!u;'S! ];'S;=`!#e<%lO! ]V!1WX_QOY! ]YZ$WZz! ]z{! w{!{! ]!{!|!*X!|;'S! ];'S;=`!#e<%lO! ]V!1xZ_QOY! ]YZ$WZz! ]z{! w{!c! ]!c!d!2k!d!g! ]!g!h!3}!h;'S! ];'S;=`!#e<%lO! ]V!2pX_QOY! ]YZ$WZz! ]z{! w{!d! ]!d!e!3]!e;'S! ];'S;=`!#e<%lO! ]V!3bX_QOY! ]YZ$WZz! ]z{! w{!n! ]!n!o!.]!o;'S! ];'S;=`!#e<%lO! ]V!4SX_QOY! ]YZ$WZz! ]z{! w{!u! ]!u!v!4o!v;'S! ];'S;=`!#e<%lO! ]V!4tX_QOY! ]YZ$WZz! ]z{! w{!v! ]!v!w!5a!w;'S! ];'S;=`!#e<%lO! ]V!5fX_QOY! ]YZ$WZz! ]z{! w{!f! ]!f!g!6R!g;'S! ];'S;=`!#e<%lO! ]V!6WX_QOY! ]YZ$WZz! ]z{! w{!c! ]!c!d!6s!d;'S! ];'S;=`!#e<%lO! ]V!6xX_QOY! ]YZ$WZz! ]z{! w{!v! ]!v!w!7e!w;'S! ];'S;=`!#e<%lO! ]V!7jX_QOY! ]YZ$WZz! ]z{! w{!c! ]!c!d!*X!d;'S! ];'S;=`!#e<%lO! ]V!8^`_Q[QOXNYXY! ]YZ$WZ]NY]^! ]^pNYpq! ]qtNYtu! ]uzNYz{!#k{!zNY!z!{!9`!{;'SNY;'S;=`!&p<%lONYV!9g`_Q[QOXNYXY! ]YZ$WZ]NY]^! ]^pNYpq! ]qtNYtu! ]uzNYz{!#k{!gNY!g!h!:i!h;'SNY;'S;=`!&p<%lONYV!:p`_Q[QOXNYXY! ]YZ$WZ]NY]^! ]^pNYpq! ]qtNYtu! ]uzNYz{!#k{!eNY!e!f!;r!f;'SNY;'S;=`!&p<%lONYV!;{^VR_Q[QOXNYXY! ]YZ$WZ]NY]^! ]^pNYpq! ]qtNYtu! ]uzNYz{!#k{;'SNY;'S;=`!&p<%lONYV!=O`_Q[QOXNYXY! ]YZ$WZ]NY]^! ]^pNYpq! ]qtNYtu! ]uzNYz{!#k{!kNY!k!l!>Q!l;'SNY;'S;=`!&p<%lONYV!>X`_Q[QOXNYXY! ]YZ$WZ]NY]^! ]^pNYpq! ]qtNYtu! ]uzNYz{!#k{!iNY!i!j!?Z!j;'SNY;'S;=`!&p<%lONYV!?b`_Q[QOXNYXY! ]YZ$WZ]NY]^! ]^pNYpq! ]qtNYtu! ]uzNYz{!#k{!tNY!t!u!@d!u;'SNY;'S;=`!&p<%lONYV!@k`_Q[QOXNYXY! ]YZ$WZ]NY]^! ]^pNYpq! ]qtNYtu! ]uzNYz{!#k{!cNY!c!d!Am!d;'SNY;'S;=`!&p<%lONYV!At`_Q[QOXNYXY! ]YZ$WZ]NY]^! ]^pNYpq! ]qtNYtu! ]uzNYz{!#k{!vNY!v!w!Bv!w;'SNY;'S;=`!&p<%lONYV!B}`_Q[QOXNYXY! ]YZ$WZ]NY]^! ]^pNYpq! ]qtNYtu! ]uzNYz{!#k{!gNY!g!h!;r!h;'SNY;'S;=`!&p<%lONYV!DW`_Q[QOXNYXY! ]YZ$WZ]NY]^! ]^pNYpq! ]qtNYtu! ]uzNYz{!#k{!wNY!w!x!EY!x;'SNY;'S;=`!&p<%lONYV!Ea`_Q[QOXNYXY! ]YZ$WZ]NY]^! ]^pNYpq! ]qtNYtu! ]uzNYz{!#k{!gNY!g!h!Fc!h;'SNY;'S;=`!&p<%lONYV!Fj`_Q[QOXNYXY! ]YZ$WZ]NY]^! ]^pNYpq! ]qtNYtu! ]uzNYz{!#k{!tNY!t!u!Gl!u;'SNY;'S;=`!&p<%lONYV!Gs`_Q[QOXNYXY! ]YZ$WZ]NY]^! ]^pNYpq! ]qtNYtu! ]uzNYz{!#k{!{NY!{!|!;r!|;'SNY;'S;=`!&p<%lONYV!H|b_Q[QOXNYXY! ]YZ$WZ]NY]^! ]^pNYpq! ]qtNYtu! ]uzNYz{!#k{!cNY!c!d!JU!d!gNY!g!h!Lh!h;'SNY;'S;=`!&p<%lONYV!J]`_Q[QOXNYXY! ]YZ$WZ]NY]^! ]^pNYpq! ]qtNYtu! ]uzNYz{!#k{!dNY!d!e!K_!e;'SNY;'S;=`!&p<%lONYV!Kf`_Q[QOXNYXY! ]YZ$WZ]NY]^! ]^pNYpq! ]qtNYtu! ]uzNYz{!#k{!nNY!n!o!Bv!o;'SNY;'S;=`!&p<%lONYV!Lo`_Q[QOXNYXY! ]YZ$WZ]NY]^! ]^pNYpq! ]qtNYtu! ]uzNYz{!#k{!uNY!u!v!Mq!v;'SNY;'S;=`!&p<%lONYV!Mx`_Q[QOXNYXY! ]YZ$WZ]NY]^! ]^pNYpq! ]qtNYtu! ]uzNYz{!#k{!vNY!v!w!Nz!w;'SNY;'S;=`!&p<%lONYV# R`_Q[QOXNYXY! ]YZ$WZ]NY]^! ]^pNYpq! ]qtNYtu! ]uzNYz{!#k{!fNY!f!g#!T!g;'SNY;'S;=`!&p<%lONYV#![`_Q[QOXNYXY! ]YZ$WZ]NY]^! ]^pNYpq! ]qtNYtu! ]uzNYz{!#k{!cNY!c!d##^!d;'SNY;'S;=`!&p<%lONYV##e`_Q[QOXNYXY! ]YZ$WZ]NY]^! ]^pNYpq! ]qtNYtu! ]uzNYz{!#k{!vNY!v!w#$g!w;'SNY;'S;=`!&p<%lONYV#$n`_Q[QOXNYXY! ]YZ$WZ]NY]^! ]^pNYpq! ]qtNYtu! ]uzNYz{!#k{!cNY!c!d!;r!d;'SNY;'S;=`!&p<%lONYV#%u][QOX#YXZ$WZ]#Y]^$W^p#Ypq$Wqt#Ytu$Wuz#Yz{#&n{;'S#Y;'S;=`'q<%lO#YV#&sh[QOX#(_XY#,`YZ#,`Z]#(_]^#)]^p#(_pq#,`qt#(_tu#)]uz#(_z{#*f{!P#(_!P!Q#9m!Q!g#(_!g!h#>j!h!o#(_!o!p#Bv!p!s#(_!s!t#I`!t!v#(_!v!w#Mp!w;'S#(_;'S;=`#,Y<%lO#(_U#(d][QOX#(_XZ#)]Z]#(_]^#)]^p#(_pq#)]qt#(_tu#)]uz#(_z{#*f{;'S#(_;'S;=`#,Y<%lO#(_U#)`TOz#)]z{#)o{;'S#)];'S;=`#*`<%lO#)]U#)rVOz#)]z{#)o{!P#)]!P!Q#*X!Q;'S#)];'S;=`#*`<%lO#)]U#*`O^QmSU#*cP;=`<%l#)]U#*k_[QOX#(_XZ#)]Z]#(_]^#)]^p#(_pq#)]qt#(_tu#)]uz#(_z{#*f{!P#(_!P!Q#+j!Q;'S#(_;'S;=`#,Y<%lO#(_U#+sV^QmS[QOX'PZ]'P^p'Pqt'Pu;'S'P;'S;=`'k<%lO'PU#,]P;=`<%l#(_V#,cbOX#)]XY#,`YZ#,`Zp#)]pq#,`qz#)]z{#)o{!g#)]!g!h#-k!h!o#)]!o!p#/k!p!s#)]!s!t#2q!t!v#)]!v!w#4u!w;'S#)];'S;=`#*`<%lO#)]V#-nVOz#)]z{#)o{!z#)]!z!{#.T!{;'S#)];'S;=`#*`<%lO#)]V#.WVOz#)]z{#)o{!g#)]!g!h#.m!h;'S#)];'S;=`#*`<%lO#)]V#.pVOz#)]z{#)o{!e#)]!e!f#/V!f;'S#)];'S;=`#*`<%lO#)]V#/[TRROz#)]z{#)o{;'S#)];'S;=`#*`<%lO#)]V#/nVOz#)]z{#)o{!k#)]!k!l#0T!l;'S#)];'S;=`#*`<%lO#)]V#0WVOz#)]z{#)o{!i#)]!i!j#0m!j;'S#)];'S;=`#*`<%lO#)]V#0pVOz#)]z{#)o{!t#)]!t!u#1V!u;'S#)];'S;=`#*`<%lO#)]V#1YVOz#)]z{#)o{!c#)]!c!d#1o!d;'S#)];'S;=`#*`<%lO#)]V#1rVOz#)]z{#)o{!v#)]!v!w#2X!w;'S#)];'S;=`#*`<%lO#)]V#2[VOz#)]z{#)o{!g#)]!g!h#/V!h;'S#)];'S;=`#*`<%lO#)]V#2tVOz#)]z{#)o{!w#)]!w!x#3Z!x;'S#)];'S;=`#*`<%lO#)]V#3^VOz#)]z{#)o{!g#)]!g!h#3s!h;'S#)];'S;=`#*`<%lO#)]V#3vVOz#)]z{#)o{!t#)]!t!u#4]!u;'S#)];'S;=`#*`<%lO#)]V#4`VOz#)]z{#)o{!{#)]!{!|#/V!|;'S#)];'S;=`#*`<%lO#)]V#4xXOz#)]z{#)o{!c#)]!c!d#5e!d!g#)]!g!h#6g!h;'S#)];'S;=`#*`<%lO#)]V#5hVOz#)]z{#)o{!d#)]!d!e#5}!e;'S#)];'S;=`#*`<%lO#)]V#6QVOz#)]z{#)o{!n#)]!n!o#2X!o;'S#)];'S;=`#*`<%lO#)]V#6jVOz#)]z{#)o{!u#)]!u!v#7P!v;'S#)];'S;=`#*`<%lO#)]V#7SVOz#)]z{#)o{!v#)]!v!w#7i!w;'S#)];'S;=`#*`<%lO#)]V#7lVOz#)]z{#)o{!f#)]!f!g#8R!g;'S#)];'S;=`#*`<%lO#)]V#8UVOz#)]z{#)o{!c#)]!c!d#8k!d;'S#)];'S;=`#*`<%lO#)]V#8nVOz#)]z{#)o{!v#)]!v!w#9T!w;'S#)];'S;=`#*`<%lO#)]V#9WVOz#)]z{#)o{!c#)]!c!d#/V!d;'S#)];'S;=`#*`<%lO#)]U#9t]mS[QOX#:mXZ#;kZ]#:m]^#;k^p#:mpq#;kqt#:mtu#;kuz#:mz{#<r{;'S#:m;'S;=`#>d<%lO#:mQ#:r][QOX#:mXZ#;kZ]#:m]^#;k^p#:mpq#;kqt#:mtu#;kuz#:mz{#<r{;'S#:m;'S;=`#>d<%lO#:mQ#;nTOz#;kz{#;}{;'S#;k;'S;=`#<l<%lO#;kQ#<QVOz#;kz{#;}{!P#;k!P!Q#<g!Q;'S#;k;'S;=`#<l<%lO#;kQ#<lO^QQ#<oP;=`<%l#;kQ#<w_[QOX#:mXZ#;kZ]#:m]^#;k^p#:mpq#;kqt#:mtu#;kuz#:mz{#<r{!P#:m!P!Q#=v!Q;'S#:m;'S;=`#>d<%lO#:mQ#=}V^Q[QOX'PZ]'P^p'Pqt'Pu;'S'P;'S;=`'k<%lO'PQ#>gP;=`<%l#:mV#>o_[QOX#(_XZ#)]Z]#(_]^#)]^p#(_pq#)]qt#(_tu#)]uz#(_z{#*f{!z#(_!z!{#?n!{;'S#(_;'S;=`#,Y<%lO#(_V#?s_[QOX#(_XZ#)]Z]#(_]^#)]^p#(_pq#)]qt#(_tu#)]uz#(_z{#*f{!g#(_!g!h#@r!h;'S#(_;'S;=`#,Y<%lO#(_V#@w_[QOX#(_XZ#)]Z]#(_]^#)]^p#(_pq#)]qt#(_tu#)]uz#(_z{#*f{!e#(_!e!f#Av!f;'S#(_;'S;=`#,Y<%lO#(_V#A}]RR[QOX#(_XZ#)]Z]#(_]^#)]^p#(_pq#)]qt#(_tu#)]uz#(_z{#*f{;'S#(_;'S;=`#,Y<%lO#(_V#B{_[QOX#(_XZ#)]Z]#(_]^#)]^p#(_pq#)]qt#(_tu#)]uz#(_z{#*f{!k#(_!k!l#Cz!l;'S#(_;'S;=`#,Y<%lO#(_V#DP_[QOX#(_XZ#)]Z]#(_]^#)]^p#(_pq#)]qt#(_tu#)]uz#(_z{#*f{!i#(_!i!j#EO!j;'S#(_;'S;=`#,Y<%lO#(_V#ET_[QOX#(_XZ#)]Z]#(_]^#)]^p#(_pq#)]qt#(_tu#)]uz#(_z{#*f{!t#(_!t!u#FS!u;'S#(_;'S;=`#,Y<%lO#(_V#FX_[QOX#(_XZ#)]Z]#(_]^#)]^p#(_pq#)]qt#(_tu#)]uz#(_z{#*f{!c#(_!c!d#GW!d;'S#(_;'S;=`#,Y<%lO#(_V#G]_[QOX#(_XZ#)]Z]#(_]^#)]^p#(_pq#)]qt#(_tu#)]uz#(_z{#*f{!v#(_!v!w#H[!w;'S#(_;'S;=`#,Y<%lO#(_V#Ha_[QOX#(_XZ#)]Z]#(_]^#)]^p#(_pq#)]qt#(_tu#)]uz#(_z{#*f{!g#(_!g!h#Av!h;'S#(_;'S;=`#,Y<%lO#(_V#Ie_[QOX#(_XZ#)]Z]#(_]^#)]^p#(_pq#)]qt#(_tu#)]uz#(_z{#*f{!w#(_!w!x#Jd!x;'S#(_;'S;=`#,Y<%lO#(_V#Ji_[QOX#(_XZ#)]Z]#(_]^#)]^p#(_pq#)]qt#(_tu#)]uz#(_z{#*f{!g#(_!g!h#Kh!h;'S#(_;'S;=`#,Y<%lO#(_V#Km_[QOX#(_XZ#)]Z]#(_]^#)]^p#(_pq#)]qt#(_tu#)]uz#(_z{#*f{!t#(_!t!u#Ll!u;'S#(_;'S;=`#,Y<%lO#(_V#Lq_[QOX#(_XZ#)]Z]#(_]^#)]^p#(_pq#)]qt#(_tu#)]uz#(_z{#*f{!{#(_!{!|#Av!|;'S#(_;'S;=`#,Y<%lO#(_V#Mua[QOX#(_XZ#)]Z]#(_]^#)]^p#(_pq#)]qt#(_tu#)]uz#(_z{#*f{!c#(_!c!d#Nz!d!g#(_!g!h$#S!h;'S#(_;'S;=`#,Y<%lO#(_V$ P_[QOX#(_XZ#)]Z]#(_]^#)]^p#(_pq#)]qt#(_tu#)]uz#(_z{#*f{!d#(_!d!e$!O!e;'S#(_;'S;=`#,Y<%lO#(_V$!T_[QOX#(_XZ#)]Z]#(_]^#)]^p#(_pq#)]qt#(_tu#)]uz#(_z{#*f{!n#(_!n!o#H[!o;'S#(_;'S;=`#,Y<%lO#(_V$#X_[QOX#(_XZ#)]Z]#(_]^#)]^p#(_pq#)]qt#(_tu#)]uz#(_z{#*f{!u#(_!u!v$$W!v;'S#(_;'S;=`#,Y<%lO#(_V$$]_[QOX#(_XZ#)]Z]#(_]^#)]^p#(_pq#)]qt#(_tu#)]uz#(_z{#*f{!v#(_!v!w$%[!w;'S#(_;'S;=`#,Y<%lO#(_V$%a_[QOX#(_XZ#)]Z]#(_]^#)]^p#(_pq#)]qt#(_tu#)]uz#(_z{#*f{!f#(_!f!g$&`!g;'S#(_;'S;=`#,Y<%lO#(_V$&e_[QOX#(_XZ#)]Z]#(_]^#)]^p#(_pq#)]qt#(_tu#)]uz#(_z{#*f{!c#(_!c!d$'d!d;'S#(_;'S;=`#,Y<%lO#(_V$'i_[QOX#(_XZ#)]Z]#(_]^#)]^p#(_pq#)]qt#(_tu#)]uz#(_z{#*f{!v#(_!v!w$(h!w;'S#(_;'S;=`#,Y<%lO#(_V$(m_[QOX#(_XZ#)]Z]#(_]^#)]^p#(_pq#)]qt#(_tu#)]uz#(_z{#*f{!c#(_!c!d#Av!d;'S#(_;'S;=`#,Y<%lO#(_V$)seSP[QOX#YXZ$WZ]#Y]^$W^p#Ypq$Wqt#Ytu$Wuz#Yz{%_{!Q#Y!Q![$)l![!c#Y!c!}$)l!}#R#Y#R#S$)l#S#T#Y#T#o$)l#o;'S#Y;'S;=`'q<%lO#Y~$+Ze[QOX#YXZ$WZ]#Y]^$W^p#Ypq$Wqt#Ytu$Wuz#Yz{%_{!Q#Y!Q![$,l![!c#Y!c!}$,l!}#R#Y#R#S$,l#S#T#Y#T#o$,l#o;'S#Y;'S;=`'q<%lO#Y~$,seT~[QOX#YXZ$WZ]#Y]^$W^p#Ypq$Wqt#Ytu$Wuz#Yz{%_{!Q#Y!Q![$,l![!c#Y!c!}$,l!}#R#Y#R#S$,l#S#T#Y#T#o$,l#o;'S#Y;'S;=`'q<%lO#YV$.]]pP[QOX#YXZ$WZ]#Y]^$W^p#Ypq$Wqt#Ytu$Wuz#Yz{%_{;'S#Y;'S;=`'q<%lO#YU$/Z_[QOX#YXZ$WZ]#Y]^$W^p#Ypq$Wqt#Ytu$Wuz#Yz{%_{#g#Y#g#h$0Y#h;'S#Y;'S;=`'q<%lO#YU$0__[QOX#YXZ$WZ]#Y]^$W^p#Ypq$Wqt#Ytu$Wuz#Yz{%_{#X#Y#X#Y$1^#Y;'S#Y;'S;=`'q<%lO#YU$1c_[QOX#YXZ$WZ]#Y]^$W^p#Ypq$Wqt#Ytu$Wuz#Yz{%_{#h#Y#h#i$2b#i;'S#Y;'S;=`'q<%lO#YU$2i]oQ[QOX#YXZ$WZ]#Y]^$W^p#Ypq$Wqt#Ytu$Wuz#Yz{%_{;'S#Y;'S;=`'q<%lO#Y",
|
|
329
|
-
tokenizers: [
|
|
330
|
-
0,
|
|
331
|
-
1,
|
|
332
|
-
2
|
|
333
|
-
],
|
|
334
|
-
topRules: { "File": [0, 1] },
|
|
335
|
-
tokenPrec: 245
|
|
336
|
-
});
|
|
337
|
-
|
|
338
|
-
//#endregion
|
|
339
|
-
//#region src/sql-query.ts
|
|
340
|
-
var ListType = class {
|
|
341
|
-
constructor(baseType) {
|
|
342
|
-
this.baseType = baseType;
|
|
343
|
-
}
|
|
344
|
-
toString() {
|
|
345
|
-
return `${this.baseType.toString()}[]`;
|
|
346
|
-
}
|
|
347
|
-
};
|
|
348
|
-
var StructType = class {
|
|
349
|
-
constructor(fields) {
|
|
350
|
-
this.fields = fields;
|
|
351
|
-
}
|
|
352
|
-
toString() {
|
|
353
|
-
return `STRUCT(${this.fields.map((f) => `"${f.name}" ${f.type.toString()}`).join(", ")})`;
|
|
354
|
-
}
|
|
355
|
-
};
|
|
356
|
-
var MapType = class {
|
|
357
|
-
constructor(keyType, valueType) {
|
|
358
|
-
this.keyType = keyType;
|
|
359
|
-
this.valueType = valueType;
|
|
360
|
-
}
|
|
361
|
-
toString() {
|
|
362
|
-
return `MAP(${this.keyType.toString()}, ${this.valueType.toString()})`;
|
|
363
|
-
}
|
|
364
|
-
};
|
|
365
|
-
var EnumType = class {
|
|
366
|
-
constructor(values) {
|
|
367
|
-
this.values = values;
|
|
368
|
-
}
|
|
369
|
-
toString() {
|
|
370
|
-
return `ENUM(${this.values.map((v) => `'${v}'`).join(", ")})`;
|
|
371
|
-
}
|
|
372
|
-
};
|
|
373
|
-
var SQLQuery = class {
|
|
374
|
-
columns;
|
|
375
|
-
allColumns;
|
|
376
|
-
constructor(filename, id, rawQuery, queryAnonymous, queryNamed, queryPositional, type, isOne, isPluck, variables, config) {
|
|
377
|
-
this.filename = filename;
|
|
378
|
-
this.id = id;
|
|
379
|
-
this.rawQuery = rawQuery;
|
|
380
|
-
this.queryAnonymous = queryAnonymous;
|
|
381
|
-
this.queryNamed = queryNamed;
|
|
382
|
-
this.queryPositional = queryPositional;
|
|
383
|
-
this.type = type;
|
|
384
|
-
this.isOne = isOne;
|
|
385
|
-
this.isPluck = isPluck;
|
|
386
|
-
this.variables = variables;
|
|
387
|
-
this.config = config;
|
|
388
|
-
this.columns = [];
|
|
389
|
-
}
|
|
390
|
-
get isQuery() {
|
|
391
|
-
return this.type === "QUERY";
|
|
392
|
-
}
|
|
393
|
-
get isExec() {
|
|
394
|
-
return this.type === "EXEC";
|
|
395
|
-
}
|
|
396
|
-
get isMigrate() {
|
|
397
|
-
return this.type === "MIGRATE";
|
|
398
|
-
}
|
|
399
|
-
get isTestdata() {
|
|
400
|
-
return this.type === "TESTDATA";
|
|
401
|
-
}
|
|
402
|
-
get skipGenerateFunction() {
|
|
403
|
-
return this.isTestdata || this.isMigrate || this.id.startsWith("_");
|
|
404
|
-
}
|
|
405
|
-
validateVariables() {
|
|
406
|
-
const missingVars = [];
|
|
407
|
-
const varRegex = /\$\{([a-zA-Z_][a-zA-Z0-9_]*)\}/g;
|
|
408
|
-
let match;
|
|
409
|
-
while (true) {
|
|
410
|
-
match = varRegex.exec(this.rawQuery);
|
|
411
|
-
if (match === null) break;
|
|
412
|
-
const varName = match[1];
|
|
413
|
-
if (!this.variables.has(varName)) missingVars.push(varName);
|
|
414
|
-
}
|
|
415
|
-
return missingVars;
|
|
416
|
-
}
|
|
417
|
-
};
|
|
358
|
+
//#region src/init.ts
|
|
418
359
|
/**
|
|
419
|
-
*
|
|
420
|
-
* TABLE annotations specify a table name for which to generate bulk insert appenders.
|
|
360
|
+
* SQG Project Initialization - Creates new SQG projects with example files
|
|
421
361
|
*/
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
362
|
+
/**
|
|
363
|
+
* Get the default generator for a language preference
|
|
364
|
+
*/
|
|
365
|
+
function getDefaultGenerator() {
|
|
366
|
+
return "typescript/sqlite";
|
|
367
|
+
}
|
|
368
|
+
/**
|
|
369
|
+
* Generate example SQL content based on engine
|
|
370
|
+
*/
|
|
371
|
+
function getExampleSql(engine) {
|
|
372
|
+
return {
|
|
373
|
+
sqlite: `-- MIGRATE 1
|
|
374
|
+
-- Create the users table (SQG Example - https://sqg.dev/guides/sql-syntax/)
|
|
375
|
+
CREATE TABLE users (
|
|
376
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
377
|
+
name TEXT NOT NULL,
|
|
378
|
+
email TEXT UNIQUE NOT NULL,
|
|
379
|
+
created_at TEXT DEFAULT CURRENT_TIMESTAMP
|
|
380
|
+
);
|
|
381
|
+
|
|
382
|
+
-- MIGRATE 2
|
|
383
|
+
CREATE TABLE posts (
|
|
384
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
385
|
+
user_id INTEGER NOT NULL REFERENCES users(id),
|
|
386
|
+
title TEXT NOT NULL,
|
|
387
|
+
content TEXT,
|
|
388
|
+
published INTEGER DEFAULT 0,
|
|
389
|
+
created_at TEXT DEFAULT CURRENT_TIMESTAMP
|
|
390
|
+
);
|
|
391
|
+
|
|
392
|
+
-- TESTDATA seed_data
|
|
393
|
+
INSERT INTO users (name, email) VALUES ('Alice', 'alice@example.com');
|
|
394
|
+
INSERT INTO users (name, email) VALUES ('Bob', 'bob@example.com');
|
|
395
|
+
INSERT INTO posts (user_id, title, content, published) VALUES (1, 'Hello World', 'My first post!', 1);
|
|
396
|
+
`,
|
|
397
|
+
duckdb: `-- MIGRATE 1
|
|
398
|
+
-- Create the users table (SQG Example - https://sqg.dev/guides/sql-syntax/)
|
|
399
|
+
CREATE TABLE users (
|
|
400
|
+
id INTEGER PRIMARY KEY,
|
|
401
|
+
name VARCHAR NOT NULL,
|
|
402
|
+
email VARCHAR UNIQUE NOT NULL,
|
|
403
|
+
metadata STRUCT(role VARCHAR, active BOOLEAN),
|
|
404
|
+
tags VARCHAR[],
|
|
405
|
+
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
406
|
+
);
|
|
407
|
+
|
|
408
|
+
-- MIGRATE 2
|
|
409
|
+
CREATE TABLE posts (
|
|
410
|
+
id INTEGER PRIMARY KEY,
|
|
411
|
+
user_id INTEGER NOT NULL REFERENCES users(id),
|
|
412
|
+
title VARCHAR NOT NULL,
|
|
413
|
+
content VARCHAR,
|
|
414
|
+
published BOOLEAN DEFAULT FALSE,
|
|
415
|
+
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
416
|
+
);
|
|
417
|
+
|
|
418
|
+
-- TESTDATA seed_data
|
|
419
|
+
INSERT INTO users (id, name, email, metadata, tags)
|
|
420
|
+
VALUES (1, 'Alice', 'alice@example.com', {'role': 'admin', 'active': true}, ['developer', 'lead']);
|
|
421
|
+
INSERT INTO users (id, name, email, metadata, tags)
|
|
422
|
+
VALUES (2, 'Bob', 'bob@example.com', {'role': 'user', 'active': true}, ['developer']);
|
|
423
|
+
INSERT INTO posts (id, user_id, title, content, published)
|
|
424
|
+
VALUES (1, 1, 'Hello World', 'My first post!', TRUE);
|
|
425
|
+
`,
|
|
426
|
+
postgres: `-- MIGRATE 1
|
|
427
|
+
-- Create the users table (SQG Example - https://sqg.dev/guides/sql-syntax/)
|
|
428
|
+
CREATE TABLE users (
|
|
429
|
+
id SERIAL PRIMARY KEY,
|
|
430
|
+
name TEXT NOT NULL,
|
|
431
|
+
email TEXT UNIQUE NOT NULL,
|
|
432
|
+
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
433
|
+
);
|
|
434
|
+
|
|
435
|
+
-- MIGRATE 2
|
|
436
|
+
CREATE TABLE posts (
|
|
437
|
+
id SERIAL PRIMARY KEY,
|
|
438
|
+
user_id INTEGER NOT NULL REFERENCES users(id),
|
|
439
|
+
title TEXT NOT NULL,
|
|
440
|
+
content TEXT,
|
|
441
|
+
published BOOLEAN DEFAULT FALSE,
|
|
442
|
+
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
443
|
+
);
|
|
444
|
+
|
|
445
|
+
-- TESTDATA seed_data
|
|
446
|
+
INSERT INTO users (name, email) VALUES ('Alice', 'alice@example.com');
|
|
447
|
+
INSERT INTO users (name, email) VALUES ('Bob', 'bob@example.com');
|
|
448
|
+
INSERT INTO posts (user_id, title, content, published) VALUES (1, 'Hello World', 'My first post!', TRUE);
|
|
449
|
+
`
|
|
450
|
+
}[engine] + `
|
|
451
|
+
-- QUERY list_users
|
|
452
|
+
SELECT id, name, email, created_at
|
|
453
|
+
FROM users
|
|
454
|
+
ORDER BY created_at DESC;
|
|
455
|
+
|
|
456
|
+
-- QUERY get_user_by_id :one
|
|
457
|
+
@set id = 1
|
|
458
|
+
SELECT id, name, email, created_at
|
|
459
|
+
FROM users
|
|
460
|
+
WHERE id = \${id};
|
|
461
|
+
|
|
462
|
+
-- QUERY get_user_by_email :one
|
|
463
|
+
@set email = 'alice@example.com'
|
|
464
|
+
SELECT id, name, email, created_at
|
|
465
|
+
FROM users
|
|
466
|
+
WHERE email = \${email};
|
|
467
|
+
|
|
468
|
+
-- QUERY count_users :one :pluck
|
|
469
|
+
SELECT COUNT(*) FROM users;
|
|
470
|
+
|
|
471
|
+
-- QUERY list_posts_by_user
|
|
472
|
+
@set user_id = 1
|
|
473
|
+
SELECT p.id, p.title, p.content, p.published, p.created_at
|
|
474
|
+
FROM posts p
|
|
475
|
+
WHERE p.user_id = \${user_id}
|
|
476
|
+
ORDER BY p.created_at DESC;
|
|
477
|
+
|
|
478
|
+
-- QUERY list_published_posts
|
|
479
|
+
SELECT
|
|
480
|
+
p.id,
|
|
481
|
+
p.title,
|
|
482
|
+
p.content,
|
|
483
|
+
p.created_at,
|
|
484
|
+
u.name as author_name,
|
|
485
|
+
u.email as author_email
|
|
486
|
+
FROM posts p
|
|
487
|
+
JOIN users u ON p.user_id = u.id
|
|
488
|
+
WHERE p.published = 1
|
|
489
|
+
ORDER BY p.created_at DESC;
|
|
490
|
+
` + {
|
|
491
|
+
sqlite: `
|
|
492
|
+
-- EXEC create_user
|
|
493
|
+
@set name = 'New User'
|
|
494
|
+
@set email = 'new@example.com'
|
|
495
|
+
INSERT INTO users (name, email)
|
|
496
|
+
VALUES (\${name}, \${email});
|
|
497
|
+
|
|
498
|
+
-- EXEC create_post
|
|
499
|
+
@set user_id = 1
|
|
500
|
+
@set title = 'New Post'
|
|
501
|
+
@set content = 'Post content here'
|
|
502
|
+
INSERT INTO posts (user_id, title, content)
|
|
503
|
+
VALUES (\${user_id}, \${title}, \${content});
|
|
504
|
+
|
|
505
|
+
-- EXEC publish_post
|
|
506
|
+
@set id = 1
|
|
507
|
+
UPDATE posts SET published = 1 WHERE id = \${id};
|
|
508
|
+
|
|
509
|
+
-- EXEC delete_post
|
|
510
|
+
@set id = 1
|
|
511
|
+
DELETE FROM posts WHERE id = \${id};
|
|
512
|
+
`,
|
|
513
|
+
duckdb: `
|
|
514
|
+
-- EXEC create_user
|
|
515
|
+
@set id = 100
|
|
516
|
+
@set name = 'New User'
|
|
517
|
+
@set email = 'new@example.com'
|
|
518
|
+
INSERT INTO users (id, name, email)
|
|
519
|
+
VALUES (\${id}, \${name}, \${email});
|
|
520
|
+
|
|
521
|
+
-- EXEC create_post
|
|
522
|
+
@set id = 100
|
|
523
|
+
@set user_id = 1
|
|
524
|
+
@set title = 'New Post'
|
|
525
|
+
@set content = 'Post content here'
|
|
526
|
+
INSERT INTO posts (id, user_id, title, content)
|
|
527
|
+
VALUES (\${id}, \${user_id}, \${title}, \${content});
|
|
528
|
+
|
|
529
|
+
-- EXEC publish_post
|
|
530
|
+
@set id = 1
|
|
531
|
+
UPDATE posts SET published = TRUE WHERE id = \${id};
|
|
532
|
+
|
|
533
|
+
-- EXEC delete_post
|
|
534
|
+
@set id = 1
|
|
535
|
+
DELETE FROM posts WHERE id = \${id};
|
|
536
|
+
`,
|
|
537
|
+
postgres: `
|
|
538
|
+
-- EXEC create_user
|
|
539
|
+
@set name = 'New User'
|
|
540
|
+
@set email = 'new@example.com'
|
|
541
|
+
INSERT INTO users (name, email)
|
|
542
|
+
VALUES (\${name}, \${email});
|
|
543
|
+
|
|
544
|
+
-- EXEC create_post
|
|
545
|
+
@set user_id = 1
|
|
546
|
+
@set title = 'New Post'
|
|
547
|
+
@set content = 'Post content here'
|
|
548
|
+
INSERT INTO posts (user_id, title, content)
|
|
549
|
+
VALUES (\${user_id}, \${title}, \${content});
|
|
550
|
+
|
|
551
|
+
-- EXEC publish_post
|
|
552
|
+
@set id = 1
|
|
553
|
+
UPDATE posts SET published = TRUE WHERE id = \${id};
|
|
554
|
+
|
|
555
|
+
-- EXEC delete_post
|
|
556
|
+
@set id = 1
|
|
557
|
+
DELETE FROM posts WHERE id = \${id};
|
|
558
|
+
`
|
|
559
|
+
}[engine];
|
|
560
|
+
}
|
|
561
|
+
/**
|
|
562
|
+
* Generate sqg.yaml configuration
|
|
563
|
+
*/
|
|
564
|
+
function getConfigYaml(generator, output) {
|
|
565
|
+
const isJava = parseGenerator(generator).language === "java";
|
|
566
|
+
return `# SQG Configuration
|
|
567
|
+
# Generated by: sqg init
|
|
568
|
+
# Documentation: https://sqg.dev
|
|
569
|
+
|
|
570
|
+
version: 1
|
|
571
|
+
name: my-project
|
|
572
|
+
|
|
573
|
+
sql:
|
|
574
|
+
- files:
|
|
575
|
+
- queries.sql
|
|
576
|
+
gen:
|
|
577
|
+
- generator: ${generator}
|
|
578
|
+
output: ${output.endsWith("/") ? output : `${output}/`}${isJava ? `
|
|
579
|
+
config:
|
|
580
|
+
package: generated` : ""}
|
|
581
|
+
`;
|
|
582
|
+
}
|
|
583
|
+
/**
|
|
584
|
+
* Initialize a new SQG project
|
|
585
|
+
*/
|
|
586
|
+
async function initProject(options) {
|
|
587
|
+
const generator = options.generator || getDefaultGenerator();
|
|
588
|
+
const output = options.output || "./generated";
|
|
589
|
+
if (!isValidGenerator(generator)) {
|
|
590
|
+
const similar = findSimilarGenerators(generator);
|
|
591
|
+
throw new InvalidGeneratorError(generator, [...SHORT_GENERATOR_NAMES, ...GENERATOR_NAMES], similar.length > 0 ? similar[0] : void 0);
|
|
592
|
+
}
|
|
593
|
+
const engine = parseGenerator(generator).engine;
|
|
594
|
+
const configPath = "sqg.yaml";
|
|
595
|
+
const sqlPath = "queries.sql";
|
|
596
|
+
if (!options.force) {
|
|
597
|
+
if (existsSync(configPath)) throw new SqgError(`File already exists: ${configPath}`, "VALIDATION_ERROR", "Use --force to overwrite existing files");
|
|
598
|
+
if (existsSync(sqlPath)) throw new SqgError(`File already exists: ${sqlPath}`, "VALIDATION_ERROR", "Use --force to overwrite existing files");
|
|
599
|
+
}
|
|
600
|
+
if (!existsSync(output)) {
|
|
601
|
+
mkdirSync(output, { recursive: true });
|
|
602
|
+
consola.success(`Created output directory: ${output}`);
|
|
603
|
+
}
|
|
604
|
+
writeFileSync(configPath, getConfigYaml(generator, output));
|
|
605
|
+
consola.success(`Created ${configPath}`);
|
|
606
|
+
writeFileSync(sqlPath, getExampleSql(engine));
|
|
607
|
+
consola.success(`Created ${sqlPath}`);
|
|
608
|
+
consola.box(`
|
|
609
|
+
SQG project initialized!
|
|
610
|
+
|
|
611
|
+
Generator: ${generator}
|
|
612
|
+
Engine: ${engine}
|
|
613
|
+
Output: ${output}
|
|
614
|
+
|
|
615
|
+
Next steps:
|
|
616
|
+
1. Edit queries.sql to add your SQL queries
|
|
617
|
+
2. Run: sqg sqg.yaml
|
|
618
|
+
3. Import the generated code from ${output}
|
|
619
|
+
|
|
620
|
+
Documentation: https://sqg.dev
|
|
621
|
+
`);
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
//#endregion
|
|
625
|
+
//#region src/parser/sql-parser.ts
|
|
626
|
+
const parser = LRParser.deserialize({
|
|
627
|
+
version: 14,
|
|
628
|
+
states: "&SOVQPOOO_QPO'#CwOdQPO'#CzOiQPO'#CvO!SQQO'#C^OOQO'#Cn'#CnQVQPOOO!aQSO,59cO!lQPO,59fOOQO'#Cp'#CpO!tQQO,59bOOQO'#C}'#C}O#iQQO'#CiOOQO,58x,58xOOQO-E6l-E6lOOQO'#Co'#CoO!aQSO1G.}O!dQSO1G.}OOQO'#Cb'#CbOOQO1G.}1G.}O#yQPO1G/QOOQO-E6n-E6nO$RQPO'#CdOOQO'#Cq'#CqO$WQQO1G.|OOQO'#Cm'#CmOOQO'#Cr'#CrO$xQQO,59TOOQO-E6m-E6mO!dQSO7+$iOOQO7+$i7+$iO%YQPO,59OOOQO-E6o-E6oOOQO-E6p-E6pOOQO<<HT<<HTO%_QQO1G.jOOQO'#Ce'#CeOiQPO7+$UO%jQQO<<Gp",
|
|
629
|
+
stateData: "&l~OiOS~ORPOVQO~OSVO~OSWO~OlXO~OYZOZZO[ZO^ZO_ZO`ZO~OR]PV]Pg]P~PnOT_OlXOmbO~OT_Olna~OlXOofORjaVjaYjaZja[ja^ja_ja`jagja~OliOR]XV]Xg]X~PnOT_Olni~OSoO~OofORjiVjiYjiZji[ji^ji_ji`jigji~OliOR]aV]ag]a~PnOpsO~OYtOZtO[tO~OlXORWyVWyYWyZWy[Wy^Wy_Wy`WygWyoWy~OR`o^iZTmYV_[~",
|
|
630
|
+
goto: "#prPPsPPPwP!R!VPPP!YPPP!]!a!g!q#T#ZPPP#a#ePP#ePP#iTTOUQcVSn`aRrmTgYhRusR]STj[kQUOR^UQ`VQdWTl`dQYRQaVWeYamvQm`RvuQhYRphQk[RqkTSOUTROUQ[STj[k",
|
|
631
|
+
nodeNames: "⚠ File QueryBlock BlockCommentStartSpecial Name Modifiers Config LineCommentStartSpecial SetVarLine Value StringLiteral StringLiteralSingle SQLText SQLBlock BlockComment LineComment VarRef BR",
|
|
632
|
+
maxTerm: 33,
|
|
633
|
+
skippedNodes: [0],
|
|
634
|
+
repeatNodeCount: 5,
|
|
635
|
+
tokenData: "$3b~RqOX#YXY'wYZ(iZ]#Y]^$W^p#Ypq'wqr#Yrs(}st#Ytu6^uw#Ywx9[xz#Yz{%_{}#Y}!OKi!O!P#Y!P!Q#%p!Q![$)l![!]$+U!]!_#Y!_!`$.U!`!b#Y!b!c$/U!c!}$)l!}#R#Y#R#S$)l#S#T#Y#T#o$)l#o;'S#Y;'S;=`'q<%lO#YU#_][QOX#YXZ$WZ]#Y]^$W^p#Ypq$Wqt#Ytu$Wuz#Yz{%_{;'S#Y;'S;=`'q<%lO#YS$ZTOz$Wz{$j{;'S$W;'S;=`%X<%lO$WS$mVOz$Wz{$j{!P$W!P!Q%S!Q;'S$W;'S;=`%X<%lO$WS%XOmSS%[P;=`<%l$WU%d_[QOX#YXZ$WZ]#Y]^$W^p#Ypq$Wqt#Ytu$Wuz#Yz{%_{!P#Y!P!Q&c!Q;'S#Y;'S;=`'q<%lO#YU&jVmS[QOX'PZ]'P^p'Pqt'Pu;'S'P;'S;=`'k<%lO'PQ'UV[QOX'PZ]'P^p'Pqt'Pu;'S'P;'S;=`'k<%lO'PQ'nP;=`<%l'PU'tP;=`<%l#Y~'|Xi~OX$WXY'wYp$Wpq'wqz$Wz{$j{;'S$W;'S;=`%X<%lO$W~(nTl~Oz$Wz{$j{;'S$W;'S;=`%X<%lO$WU)Sb[QOX(}XY*[YZ$WZ](}]^*[^p(}pq*[qr(}rs.yst(}tu*[uz(}z{/y{#O(}#O#P5V#P;'S(};'S;=`6W<%lO(}U*_ZOY*[YZ$WZr*[rs+Qsz*[z{+f{#O*[#O#P.Z#P;'S*[;'S;=`.s<%lO*[U+VTYQOz$Wz{$j{;'S$W;'S;=`%X<%lO$WU+i]OY*[YZ$WZr*[rs+Qsz*[z{+f{!P*[!P!Q,b!Q#O*[#O#P.Z#P;'S*[;'S;=`.s<%lO*[U,gWmSOY-PZr-Prs-ls#O-P#O#P-q#P;'S-P;'S;=`.T<%lO-PQ-SWOY-PZr-Prs-ls#O-P#O#P-q#P;'S-P;'S;=`.T<%lO-PQ-qOYQQ-tTOY-PYZ-PZ;'S-P;'S;=`.T<%lO-PQ.WP;=`<%l-PU.^VOY*[YZ*[Zz*[z{+f{;'S*[;'S;=`.s<%lO*[U.vP;=`<%l*[U/Q]YQ[QOX#YXZ$WZ]#Y]^$W^p#Ypq$Wqt#Ytu$Wuz#Yz{%_{;'S#Y;'S;=`'q<%lO#YU0Od[QOX(}XY*[YZ$WZ](}]^*[^p(}pq*[qr(}rs.yst(}tu*[uz(}z{/y{!P(}!P!Q1^!Q#O(}#O#P5V#P;'S(};'S;=`6W<%lO(}U1e_mS[QOX2dXY-PZ]2d]^-P^p2dpq-Pqr2drs3hst2dtu-Pu#O2d#O#P4U#P;'S2d;'S;=`5P<%lO2dQ2i_[QOX2dXY-PZ]2d]^-P^p2dpq-Pqr2drs3hst2dtu-Pu#O2d#O#P4U#P;'S2d;'S;=`5P<%lO2dQ3oVYQ[QOX'PZ]'P^p'Pqt'Pu;'S'P;'S;=`'k<%lO'PQ4Z[[QOX2dXY-PYZ-PZ]2d]^-P^p2dpq-Pqt2dtu-Pu;'S2d;'S;=`5P<%lO2dQ5SP;=`<%l2dU5[^[QOX(}XY*[YZ*[Z](}]^*[^p(}pq*[qt(}tu*[uz(}z{/y{;'S(};'S;=`6W<%lO(}U6ZP;=`<%l(}U6cV[QOz$Wz{$j{#o$W#o#p6x#p;'S$W;'S;=`%X<%lO$WU6{]Oz$Wz{$j{!Q$W!Q![7t![!c$W!c!}7t!}#R$W#R#S7t#S#T$W#T#o7t#o;'S$W;'S;=`%X<%lO$WU7w_Oz$Wz{$j{!Q$W!Q![7t![!c$W!c!}7t!}#R$W#R#S7t#S#T$W#T#o7t#o#q$W#q#r8v#r;'S$W;'S;=`%X<%lO$WU8{T`QOz$Wz{$j{;'S$W;'S;=`%X<%lO$WU9ab[QOX9[XY:iYZ$WZ]9[]^:i^p9[pq:iqt9[tu:iuw9[wxAVxz9[z{BV{#O9[#O#PHu#P;'S9[;'S;=`Kc<%lO9[U:lZOY:iYZ$WZw:iwx;_xz:iz{;s{#O:i#O#P?c#P;'S:i;'S;=`AP<%lO:iU;dTZQOz$Wz{$j{;'S$W;'S;=`%X<%lO$WU;v]OY:iYZ$WZw:iwx;_xz:iz{;s{!P:i!P!Q<o!Q#O:i#O#P?c#P;'S:i;'S;=`AP<%lO:iU<tWmSOY=^Zw=^wx=yx#O=^#O#P>O#P;'S=^;'S;=`?]<%lO=^Q=aWOY=^Zw=^wx=yx#O=^#O#P>O#P;'S=^;'S;=`?]<%lO=^Q>OOZQQ>RXOY=^YZ=^Zw=^wx>nx#O=^#O#P>O#P;'S=^;'S;=`?]<%lO=^Q>sWZQOY=^Zw=^wx=yx#O=^#O#P>O#P;'S=^;'S;=`?]<%lO=^Q?`P;=`<%l=^U?fZOY:iYZ:iZw:iwx@Xxz:iz{;s{#O:i#O#P?c#P;'S:i;'S;=`AP<%lO:iU@^ZZQOY:iYZ$WZw:iwx;_xz:iz{;s{#O:i#O#P?c#P;'S:i;'S;=`AP<%lO:iUASP;=`<%l:iUA^]ZQ[QOX#YXZ$WZ]#Y]^$W^p#Ypq$Wqt#Ytu$Wuz#Yz{%_{;'S#Y;'S;=`'q<%lO#YUB[d[QOX9[XY:iYZ$WZ]9[]^:i^p9[pq:iqt9[tu:iuw9[wxAVxz9[z{BV{!P9[!P!QCj!Q#O9[#O#PHu#P;'S9[;'S;=`Kc<%lO9[UCq_mS[QOXDpXY=^Z]Dp]^=^^pDppq=^qtDptu=^uwDpwxEtx#ODp#O#PFb#P;'SDp;'S;=`Ho<%lODpQDu_[QOXDpXY=^Z]Dp]^=^^pDppq=^qtDptu=^uwDpwxEtx#ODp#O#PFb#P;'SDp;'S;=`Ho<%lODpQE{VZQ[QOX'PZ]'P^p'Pqt'Pu;'S'P;'S;=`'k<%lO'PQFg`[QOXDpXY=^YZ=^Z]Dp]^=^^pDppq=^qtDptu=^uwDpwxGix#ODp#O#PFb#P;'SDp;'S;=`Ho<%lODpQGp_ZQ[QOXDpXY=^Z]Dp]^=^^pDppq=^qtDptu=^uwDpwxEtx#ODp#O#PFb#P;'SDp;'S;=`Ho<%lODpQHrP;=`<%lDpUHzb[QOX9[XY:iYZ:iZ]9[]^:i^p9[pq:iqt9[tu:iuw9[wxJSxz9[z{BV{#O9[#O#PHu#P;'S9[;'S;=`Kc<%lO9[UJZbZQ[QOX9[XY:iYZ$WZ]9[]^:i^p9[pq:iqt9[tu:iuw9[wxAVxz9[z{BV{#O9[#O#PHu#P;'S9[;'S;=`Kc<%lO9[UKfP;=`<%l9[VKn_[QOX#YXZ$WZ]#Y]^$W^p#Ypq$Wqt#Ytu$Wuz#Yz{%_{}#Y}!OLm!O;'S#Y;'S;=`'q<%lO#YVLtf_Q[QOXNYXY!&vYZ$WZ]NY]^! ]^pNYpq!&vqtNYtu! ]uzNYz{!#k{!gNY!g!h!8V!h!oNY!o!p!<w!p!sNY!s!t!DP!t!vNY!v!w!Hu!w;'SNY;'S;=`!&p<%lONYUNa^_Q[QOXNYXY! ]YZ$WZ]NY]^! ]^pNYpq! ]qtNYtu! ]uzNYz{!#k{;'SNY;'S;=`!&p<%lONYU! bV_QOY! ]YZ$WZz! ]z{! w{;'S! ];'S;=`!#e<%lO! ]U! |X_QOY! ]YZ$WZz! ]z{! w{!P! ]!P!Q!!i!Q;'S! ];'S;=`!#e<%lO! ]U!!pSmS_QOY!!|Z;'S!!|;'S;=`!#_<%lO!!|Q!#RS_QOY!!|Z;'S!!|;'S;=`!#_<%lO!!|Q!#bP;=`<%l!!|U!#hP;=`<%l! ]U!#r`_Q[QOXNYXY! ]YZ$WZ]NY]^! ]^pNYpq! ]qtNYtu! ]uzNYz{!#k{!PNY!P!Q!$t!Q;'SNY;'S;=`!&p<%lONYU!$}ZmS_Q[QOX!%pXY!!|Z]!%p]^!!|^p!%ppq!!|qt!%ptu!!|u;'S!%p;'S;=`!&j<%lO!%pQ!%wZ_Q[QOX!%pXY!!|Z]!%p]^!!|^p!%ppq!!|qt!%ptu!!|u;'S!%p;'S;=`!&j<%lO!%pQ!&mP;=`<%l!%pU!&sP;=`<%lNYV!&{b_QOX! ]XY!&vYZ$WZp! ]pq!&vqz! ]z{! w{!g! ]!g!h!(T!h!o! ]!o!p!*u!p!s! ]!s!t!.}!t!v! ]!v!w!1s!w;'S! ];'S;=`!#e<%lO! ]V!(YX_QOY! ]YZ$WZz! ]z{! w{!z! ]!z!{!(u!{;'S! ];'S;=`!#e<%lO! ]V!(zX_QOY! ]YZ$WZz! ]z{! w{!g! ]!g!h!)g!h;'S! ];'S;=`!#e<%lO! ]V!)lX_QOY! ]YZ$WZz! ]z{! w{!e! ]!e!f!*X!f;'S! ];'S;=`!#e<%lO! ]V!*`VVR_QOY! ]YZ$WZz! ]z{! w{;'S! ];'S;=`!#e<%lO! ]V!*zX_QOY! ]YZ$WZz! ]z{! w{!k! ]!k!l!+g!l;'S! ];'S;=`!#e<%lO! ]V!+lX_QOY! ]YZ$WZz! ]z{! w{!i! ]!i!j!,X!j;'S! ];'S;=`!#e<%lO! ]V!,^X_QOY! ]YZ$WZz! ]z{! w{!t! ]!t!u!,y!u;'S! ];'S;=`!#e<%lO! ]V!-OX_QOY! ]YZ$WZz! ]z{! w{!c! ]!c!d!-k!d;'S! ];'S;=`!#e<%lO! ]V!-pX_QOY! ]YZ$WZz! ]z{! w{!v! ]!v!w!.]!w;'S! ];'S;=`!#e<%lO! ]V!.bX_QOY! ]YZ$WZz! ]z{! w{!g! ]!g!h!*X!h;'S! ];'S;=`!#e<%lO! ]V!/SX_QOY! ]YZ$WZz! ]z{! w{!w! ]!w!x!/o!x;'S! ];'S;=`!#e<%lO! ]V!/tX_QOY! ]YZ$WZz! ]z{! w{!g! ]!g!h!0a!h;'S! ];'S;=`!#e<%lO! ]V!0fX_QOY! ]YZ$WZz! ]z{! w{!t! ]!t!u!1R!u;'S! ];'S;=`!#e<%lO! ]V!1WX_QOY! ]YZ$WZz! ]z{! w{!{! ]!{!|!*X!|;'S! ];'S;=`!#e<%lO! ]V!1xZ_QOY! ]YZ$WZz! ]z{! w{!c! ]!c!d!2k!d!g! ]!g!h!3}!h;'S! ];'S;=`!#e<%lO! ]V!2pX_QOY! ]YZ$WZz! ]z{! w{!d! ]!d!e!3]!e;'S! ];'S;=`!#e<%lO! ]V!3bX_QOY! ]YZ$WZz! ]z{! w{!n! ]!n!o!.]!o;'S! ];'S;=`!#e<%lO! ]V!4SX_QOY! ]YZ$WZz! ]z{! w{!u! ]!u!v!4o!v;'S! ];'S;=`!#e<%lO! ]V!4tX_QOY! ]YZ$WZz! ]z{! w{!v! ]!v!w!5a!w;'S! ];'S;=`!#e<%lO! ]V!5fX_QOY! ]YZ$WZz! ]z{! w{!f! ]!f!g!6R!g;'S! ];'S;=`!#e<%lO! ]V!6WX_QOY! ]YZ$WZz! ]z{! w{!c! ]!c!d!6s!d;'S! ];'S;=`!#e<%lO! ]V!6xX_QOY! ]YZ$WZz! ]z{! w{!v! ]!v!w!7e!w;'S! ];'S;=`!#e<%lO! ]V!7jX_QOY! ]YZ$WZz! ]z{! w{!c! ]!c!d!*X!d;'S! ];'S;=`!#e<%lO! ]V!8^`_Q[QOXNYXY! ]YZ$WZ]NY]^! ]^pNYpq! ]qtNYtu! ]uzNYz{!#k{!zNY!z!{!9`!{;'SNY;'S;=`!&p<%lONYV!9g`_Q[QOXNYXY! ]YZ$WZ]NY]^! ]^pNYpq! ]qtNYtu! ]uzNYz{!#k{!gNY!g!h!:i!h;'SNY;'S;=`!&p<%lONYV!:p`_Q[QOXNYXY! ]YZ$WZ]NY]^! ]^pNYpq! ]qtNYtu! ]uzNYz{!#k{!eNY!e!f!;r!f;'SNY;'S;=`!&p<%lONYV!;{^VR_Q[QOXNYXY! ]YZ$WZ]NY]^! ]^pNYpq! ]qtNYtu! ]uzNYz{!#k{;'SNY;'S;=`!&p<%lONYV!=O`_Q[QOXNYXY! ]YZ$WZ]NY]^! ]^pNYpq! ]qtNYtu! ]uzNYz{!#k{!kNY!k!l!>Q!l;'SNY;'S;=`!&p<%lONYV!>X`_Q[QOXNYXY! ]YZ$WZ]NY]^! ]^pNYpq! ]qtNYtu! ]uzNYz{!#k{!iNY!i!j!?Z!j;'SNY;'S;=`!&p<%lONYV!?b`_Q[QOXNYXY! ]YZ$WZ]NY]^! ]^pNYpq! ]qtNYtu! ]uzNYz{!#k{!tNY!t!u!@d!u;'SNY;'S;=`!&p<%lONYV!@k`_Q[QOXNYXY! ]YZ$WZ]NY]^! ]^pNYpq! ]qtNYtu! ]uzNYz{!#k{!cNY!c!d!Am!d;'SNY;'S;=`!&p<%lONYV!At`_Q[QOXNYXY! ]YZ$WZ]NY]^! ]^pNYpq! ]qtNYtu! ]uzNYz{!#k{!vNY!v!w!Bv!w;'SNY;'S;=`!&p<%lONYV!B}`_Q[QOXNYXY! ]YZ$WZ]NY]^! ]^pNYpq! ]qtNYtu! ]uzNYz{!#k{!gNY!g!h!;r!h;'SNY;'S;=`!&p<%lONYV!DW`_Q[QOXNYXY! ]YZ$WZ]NY]^! ]^pNYpq! ]qtNYtu! ]uzNYz{!#k{!wNY!w!x!EY!x;'SNY;'S;=`!&p<%lONYV!Ea`_Q[QOXNYXY! ]YZ$WZ]NY]^! ]^pNYpq! ]qtNYtu! ]uzNYz{!#k{!gNY!g!h!Fc!h;'SNY;'S;=`!&p<%lONYV!Fj`_Q[QOXNYXY! ]YZ$WZ]NY]^! ]^pNYpq! ]qtNYtu! ]uzNYz{!#k{!tNY!t!u!Gl!u;'SNY;'S;=`!&p<%lONYV!Gs`_Q[QOXNYXY! ]YZ$WZ]NY]^! ]^pNYpq! ]qtNYtu! ]uzNYz{!#k{!{NY!{!|!;r!|;'SNY;'S;=`!&p<%lONYV!H|b_Q[QOXNYXY! ]YZ$WZ]NY]^! ]^pNYpq! ]qtNYtu! ]uzNYz{!#k{!cNY!c!d!JU!d!gNY!g!h!Lh!h;'SNY;'S;=`!&p<%lONYV!J]`_Q[QOXNYXY! ]YZ$WZ]NY]^! ]^pNYpq! ]qtNYtu! ]uzNYz{!#k{!dNY!d!e!K_!e;'SNY;'S;=`!&p<%lONYV!Kf`_Q[QOXNYXY! ]YZ$WZ]NY]^! ]^pNYpq! ]qtNYtu! ]uzNYz{!#k{!nNY!n!o!Bv!o;'SNY;'S;=`!&p<%lONYV!Lo`_Q[QOXNYXY! ]YZ$WZ]NY]^! ]^pNYpq! ]qtNYtu! ]uzNYz{!#k{!uNY!u!v!Mq!v;'SNY;'S;=`!&p<%lONYV!Mx`_Q[QOXNYXY! ]YZ$WZ]NY]^! ]^pNYpq! ]qtNYtu! ]uzNYz{!#k{!vNY!v!w!Nz!w;'SNY;'S;=`!&p<%lONYV# R`_Q[QOXNYXY! ]YZ$WZ]NY]^! ]^pNYpq! ]qtNYtu! ]uzNYz{!#k{!fNY!f!g#!T!g;'SNY;'S;=`!&p<%lONYV#![`_Q[QOXNYXY! ]YZ$WZ]NY]^! ]^pNYpq! ]qtNYtu! ]uzNYz{!#k{!cNY!c!d##^!d;'SNY;'S;=`!&p<%lONYV##e`_Q[QOXNYXY! ]YZ$WZ]NY]^! ]^pNYpq! ]qtNYtu! ]uzNYz{!#k{!vNY!v!w#$g!w;'SNY;'S;=`!&p<%lONYV#$n`_Q[QOXNYXY! ]YZ$WZ]NY]^! ]^pNYpq! ]qtNYtu! ]uzNYz{!#k{!cNY!c!d!;r!d;'SNY;'S;=`!&p<%lONYV#%u][QOX#YXZ$WZ]#Y]^$W^p#Ypq$Wqt#Ytu$Wuz#Yz{#&n{;'S#Y;'S;=`'q<%lO#YV#&sh[QOX#(_XY#,`YZ#,`Z]#(_]^#)]^p#(_pq#,`qt#(_tu#)]uz#(_z{#*f{!P#(_!P!Q#9m!Q!g#(_!g!h#>j!h!o#(_!o!p#Bv!p!s#(_!s!t#I`!t!v#(_!v!w#Mp!w;'S#(_;'S;=`#,Y<%lO#(_U#(d][QOX#(_XZ#)]Z]#(_]^#)]^p#(_pq#)]qt#(_tu#)]uz#(_z{#*f{;'S#(_;'S;=`#,Y<%lO#(_U#)`TOz#)]z{#)o{;'S#)];'S;=`#*`<%lO#)]U#)rVOz#)]z{#)o{!P#)]!P!Q#*X!Q;'S#)];'S;=`#*`<%lO#)]U#*`O^QmSU#*cP;=`<%l#)]U#*k_[QOX#(_XZ#)]Z]#(_]^#)]^p#(_pq#)]qt#(_tu#)]uz#(_z{#*f{!P#(_!P!Q#+j!Q;'S#(_;'S;=`#,Y<%lO#(_U#+sV^QmS[QOX'PZ]'P^p'Pqt'Pu;'S'P;'S;=`'k<%lO'PU#,]P;=`<%l#(_V#,cbOX#)]XY#,`YZ#,`Zp#)]pq#,`qz#)]z{#)o{!g#)]!g!h#-k!h!o#)]!o!p#/k!p!s#)]!s!t#2q!t!v#)]!v!w#4u!w;'S#)];'S;=`#*`<%lO#)]V#-nVOz#)]z{#)o{!z#)]!z!{#.T!{;'S#)];'S;=`#*`<%lO#)]V#.WVOz#)]z{#)o{!g#)]!g!h#.m!h;'S#)];'S;=`#*`<%lO#)]V#.pVOz#)]z{#)o{!e#)]!e!f#/V!f;'S#)];'S;=`#*`<%lO#)]V#/[TRROz#)]z{#)o{;'S#)];'S;=`#*`<%lO#)]V#/nVOz#)]z{#)o{!k#)]!k!l#0T!l;'S#)];'S;=`#*`<%lO#)]V#0WVOz#)]z{#)o{!i#)]!i!j#0m!j;'S#)];'S;=`#*`<%lO#)]V#0pVOz#)]z{#)o{!t#)]!t!u#1V!u;'S#)];'S;=`#*`<%lO#)]V#1YVOz#)]z{#)o{!c#)]!c!d#1o!d;'S#)];'S;=`#*`<%lO#)]V#1rVOz#)]z{#)o{!v#)]!v!w#2X!w;'S#)];'S;=`#*`<%lO#)]V#2[VOz#)]z{#)o{!g#)]!g!h#/V!h;'S#)];'S;=`#*`<%lO#)]V#2tVOz#)]z{#)o{!w#)]!w!x#3Z!x;'S#)];'S;=`#*`<%lO#)]V#3^VOz#)]z{#)o{!g#)]!g!h#3s!h;'S#)];'S;=`#*`<%lO#)]V#3vVOz#)]z{#)o{!t#)]!t!u#4]!u;'S#)];'S;=`#*`<%lO#)]V#4`VOz#)]z{#)o{!{#)]!{!|#/V!|;'S#)];'S;=`#*`<%lO#)]V#4xXOz#)]z{#)o{!c#)]!c!d#5e!d!g#)]!g!h#6g!h;'S#)];'S;=`#*`<%lO#)]V#5hVOz#)]z{#)o{!d#)]!d!e#5}!e;'S#)];'S;=`#*`<%lO#)]V#6QVOz#)]z{#)o{!n#)]!n!o#2X!o;'S#)];'S;=`#*`<%lO#)]V#6jVOz#)]z{#)o{!u#)]!u!v#7P!v;'S#)];'S;=`#*`<%lO#)]V#7SVOz#)]z{#)o{!v#)]!v!w#7i!w;'S#)];'S;=`#*`<%lO#)]V#7lVOz#)]z{#)o{!f#)]!f!g#8R!g;'S#)];'S;=`#*`<%lO#)]V#8UVOz#)]z{#)o{!c#)]!c!d#8k!d;'S#)];'S;=`#*`<%lO#)]V#8nVOz#)]z{#)o{!v#)]!v!w#9T!w;'S#)];'S;=`#*`<%lO#)]V#9WVOz#)]z{#)o{!c#)]!c!d#/V!d;'S#)];'S;=`#*`<%lO#)]U#9t]mS[QOX#:mXZ#;kZ]#:m]^#;k^p#:mpq#;kqt#:mtu#;kuz#:mz{#<r{;'S#:m;'S;=`#>d<%lO#:mQ#:r][QOX#:mXZ#;kZ]#:m]^#;k^p#:mpq#;kqt#:mtu#;kuz#:mz{#<r{;'S#:m;'S;=`#>d<%lO#:mQ#;nTOz#;kz{#;}{;'S#;k;'S;=`#<l<%lO#;kQ#<QVOz#;kz{#;}{!P#;k!P!Q#<g!Q;'S#;k;'S;=`#<l<%lO#;kQ#<lO^QQ#<oP;=`<%l#;kQ#<w_[QOX#:mXZ#;kZ]#:m]^#;k^p#:mpq#;kqt#:mtu#;kuz#:mz{#<r{!P#:m!P!Q#=v!Q;'S#:m;'S;=`#>d<%lO#:mQ#=}V^Q[QOX'PZ]'P^p'Pqt'Pu;'S'P;'S;=`'k<%lO'PQ#>gP;=`<%l#:mV#>o_[QOX#(_XZ#)]Z]#(_]^#)]^p#(_pq#)]qt#(_tu#)]uz#(_z{#*f{!z#(_!z!{#?n!{;'S#(_;'S;=`#,Y<%lO#(_V#?s_[QOX#(_XZ#)]Z]#(_]^#)]^p#(_pq#)]qt#(_tu#)]uz#(_z{#*f{!g#(_!g!h#@r!h;'S#(_;'S;=`#,Y<%lO#(_V#@w_[QOX#(_XZ#)]Z]#(_]^#)]^p#(_pq#)]qt#(_tu#)]uz#(_z{#*f{!e#(_!e!f#Av!f;'S#(_;'S;=`#,Y<%lO#(_V#A}]RR[QOX#(_XZ#)]Z]#(_]^#)]^p#(_pq#)]qt#(_tu#)]uz#(_z{#*f{;'S#(_;'S;=`#,Y<%lO#(_V#B{_[QOX#(_XZ#)]Z]#(_]^#)]^p#(_pq#)]qt#(_tu#)]uz#(_z{#*f{!k#(_!k!l#Cz!l;'S#(_;'S;=`#,Y<%lO#(_V#DP_[QOX#(_XZ#)]Z]#(_]^#)]^p#(_pq#)]qt#(_tu#)]uz#(_z{#*f{!i#(_!i!j#EO!j;'S#(_;'S;=`#,Y<%lO#(_V#ET_[QOX#(_XZ#)]Z]#(_]^#)]^p#(_pq#)]qt#(_tu#)]uz#(_z{#*f{!t#(_!t!u#FS!u;'S#(_;'S;=`#,Y<%lO#(_V#FX_[QOX#(_XZ#)]Z]#(_]^#)]^p#(_pq#)]qt#(_tu#)]uz#(_z{#*f{!c#(_!c!d#GW!d;'S#(_;'S;=`#,Y<%lO#(_V#G]_[QOX#(_XZ#)]Z]#(_]^#)]^p#(_pq#)]qt#(_tu#)]uz#(_z{#*f{!v#(_!v!w#H[!w;'S#(_;'S;=`#,Y<%lO#(_V#Ha_[QOX#(_XZ#)]Z]#(_]^#)]^p#(_pq#)]qt#(_tu#)]uz#(_z{#*f{!g#(_!g!h#Av!h;'S#(_;'S;=`#,Y<%lO#(_V#Ie_[QOX#(_XZ#)]Z]#(_]^#)]^p#(_pq#)]qt#(_tu#)]uz#(_z{#*f{!w#(_!w!x#Jd!x;'S#(_;'S;=`#,Y<%lO#(_V#Ji_[QOX#(_XZ#)]Z]#(_]^#)]^p#(_pq#)]qt#(_tu#)]uz#(_z{#*f{!g#(_!g!h#Kh!h;'S#(_;'S;=`#,Y<%lO#(_V#Km_[QOX#(_XZ#)]Z]#(_]^#)]^p#(_pq#)]qt#(_tu#)]uz#(_z{#*f{!t#(_!t!u#Ll!u;'S#(_;'S;=`#,Y<%lO#(_V#Lq_[QOX#(_XZ#)]Z]#(_]^#)]^p#(_pq#)]qt#(_tu#)]uz#(_z{#*f{!{#(_!{!|#Av!|;'S#(_;'S;=`#,Y<%lO#(_V#Mua[QOX#(_XZ#)]Z]#(_]^#)]^p#(_pq#)]qt#(_tu#)]uz#(_z{#*f{!c#(_!c!d#Nz!d!g#(_!g!h$#S!h;'S#(_;'S;=`#,Y<%lO#(_V$ P_[QOX#(_XZ#)]Z]#(_]^#)]^p#(_pq#)]qt#(_tu#)]uz#(_z{#*f{!d#(_!d!e$!O!e;'S#(_;'S;=`#,Y<%lO#(_V$!T_[QOX#(_XZ#)]Z]#(_]^#)]^p#(_pq#)]qt#(_tu#)]uz#(_z{#*f{!n#(_!n!o#H[!o;'S#(_;'S;=`#,Y<%lO#(_V$#X_[QOX#(_XZ#)]Z]#(_]^#)]^p#(_pq#)]qt#(_tu#)]uz#(_z{#*f{!u#(_!u!v$$W!v;'S#(_;'S;=`#,Y<%lO#(_V$$]_[QOX#(_XZ#)]Z]#(_]^#)]^p#(_pq#)]qt#(_tu#)]uz#(_z{#*f{!v#(_!v!w$%[!w;'S#(_;'S;=`#,Y<%lO#(_V$%a_[QOX#(_XZ#)]Z]#(_]^#)]^p#(_pq#)]qt#(_tu#)]uz#(_z{#*f{!f#(_!f!g$&`!g;'S#(_;'S;=`#,Y<%lO#(_V$&e_[QOX#(_XZ#)]Z]#(_]^#)]^p#(_pq#)]qt#(_tu#)]uz#(_z{#*f{!c#(_!c!d$'d!d;'S#(_;'S;=`#,Y<%lO#(_V$'i_[QOX#(_XZ#)]Z]#(_]^#)]^p#(_pq#)]qt#(_tu#)]uz#(_z{#*f{!v#(_!v!w$(h!w;'S#(_;'S;=`#,Y<%lO#(_V$(m_[QOX#(_XZ#)]Z]#(_]^#)]^p#(_pq#)]qt#(_tu#)]uz#(_z{#*f{!c#(_!c!d#Av!d;'S#(_;'S;=`#,Y<%lO#(_V$)seSP[QOX#YXZ$WZ]#Y]^$W^p#Ypq$Wqt#Ytu$Wuz#Yz{%_{!Q#Y!Q![$)l![!c#Y!c!}$)l!}#R#Y#R#S$)l#S#T#Y#T#o$)l#o;'S#Y;'S;=`'q<%lO#Y~$+Ze[QOX#YXZ$WZ]#Y]^$W^p#Ypq$Wqt#Ytu$Wuz#Yz{%_{!Q#Y!Q![$,l![!c#Y!c!}$,l!}#R#Y#R#S$,l#S#T#Y#T#o$,l#o;'S#Y;'S;=`'q<%lO#Y~$,seT~[QOX#YXZ$WZ]#Y]^$W^p#Ypq$Wqt#Ytu$Wuz#Yz{%_{!Q#Y!Q![$,l![!c#Y!c!}$,l!}#R#Y#R#S$,l#S#T#Y#T#o$,l#o;'S#Y;'S;=`'q<%lO#YV$.]]pP[QOX#YXZ$WZ]#Y]^$W^p#Ypq$Wqt#Ytu$Wuz#Yz{%_{;'S#Y;'S;=`'q<%lO#YU$/Z_[QOX#YXZ$WZ]#Y]^$W^p#Ypq$Wqt#Ytu$Wuz#Yz{%_{#g#Y#g#h$0Y#h;'S#Y;'S;=`'q<%lO#YU$0__[QOX#YXZ$WZ]#Y]^$W^p#Ypq$Wqt#Ytu$Wuz#Yz{%_{#X#Y#X#Y$1^#Y;'S#Y;'S;=`'q<%lO#YU$1c_[QOX#YXZ$WZ]#Y]^$W^p#Ypq$Wqt#Ytu$Wuz#Yz{%_{#h#Y#h#i$2b#i;'S#Y;'S;=`'q<%lO#YU$2i]oQ[QOX#YXZ$WZ]#Y]^$W^p#Ypq$Wqt#Ytu$Wuz#Yz{%_{;'S#Y;'S;=`'q<%lO#Y",
|
|
636
|
+
tokenizers: [
|
|
637
|
+
0,
|
|
638
|
+
1,
|
|
639
|
+
2
|
|
640
|
+
],
|
|
641
|
+
topRules: { "File": [0, 1] },
|
|
642
|
+
tokenPrec: 245
|
|
643
|
+
});
|
|
644
|
+
|
|
645
|
+
//#endregion
|
|
646
|
+
//#region src/sql-query.ts
|
|
647
|
+
var ListType = class {
|
|
648
|
+
constructor(baseType) {
|
|
649
|
+
this.baseType = baseType;
|
|
650
|
+
}
|
|
651
|
+
toString() {
|
|
652
|
+
return `${this.baseType.toString()}[]`;
|
|
653
|
+
}
|
|
654
|
+
};
|
|
655
|
+
var StructType = class {
|
|
656
|
+
constructor(fields) {
|
|
657
|
+
this.fields = fields;
|
|
658
|
+
}
|
|
659
|
+
toString() {
|
|
660
|
+
return `STRUCT(${this.fields.map((f) => `"${f.name}" ${f.type.toString()}`).join(", ")})`;
|
|
661
|
+
}
|
|
662
|
+
};
|
|
663
|
+
var MapType = class {
|
|
664
|
+
constructor(keyType, valueType) {
|
|
665
|
+
this.keyType = keyType;
|
|
666
|
+
this.valueType = valueType;
|
|
667
|
+
}
|
|
668
|
+
toString() {
|
|
669
|
+
return `MAP(${this.keyType.toString()}, ${this.valueType.toString()})`;
|
|
670
|
+
}
|
|
671
|
+
};
|
|
672
|
+
var EnumType = class {
|
|
673
|
+
constructor(values) {
|
|
674
|
+
this.values = values;
|
|
675
|
+
}
|
|
676
|
+
toString() {
|
|
677
|
+
return `ENUM(${this.values.map((v) => `'${v}'`).join(", ")})`;
|
|
678
|
+
}
|
|
679
|
+
};
|
|
680
|
+
var SQLQuery = class {
|
|
681
|
+
columns;
|
|
682
|
+
allColumns;
|
|
683
|
+
constructor(filename, id, rawQuery, queryAnonymous, queryNamed, queryPositional, type, isOne, isPluck, variables, config) {
|
|
684
|
+
this.filename = filename;
|
|
685
|
+
this.id = id;
|
|
686
|
+
this.rawQuery = rawQuery;
|
|
687
|
+
this.queryAnonymous = queryAnonymous;
|
|
688
|
+
this.queryNamed = queryNamed;
|
|
689
|
+
this.queryPositional = queryPositional;
|
|
690
|
+
this.type = type;
|
|
691
|
+
this.isOne = isOne;
|
|
692
|
+
this.isPluck = isPluck;
|
|
693
|
+
this.variables = variables;
|
|
694
|
+
this.config = config;
|
|
695
|
+
this.columns = [];
|
|
696
|
+
}
|
|
697
|
+
get isQuery() {
|
|
698
|
+
return this.type === "QUERY";
|
|
699
|
+
}
|
|
700
|
+
get isExec() {
|
|
701
|
+
return this.type === "EXEC";
|
|
702
|
+
}
|
|
703
|
+
get isMigrate() {
|
|
704
|
+
return this.type === "MIGRATE";
|
|
705
|
+
}
|
|
706
|
+
get isTestdata() {
|
|
707
|
+
return this.type === "TESTDATA";
|
|
708
|
+
}
|
|
709
|
+
get skipGenerateFunction() {
|
|
710
|
+
return this.isTestdata || this.isMigrate || this.id.startsWith("_");
|
|
711
|
+
}
|
|
712
|
+
validateVariables() {
|
|
713
|
+
const missingVars = [];
|
|
714
|
+
const varRegex = /\$\{([a-zA-Z_][a-zA-Z0-9_]*)\}/g;
|
|
715
|
+
let match;
|
|
716
|
+
while (true) {
|
|
717
|
+
match = varRegex.exec(this.rawQuery);
|
|
718
|
+
if (match === null) break;
|
|
719
|
+
const varName = match[1];
|
|
720
|
+
if (!this.variables.has(varName)) missingVars.push(varName);
|
|
721
|
+
}
|
|
722
|
+
return missingVars;
|
|
723
|
+
}
|
|
724
|
+
};
|
|
725
|
+
/**
|
|
726
|
+
* Represents a TABLE annotation for generating appenders.
|
|
727
|
+
* TABLE annotations specify a table name for which to generate bulk insert appenders.
|
|
728
|
+
*/
|
|
729
|
+
var TableInfo = class {
|
|
730
|
+
/** Columns introspected from the database table schema */
|
|
731
|
+
columns = [];
|
|
732
|
+
constructor(filename, id, tableName, includeColumns, hasAppender) {
|
|
733
|
+
this.filename = filename;
|
|
734
|
+
this.id = id;
|
|
735
|
+
this.tableName = tableName;
|
|
736
|
+
this.includeColumns = includeColumns;
|
|
737
|
+
this.hasAppender = hasAppender;
|
|
738
|
+
}
|
|
739
|
+
get skipGenerateFunction() {
|
|
740
|
+
return !this.hasAppender;
|
|
741
|
+
}
|
|
742
|
+
};
|
|
743
|
+
function parseSQLQueries(filePath, extraVariables) {
|
|
744
|
+
const content = readFileSync(filePath, "utf-8");
|
|
745
|
+
consola.info(`Parsing SQL file: ${filePath}`);
|
|
746
|
+
consola.debug(`File start: ${content.slice(0, 200)}`);
|
|
747
|
+
const queries = [];
|
|
748
|
+
const tables = [];
|
|
749
|
+
const cursor = parser.parse(content).cursor();
|
|
750
|
+
function getLineNumber(position) {
|
|
751
|
+
return content.slice(0, position).split("\n").length;
|
|
752
|
+
}
|
|
753
|
+
function getStr(nodeName, optional = false) {
|
|
754
|
+
const node = cursor.node.getChild(nodeName);
|
|
755
|
+
if (!node) {
|
|
756
|
+
if (optional) return;
|
|
757
|
+
const lineNumber = getLineNumber(cursor.node.from);
|
|
758
|
+
throw new Error(`Node '${nodeName}' not found at line ${lineNumber}`);
|
|
759
|
+
}
|
|
760
|
+
return nodeStr(node);
|
|
761
|
+
}
|
|
762
|
+
function nodeStr(node) {
|
|
763
|
+
return content.slice(node.from, node.to);
|
|
764
|
+
}
|
|
765
|
+
const queryNames = /* @__PURE__ */ new Set();
|
|
766
|
+
do
|
|
767
|
+
if (cursor.name === "QueryBlock") {
|
|
768
|
+
const queryType = (getStr("LineCommentStartSpecial", true) ?? getStr("BlockCommentStartSpecial")).replace("--", "").replace("/*", "").trim();
|
|
769
|
+
const name = getStr("Name").trim();
|
|
770
|
+
const modifiers = cursor.node.getChildren("Modifiers").map((node) => nodeStr(node));
|
|
771
|
+
const isOne = modifiers.includes(":one");
|
|
772
|
+
const isPluck = modifiers.includes(":pluck");
|
|
773
|
+
let configStr = getStr("Config", true);
|
|
774
|
+
if (configStr?.endsWith("*/")) configStr = configStr.slice(0, -2);
|
|
775
|
+
let config = null;
|
|
776
|
+
if (configStr) config = Config.fromYaml(name, filePath, configStr);
|
|
777
|
+
const setVars = cursor.node.getChildren("SetVarLine");
|
|
778
|
+
const variables = /* @__PURE__ */ new Map();
|
|
779
|
+
for (const setVar of setVars) {
|
|
780
|
+
const varName = nodeStr(setVar.getChild("Name"));
|
|
781
|
+
const value = nodeStr(setVar.getChild("Value"));
|
|
782
|
+
variables.set(varName, value.trim());
|
|
783
|
+
}
|
|
784
|
+
function getVariable(varName) {
|
|
785
|
+
if (variables.has(varName)) return variables.get(varName);
|
|
786
|
+
for (const extraVariable of extraVariables) if (extraVariable.name === varName) {
|
|
787
|
+
variables.set(varName, extraVariable.value);
|
|
788
|
+
return extraVariable.value;
|
|
789
|
+
}
|
|
790
|
+
const definedVars = Array.from(variables.keys());
|
|
791
|
+
const suggestion = definedVars.length > 0 ? `Add '@set ${varName} = <value>' before the query. Defined variables: ${definedVars.join(", ")}` : `Add '@set ${varName} = <value>' before the query`;
|
|
792
|
+
throw SqgError.inQuery(`Variable '\${${varName}}' is referenced but not defined`, "MISSING_VARIABLE", name, filePath, { suggestion });
|
|
793
|
+
}
|
|
794
|
+
const sqlNode = cursor.node.getChild("SQLBlock");
|
|
795
|
+
if (!sqlNode) throw SqgError.inQuery("SQL block not found", "SQL_PARSE_ERROR", name, filePath, { suggestion: "Ensure the query has valid SQL content after the annotation comment" });
|
|
796
|
+
const sqlContentStr = nodeStr(sqlNode).trim();
|
|
797
|
+
const sqlCursor = sqlNode.cursor();
|
|
798
|
+
let from = -1;
|
|
799
|
+
let to = -1;
|
|
800
|
+
class SQLQueryBuilder {
|
|
801
|
+
sqlParts = [];
|
|
802
|
+
appendSql(sql$1) {
|
|
803
|
+
this.sqlParts.push(sql$1);
|
|
804
|
+
}
|
|
805
|
+
appendVariable(varName, value) {
|
|
806
|
+
this.sqlParts.push({
|
|
807
|
+
name: varName,
|
|
808
|
+
value
|
|
809
|
+
});
|
|
810
|
+
}
|
|
811
|
+
trim() {
|
|
812
|
+
const lastPart = this.sqlParts.length > 0 ? this.sqlParts[this.sqlParts.length - 1] : null;
|
|
813
|
+
if (lastPart && typeof lastPart === "string") this.sqlParts[this.sqlParts.length - 1] = lastPart.trimEnd();
|
|
814
|
+
}
|
|
815
|
+
parameters() {
|
|
816
|
+
return this.sqlParts.filter((part) => typeof part !== "string" && !part.name.startsWith("sources_"));
|
|
817
|
+
}
|
|
818
|
+
toSqlWithAnonymousPlaceholders() {
|
|
819
|
+
let sql$1 = "";
|
|
820
|
+
const sqlParts = [];
|
|
821
|
+
for (const part of this.sqlParts) if (typeof part === "string") {
|
|
822
|
+
sql$1 += part;
|
|
823
|
+
sqlParts.push(part);
|
|
824
|
+
} else {
|
|
825
|
+
if (sql$1.length > 0) {
|
|
826
|
+
const last = sql$1[sql$1.length - 1];
|
|
827
|
+
if (last !== " " && last !== "=" && last !== ">" && last !== "<") sql$1 += " ";
|
|
828
|
+
}
|
|
829
|
+
sql$1 += "?";
|
|
830
|
+
if (part.name.startsWith("sources_")) sqlParts.push(part);
|
|
831
|
+
else sqlParts.push("?");
|
|
832
|
+
}
|
|
833
|
+
return {
|
|
834
|
+
parameters: this.parameters(),
|
|
835
|
+
sql: sql$1,
|
|
836
|
+
sqlParts
|
|
837
|
+
};
|
|
838
|
+
}
|
|
839
|
+
toSqlWithPositionalPlaceholders() {
|
|
840
|
+
const parameters = [];
|
|
841
|
+
const sqlParts = [];
|
|
842
|
+
for (const part of this.sqlParts) if (typeof part === "string") sqlParts.push(part);
|
|
843
|
+
else {
|
|
844
|
+
const varName = part.name;
|
|
845
|
+
const value = part.value;
|
|
846
|
+
if (varName.startsWith("sources_")) sqlParts.push(part);
|
|
847
|
+
else {
|
|
848
|
+
let pos = parameters.findIndex((p) => p.name === varName);
|
|
849
|
+
if (pos < 0) {
|
|
850
|
+
parameters.push({
|
|
851
|
+
name: varName,
|
|
852
|
+
value
|
|
853
|
+
});
|
|
854
|
+
pos = parameters.length;
|
|
855
|
+
} else pos = pos + 1;
|
|
856
|
+
sqlParts.push(`$${pos}`);
|
|
857
|
+
}
|
|
858
|
+
}
|
|
859
|
+
return {
|
|
860
|
+
parameters,
|
|
861
|
+
sqlParts,
|
|
862
|
+
sql: sqlParts.map((part) => typeof part === "string" ? part : ` ${part.value} `).join("").trim()
|
|
863
|
+
};
|
|
864
|
+
}
|
|
558
865
|
toSqlWithNamedPlaceholders() {
|
|
559
866
|
const sqlParts = [];
|
|
560
867
|
for (const part of this.sqlParts) if (typeof part === "string") sqlParts.push(part);
|
|
@@ -602,7 +909,7 @@ function parseSQLQueries(filePath, extraVariables) {
|
|
|
602
909
|
if (match) includeColumns.push(...match[1].split(",").map((c) => c.trim()));
|
|
603
910
|
}
|
|
604
911
|
const table = new TableInfo(filePath, name, tableName, includeColumns, hasAppender);
|
|
605
|
-
if (queryNames.has(name)) throw SqgError.inFile(`Duplicate name '${name}'`, "DUPLICATE_QUERY", filePath, { suggestion:
|
|
912
|
+
if (queryNames.has(name)) throw SqgError.inFile(`Duplicate name '${name}'`, "DUPLICATE_QUERY", filePath, { suggestion: "Rename one of the tables/queries to have a unique name" });
|
|
606
913
|
queryNames.add(name);
|
|
607
914
|
tables.push(table);
|
|
608
915
|
consola.debug(`Added table: ${name} -> ${tableName} (appender: ${hasAppender})`);
|
|
@@ -618,7 +925,7 @@ function parseSQLQueries(filePath, extraVariables) {
|
|
|
618
925
|
config
|
|
619
926
|
});
|
|
620
927
|
const query = new SQLQuery(filePath, name, sqlContentStr, sql.toSqlWithAnonymousPlaceholders(), sql.toSqlWithNamedPlaceholders(), sql.toSqlWithPositionalPlaceholders(), queryType, isOne, isPluck, variables, config);
|
|
621
|
-
if (queryNames.has(name)) throw SqgError.inFile(`Duplicate query name '${name}'`, "DUPLICATE_QUERY", filePath, { suggestion:
|
|
928
|
+
if (queryNames.has(name)) throw SqgError.inFile(`Duplicate query name '${name}'`, "DUPLICATE_QUERY", filePath, { suggestion: "Rename one of the queries to have a unique name" });
|
|
622
929
|
queryNames.add(name);
|
|
623
930
|
queries.push(query);
|
|
624
931
|
consola.debug(`Added query: ${name} (${queryType})`);
|
|
@@ -1020,7 +1327,7 @@ var TypeMapper = class {
|
|
|
1020
1327
|
}
|
|
1021
1328
|
if (column.type instanceof StructType) return path + this.formatStructTypeName(column.name);
|
|
1022
1329
|
if (column.type instanceof MapType) return path + this.formatMapTypeName(column.name);
|
|
1023
|
-
if (!column.type) throw new TypeMappingError(
|
|
1330
|
+
if (!column.type) throw new TypeMappingError("Missing type information", column.name);
|
|
1024
1331
|
return this.mapPrimitiveType(column.type.toString(), column.nullable);
|
|
1025
1332
|
}
|
|
1026
1333
|
/**
|
|
@@ -1798,7 +2105,10 @@ function getGenerator(generator) {
|
|
|
1798
2105
|
const info = parseGenerator(generator);
|
|
1799
2106
|
const key = `${info.language}/${info.driver}`;
|
|
1800
2107
|
switch (key) {
|
|
1801
|
-
case "typescript/better-sqlite3":
|
|
2108
|
+
case "typescript/better-sqlite3":
|
|
2109
|
+
case "typescript/node":
|
|
2110
|
+
case "typescript/libsql":
|
|
2111
|
+
case "typescript/turso": return new TsGenerator(`templates/${info.template}`);
|
|
1802
2112
|
case "typescript/node-api": return new TsDuckDBGenerator(`templates/${info.template}`);
|
|
1803
2113
|
case "java/jdbc": return new JavaGenerator(`templates/${info.template}`);
|
|
1804
2114
|
case "java/arrow": return new JavaDuckDBArrowGenerator(`templates/${info.template}`);
|
|
@@ -2255,275 +2565,339 @@ async function processProject(projectPath) {
|
|
|
2255
2565
|
}
|
|
2256
2566
|
|
|
2257
2567
|
//#endregion
|
|
2258
|
-
//#region src/
|
|
2259
|
-
|
|
2260
|
-
|
|
2261
|
-
|
|
2262
|
-
|
|
2263
|
-
|
|
2264
|
-
|
|
2265
|
-
|
|
2266
|
-
|
|
2568
|
+
//#region src/mcp-server.ts
|
|
2569
|
+
const server = new Server({
|
|
2570
|
+
name: "sqg-mcp",
|
|
2571
|
+
version: process.env.npm_package_version ?? "0.7.0"
|
|
2572
|
+
}, { capabilities: {
|
|
2573
|
+
tools: {},
|
|
2574
|
+
resources: {}
|
|
2575
|
+
} });
|
|
2576
|
+
function formatGeneratorListWithDescriptions() {
|
|
2577
|
+
const lines = [];
|
|
2578
|
+
const seen = /* @__PURE__ */ new Set();
|
|
2579
|
+
for (const shortName of SHORT_GENERATOR_NAMES) {
|
|
2580
|
+
const fullName = Object.keys(GENERATORS).find((g) => g.startsWith(`${shortName}/`));
|
|
2581
|
+
if (fullName) {
|
|
2582
|
+
const info = GENERATORS[fullName];
|
|
2583
|
+
lines.push(`- ${shortName} - ${info.description}`);
|
|
2584
|
+
seen.add(fullName);
|
|
2585
|
+
}
|
|
2586
|
+
}
|
|
2587
|
+
for (const [fullName, info] of Object.entries(GENERATORS)) if (!seen.has(fullName)) lines.push(`- ${fullName} - ${info.description}`);
|
|
2588
|
+
return lines.join("\n");
|
|
2267
2589
|
}
|
|
2268
|
-
|
|
2269
|
-
|
|
2270
|
-
|
|
2271
|
-
|
|
2272
|
-
return
|
|
2273
|
-
|
|
2274
|
-
|
|
2275
|
-
|
|
2276
|
-
|
|
2277
|
-
|
|
2278
|
-
|
|
2279
|
-
|
|
2280
|
-
);
|
|
2590
|
+
function formatGeneratorListSimple() {
|
|
2591
|
+
const generators = [...SHORT_GENERATOR_NAMES];
|
|
2592
|
+
const seen = new Set(SHORT_GENERATOR_NAMES.map((s) => Object.keys(GENERATORS).find((g) => g.startsWith(`${s}/`))));
|
|
2593
|
+
for (const fullName of Object.keys(GENERATORS)) if (!seen.has(fullName)) generators.push(fullName);
|
|
2594
|
+
return generators.join(", ");
|
|
2595
|
+
}
|
|
2596
|
+
async function generateCode(sql, generator) {
|
|
2597
|
+
const engine = getGeneratorEngine(generator);
|
|
2598
|
+
const tempDir = join(tmpdir(), `sqg-mcp-${randomUUID()}`);
|
|
2599
|
+
const sqlFile = join(tempDir, "queries.sql");
|
|
2600
|
+
const configFile = join(tempDir, "sqg.yaml");
|
|
2601
|
+
try {
|
|
2602
|
+
mkdirSync(tempDir, { recursive: true });
|
|
2603
|
+
writeFileSync(sqlFile, sql, "utf-8");
|
|
2604
|
+
const genConfig = {
|
|
2605
|
+
generator,
|
|
2606
|
+
output: "./generated/"
|
|
2607
|
+
};
|
|
2608
|
+
if (generator.startsWith("java/")) genConfig.config = { package: "sqg.generated" };
|
|
2609
|
+
const projectYaml = {
|
|
2610
|
+
version: 1,
|
|
2611
|
+
name: "generated",
|
|
2612
|
+
sql: [{
|
|
2613
|
+
engine,
|
|
2614
|
+
files: ["queries.sql"],
|
|
2615
|
+
gen: [genConfig]
|
|
2616
|
+
}]
|
|
2617
|
+
};
|
|
2618
|
+
writeFileSync(configFile, YAML.stringify(projectYaml), "utf-8");
|
|
2619
|
+
const files = await processProject(configFile);
|
|
2620
|
+
if (files.length === 0) return {
|
|
2621
|
+
code: "",
|
|
2622
|
+
error: "No files were generated"
|
|
2623
|
+
};
|
|
2624
|
+
return { code: readFileSync(files[0], "utf-8") };
|
|
2625
|
+
} catch (error) {
|
|
2626
|
+
return {
|
|
2627
|
+
code: "",
|
|
2628
|
+
error: error instanceof Error ? error.message : String(error)
|
|
2629
|
+
};
|
|
2630
|
+
} finally {
|
|
2631
|
+
try {
|
|
2632
|
+
rmSync(tempDir, {
|
|
2633
|
+
recursive: true,
|
|
2634
|
+
force: true
|
|
2635
|
+
});
|
|
2636
|
+
} catch (error) {}
|
|
2637
|
+
}
|
|
2638
|
+
}
|
|
2639
|
+
const GENERATE_CODE_DESCRIPTION = `Generate type-safe database access code from annotated SQL queries.
|
|
2281
2640
|
|
|
2282
|
-
|
|
2283
|
-
|
|
2284
|
-
|
|
2285
|
-
|
|
2286
|
-
title TEXT NOT NULL,
|
|
2287
|
-
content TEXT,
|
|
2288
|
-
published INTEGER DEFAULT 0,
|
|
2289
|
-
created_at TEXT DEFAULT CURRENT_TIMESTAMP
|
|
2290
|
-
);
|
|
2641
|
+
CRITICAL REQUIREMENTS:
|
|
2642
|
+
1. MIGRATE statements MUST come BEFORE any QUERY/EXEC that references those tables
|
|
2643
|
+
2. Each query block needs a unique name
|
|
2644
|
+
3. Parameters require @set declarations with sample values
|
|
2291
2645
|
|
|
2292
|
-
|
|
2293
|
-
INSERT INTO users (name, email) VALUES ('Alice', 'alice@example.com');
|
|
2294
|
-
INSERT INTO users (name, email) VALUES ('Bob', 'bob@example.com');
|
|
2295
|
-
INSERT INTO posts (user_id, title, content, published) VALUES (1, 'Hello World', 'My first post!', 1);
|
|
2296
|
-
`,
|
|
2297
|
-
duckdb: `-- MIGRATE 1
|
|
2298
|
-
-- Create the users table (SQG Example - https://sqg.dev/guides/sql-syntax/)
|
|
2299
|
-
CREATE TABLE users (
|
|
2300
|
-
id INTEGER PRIMARY KEY,
|
|
2301
|
-
name VARCHAR NOT NULL,
|
|
2302
|
-
email VARCHAR UNIQUE NOT NULL,
|
|
2303
|
-
metadata STRUCT(role VARCHAR, active BOOLEAN),
|
|
2304
|
-
tags VARCHAR[],
|
|
2305
|
-
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
2306
|
-
);
|
|
2646
|
+
${SQL_SYNTAX_REFERENCE}
|
|
2307
2647
|
|
|
2308
|
-
|
|
2309
|
-
|
|
2310
|
-
id INTEGER PRIMARY KEY,
|
|
2311
|
-
user_id INTEGER NOT NULL REFERENCES users(id),
|
|
2312
|
-
title VARCHAR NOT NULL,
|
|
2313
|
-
content VARCHAR,
|
|
2314
|
-
published BOOLEAN DEFAULT FALSE,
|
|
2315
|
-
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
2316
|
-
);
|
|
2648
|
+
VALID GENERATORS (use short form):
|
|
2649
|
+
${formatGeneratorListWithDescriptions()}
|
|
2317
2650
|
|
|
2318
|
-
|
|
2319
|
-
|
|
2320
|
-
|
|
2321
|
-
|
|
2322
|
-
|
|
2323
|
-
|
|
2324
|
-
VALUES (1, 1, 'Hello World', 'My first post!', TRUE);
|
|
2325
|
-
`,
|
|
2326
|
-
postgres: `-- MIGRATE 1
|
|
2327
|
-
-- Create the users table (SQG Example - https://sqg.dev/guides/sql-syntax/)
|
|
2328
|
-
CREATE TABLE users (
|
|
2329
|
-
id SERIAL PRIMARY KEY,
|
|
2330
|
-
name TEXT NOT NULL,
|
|
2331
|
-
email TEXT UNIQUE NOT NULL,
|
|
2332
|
-
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
2333
|
-
);
|
|
2651
|
+
COMMON MISTAKES TO AVOID:
|
|
2652
|
+
- Missing MIGRATE before QUERY (causes "no such table" error)
|
|
2653
|
+
- Missing @set for parameters (causes "undefined variable" error)
|
|
2654
|
+
- Duplicate query names (causes "duplicate query" error)
|
|
2655
|
+
- Using :pluck with multiple columns (only works with 1 column)`;
|
|
2656
|
+
const VALIDATE_SQL_DESCRIPTION = `Validate SQL queries with SQG annotations without generating code. Use this to check for errors before generating.
|
|
2334
2657
|
|
|
2335
|
-
|
|
2336
|
-
|
|
2337
|
-
|
|
2338
|
-
|
|
2339
|
-
|
|
2340
|
-
|
|
2341
|
-
published BOOLEAN DEFAULT FALSE,
|
|
2342
|
-
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
2343
|
-
);
|
|
2658
|
+
Returns JSON with validation results including:
|
|
2659
|
+
- valid: boolean indicating success
|
|
2660
|
+
- project: project metadata if valid
|
|
2661
|
+
- sqlFiles: list of SQL files processed
|
|
2662
|
+
- generators: list of generators used
|
|
2663
|
+
- errors: array of error messages if invalid
|
|
2344
2664
|
|
|
2345
|
-
|
|
2346
|
-
|
|
2347
|
-
|
|
2348
|
-
|
|
2349
|
-
|
|
2350
|
-
|
|
2351
|
-
|
|
2352
|
-
|
|
2353
|
-
|
|
2354
|
-
|
|
2665
|
+
See generate_code tool description for complete syntax reference.`;
|
|
2666
|
+
server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
2667
|
+
return { tools: [{
|
|
2668
|
+
name: "generate_code",
|
|
2669
|
+
description: GENERATE_CODE_DESCRIPTION,
|
|
2670
|
+
inputSchema: {
|
|
2671
|
+
type: "object",
|
|
2672
|
+
properties: {
|
|
2673
|
+
sql: {
|
|
2674
|
+
type: "string",
|
|
2675
|
+
description: "Complete SQL file content with SQG annotations. IMPORTANT: Include MIGRATE statements first to create tables before QUERY statements that use them."
|
|
2676
|
+
},
|
|
2677
|
+
generator: {
|
|
2678
|
+
type: "string",
|
|
2679
|
+
description: `Code generator to use. Valid options: ${formatGeneratorListSimple()}`
|
|
2680
|
+
}
|
|
2681
|
+
},
|
|
2682
|
+
required: ["sql", "generator"]
|
|
2683
|
+
}
|
|
2684
|
+
}, {
|
|
2685
|
+
name: "validate_sql",
|
|
2686
|
+
description: VALIDATE_SQL_DESCRIPTION,
|
|
2687
|
+
inputSchema: {
|
|
2688
|
+
type: "object",
|
|
2689
|
+
properties: {
|
|
2690
|
+
sql: {
|
|
2691
|
+
type: "string",
|
|
2692
|
+
description: "Complete SQL file content with SQG annotations to validate. Include MIGRATE statements before QUERY statements."
|
|
2693
|
+
},
|
|
2694
|
+
generator: {
|
|
2695
|
+
type: "string",
|
|
2696
|
+
description: `Code generator for validation context. Valid options: ${formatGeneratorListSimple()}`
|
|
2697
|
+
}
|
|
2698
|
+
},
|
|
2699
|
+
required: ["sql", "generator"]
|
|
2700
|
+
}
|
|
2701
|
+
}] };
|
|
2702
|
+
});
|
|
2703
|
+
server.setRequestHandler(ListResourcesRequestSchema, async () => {
|
|
2704
|
+
return { resources: [{
|
|
2705
|
+
uri: "sqg://documentation",
|
|
2706
|
+
name: "SQG Documentation",
|
|
2707
|
+
description: "Complete documentation for SQG (SQL Query Generator) including syntax, generators, and usage examples",
|
|
2708
|
+
mimeType: "text/markdown"
|
|
2709
|
+
}] };
|
|
2710
|
+
});
|
|
2711
|
+
server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
|
|
2712
|
+
const { uri } = request.params;
|
|
2713
|
+
if (uri === "sqg://documentation") {
|
|
2714
|
+
const generatorListMarkdown = Object.entries(GENERATORS).map(([name, info]) => {
|
|
2715
|
+
const shortName = `${info.language}/${info.engine}`;
|
|
2716
|
+
return `- \`${Object.keys(GENERATORS).find((g) => g.startsWith(`${shortName}/`)) === name ? shortName : name}\` - ${info.description}`;
|
|
2717
|
+
}).filter((line, index, arr) => arr.indexOf(line) === index).join("\n");
|
|
2718
|
+
return { contents: [{
|
|
2719
|
+
uri,
|
|
2720
|
+
mimeType: "text/markdown",
|
|
2721
|
+
text: `# SQG - SQL Query Generator
|
|
2355
2722
|
|
|
2356
|
-
|
|
2357
|
-
@set id = 1
|
|
2358
|
-
SELECT id, name, email, created_at
|
|
2359
|
-
FROM users
|
|
2360
|
-
WHERE id = \${id};
|
|
2723
|
+
SQG is a type-safe SQL code generator that reads SQL queries from \`.sql\` files with special annotations and generates type-safe database access code in multiple target languages (TypeScript and Java).
|
|
2361
2724
|
|
|
2362
|
-
|
|
2363
|
-
@set email = 'alice@example.com'
|
|
2364
|
-
SELECT id, name, email, created_at
|
|
2365
|
-
FROM users
|
|
2366
|
-
WHERE email = \${email};
|
|
2725
|
+
## Overview
|
|
2367
2726
|
|
|
2368
|
-
|
|
2369
|
-
SELECT COUNT(*) FROM users;
|
|
2727
|
+
SQG introspects SQL queries at build time against real database engines to determine column types and generates strongly-typed wrapper functions.
|
|
2370
2728
|
|
|
2371
|
-
|
|
2372
|
-
|
|
2373
|
-
SELECT p.id, p.title, p.content, p.published, p.created_at
|
|
2374
|
-
FROM posts p
|
|
2375
|
-
WHERE p.user_id = \${user_id}
|
|
2376
|
-
ORDER BY p.created_at DESC;
|
|
2729
|
+
**Website:** https://sqg.dev
|
|
2730
|
+
**Repository:** https://github.com/sqg-dev/sqg
|
|
2377
2731
|
|
|
2378
|
-
|
|
2379
|
-
SELECT
|
|
2380
|
-
p.id,
|
|
2381
|
-
p.title,
|
|
2382
|
-
p.content,
|
|
2383
|
-
p.created_at,
|
|
2384
|
-
u.name as author_name,
|
|
2385
|
-
u.email as author_email
|
|
2386
|
-
FROM posts p
|
|
2387
|
-
JOIN users u ON p.user_id = u.id
|
|
2388
|
-
WHERE p.published = 1
|
|
2389
|
-
ORDER BY p.created_at DESC;
|
|
2390
|
-
` + {
|
|
2391
|
-
sqlite: `
|
|
2392
|
-
-- EXEC create_user
|
|
2393
|
-
@set name = 'New User'
|
|
2394
|
-
@set email = 'new@example.com'
|
|
2395
|
-
INSERT INTO users (name, email)
|
|
2396
|
-
VALUES (\${name}, \${email});
|
|
2732
|
+
## Key Features
|
|
2397
2733
|
|
|
2398
|
-
|
|
2399
|
-
|
|
2400
|
-
|
|
2401
|
-
|
|
2402
|
-
|
|
2403
|
-
|
|
2734
|
+
- **Type-safe by design** - Generates fully-typed code with accurate column types inferred from your database
|
|
2735
|
+
- **Multiple database engines** - Supports ${DB_ENGINES.join(", ")}
|
|
2736
|
+
- **Multiple language targets** - Generate TypeScript or Java code from the same SQL files
|
|
2737
|
+
- **Arrow API support** - Can generate Apache Arrow API bindings for DuckDB (Java)
|
|
2738
|
+
- **DBeaver compatible** - Works seamlessly with DBeaver for database development and testing
|
|
2739
|
+
- **Complex type support** - DuckDB: Handles structs, lists, and maps
|
|
2740
|
+
- **Migration management** - Built-in support for schema migrations and test data
|
|
2404
2741
|
|
|
2405
|
-
|
|
2406
|
-
@set id = 1
|
|
2407
|
-
UPDATE posts SET published = 1 WHERE id = \${id};
|
|
2742
|
+
## SQL Annotations
|
|
2408
2743
|
|
|
2409
|
-
|
|
2410
|
-
@set id = 1
|
|
2411
|
-
DELETE FROM posts WHERE id = \${id};
|
|
2412
|
-
`,
|
|
2413
|
-
duckdb: `
|
|
2414
|
-
-- EXEC create_user
|
|
2415
|
-
@set id = 100
|
|
2416
|
-
@set name = 'New User'
|
|
2417
|
-
@set email = 'new@example.com'
|
|
2418
|
-
INSERT INTO users (id, name, email)
|
|
2419
|
-
VALUES (\${id}, \${name}, \${email});
|
|
2744
|
+
${SQL_SYNTAX_REFERENCE}
|
|
2420
2745
|
|
|
2421
|
-
|
|
2422
|
-
@set id = 100
|
|
2423
|
-
@set user_id = 1
|
|
2424
|
-
@set title = 'New Post'
|
|
2425
|
-
@set content = 'Post content here'
|
|
2426
|
-
INSERT INTO posts (id, user_id, title, content)
|
|
2427
|
-
VALUES (\${id}, \${user_id}, \${title}, \${content});
|
|
2746
|
+
## Supported Generators
|
|
2428
2747
|
|
|
2429
|
-
|
|
2430
|
-
@set id = 1
|
|
2431
|
-
UPDATE posts SET published = TRUE WHERE id = \${id};
|
|
2748
|
+
Valid generator strings:
|
|
2432
2749
|
|
|
2433
|
-
|
|
2434
|
-
@set id = 1
|
|
2435
|
-
DELETE FROM posts WHERE id = \${id};
|
|
2436
|
-
`,
|
|
2437
|
-
postgres: `
|
|
2438
|
-
-- EXEC create_user
|
|
2439
|
-
@set name = 'New User'
|
|
2440
|
-
@set email = 'new@example.com'
|
|
2441
|
-
INSERT INTO users (name, email)
|
|
2442
|
-
VALUES (\${name}, \${email});
|
|
2750
|
+
${generatorListMarkdown}
|
|
2443
2751
|
|
|
2444
|
-
|
|
2445
|
-
@set user_id = 1
|
|
2446
|
-
@set title = 'New Post'
|
|
2447
|
-
@set content = 'Post content here'
|
|
2448
|
-
INSERT INTO posts (user_id, title, content)
|
|
2449
|
-
VALUES (\${user_id}, \${title}, \${content});
|
|
2752
|
+
## MCP Tools
|
|
2450
2753
|
|
|
2451
|
-
|
|
2452
|
-
@set id = 1
|
|
2453
|
-
UPDATE posts SET published = TRUE WHERE id = \${id};
|
|
2754
|
+
### generate_code
|
|
2454
2755
|
|
|
2455
|
-
|
|
2456
|
-
|
|
2457
|
-
|
|
2458
|
-
|
|
2459
|
-
|
|
2756
|
+
Generate type-safe database access code from SQL queries with SQG annotations.
|
|
2757
|
+
|
|
2758
|
+
**Parameters:**
|
|
2759
|
+
- \`sql\` (string, required): SQL queries with SQG annotations
|
|
2760
|
+
- \`generator\` (string, required): Code generation generator (see supported generators above)
|
|
2761
|
+
|
|
2762
|
+
**Example:**
|
|
2763
|
+
\`\`\`json
|
|
2764
|
+
{
|
|
2765
|
+
"sql": "-- MIGRATE 1\\nCREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT);\\n\\n-- QUERY getUsers\\nSELECT * FROM users;",
|
|
2766
|
+
"generator": "typescript/sqlite"
|
|
2460
2767
|
}
|
|
2461
|
-
|
|
2462
|
-
* Generate sqg.yaml configuration
|
|
2463
|
-
*/
|
|
2464
|
-
function getConfigYaml(generator, output) {
|
|
2465
|
-
const isJava = parseGenerator(generator).language === "java";
|
|
2466
|
-
return `# SQG Configuration
|
|
2467
|
-
# Generated by: sqg init
|
|
2468
|
-
# Documentation: https://sqg.dev
|
|
2768
|
+
\`\`\`
|
|
2469
2769
|
|
|
2470
|
-
|
|
2471
|
-
name: my-project
|
|
2770
|
+
### validate_sql
|
|
2472
2771
|
|
|
2473
|
-
|
|
2474
|
-
|
|
2475
|
-
|
|
2476
|
-
|
|
2477
|
-
|
|
2478
|
-
|
|
2479
|
-
|
|
2480
|
-
|
|
2481
|
-
|
|
2772
|
+
Validate SQL queries with SQG annotations without generating code.
|
|
2773
|
+
|
|
2774
|
+
**Parameters:**
|
|
2775
|
+
- \`sql\` (string, required): SQL queries with SQG annotations to validate
|
|
2776
|
+
- \`generator\` (string, required): Code generation generator to use for validation
|
|
2777
|
+
|
|
2778
|
+
**Example:**
|
|
2779
|
+
\`\`\`json
|
|
2780
|
+
{
|
|
2781
|
+
"sql": "-- QUERY getUsers\\nSELECT * FROM users;",
|
|
2782
|
+
"generator": "typescript/sqlite"
|
|
2482
2783
|
}
|
|
2483
|
-
|
|
2484
|
-
* Initialize a new SQG project
|
|
2485
|
-
*/
|
|
2486
|
-
async function initProject(options) {
|
|
2487
|
-
const generator = options.generator || getDefaultGenerator();
|
|
2488
|
-
const output = options.output || "./generated";
|
|
2489
|
-
if (!isValidGenerator(generator)) {
|
|
2490
|
-
const similar = findSimilarGenerators(generator);
|
|
2491
|
-
throw new InvalidGeneratorError(generator, [...SHORT_GENERATOR_NAMES, ...GENERATOR_NAMES], similar.length > 0 ? similar[0] : void 0);
|
|
2492
|
-
}
|
|
2493
|
-
const engine = parseGenerator(generator).engine;
|
|
2494
|
-
const configPath = "sqg.yaml";
|
|
2495
|
-
const sqlPath = "queries.sql";
|
|
2496
|
-
if (!options.force) {
|
|
2497
|
-
if (existsSync(configPath)) throw new SqgError(`File already exists: ${configPath}`, "VALIDATION_ERROR", "Use --force to overwrite existing files");
|
|
2498
|
-
if (existsSync(sqlPath)) throw new SqgError(`File already exists: ${sqlPath}`, "VALIDATION_ERROR", "Use --force to overwrite existing files");
|
|
2499
|
-
}
|
|
2500
|
-
if (!existsSync(output)) {
|
|
2501
|
-
mkdirSync(output, { recursive: true });
|
|
2502
|
-
consola.success(`Created output directory: ${output}`);
|
|
2503
|
-
}
|
|
2504
|
-
writeFileSync(configPath, getConfigYaml(generator, output));
|
|
2505
|
-
consola.success(`Created ${configPath}`);
|
|
2506
|
-
writeFileSync(sqlPath, getExampleSql(engine));
|
|
2507
|
-
consola.success(`Created ${sqlPath}`);
|
|
2508
|
-
consola.box(`
|
|
2509
|
-
SQG project initialized!
|
|
2784
|
+
\`\`\`
|
|
2510
2785
|
|
|
2511
|
-
Generator
|
|
2512
|
-
Engine: ${engine}
|
|
2513
|
-
Output: ${output}
|
|
2786
|
+
## Generator Format
|
|
2514
2787
|
|
|
2515
|
-
|
|
2516
|
-
1. Edit queries.sql to add your SQL queries
|
|
2517
|
-
2. Run: sqg sqg.yaml
|
|
2518
|
-
3. Import the generated code from ${output}
|
|
2788
|
+
Generators follow the pattern \`<language>/<engine>[/<driver>]\`:
|
|
2519
2789
|
|
|
2520
|
-
|
|
2521
|
-
|
|
2790
|
+
- **Short form**: \`typescript/sqlite\`, \`java/duckdb\` (uses default driver)
|
|
2791
|
+
- **Full form**: \`typescript/sqlite/better-sqlite3\`, \`java/duckdb/arrow\` (specifies driver)
|
|
2792
|
+
|
|
2793
|
+
The MCP server accepts both short and full forms, but short forms are recommended.
|
|
2794
|
+
|
|
2795
|
+
## More Information
|
|
2796
|
+
|
|
2797
|
+
- Full documentation: https://sqg.dev
|
|
2798
|
+
- GitHub: https://github.com/sqg-dev/sqg
|
|
2799
|
+
- SQL Syntax Reference: Run \`sqg syntax\` command
|
|
2800
|
+
`
|
|
2801
|
+
}] };
|
|
2802
|
+
}
|
|
2803
|
+
return {
|
|
2804
|
+
contents: [],
|
|
2805
|
+
isError: true
|
|
2806
|
+
};
|
|
2807
|
+
});
|
|
2808
|
+
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
2809
|
+
const { name, arguments: args } = request.params;
|
|
2810
|
+
if (name === "generate_code") {
|
|
2811
|
+
const { sql, generator } = args;
|
|
2812
|
+
const result = await generateCode(sql, generator);
|
|
2813
|
+
if (result.error) return {
|
|
2814
|
+
content: [{
|
|
2815
|
+
type: "text",
|
|
2816
|
+
text: `Error generating code: ${result.error}`
|
|
2817
|
+
}],
|
|
2818
|
+
isError: true
|
|
2819
|
+
};
|
|
2820
|
+
return { content: [{
|
|
2821
|
+
type: "text",
|
|
2822
|
+
text: result.code
|
|
2823
|
+
}] };
|
|
2824
|
+
}
|
|
2825
|
+
if (name === "validate_sql") {
|
|
2826
|
+
const { sql, generator } = args;
|
|
2827
|
+
const engine = getGeneratorEngine(generator);
|
|
2828
|
+
const tempDir = join(tmpdir(), `sqg-mcp-validate-${randomUUID()}`);
|
|
2829
|
+
const sqlFile = join(tempDir, "queries.sql");
|
|
2830
|
+
const configFile = join(tempDir, "sqg.yaml");
|
|
2831
|
+
try {
|
|
2832
|
+
mkdirSync(tempDir, { recursive: true });
|
|
2833
|
+
writeFileSync(sqlFile, sql, "utf-8");
|
|
2834
|
+
const projectYaml = {
|
|
2835
|
+
version: 1,
|
|
2836
|
+
name: "validation",
|
|
2837
|
+
sql: [{
|
|
2838
|
+
engine,
|
|
2839
|
+
files: ["queries.sql"],
|
|
2840
|
+
gen: [{
|
|
2841
|
+
generator,
|
|
2842
|
+
output: "./generated/"
|
|
2843
|
+
}]
|
|
2844
|
+
}]
|
|
2845
|
+
};
|
|
2846
|
+
writeFileSync(configFile, YAML.stringify(projectYaml), "utf-8");
|
|
2847
|
+
const validation = await validateProject(configFile);
|
|
2848
|
+
if (validation.valid) return { content: [{
|
|
2849
|
+
type: "text",
|
|
2850
|
+
text: JSON.stringify({
|
|
2851
|
+
valid: true,
|
|
2852
|
+
project: validation.project,
|
|
2853
|
+
sqlFiles: validation.sqlFiles,
|
|
2854
|
+
generators: validation.generators
|
|
2855
|
+
}, null, 2)
|
|
2856
|
+
}] };
|
|
2857
|
+
return {
|
|
2858
|
+
content: [{
|
|
2859
|
+
type: "text",
|
|
2860
|
+
text: JSON.stringify({
|
|
2861
|
+
valid: false,
|
|
2862
|
+
errors: validation.errors
|
|
2863
|
+
}, null, 2)
|
|
2864
|
+
}],
|
|
2865
|
+
isError: true
|
|
2866
|
+
};
|
|
2867
|
+
} catch (error) {
|
|
2868
|
+
return {
|
|
2869
|
+
content: [{
|
|
2870
|
+
type: "text",
|
|
2871
|
+
text: `Error validating SQL: ${error instanceof Error ? error.message : String(error)}`
|
|
2872
|
+
}],
|
|
2873
|
+
isError: true
|
|
2874
|
+
};
|
|
2875
|
+
} finally {
|
|
2876
|
+
try {
|
|
2877
|
+
rmSync(tempDir, {
|
|
2878
|
+
recursive: true,
|
|
2879
|
+
force: true
|
|
2880
|
+
});
|
|
2881
|
+
} catch (error) {}
|
|
2882
|
+
}
|
|
2883
|
+
}
|
|
2884
|
+
return {
|
|
2885
|
+
content: [{
|
|
2886
|
+
type: "text",
|
|
2887
|
+
text: `Unknown tool: ${name}`
|
|
2888
|
+
}],
|
|
2889
|
+
isError: true
|
|
2890
|
+
};
|
|
2891
|
+
});
|
|
2892
|
+
async function startMcpServer() {
|
|
2893
|
+
const transport = new StdioServerTransport();
|
|
2894
|
+
await server.connect(transport);
|
|
2895
|
+
console.error("SQG MCP server running on stdio");
|
|
2522
2896
|
}
|
|
2523
2897
|
|
|
2524
2898
|
//#endregion
|
|
2525
2899
|
//#region src/sqg.ts
|
|
2526
|
-
const version = process.env.npm_package_version ?? "0.
|
|
2900
|
+
const version = process.env.npm_package_version ?? "0.7.0";
|
|
2527
2901
|
const description = process.env.npm_package_description ?? "SQG - SQL Query Generator - Type-safe code generation from SQL (https://sqg.dev)";
|
|
2528
2902
|
consola.level = LogLevels.info;
|
|
2529
2903
|
const program = new Command().name("sqg").description(`${description}
|
|
@@ -2628,6 +3002,14 @@ program.command("init").description("Initialize a new SQG project with example c
|
|
|
2628
3002
|
program.command("syntax").description("Show SQL annotation syntax reference").action(() => {
|
|
2629
3003
|
console.log(SQL_SYNTAX_REFERENCE);
|
|
2630
3004
|
});
|
|
3005
|
+
program.command("mcp").description("Start MCP (Model Context Protocol) server for AI assistants").action(async () => {
|
|
3006
|
+
try {
|
|
3007
|
+
await startMcpServer();
|
|
3008
|
+
} catch (error) {
|
|
3009
|
+
consola.error("Fatal error in MCP server:", error);
|
|
3010
|
+
exit(1);
|
|
3011
|
+
}
|
|
3012
|
+
});
|
|
2631
3013
|
if (process.argv.length <= 2) {
|
|
2632
3014
|
program.outputHelp();
|
|
2633
3015
|
exit(1);
|