@sqg/sqg 0.5.0 → 0.6.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 +854 -490
- package/dist/templates/node-sqlite.hbs +108 -0
- package/package.json +3 -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,14 @@ 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
|
+
},
|
|
34
58
|
"typescript/duckdb/node-api": {
|
|
35
59
|
language: "typescript",
|
|
36
60
|
engine: "duckdb",
|
|
@@ -315,254 +339,521 @@ function formatErrorForOutput(err) {
|
|
|
315
339
|
}
|
|
316
340
|
|
|
317
341
|
//#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
|
-
};
|
|
342
|
+
//#region src/init.ts
|
|
418
343
|
/**
|
|
419
|
-
*
|
|
420
|
-
* TABLE annotations specify a table name for which to generate bulk insert appenders.
|
|
344
|
+
* SQG Project Initialization - Creates new SQG projects with example files
|
|
421
345
|
*/
|
|
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
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
346
|
+
/**
|
|
347
|
+
* Get the default generator for a language preference
|
|
348
|
+
*/
|
|
349
|
+
function getDefaultGenerator() {
|
|
350
|
+
return "typescript/sqlite";
|
|
351
|
+
}
|
|
352
|
+
/**
|
|
353
|
+
* Generate example SQL content based on engine
|
|
354
|
+
*/
|
|
355
|
+
function getExampleSql(engine) {
|
|
356
|
+
return {
|
|
357
|
+
sqlite: `-- MIGRATE 1
|
|
358
|
+
-- Create the users table (SQG Example - https://sqg.dev/guides/sql-syntax/)
|
|
359
|
+
CREATE TABLE users (
|
|
360
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
361
|
+
name TEXT NOT NULL,
|
|
362
|
+
email TEXT UNIQUE NOT NULL,
|
|
363
|
+
created_at TEXT DEFAULT CURRENT_TIMESTAMP
|
|
364
|
+
);
|
|
365
|
+
|
|
366
|
+
-- MIGRATE 2
|
|
367
|
+
CREATE TABLE posts (
|
|
368
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
369
|
+
user_id INTEGER NOT NULL REFERENCES users(id),
|
|
370
|
+
title TEXT NOT NULL,
|
|
371
|
+
content TEXT,
|
|
372
|
+
published INTEGER DEFAULT 0,
|
|
373
|
+
created_at TEXT DEFAULT CURRENT_TIMESTAMP
|
|
374
|
+
);
|
|
375
|
+
|
|
376
|
+
-- TESTDATA seed_data
|
|
377
|
+
INSERT INTO users (name, email) VALUES ('Alice', 'alice@example.com');
|
|
378
|
+
INSERT INTO users (name, email) VALUES ('Bob', 'bob@example.com');
|
|
379
|
+
INSERT INTO posts (user_id, title, content, published) VALUES (1, 'Hello World', 'My first post!', 1);
|
|
380
|
+
`,
|
|
381
|
+
duckdb: `-- MIGRATE 1
|
|
382
|
+
-- Create the users table (SQG Example - https://sqg.dev/guides/sql-syntax/)
|
|
383
|
+
CREATE TABLE users (
|
|
384
|
+
id INTEGER PRIMARY KEY,
|
|
385
|
+
name VARCHAR NOT NULL,
|
|
386
|
+
email VARCHAR UNIQUE NOT NULL,
|
|
387
|
+
metadata STRUCT(role VARCHAR, active BOOLEAN),
|
|
388
|
+
tags VARCHAR[],
|
|
389
|
+
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
390
|
+
);
|
|
391
|
+
|
|
392
|
+
-- MIGRATE 2
|
|
393
|
+
CREATE TABLE posts (
|
|
394
|
+
id INTEGER PRIMARY KEY,
|
|
395
|
+
user_id INTEGER NOT NULL REFERENCES users(id),
|
|
396
|
+
title VARCHAR NOT NULL,
|
|
397
|
+
content VARCHAR,
|
|
398
|
+
published BOOLEAN DEFAULT FALSE,
|
|
399
|
+
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
400
|
+
);
|
|
401
|
+
|
|
402
|
+
-- TESTDATA seed_data
|
|
403
|
+
INSERT INTO users (id, name, email, metadata, tags)
|
|
404
|
+
VALUES (1, 'Alice', 'alice@example.com', {'role': 'admin', 'active': true}, ['developer', 'lead']);
|
|
405
|
+
INSERT INTO users (id, name, email, metadata, tags)
|
|
406
|
+
VALUES (2, 'Bob', 'bob@example.com', {'role': 'user', 'active': true}, ['developer']);
|
|
407
|
+
INSERT INTO posts (id, user_id, title, content, published)
|
|
408
|
+
VALUES (1, 1, 'Hello World', 'My first post!', TRUE);
|
|
409
|
+
`,
|
|
410
|
+
postgres: `-- MIGRATE 1
|
|
411
|
+
-- Create the users table (SQG Example - https://sqg.dev/guides/sql-syntax/)
|
|
412
|
+
CREATE TABLE users (
|
|
413
|
+
id SERIAL PRIMARY KEY,
|
|
414
|
+
name TEXT NOT NULL,
|
|
415
|
+
email TEXT UNIQUE NOT NULL,
|
|
416
|
+
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
417
|
+
);
|
|
418
|
+
|
|
419
|
+
-- MIGRATE 2
|
|
420
|
+
CREATE TABLE posts (
|
|
421
|
+
id SERIAL PRIMARY KEY,
|
|
422
|
+
user_id INTEGER NOT NULL REFERENCES users(id),
|
|
423
|
+
title TEXT NOT NULL,
|
|
424
|
+
content TEXT,
|
|
425
|
+
published BOOLEAN DEFAULT FALSE,
|
|
426
|
+
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
427
|
+
);
|
|
428
|
+
|
|
429
|
+
-- TESTDATA seed_data
|
|
430
|
+
INSERT INTO users (name, email) VALUES ('Alice', 'alice@example.com');
|
|
431
|
+
INSERT INTO users (name, email) VALUES ('Bob', 'bob@example.com');
|
|
432
|
+
INSERT INTO posts (user_id, title, content, published) VALUES (1, 'Hello World', 'My first post!', TRUE);
|
|
433
|
+
`
|
|
434
|
+
}[engine] + `
|
|
435
|
+
-- QUERY list_users
|
|
436
|
+
SELECT id, name, email, created_at
|
|
437
|
+
FROM users
|
|
438
|
+
ORDER BY created_at DESC;
|
|
439
|
+
|
|
440
|
+
-- QUERY get_user_by_id :one
|
|
441
|
+
@set id = 1
|
|
442
|
+
SELECT id, name, email, created_at
|
|
443
|
+
FROM users
|
|
444
|
+
WHERE id = \${id};
|
|
445
|
+
|
|
446
|
+
-- QUERY get_user_by_email :one
|
|
447
|
+
@set email = 'alice@example.com'
|
|
448
|
+
SELECT id, name, email, created_at
|
|
449
|
+
FROM users
|
|
450
|
+
WHERE email = \${email};
|
|
451
|
+
|
|
452
|
+
-- QUERY count_users :one :pluck
|
|
453
|
+
SELECT COUNT(*) FROM users;
|
|
454
|
+
|
|
455
|
+
-- QUERY list_posts_by_user
|
|
456
|
+
@set user_id = 1
|
|
457
|
+
SELECT p.id, p.title, p.content, p.published, p.created_at
|
|
458
|
+
FROM posts p
|
|
459
|
+
WHERE p.user_id = \${user_id}
|
|
460
|
+
ORDER BY p.created_at DESC;
|
|
461
|
+
|
|
462
|
+
-- QUERY list_published_posts
|
|
463
|
+
SELECT
|
|
464
|
+
p.id,
|
|
465
|
+
p.title,
|
|
466
|
+
p.content,
|
|
467
|
+
p.created_at,
|
|
468
|
+
u.name as author_name,
|
|
469
|
+
u.email as author_email
|
|
470
|
+
FROM posts p
|
|
471
|
+
JOIN users u ON p.user_id = u.id
|
|
472
|
+
WHERE p.published = 1
|
|
473
|
+
ORDER BY p.created_at DESC;
|
|
474
|
+
` + {
|
|
475
|
+
sqlite: `
|
|
476
|
+
-- EXEC create_user
|
|
477
|
+
@set name = 'New User'
|
|
478
|
+
@set email = 'new@example.com'
|
|
479
|
+
INSERT INTO users (name, email)
|
|
480
|
+
VALUES (\${name}, \${email});
|
|
481
|
+
|
|
482
|
+
-- EXEC create_post
|
|
483
|
+
@set user_id = 1
|
|
484
|
+
@set title = 'New Post'
|
|
485
|
+
@set content = 'Post content here'
|
|
486
|
+
INSERT INTO posts (user_id, title, content)
|
|
487
|
+
VALUES (\${user_id}, \${title}, \${content});
|
|
488
|
+
|
|
489
|
+
-- EXEC publish_post
|
|
490
|
+
@set id = 1
|
|
491
|
+
UPDATE posts SET published = 1 WHERE id = \${id};
|
|
492
|
+
|
|
493
|
+
-- EXEC delete_post
|
|
494
|
+
@set id = 1
|
|
495
|
+
DELETE FROM posts WHERE id = \${id};
|
|
496
|
+
`,
|
|
497
|
+
duckdb: `
|
|
498
|
+
-- EXEC create_user
|
|
499
|
+
@set id = 100
|
|
500
|
+
@set name = 'New User'
|
|
501
|
+
@set email = 'new@example.com'
|
|
502
|
+
INSERT INTO users (id, name, email)
|
|
503
|
+
VALUES (\${id}, \${name}, \${email});
|
|
504
|
+
|
|
505
|
+
-- EXEC create_post
|
|
506
|
+
@set id = 100
|
|
507
|
+
@set user_id = 1
|
|
508
|
+
@set title = 'New Post'
|
|
509
|
+
@set content = 'Post content here'
|
|
510
|
+
INSERT INTO posts (id, user_id, title, content)
|
|
511
|
+
VALUES (\${id}, \${user_id}, \${title}, \${content});
|
|
512
|
+
|
|
513
|
+
-- EXEC publish_post
|
|
514
|
+
@set id = 1
|
|
515
|
+
UPDATE posts SET published = TRUE WHERE id = \${id};
|
|
516
|
+
|
|
517
|
+
-- EXEC delete_post
|
|
518
|
+
@set id = 1
|
|
519
|
+
DELETE FROM posts WHERE id = \${id};
|
|
520
|
+
`,
|
|
521
|
+
postgres: `
|
|
522
|
+
-- EXEC create_user
|
|
523
|
+
@set name = 'New User'
|
|
524
|
+
@set email = 'new@example.com'
|
|
525
|
+
INSERT INTO users (name, email)
|
|
526
|
+
VALUES (\${name}, \${email});
|
|
527
|
+
|
|
528
|
+
-- EXEC create_post
|
|
529
|
+
@set user_id = 1
|
|
530
|
+
@set title = 'New Post'
|
|
531
|
+
@set content = 'Post content here'
|
|
532
|
+
INSERT INTO posts (user_id, title, content)
|
|
533
|
+
VALUES (\${user_id}, \${title}, \${content});
|
|
534
|
+
|
|
535
|
+
-- EXEC publish_post
|
|
536
|
+
@set id = 1
|
|
537
|
+
UPDATE posts SET published = TRUE WHERE id = \${id};
|
|
538
|
+
|
|
539
|
+
-- EXEC delete_post
|
|
540
|
+
@set id = 1
|
|
541
|
+
DELETE FROM posts WHERE id = \${id};
|
|
542
|
+
`
|
|
543
|
+
}[engine];
|
|
544
|
+
}
|
|
545
|
+
/**
|
|
546
|
+
* Generate sqg.yaml configuration
|
|
547
|
+
*/
|
|
548
|
+
function getConfigYaml(generator, output) {
|
|
549
|
+
const isJava = parseGenerator(generator).language === "java";
|
|
550
|
+
return `# SQG Configuration
|
|
551
|
+
# Generated by: sqg init
|
|
552
|
+
# Documentation: https://sqg.dev
|
|
553
|
+
|
|
554
|
+
version: 1
|
|
555
|
+
name: my-project
|
|
556
|
+
|
|
557
|
+
sql:
|
|
558
|
+
- files:
|
|
559
|
+
- queries.sql
|
|
560
|
+
gen:
|
|
561
|
+
- generator: ${generator}
|
|
562
|
+
output: ${output.endsWith("/") ? output : `${output}/`}${isJava ? `
|
|
563
|
+
config:
|
|
564
|
+
package: generated` : ""}
|
|
565
|
+
`;
|
|
566
|
+
}
|
|
567
|
+
/**
|
|
568
|
+
* Initialize a new SQG project
|
|
569
|
+
*/
|
|
570
|
+
async function initProject(options) {
|
|
571
|
+
const generator = options.generator || getDefaultGenerator();
|
|
572
|
+
const output = options.output || "./generated";
|
|
573
|
+
if (!isValidGenerator(generator)) {
|
|
574
|
+
const similar = findSimilarGenerators(generator);
|
|
575
|
+
throw new InvalidGeneratorError(generator, [...SHORT_GENERATOR_NAMES, ...GENERATOR_NAMES], similar.length > 0 ? similar[0] : void 0);
|
|
576
|
+
}
|
|
577
|
+
const engine = parseGenerator(generator).engine;
|
|
578
|
+
const configPath = "sqg.yaml";
|
|
579
|
+
const sqlPath = "queries.sql";
|
|
580
|
+
if (!options.force) {
|
|
581
|
+
if (existsSync(configPath)) throw new SqgError(`File already exists: ${configPath}`, "VALIDATION_ERROR", "Use --force to overwrite existing files");
|
|
582
|
+
if (existsSync(sqlPath)) throw new SqgError(`File already exists: ${sqlPath}`, "VALIDATION_ERROR", "Use --force to overwrite existing files");
|
|
583
|
+
}
|
|
584
|
+
if (!existsSync(output)) {
|
|
585
|
+
mkdirSync(output, { recursive: true });
|
|
586
|
+
consola.success(`Created output directory: ${output}`);
|
|
587
|
+
}
|
|
588
|
+
writeFileSync(configPath, getConfigYaml(generator, output));
|
|
589
|
+
consola.success(`Created ${configPath}`);
|
|
590
|
+
writeFileSync(sqlPath, getExampleSql(engine));
|
|
591
|
+
consola.success(`Created ${sqlPath}`);
|
|
592
|
+
consola.box(`
|
|
593
|
+
SQG project initialized!
|
|
594
|
+
|
|
595
|
+
Generator: ${generator}
|
|
596
|
+
Engine: ${engine}
|
|
597
|
+
Output: ${output}
|
|
598
|
+
|
|
599
|
+
Next steps:
|
|
600
|
+
1. Edit queries.sql to add your SQL queries
|
|
601
|
+
2. Run: sqg sqg.yaml
|
|
602
|
+
3. Import the generated code from ${output}
|
|
603
|
+
|
|
604
|
+
Documentation: https://sqg.dev
|
|
605
|
+
`);
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
//#endregion
|
|
609
|
+
//#region src/parser/sql-parser.ts
|
|
610
|
+
const parser = LRParser.deserialize({
|
|
611
|
+
version: 14,
|
|
612
|
+
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",
|
|
613
|
+
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_[~",
|
|
614
|
+
goto: "#prPPsPPPwP!R!VPPP!YPPP!]!a!g!q#T#ZPPP#a#ePP#ePP#iTTOUQcVSn`aRrmTgYhRusR]STj[kQUOR^UQ`VQdWTl`dQYRQaVWeYamvQm`RvuQhYRphQk[RqkTSOUTROUQ[STj[k",
|
|
615
|
+
nodeNames: "⚠ File QueryBlock BlockCommentStartSpecial Name Modifiers Config LineCommentStartSpecial SetVarLine Value StringLiteral StringLiteralSingle SQLText SQLBlock BlockComment LineComment VarRef BR",
|
|
616
|
+
maxTerm: 33,
|
|
617
|
+
skippedNodes: [0],
|
|
618
|
+
repeatNodeCount: 5,
|
|
619
|
+
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",
|
|
620
|
+
tokenizers: [
|
|
621
|
+
0,
|
|
622
|
+
1,
|
|
623
|
+
2
|
|
624
|
+
],
|
|
625
|
+
topRules: { "File": [0, 1] },
|
|
626
|
+
tokenPrec: 245
|
|
627
|
+
});
|
|
628
|
+
|
|
629
|
+
//#endregion
|
|
630
|
+
//#region src/sql-query.ts
|
|
631
|
+
var ListType = class {
|
|
632
|
+
constructor(baseType) {
|
|
633
|
+
this.baseType = baseType;
|
|
634
|
+
}
|
|
635
|
+
toString() {
|
|
636
|
+
return `${this.baseType.toString()}[]`;
|
|
637
|
+
}
|
|
638
|
+
};
|
|
639
|
+
var StructType = class {
|
|
640
|
+
constructor(fields) {
|
|
641
|
+
this.fields = fields;
|
|
642
|
+
}
|
|
643
|
+
toString() {
|
|
644
|
+
return `STRUCT(${this.fields.map((f) => `"${f.name}" ${f.type.toString()}`).join(", ")})`;
|
|
645
|
+
}
|
|
646
|
+
};
|
|
647
|
+
var MapType = class {
|
|
648
|
+
constructor(keyType, valueType) {
|
|
649
|
+
this.keyType = keyType;
|
|
650
|
+
this.valueType = valueType;
|
|
651
|
+
}
|
|
652
|
+
toString() {
|
|
653
|
+
return `MAP(${this.keyType.toString()}, ${this.valueType.toString()})`;
|
|
654
|
+
}
|
|
655
|
+
};
|
|
656
|
+
var EnumType = class {
|
|
657
|
+
constructor(values) {
|
|
658
|
+
this.values = values;
|
|
659
|
+
}
|
|
660
|
+
toString() {
|
|
661
|
+
return `ENUM(${this.values.map((v) => `'${v}'`).join(", ")})`;
|
|
662
|
+
}
|
|
663
|
+
};
|
|
664
|
+
var SQLQuery = class {
|
|
665
|
+
columns;
|
|
666
|
+
allColumns;
|
|
667
|
+
constructor(filename, id, rawQuery, queryAnonymous, queryNamed, queryPositional, type, isOne, isPluck, variables, config) {
|
|
668
|
+
this.filename = filename;
|
|
669
|
+
this.id = id;
|
|
670
|
+
this.rawQuery = rawQuery;
|
|
671
|
+
this.queryAnonymous = queryAnonymous;
|
|
672
|
+
this.queryNamed = queryNamed;
|
|
673
|
+
this.queryPositional = queryPositional;
|
|
674
|
+
this.type = type;
|
|
675
|
+
this.isOne = isOne;
|
|
676
|
+
this.isPluck = isPluck;
|
|
677
|
+
this.variables = variables;
|
|
678
|
+
this.config = config;
|
|
679
|
+
this.columns = [];
|
|
680
|
+
}
|
|
681
|
+
get isQuery() {
|
|
682
|
+
return this.type === "QUERY";
|
|
683
|
+
}
|
|
684
|
+
get isExec() {
|
|
685
|
+
return this.type === "EXEC";
|
|
686
|
+
}
|
|
687
|
+
get isMigrate() {
|
|
688
|
+
return this.type === "MIGRATE";
|
|
689
|
+
}
|
|
690
|
+
get isTestdata() {
|
|
691
|
+
return this.type === "TESTDATA";
|
|
692
|
+
}
|
|
693
|
+
get skipGenerateFunction() {
|
|
694
|
+
return this.isTestdata || this.isMigrate || this.id.startsWith("_");
|
|
695
|
+
}
|
|
696
|
+
validateVariables() {
|
|
697
|
+
const missingVars = [];
|
|
698
|
+
const varRegex = /\$\{([a-zA-Z_][a-zA-Z0-9_]*)\}/g;
|
|
699
|
+
let match;
|
|
700
|
+
while (true) {
|
|
701
|
+
match = varRegex.exec(this.rawQuery);
|
|
702
|
+
if (match === null) break;
|
|
703
|
+
const varName = match[1];
|
|
704
|
+
if (!this.variables.has(varName)) missingVars.push(varName);
|
|
705
|
+
}
|
|
706
|
+
return missingVars;
|
|
707
|
+
}
|
|
708
|
+
};
|
|
709
|
+
/**
|
|
710
|
+
* Represents a TABLE annotation for generating appenders.
|
|
711
|
+
* TABLE annotations specify a table name for which to generate bulk insert appenders.
|
|
712
|
+
*/
|
|
713
|
+
var TableInfo = class {
|
|
714
|
+
/** Columns introspected from the database table schema */
|
|
715
|
+
columns = [];
|
|
716
|
+
constructor(filename, id, tableName, includeColumns, hasAppender) {
|
|
717
|
+
this.filename = filename;
|
|
718
|
+
this.id = id;
|
|
719
|
+
this.tableName = tableName;
|
|
720
|
+
this.includeColumns = includeColumns;
|
|
721
|
+
this.hasAppender = hasAppender;
|
|
722
|
+
}
|
|
723
|
+
get skipGenerateFunction() {
|
|
724
|
+
return !this.hasAppender;
|
|
725
|
+
}
|
|
726
|
+
};
|
|
727
|
+
function parseSQLQueries(filePath, extraVariables) {
|
|
728
|
+
const content = readFileSync(filePath, "utf-8");
|
|
729
|
+
consola.info(`Parsing SQL file: ${filePath}`);
|
|
730
|
+
consola.debug(`File start: ${content.slice(0, 200)}`);
|
|
731
|
+
const queries = [];
|
|
732
|
+
const tables = [];
|
|
733
|
+
const cursor = parser.parse(content).cursor();
|
|
734
|
+
function getLineNumber(position) {
|
|
735
|
+
return content.slice(0, position).split("\n").length;
|
|
736
|
+
}
|
|
737
|
+
function getStr(nodeName, optional = false) {
|
|
738
|
+
const node = cursor.node.getChild(nodeName);
|
|
739
|
+
if (!node) {
|
|
740
|
+
if (optional) return;
|
|
741
|
+
const lineNumber = getLineNumber(cursor.node.from);
|
|
742
|
+
throw new Error(`Node '${nodeName}' not found at line ${lineNumber}`);
|
|
743
|
+
}
|
|
744
|
+
return nodeStr(node);
|
|
745
|
+
}
|
|
746
|
+
function nodeStr(node) {
|
|
747
|
+
return content.slice(node.from, node.to);
|
|
748
|
+
}
|
|
749
|
+
const queryNames = /* @__PURE__ */ new Set();
|
|
750
|
+
do
|
|
751
|
+
if (cursor.name === "QueryBlock") {
|
|
752
|
+
const queryType = (getStr("LineCommentStartSpecial", true) ?? getStr("BlockCommentStartSpecial")).replace("--", "").replace("/*", "").trim();
|
|
753
|
+
const name = getStr("Name").trim();
|
|
754
|
+
const modifiers = cursor.node.getChildren("Modifiers").map((node) => nodeStr(node));
|
|
755
|
+
const isOne = modifiers.includes(":one");
|
|
756
|
+
const isPluck = modifiers.includes(":pluck");
|
|
757
|
+
let configStr = getStr("Config", true);
|
|
758
|
+
if (configStr?.endsWith("*/")) configStr = configStr.slice(0, -2);
|
|
759
|
+
let config = null;
|
|
760
|
+
if (configStr) config = Config.fromYaml(name, filePath, configStr);
|
|
761
|
+
const setVars = cursor.node.getChildren("SetVarLine");
|
|
762
|
+
const variables = /* @__PURE__ */ new Map();
|
|
763
|
+
for (const setVar of setVars) {
|
|
764
|
+
const varName = nodeStr(setVar.getChild("Name"));
|
|
765
|
+
const value = nodeStr(setVar.getChild("Value"));
|
|
766
|
+
variables.set(varName, value.trim());
|
|
767
|
+
}
|
|
768
|
+
function getVariable(varName) {
|
|
769
|
+
if (variables.has(varName)) return variables.get(varName);
|
|
770
|
+
for (const extraVariable of extraVariables) if (extraVariable.name === varName) {
|
|
771
|
+
variables.set(varName, extraVariable.value);
|
|
772
|
+
return extraVariable.value;
|
|
773
|
+
}
|
|
774
|
+
const definedVars = Array.from(variables.keys());
|
|
775
|
+
const suggestion = definedVars.length > 0 ? `Add '@set ${varName} = <value>' before the query. Defined variables: ${definedVars.join(", ")}` : `Add '@set ${varName} = <value>' before the query`;
|
|
776
|
+
throw SqgError.inQuery(`Variable '\${${varName}}' is referenced but not defined`, "MISSING_VARIABLE", name, filePath, { suggestion });
|
|
777
|
+
}
|
|
778
|
+
const sqlNode = cursor.node.getChild("SQLBlock");
|
|
779
|
+
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" });
|
|
780
|
+
const sqlContentStr = nodeStr(sqlNode).trim();
|
|
781
|
+
const sqlCursor = sqlNode.cursor();
|
|
782
|
+
let from = -1;
|
|
783
|
+
let to = -1;
|
|
784
|
+
class SQLQueryBuilder {
|
|
785
|
+
sqlParts = [];
|
|
786
|
+
appendSql(sql$1) {
|
|
787
|
+
this.sqlParts.push(sql$1);
|
|
788
|
+
}
|
|
789
|
+
appendVariable(varName, value) {
|
|
790
|
+
this.sqlParts.push({
|
|
791
|
+
name: varName,
|
|
792
|
+
value
|
|
793
|
+
});
|
|
794
|
+
}
|
|
795
|
+
trim() {
|
|
796
|
+
const lastPart = this.sqlParts.length > 0 ? this.sqlParts[this.sqlParts.length - 1] : null;
|
|
797
|
+
if (lastPart && typeof lastPart === "string") this.sqlParts[this.sqlParts.length - 1] = lastPart.trimEnd();
|
|
798
|
+
}
|
|
799
|
+
parameters() {
|
|
800
|
+
return this.sqlParts.filter((part) => typeof part !== "string" && !part.name.startsWith("sources_"));
|
|
801
|
+
}
|
|
802
|
+
toSqlWithAnonymousPlaceholders() {
|
|
803
|
+
let sql$1 = "";
|
|
804
|
+
const sqlParts = [];
|
|
805
|
+
for (const part of this.sqlParts) if (typeof part === "string") {
|
|
806
|
+
sql$1 += part;
|
|
807
|
+
sqlParts.push(part);
|
|
808
|
+
} else {
|
|
809
|
+
if (sql$1.length > 0) {
|
|
810
|
+
const last = sql$1[sql$1.length - 1];
|
|
811
|
+
if (last !== " " && last !== "=" && last !== ">" && last !== "<") sql$1 += " ";
|
|
812
|
+
}
|
|
813
|
+
sql$1 += "?";
|
|
814
|
+
if (part.name.startsWith("sources_")) sqlParts.push(part);
|
|
815
|
+
else sqlParts.push("?");
|
|
816
|
+
}
|
|
817
|
+
return {
|
|
818
|
+
parameters: this.parameters(),
|
|
819
|
+
sql: sql$1,
|
|
820
|
+
sqlParts
|
|
821
|
+
};
|
|
822
|
+
}
|
|
823
|
+
toSqlWithPositionalPlaceholders() {
|
|
824
|
+
const parameters = [];
|
|
825
|
+
const sqlParts = [];
|
|
826
|
+
for (const part of this.sqlParts) if (typeof part === "string") sqlParts.push(part);
|
|
827
|
+
else {
|
|
828
|
+
const varName = part.name;
|
|
829
|
+
const value = part.value;
|
|
830
|
+
if (varName.startsWith("sources_")) sqlParts.push(part);
|
|
831
|
+
else {
|
|
832
|
+
let pos = parameters.findIndex((p) => p.name === varName);
|
|
833
|
+
if (pos < 0) {
|
|
834
|
+
parameters.push({
|
|
835
|
+
name: varName,
|
|
836
|
+
value
|
|
837
|
+
});
|
|
838
|
+
pos = parameters.length;
|
|
839
|
+
} else pos = pos + 1;
|
|
840
|
+
sqlParts.push(`$${pos}`);
|
|
841
|
+
}
|
|
842
|
+
}
|
|
843
|
+
return {
|
|
844
|
+
parameters,
|
|
845
|
+
sqlParts,
|
|
846
|
+
sql: sqlParts.map((part) => typeof part === "string" ? part : ` ${part.value} `).join("").trim()
|
|
847
|
+
};
|
|
848
|
+
}
|
|
849
|
+
toSqlWithNamedPlaceholders() {
|
|
850
|
+
const sqlParts = [];
|
|
851
|
+
for (const part of this.sqlParts) if (typeof part === "string") sqlParts.push(part);
|
|
852
|
+
else if (part.name.startsWith("sources_")) sqlParts.push(part);
|
|
853
|
+
else sqlParts.push(`$${part.name}`);
|
|
854
|
+
return {
|
|
855
|
+
parameters: this.parameters(),
|
|
856
|
+
sqlParts,
|
|
566
857
|
sql: sqlParts.map((part) => typeof part === "string" ? part : `$${part.name}`).join("").trim()
|
|
567
858
|
};
|
|
568
859
|
}
|
|
@@ -602,7 +893,7 @@ function parseSQLQueries(filePath, extraVariables) {
|
|
|
602
893
|
if (match) includeColumns.push(...match[1].split(",").map((c) => c.trim()));
|
|
603
894
|
}
|
|
604
895
|
const table = new TableInfo(filePath, name, tableName, includeColumns, hasAppender);
|
|
605
|
-
if (queryNames.has(name)) throw SqgError.inFile(`Duplicate name '${name}'`, "DUPLICATE_QUERY", filePath, { suggestion:
|
|
896
|
+
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
897
|
queryNames.add(name);
|
|
607
898
|
tables.push(table);
|
|
608
899
|
consola.debug(`Added table: ${name} -> ${tableName} (appender: ${hasAppender})`);
|
|
@@ -618,7 +909,7 @@ function parseSQLQueries(filePath, extraVariables) {
|
|
|
618
909
|
config
|
|
619
910
|
});
|
|
620
911
|
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:
|
|
912
|
+
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
913
|
queryNames.add(name);
|
|
623
914
|
queries.push(query);
|
|
624
915
|
consola.debug(`Added query: ${name} (${queryType})`);
|
|
@@ -1020,7 +1311,7 @@ var TypeMapper = class {
|
|
|
1020
1311
|
}
|
|
1021
1312
|
if (column.type instanceof StructType) return path + this.formatStructTypeName(column.name);
|
|
1022
1313
|
if (column.type instanceof MapType) return path + this.formatMapTypeName(column.name);
|
|
1023
|
-
if (!column.type) throw new TypeMappingError(
|
|
1314
|
+
if (!column.type) throw new TypeMappingError("Missing type information", column.name);
|
|
1024
1315
|
return this.mapPrimitiveType(column.type.toString(), column.nullable);
|
|
1025
1316
|
}
|
|
1026
1317
|
/**
|
|
@@ -1798,7 +2089,8 @@ function getGenerator(generator) {
|
|
|
1798
2089
|
const info = parseGenerator(generator);
|
|
1799
2090
|
const key = `${info.language}/${info.driver}`;
|
|
1800
2091
|
switch (key) {
|
|
1801
|
-
case "typescript/better-sqlite3":
|
|
2092
|
+
case "typescript/better-sqlite3":
|
|
2093
|
+
case "typescript/node": return new TsGenerator(`templates/${info.template}`);
|
|
1802
2094
|
case "typescript/node-api": return new TsDuckDBGenerator(`templates/${info.template}`);
|
|
1803
2095
|
case "java/jdbc": return new JavaGenerator(`templates/${info.template}`);
|
|
1804
2096
|
case "java/arrow": return new JavaDuckDBArrowGenerator(`templates/${info.template}`);
|
|
@@ -2255,275 +2547,339 @@ async function processProject(projectPath) {
|
|
|
2255
2547
|
}
|
|
2256
2548
|
|
|
2257
2549
|
//#endregion
|
|
2258
|
-
//#region src/
|
|
2259
|
-
|
|
2260
|
-
|
|
2261
|
-
|
|
2262
|
-
|
|
2263
|
-
|
|
2264
|
-
|
|
2265
|
-
|
|
2266
|
-
|
|
2550
|
+
//#region src/mcp-server.ts
|
|
2551
|
+
const server = new Server({
|
|
2552
|
+
name: "sqg-mcp",
|
|
2553
|
+
version: process.env.npm_package_version ?? "0.6.0"
|
|
2554
|
+
}, { capabilities: {
|
|
2555
|
+
tools: {},
|
|
2556
|
+
resources: {}
|
|
2557
|
+
} });
|
|
2558
|
+
function formatGeneratorListWithDescriptions() {
|
|
2559
|
+
const lines = [];
|
|
2560
|
+
const seen = /* @__PURE__ */ new Set();
|
|
2561
|
+
for (const shortName of SHORT_GENERATOR_NAMES) {
|
|
2562
|
+
const fullName = Object.keys(GENERATORS).find((g) => g.startsWith(`${shortName}/`));
|
|
2563
|
+
if (fullName) {
|
|
2564
|
+
const info = GENERATORS[fullName];
|
|
2565
|
+
lines.push(`- ${shortName} - ${info.description}`);
|
|
2566
|
+
seen.add(fullName);
|
|
2567
|
+
}
|
|
2568
|
+
}
|
|
2569
|
+
for (const [fullName, info] of Object.entries(GENERATORS)) if (!seen.has(fullName)) lines.push(`- ${fullName} - ${info.description}`);
|
|
2570
|
+
return lines.join("\n");
|
|
2267
2571
|
}
|
|
2268
|
-
|
|
2269
|
-
|
|
2270
|
-
|
|
2271
|
-
|
|
2272
|
-
return
|
|
2273
|
-
|
|
2274
|
-
|
|
2275
|
-
|
|
2276
|
-
|
|
2277
|
-
|
|
2278
|
-
|
|
2279
|
-
|
|
2280
|
-
);
|
|
2572
|
+
function formatGeneratorListSimple() {
|
|
2573
|
+
const generators = [...SHORT_GENERATOR_NAMES];
|
|
2574
|
+
const seen = new Set(SHORT_GENERATOR_NAMES.map((s) => Object.keys(GENERATORS).find((g) => g.startsWith(`${s}/`))));
|
|
2575
|
+
for (const fullName of Object.keys(GENERATORS)) if (!seen.has(fullName)) generators.push(fullName);
|
|
2576
|
+
return generators.join(", ");
|
|
2577
|
+
}
|
|
2578
|
+
async function generateCode(sql, generator) {
|
|
2579
|
+
const engine = getGeneratorEngine(generator);
|
|
2580
|
+
const tempDir = join(tmpdir(), `sqg-mcp-${randomUUID()}`);
|
|
2581
|
+
const sqlFile = join(tempDir, "queries.sql");
|
|
2582
|
+
const configFile = join(tempDir, "sqg.yaml");
|
|
2583
|
+
try {
|
|
2584
|
+
mkdirSync(tempDir, { recursive: true });
|
|
2585
|
+
writeFileSync(sqlFile, sql, "utf-8");
|
|
2586
|
+
const genConfig = {
|
|
2587
|
+
generator,
|
|
2588
|
+
output: "./generated/"
|
|
2589
|
+
};
|
|
2590
|
+
if (generator.startsWith("java/")) genConfig.config = { package: "sqg.generated" };
|
|
2591
|
+
const projectYaml = {
|
|
2592
|
+
version: 1,
|
|
2593
|
+
name: "generated",
|
|
2594
|
+
sql: [{
|
|
2595
|
+
engine,
|
|
2596
|
+
files: ["queries.sql"],
|
|
2597
|
+
gen: [genConfig]
|
|
2598
|
+
}]
|
|
2599
|
+
};
|
|
2600
|
+
writeFileSync(configFile, YAML.stringify(projectYaml), "utf-8");
|
|
2601
|
+
const files = await processProject(configFile);
|
|
2602
|
+
if (files.length === 0) return {
|
|
2603
|
+
code: "",
|
|
2604
|
+
error: "No files were generated"
|
|
2605
|
+
};
|
|
2606
|
+
return { code: readFileSync(files[0], "utf-8") };
|
|
2607
|
+
} catch (error) {
|
|
2608
|
+
return {
|
|
2609
|
+
code: "",
|
|
2610
|
+
error: error instanceof Error ? error.message : String(error)
|
|
2611
|
+
};
|
|
2612
|
+
} finally {
|
|
2613
|
+
try {
|
|
2614
|
+
rmSync(tempDir, {
|
|
2615
|
+
recursive: true,
|
|
2616
|
+
force: true
|
|
2617
|
+
});
|
|
2618
|
+
} catch (error) {}
|
|
2619
|
+
}
|
|
2620
|
+
}
|
|
2621
|
+
const GENERATE_CODE_DESCRIPTION = `Generate type-safe database access code from annotated SQL queries.
|
|
2281
2622
|
|
|
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
|
-
);
|
|
2623
|
+
CRITICAL REQUIREMENTS:
|
|
2624
|
+
1. MIGRATE statements MUST come BEFORE any QUERY/EXEC that references those tables
|
|
2625
|
+
2. Each query block needs a unique name
|
|
2626
|
+
3. Parameters require @set declarations with sample values
|
|
2291
2627
|
|
|
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
|
-
);
|
|
2628
|
+
${SQL_SYNTAX_REFERENCE}
|
|
2307
2629
|
|
|
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
|
-
);
|
|
2630
|
+
VALID GENERATORS (use short form):
|
|
2631
|
+
${formatGeneratorListWithDescriptions()}
|
|
2317
2632
|
|
|
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
|
-
);
|
|
2633
|
+
COMMON MISTAKES TO AVOID:
|
|
2634
|
+
- Missing MIGRATE before QUERY (causes "no such table" error)
|
|
2635
|
+
- Missing @set for parameters (causes "undefined variable" error)
|
|
2636
|
+
- Duplicate query names (causes "duplicate query" error)
|
|
2637
|
+
- Using :pluck with multiple columns (only works with 1 column)`;
|
|
2638
|
+
const VALIDATE_SQL_DESCRIPTION = `Validate SQL queries with SQG annotations without generating code. Use this to check for errors before generating.
|
|
2334
2639
|
|
|
2335
|
-
|
|
2336
|
-
|
|
2337
|
-
|
|
2338
|
-
|
|
2339
|
-
|
|
2340
|
-
|
|
2341
|
-
published BOOLEAN DEFAULT FALSE,
|
|
2342
|
-
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
2343
|
-
);
|
|
2640
|
+
Returns JSON with validation results including:
|
|
2641
|
+
- valid: boolean indicating success
|
|
2642
|
+
- project: project metadata if valid
|
|
2643
|
+
- sqlFiles: list of SQL files processed
|
|
2644
|
+
- generators: list of generators used
|
|
2645
|
+
- errors: array of error messages if invalid
|
|
2344
2646
|
|
|
2345
|
-
|
|
2346
|
-
|
|
2347
|
-
|
|
2348
|
-
|
|
2349
|
-
|
|
2350
|
-
|
|
2351
|
-
|
|
2352
|
-
|
|
2353
|
-
|
|
2354
|
-
|
|
2647
|
+
See generate_code tool description for complete syntax reference.`;
|
|
2648
|
+
server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
2649
|
+
return { tools: [{
|
|
2650
|
+
name: "generate_code",
|
|
2651
|
+
description: GENERATE_CODE_DESCRIPTION,
|
|
2652
|
+
inputSchema: {
|
|
2653
|
+
type: "object",
|
|
2654
|
+
properties: {
|
|
2655
|
+
sql: {
|
|
2656
|
+
type: "string",
|
|
2657
|
+
description: "Complete SQL file content with SQG annotations. IMPORTANT: Include MIGRATE statements first to create tables before QUERY statements that use them."
|
|
2658
|
+
},
|
|
2659
|
+
generator: {
|
|
2660
|
+
type: "string",
|
|
2661
|
+
description: `Code generator to use. Valid options: ${formatGeneratorListSimple()}`
|
|
2662
|
+
}
|
|
2663
|
+
},
|
|
2664
|
+
required: ["sql", "generator"]
|
|
2665
|
+
}
|
|
2666
|
+
}, {
|
|
2667
|
+
name: "validate_sql",
|
|
2668
|
+
description: VALIDATE_SQL_DESCRIPTION,
|
|
2669
|
+
inputSchema: {
|
|
2670
|
+
type: "object",
|
|
2671
|
+
properties: {
|
|
2672
|
+
sql: {
|
|
2673
|
+
type: "string",
|
|
2674
|
+
description: "Complete SQL file content with SQG annotations to validate. Include MIGRATE statements before QUERY statements."
|
|
2675
|
+
},
|
|
2676
|
+
generator: {
|
|
2677
|
+
type: "string",
|
|
2678
|
+
description: `Code generator for validation context. Valid options: ${formatGeneratorListSimple()}`
|
|
2679
|
+
}
|
|
2680
|
+
},
|
|
2681
|
+
required: ["sql", "generator"]
|
|
2682
|
+
}
|
|
2683
|
+
}] };
|
|
2684
|
+
});
|
|
2685
|
+
server.setRequestHandler(ListResourcesRequestSchema, async () => {
|
|
2686
|
+
return { resources: [{
|
|
2687
|
+
uri: "sqg://documentation",
|
|
2688
|
+
name: "SQG Documentation",
|
|
2689
|
+
description: "Complete documentation for SQG (SQL Query Generator) including syntax, generators, and usage examples",
|
|
2690
|
+
mimeType: "text/markdown"
|
|
2691
|
+
}] };
|
|
2692
|
+
});
|
|
2693
|
+
server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
|
|
2694
|
+
const { uri } = request.params;
|
|
2695
|
+
if (uri === "sqg://documentation") {
|
|
2696
|
+
const generatorListMarkdown = Object.entries(GENERATORS).map(([name, info]) => {
|
|
2697
|
+
const shortName = `${info.language}/${info.engine}`;
|
|
2698
|
+
return `- \`${Object.keys(GENERATORS).find((g) => g.startsWith(`${shortName}/`)) === name ? shortName : name}\` - ${info.description}`;
|
|
2699
|
+
}).filter((line, index, arr) => arr.indexOf(line) === index).join("\n");
|
|
2700
|
+
return { contents: [{
|
|
2701
|
+
uri,
|
|
2702
|
+
mimeType: "text/markdown",
|
|
2703
|
+
text: `# SQG - SQL Query Generator
|
|
2355
2704
|
|
|
2356
|
-
|
|
2357
|
-
@set id = 1
|
|
2358
|
-
SELECT id, name, email, created_at
|
|
2359
|
-
FROM users
|
|
2360
|
-
WHERE id = \${id};
|
|
2705
|
+
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
2706
|
|
|
2362
|
-
|
|
2363
|
-
@set email = 'alice@example.com'
|
|
2364
|
-
SELECT id, name, email, created_at
|
|
2365
|
-
FROM users
|
|
2366
|
-
WHERE email = \${email};
|
|
2707
|
+
## Overview
|
|
2367
2708
|
|
|
2368
|
-
|
|
2369
|
-
SELECT COUNT(*) FROM users;
|
|
2709
|
+
SQG introspects SQL queries at build time against real database engines to determine column types and generates strongly-typed wrapper functions.
|
|
2370
2710
|
|
|
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;
|
|
2711
|
+
**Website:** https://sqg.dev
|
|
2712
|
+
**Repository:** https://github.com/sqg-dev/sqg
|
|
2377
2713
|
|
|
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});
|
|
2714
|
+
## Key Features
|
|
2397
2715
|
|
|
2398
|
-
|
|
2399
|
-
|
|
2400
|
-
|
|
2401
|
-
|
|
2402
|
-
|
|
2403
|
-
|
|
2716
|
+
- **Type-safe by design** - Generates fully-typed code with accurate column types inferred from your database
|
|
2717
|
+
- **Multiple database engines** - Supports ${DB_ENGINES.join(", ")}
|
|
2718
|
+
- **Multiple language targets** - Generate TypeScript or Java code from the same SQL files
|
|
2719
|
+
- **Arrow API support** - Can generate Apache Arrow API bindings for DuckDB (Java)
|
|
2720
|
+
- **DBeaver compatible** - Works seamlessly with DBeaver for database development and testing
|
|
2721
|
+
- **Complex type support** - DuckDB: Handles structs, lists, and maps
|
|
2722
|
+
- **Migration management** - Built-in support for schema migrations and test data
|
|
2404
2723
|
|
|
2405
|
-
|
|
2406
|
-
@set id = 1
|
|
2407
|
-
UPDATE posts SET published = 1 WHERE id = \${id};
|
|
2724
|
+
## SQL Annotations
|
|
2408
2725
|
|
|
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});
|
|
2726
|
+
${SQL_SYNTAX_REFERENCE}
|
|
2420
2727
|
|
|
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});
|
|
2728
|
+
## Supported Generators
|
|
2428
2729
|
|
|
2429
|
-
|
|
2430
|
-
@set id = 1
|
|
2431
|
-
UPDATE posts SET published = TRUE WHERE id = \${id};
|
|
2730
|
+
Valid generator strings:
|
|
2432
2731
|
|
|
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});
|
|
2732
|
+
${generatorListMarkdown}
|
|
2443
2733
|
|
|
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});
|
|
2734
|
+
## MCP Tools
|
|
2450
2735
|
|
|
2451
|
-
|
|
2452
|
-
@set id = 1
|
|
2453
|
-
UPDATE posts SET published = TRUE WHERE id = \${id};
|
|
2736
|
+
### generate_code
|
|
2454
2737
|
|
|
2455
|
-
|
|
2456
|
-
|
|
2457
|
-
|
|
2458
|
-
|
|
2459
|
-
|
|
2738
|
+
Generate type-safe database access code from SQL queries with SQG annotations.
|
|
2739
|
+
|
|
2740
|
+
**Parameters:**
|
|
2741
|
+
- \`sql\` (string, required): SQL queries with SQG annotations
|
|
2742
|
+
- \`generator\` (string, required): Code generation generator (see supported generators above)
|
|
2743
|
+
|
|
2744
|
+
**Example:**
|
|
2745
|
+
\`\`\`json
|
|
2746
|
+
{
|
|
2747
|
+
"sql": "-- MIGRATE 1\\nCREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT);\\n\\n-- QUERY getUsers\\nSELECT * FROM users;",
|
|
2748
|
+
"generator": "typescript/sqlite"
|
|
2460
2749
|
}
|
|
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
|
|
2750
|
+
\`\`\`
|
|
2469
2751
|
|
|
2470
|
-
|
|
2471
|
-
name: my-project
|
|
2752
|
+
### validate_sql
|
|
2472
2753
|
|
|
2473
|
-
|
|
2474
|
-
|
|
2475
|
-
|
|
2476
|
-
|
|
2477
|
-
|
|
2478
|
-
|
|
2479
|
-
|
|
2480
|
-
|
|
2481
|
-
|
|
2754
|
+
Validate SQL queries with SQG annotations without generating code.
|
|
2755
|
+
|
|
2756
|
+
**Parameters:**
|
|
2757
|
+
- \`sql\` (string, required): SQL queries with SQG annotations to validate
|
|
2758
|
+
- \`generator\` (string, required): Code generation generator to use for validation
|
|
2759
|
+
|
|
2760
|
+
**Example:**
|
|
2761
|
+
\`\`\`json
|
|
2762
|
+
{
|
|
2763
|
+
"sql": "-- QUERY getUsers\\nSELECT * FROM users;",
|
|
2764
|
+
"generator": "typescript/sqlite"
|
|
2482
2765
|
}
|
|
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!
|
|
2766
|
+
\`\`\`
|
|
2510
2767
|
|
|
2511
|
-
Generator
|
|
2512
|
-
Engine: ${engine}
|
|
2513
|
-
Output: ${output}
|
|
2768
|
+
## Generator Format
|
|
2514
2769
|
|
|
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}
|
|
2770
|
+
Generators follow the pattern \`<language>/<engine>[/<driver>]\`:
|
|
2519
2771
|
|
|
2520
|
-
|
|
2521
|
-
|
|
2772
|
+
- **Short form**: \`typescript/sqlite\`, \`java/duckdb\` (uses default driver)
|
|
2773
|
+
- **Full form**: \`typescript/sqlite/better-sqlite3\`, \`java/duckdb/arrow\` (specifies driver)
|
|
2774
|
+
|
|
2775
|
+
The MCP server accepts both short and full forms, but short forms are recommended.
|
|
2776
|
+
|
|
2777
|
+
## More Information
|
|
2778
|
+
|
|
2779
|
+
- Full documentation: https://sqg.dev
|
|
2780
|
+
- GitHub: https://github.com/sqg-dev/sqg
|
|
2781
|
+
- SQL Syntax Reference: Run \`sqg syntax\` command
|
|
2782
|
+
`
|
|
2783
|
+
}] };
|
|
2784
|
+
}
|
|
2785
|
+
return {
|
|
2786
|
+
contents: [],
|
|
2787
|
+
isError: true
|
|
2788
|
+
};
|
|
2789
|
+
});
|
|
2790
|
+
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
2791
|
+
const { name, arguments: args } = request.params;
|
|
2792
|
+
if (name === "generate_code") {
|
|
2793
|
+
const { sql, generator } = args;
|
|
2794
|
+
const result = await generateCode(sql, generator);
|
|
2795
|
+
if (result.error) return {
|
|
2796
|
+
content: [{
|
|
2797
|
+
type: "text",
|
|
2798
|
+
text: `Error generating code: ${result.error}`
|
|
2799
|
+
}],
|
|
2800
|
+
isError: true
|
|
2801
|
+
};
|
|
2802
|
+
return { content: [{
|
|
2803
|
+
type: "text",
|
|
2804
|
+
text: result.code
|
|
2805
|
+
}] };
|
|
2806
|
+
}
|
|
2807
|
+
if (name === "validate_sql") {
|
|
2808
|
+
const { sql, generator } = args;
|
|
2809
|
+
const engine = getGeneratorEngine(generator);
|
|
2810
|
+
const tempDir = join(tmpdir(), `sqg-mcp-validate-${randomUUID()}`);
|
|
2811
|
+
const sqlFile = join(tempDir, "queries.sql");
|
|
2812
|
+
const configFile = join(tempDir, "sqg.yaml");
|
|
2813
|
+
try {
|
|
2814
|
+
mkdirSync(tempDir, { recursive: true });
|
|
2815
|
+
writeFileSync(sqlFile, sql, "utf-8");
|
|
2816
|
+
const projectYaml = {
|
|
2817
|
+
version: 1,
|
|
2818
|
+
name: "validation",
|
|
2819
|
+
sql: [{
|
|
2820
|
+
engine,
|
|
2821
|
+
files: ["queries.sql"],
|
|
2822
|
+
gen: [{
|
|
2823
|
+
generator,
|
|
2824
|
+
output: "./generated/"
|
|
2825
|
+
}]
|
|
2826
|
+
}]
|
|
2827
|
+
};
|
|
2828
|
+
writeFileSync(configFile, YAML.stringify(projectYaml), "utf-8");
|
|
2829
|
+
const validation = await validateProject(configFile);
|
|
2830
|
+
if (validation.valid) return { content: [{
|
|
2831
|
+
type: "text",
|
|
2832
|
+
text: JSON.stringify({
|
|
2833
|
+
valid: true,
|
|
2834
|
+
project: validation.project,
|
|
2835
|
+
sqlFiles: validation.sqlFiles,
|
|
2836
|
+
generators: validation.generators
|
|
2837
|
+
}, null, 2)
|
|
2838
|
+
}] };
|
|
2839
|
+
return {
|
|
2840
|
+
content: [{
|
|
2841
|
+
type: "text",
|
|
2842
|
+
text: JSON.stringify({
|
|
2843
|
+
valid: false,
|
|
2844
|
+
errors: validation.errors
|
|
2845
|
+
}, null, 2)
|
|
2846
|
+
}],
|
|
2847
|
+
isError: true
|
|
2848
|
+
};
|
|
2849
|
+
} catch (error) {
|
|
2850
|
+
return {
|
|
2851
|
+
content: [{
|
|
2852
|
+
type: "text",
|
|
2853
|
+
text: `Error validating SQL: ${error instanceof Error ? error.message : String(error)}`
|
|
2854
|
+
}],
|
|
2855
|
+
isError: true
|
|
2856
|
+
};
|
|
2857
|
+
} finally {
|
|
2858
|
+
try {
|
|
2859
|
+
rmSync(tempDir, {
|
|
2860
|
+
recursive: true,
|
|
2861
|
+
force: true
|
|
2862
|
+
});
|
|
2863
|
+
} catch (error) {}
|
|
2864
|
+
}
|
|
2865
|
+
}
|
|
2866
|
+
return {
|
|
2867
|
+
content: [{
|
|
2868
|
+
type: "text",
|
|
2869
|
+
text: `Unknown tool: ${name}`
|
|
2870
|
+
}],
|
|
2871
|
+
isError: true
|
|
2872
|
+
};
|
|
2873
|
+
});
|
|
2874
|
+
async function startMcpServer() {
|
|
2875
|
+
const transport = new StdioServerTransport();
|
|
2876
|
+
await server.connect(transport);
|
|
2877
|
+
console.error("SQG MCP server running on stdio");
|
|
2522
2878
|
}
|
|
2523
2879
|
|
|
2524
2880
|
//#endregion
|
|
2525
2881
|
//#region src/sqg.ts
|
|
2526
|
-
const version = process.env.npm_package_version ?? "0.
|
|
2882
|
+
const version = process.env.npm_package_version ?? "0.6.0";
|
|
2527
2883
|
const description = process.env.npm_package_description ?? "SQG - SQL Query Generator - Type-safe code generation from SQL (https://sqg.dev)";
|
|
2528
2884
|
consola.level = LogLevels.info;
|
|
2529
2885
|
const program = new Command().name("sqg").description(`${description}
|
|
@@ -2628,6 +2984,14 @@ program.command("init").description("Initialize a new SQG project with example c
|
|
|
2628
2984
|
program.command("syntax").description("Show SQL annotation syntax reference").action(() => {
|
|
2629
2985
|
console.log(SQL_SYNTAX_REFERENCE);
|
|
2630
2986
|
});
|
|
2987
|
+
program.command("mcp").description("Start MCP (Model Context Protocol) server for AI assistants").action(async () => {
|
|
2988
|
+
try {
|
|
2989
|
+
await startMcpServer();
|
|
2990
|
+
} catch (error) {
|
|
2991
|
+
consola.error("Fatal error in MCP server:", error);
|
|
2992
|
+
exit(1);
|
|
2993
|
+
}
|
|
2994
|
+
});
|
|
2631
2995
|
if (process.argv.length <= 2) {
|
|
2632
2996
|
program.outputHelp();
|
|
2633
2997
|
exit(1);
|