@sqg/sqg 0.2.2 → 0.4.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/dist/sqg.mjs
CHANGED
|
@@ -26,7 +26,7 @@ import estree from "prettier/plugins/estree";
|
|
|
26
26
|
* This file enables self-documenting CLI help and validation.
|
|
27
27
|
*/
|
|
28
28
|
/** Supported database engines */
|
|
29
|
-
const
|
|
29
|
+
const DB_ENGINES = [
|
|
30
30
|
"sqlite",
|
|
31
31
|
"duckdb",
|
|
32
32
|
"postgres"
|
|
@@ -67,14 +67,16 @@ SQL Annotation Syntax:
|
|
|
67
67
|
-- EXEC <name> Execute statement (INSERT/UPDATE/DELETE)
|
|
68
68
|
-- MIGRATE <number> Schema migration (run in order)
|
|
69
69
|
-- TESTDATA <name> Test data setup (not generated)
|
|
70
|
+
-- TABLE <name> :appender Table for bulk insert appender (DuckDB only)
|
|
70
71
|
|
|
71
72
|
@set <varName> = <value> Define a variable
|
|
72
73
|
\${varName} Reference a variable in SQL
|
|
73
74
|
|
|
74
75
|
Modifiers:
|
|
75
|
-
:one
|
|
76
|
-
:pluck
|
|
77
|
-
:all
|
|
76
|
+
:one Return single row (or null) instead of array
|
|
77
|
+
:pluck Return single column value (requires exactly 1 column)
|
|
78
|
+
:all Return all rows (default)
|
|
79
|
+
:appender Generate bulk insert appender for TABLE annotation
|
|
78
80
|
|
|
79
81
|
Example:
|
|
80
82
|
-- MIGRATE 1
|
|
@@ -83,6 +85,8 @@ Example:
|
|
|
83
85
|
-- QUERY get_user :one
|
|
84
86
|
@set id = 1
|
|
85
87
|
SELECT * FROM users WHERE id = \${id};
|
|
88
|
+
|
|
89
|
+
-- TABLE users :appender
|
|
86
90
|
`.trim();
|
|
87
91
|
/**
|
|
88
92
|
* Find similar generator names for typo suggestions
|
|
@@ -110,7 +114,7 @@ function formatGeneratorsHelp() {
|
|
|
110
114
|
* Format engines for CLI help output
|
|
111
115
|
*/
|
|
112
116
|
function formatEnginesHelp() {
|
|
113
|
-
return
|
|
117
|
+
return DB_ENGINES.map((e) => ` ${e}`).join("\n");
|
|
114
118
|
}
|
|
115
119
|
|
|
116
120
|
//#endregion
|
|
@@ -280,21 +284,21 @@ function formatErrorForOutput(err) {
|
|
|
280
284
|
//#region src/parser/sql-parser.ts
|
|
281
285
|
const parser = LRParser.deserialize({
|
|
282
286
|
version: 14,
|
|
283
|
-
states: "&SOVQPOOO_QPO'#CwOdQPO'#CzOiQPO'#
|
|
284
|
-
stateData: "
|
|
287
|
+
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",
|
|
288
|
+
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_[~",
|
|
285
289
|
goto: "#prPPsPPPwP!R!VPPP!YPPP!]!a!g!q#T#ZPPP#a#ePP#ePP#iTTOUQcVSn`aRrmTgYhRusR]STj[kQUOR^UQ`VQdWTl`dQYRQaVWeYamvQm`RvuQhYRphQk[RqkTSOUTROUQ[STj[k",
|
|
286
290
|
nodeNames: "⚠ File QueryBlock BlockCommentStartSpecial Name Modifiers Config LineCommentStartSpecial SetVarLine Value StringLiteral StringLiteralSingle SQLText SQLBlock BlockComment LineComment VarRef BR",
|
|
287
291
|
maxTerm: 33,
|
|
288
292
|
skippedNodes: [0],
|
|
289
293
|
repeatNodeCount: 5,
|
|
290
|
-
tokenData: "$+x~RqOX#YXY'wYZ(iZ]#Y]^$W^p#Ypq'wqr#Yrs(}st#Ytu6^uw#Ywx9[xz#Yz{%_{}#Y}!OKi!O!P#Y!P!Q# n!Q![$!S![!]$#l!]!_#Y!_!`$&l!`!b#Y!b!c$'l!c!}$!S!}#R#Y#R#S$!S#S#T#Y#T#o$!S#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!6m!h!oNY!o!p!;_!p!sNY!s!t!Bg!t!vNY!v!w!G]!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!1xX_QOY! ]YZ$WZz! ]z{! w{!g! ]!g!h!2e!h;'S! ];'S;=`!#e<%lO! ]V!2jX_QOY! ]YZ$WZz! ]z{! w{!u! ]!u!v!3V!v;'S! ];'S;=`!#e<%lO! ]V!3[X_QOY! ]YZ$WZz! ]z{! w{!v! ]!v!w!3w!w;'S! ];'S;=`!#e<%lO! ]V!3|X_QOY! ]YZ$WZz! ]z{! w{!f! ]!f!g!4i!g;'S! ];'S;=`!#e<%lO! ]V!4nX_QOY! ]YZ$WZz! ]z{! w{!c! ]!c!d!5Z!d;'S! ];'S;=`!#e<%lO! ]V!5`X_QOY! ]YZ$WZz! ]z{! w{!v! ]!v!w!5{!w;'S! ];'S;=`!#e<%lO! ]V!6QX_QOY! ]YZ$WZz! ]z{! w{!c! ]!c!d!*X!d;'S! ];'S;=`!#e<%lO! ]V!6t`_Q[QOXNYXY! ]YZ$WZ]NY]^! ]^pNYpq! ]qtNYtu! ]uzNYz{!#k{!zNY!z!{!7v!{;'SNY;'S;=`!&p<%lONYV!7}`_Q[QOXNYXY! ]YZ$WZ]NY]^! ]^pNYpq! ]qtNYtu! ]uzNYz{!#k{!gNY!g!h!9P!h;'SNY;'S;=`!&p<%lONYV!9W`_Q[QOXNYXY! ]YZ$WZ]NY]^! ]^pNYpq! ]qtNYtu! ]uzNYz{!#k{!eNY!e!f!:Y!f;'SNY;'S;=`!&p<%lONYV!:c^VR_Q[QOXNYXY! ]YZ$WZ]NY]^! ]^pNYpq! ]qtNYtu! ]uzNYz{!#k{;'SNY;'S;=`!&p<%lONYV!;f`_Q[QOXNYXY! ]YZ$WZ]NY]^! ]^pNYpq! ]qtNYtu! ]uzNYz{!#k{!kNY!k!l!<h!l;'SNY;'S;=`!&p<%lONYV!<o`_Q[QOXNYXY! ]YZ$WZ]NY]^! ]^pNYpq! ]qtNYtu! ]uzNYz{!#k{!iNY!i!j!=q!j;'SNY;'S;=`!&p<%lONYV!=x`_Q[QOXNYXY! ]YZ$WZ]NY]^! ]^pNYpq! ]qtNYtu! ]uzNYz{!#k{!tNY!t!u!>z!u;'SNY;'S;=`!&p<%lONYV!?R`_Q[QOXNYXY! ]YZ$WZ]NY]^! ]^pNYpq! ]qtNYtu! ]uzNYz{!#k{!cNY!c!d!@T!d;'SNY;'S;=`!&p<%lONYV!@[`_Q[QOXNYXY! ]YZ$WZ]NY]^! ]^pNYpq! ]qtNYtu! ]uzNYz{!#k{!vNY!v!w!A^!w;'SNY;'S;=`!&p<%lONYV!Ae`_Q[QOXNYXY! ]YZ$WZ]NY]^! ]^pNYpq! ]qtNYtu! ]uzNYz{!#k{!gNY!g!h!:Y!h;'SNY;'S;=`!&p<%lONYV!Bn`_Q[QOXNYXY! ]YZ$WZ]NY]^! ]^pNYpq! ]qtNYtu! ]uzNYz{!#k{!wNY!w!x!Cp!x;'SNY;'S;=`!&p<%lONYV!Cw`_Q[QOXNYXY! ]YZ$WZ]NY]^! ]^pNYpq! ]qtNYtu! ]uzNYz{!#k{!gNY!g!h!Dy!h;'SNY;'S;=`!&p<%lONYV!EQ`_Q[QOXNYXY! ]YZ$WZ]NY]^! ]^pNYpq! ]qtNYtu! ]uzNYz{!#k{!tNY!t!u!FS!u;'SNY;'S;=`!&p<%lONYV!FZ`_Q[QOXNYXY! ]YZ$WZ]NY]^! ]^pNYpq! ]qtNYtu! ]uzNYz{!#k{!{NY!{!|!:Y!|;'SNY;'S;=`!&p<%lONYV!Gd`_Q[QOXNYXY! ]YZ$WZ]NY]^! ]^pNYpq! ]qtNYtu! ]uzNYz{!#k{!gNY!g!h!Hf!h;'SNY;'S;=`!&p<%lONYV!Hm`_Q[QOXNYXY! ]YZ$WZ]NY]^! ]^pNYpq! ]qtNYtu! ]uzNYz{!#k{!uNY!u!v!Io!v;'SNY;'S;=`!&p<%lONYV!Iv`_Q[QOXNYXY! ]YZ$WZ]NY]^! ]^pNYpq! ]qtNYtu! ]uzNYz{!#k{!vNY!v!w!Jx!w;'SNY;'S;=`!&p<%lONYV!KP`_Q[QOXNYXY! ]YZ$WZ]NY]^! ]^pNYpq! ]qtNYtu! ]uzNYz{!#k{!fNY!f!g!LR!g;'SNY;'S;=`!&p<%lONYV!LY`_Q[QOXNYXY! ]YZ$WZ]NY]^! ]^pNYpq! ]qtNYtu! ]uzNYz{!#k{!cNY!c!d!M[!d;'SNY;'S;=`!&p<%lONYV!Mc`_Q[QOXNYXY! ]YZ$WZ]NY]^! ]^pNYpq! ]qtNYtu! ]uzNYz{!#k{!vNY!v!w!Ne!w;'SNY;'S;=`!&p<%lONYV!Nl`_Q[QOXNYXY! ]YZ$WZ]NY]^! ]^pNYpq! ]qtNYtu! ]uzNYz{!#k{!cNY!c!d!:Y!d;'SNY;'S;=`!&p<%lONYV# s][QOX#YXZ$WZ]#Y]^$W^p#Ypq$Wqt#Ytu$Wuz#Yz{#!l{;'S#Y;'S;=`'q<%lO#YV#!qh[QOX#$]XY#(^YZ#(^Z]#$]]^#%Z^p#$]pq#(^qt#$]tu#%Zuz#$]z{#&d{!P#$]!P!Q#4c!Q!g#$]!g!h#9`!h!o#$]!o!p#=l!p!s#$]!s!t#DU!t!v#$]!v!w#Hf!w;'S#$];'S;=`#(W<%lO#$]U#$b][QOX#$]XZ#%ZZ]#$]]^#%Z^p#$]pq#%Zqt#$]tu#%Zuz#$]z{#&d{;'S#$];'S;=`#(W<%lO#$]U#%^TOz#%Zz{#%m{;'S#%Z;'S;=`#&^<%lO#%ZU#%pVOz#%Zz{#%m{!P#%Z!P!Q#&V!Q;'S#%Z;'S;=`#&^<%lO#%ZU#&^O^QmSU#&aP;=`<%l#%ZU#&i_[QOX#$]XZ#%ZZ]#$]]^#%Z^p#$]pq#%Zqt#$]tu#%Zuz#$]z{#&d{!P#$]!P!Q#'h!Q;'S#$];'S;=`#(W<%lO#$]U#'qV^QmS[QOX'PZ]'P^p'Pqt'Pu;'S'P;'S;=`'k<%lO'PU#(ZP;=`<%l#$]V#(abOX#%ZXY#(^YZ#(^Zp#%Zpq#(^qz#%Zz{#%m{!g#%Z!g!h#)i!h!o#%Z!o!p#+i!p!s#%Z!s!t#.o!t!v#%Z!v!w#0s!w;'S#%Z;'S;=`#&^<%lO#%ZV#)lVOz#%Zz{#%m{!z#%Z!z!{#*R!{;'S#%Z;'S;=`#&^<%lO#%ZV#*UVOz#%Zz{#%m{!g#%Z!g!h#*k!h;'S#%Z;'S;=`#&^<%lO#%ZV#*nVOz#%Zz{#%m{!e#%Z!e!f#+T!f;'S#%Z;'S;=`#&^<%lO#%ZV#+YTRROz#%Zz{#%m{;'S#%Z;'S;=`#&^<%lO#%ZV#+lVOz#%Zz{#%m{!k#%Z!k!l#,R!l;'S#%Z;'S;=`#&^<%lO#%ZV#,UVOz#%Zz{#%m{!i#%Z!i!j#,k!j;'S#%Z;'S;=`#&^<%lO#%ZV#,nVOz#%Zz{#%m{!t#%Z!t!u#-T!u;'S#%Z;'S;=`#&^<%lO#%ZV#-WVOz#%Zz{#%m{!c#%Z!c!d#-m!d;'S#%Z;'S;=`#&^<%lO#%ZV#-pVOz#%Zz{#%m{!v#%Z!v!w#.V!w;'S#%Z;'S;=`#&^<%lO#%ZV#.YVOz#%Zz{#%m{!g#%Z!g!h#+T!h;'S#%Z;'S;=`#&^<%lO#%ZV#.rVOz#%Zz{#%m{!w#%Z!w!x#/X!x;'S#%Z;'S;=`#&^<%lO#%ZV#/[VOz#%Zz{#%m{!g#%Z!g!h#/q!h;'S#%Z;'S;=`#&^<%lO#%ZV#/tVOz#%Zz{#%m{!t#%Z!t!u#0Z!u;'S#%Z;'S;=`#&^<%lO#%ZV#0^VOz#%Zz{#%m{!{#%Z!{!|#+T!|;'S#%Z;'S;=`#&^<%lO#%ZV#0vVOz#%Zz{#%m{!g#%Z!g!h#1]!h;'S#%Z;'S;=`#&^<%lO#%ZV#1`VOz#%Zz{#%m{!u#%Z!u!v#1u!v;'S#%Z;'S;=`#&^<%lO#%ZV#1xVOz#%Zz{#%m{!v#%Z!v!w#2_!w;'S#%Z;'S;=`#&^<%lO#%ZV#2bVOz#%Zz{#%m{!f#%Z!f!g#2w!g;'S#%Z;'S;=`#&^<%lO#%ZV#2zVOz#%Zz{#%m{!c#%Z!c!d#3a!d;'S#%Z;'S;=`#&^<%lO#%ZV#3dVOz#%Zz{#%m{!v#%Z!v!w#3y!w;'S#%Z;'S;=`#&^<%lO#%ZV#3|VOz#%Zz{#%m{!c#%Z!c!d#+T!d;'S#%Z;'S;=`#&^<%lO#%ZU#4j]mS[QOX#5cXZ#6aZ]#5c]^#6a^p#5cpq#6aqt#5ctu#6auz#5cz{#7h{;'S#5c;'S;=`#9Y<%lO#5cQ#5h][QOX#5cXZ#6aZ]#5c]^#6a^p#5cpq#6aqt#5ctu#6auz#5cz{#7h{;'S#5c;'S;=`#9Y<%lO#5cQ#6dTOz#6az{#6s{;'S#6a;'S;=`#7b<%lO#6aQ#6vVOz#6az{#6s{!P#6a!P!Q#7]!Q;'S#6a;'S;=`#7b<%lO#6aQ#7bO^QQ#7eP;=`<%l#6aQ#7m_[QOX#5cXZ#6aZ]#5c]^#6a^p#5cpq#6aqt#5ctu#6auz#5cz{#7h{!P#5c!P!Q#8l!Q;'S#5c;'S;=`#9Y<%lO#5cQ#8sV^Q[QOX'PZ]'P^p'Pqt'Pu;'S'P;'S;=`'k<%lO'PQ#9]P;=`<%l#5cV#9e_[QOX#$]XZ#%ZZ]#$]]^#%Z^p#$]pq#%Zqt#$]tu#%Zuz#$]z{#&d{!z#$]!z!{#:d!{;'S#$];'S;=`#(W<%lO#$]V#:i_[QOX#$]XZ#%ZZ]#$]]^#%Z^p#$]pq#%Zqt#$]tu#%Zuz#$]z{#&d{!g#$]!g!h#;h!h;'S#$];'S;=`#(W<%lO#$]V#;m_[QOX#$]XZ#%ZZ]#$]]^#%Z^p#$]pq#%Zqt#$]tu#%Zuz#$]z{#&d{!e#$]!e!f#<l!f;'S#$];'S;=`#(W<%lO#$]V#<s]RR[QOX#$]XZ#%ZZ]#$]]^#%Z^p#$]pq#%Zqt#$]tu#%Zuz#$]z{#&d{;'S#$];'S;=`#(W<%lO#$]V#=q_[QOX#$]XZ#%ZZ]#$]]^#%Z^p#$]pq#%Zqt#$]tu#%Zuz#$]z{#&d{!k#$]!k!l#>p!l;'S#$];'S;=`#(W<%lO#$]V#>u_[QOX#$]XZ#%ZZ]#$]]^#%Z^p#$]pq#%Zqt#$]tu#%Zuz#$]z{#&d{!i#$]!i!j#?t!j;'S#$];'S;=`#(W<%lO#$]V#?y_[QOX#$]XZ#%ZZ]#$]]^#%Z^p#$]pq#%Zqt#$]tu#%Zuz#$]z{#&d{!t#$]!t!u#@x!u;'S#$];'S;=`#(W<%lO#$]V#@}_[QOX#$]XZ#%ZZ]#$]]^#%Z^p#$]pq#%Zqt#$]tu#%Zuz#$]z{#&d{!c#$]!c!d#A|!d;'S#$];'S;=`#(W<%lO#$]V#BR_[QOX#$]XZ#%ZZ]#$]]^#%Z^p#$]pq#%Zqt#$]tu#%Zuz#$]z{#&d{!v#$]!v!w#CQ!w;'S#$];'S;=`#(W<%lO#$]V#CV_[QOX#$]XZ#%ZZ]#$]]^#%Z^p#$]pq#%Zqt#$]tu#%Zuz#$]z{#&d{!g#$]!g!h#<l!h;'S#$];'S;=`#(W<%lO#$]V#DZ_[QOX#$]XZ#%ZZ]#$]]^#%Z^p#$]pq#%Zqt#$]tu#%Zuz#$]z{#&d{!w#$]!w!x#EY!x;'S#$];'S;=`#(W<%lO#$]V#E__[QOX#$]XZ#%ZZ]#$]]^#%Z^p#$]pq#%Zqt#$]tu#%Zuz#$]z{#&d{!g#$]!g!h#F^!h;'S#$];'S;=`#(W<%lO#$]V#Fc_[QOX#$]XZ#%ZZ]#$]]^#%Z^p#$]pq#%Zqt#$]tu#%Zuz#$]z{#&d{!t#$]!t!u#Gb!u;'S#$];'S;=`#(W<%lO#$]V#Gg_[QOX#$]XZ#%ZZ]#$]]^#%Z^p#$]pq#%Zqt#$]tu#%Zuz#$]z{#&d{!{#$]!{!|#<l!|;'S#$];'S;=`#(W<%lO#$]V#Hk_[QOX#$]XZ#%ZZ]#$]]^#%Z^p#$]pq#%Zqt#$]tu#%Zuz#$]z{#&d{!g#$]!g!h#Ij!h;'S#$];'S;=`#(W<%lO#$]V#Io_[QOX#$]XZ#%ZZ]#$]]^#%Z^p#$]pq#%Zqt#$]tu#%Zuz#$]z{#&d{!u#$]!u!v#Jn!v;'S#$];'S;=`#(W<%lO#$]V#Js_[QOX#$]XZ#%ZZ]#$]]^#%Z^p#$]pq#%Zqt#$]tu#%Zuz#$]z{#&d{!v#$]!v!w#Kr!w;'S#$];'S;=`#(W<%lO#$]V#Kw_[QOX#$]XZ#%ZZ]#$]]^#%Z^p#$]pq#%Zqt#$]tu#%Zuz#$]z{#&d{!f#$]!f!g#Lv!g;'S#$];'S;=`#(W<%lO#$]V#L{_[QOX#$]XZ#%ZZ]#$]]^#%Z^p#$]pq#%Zqt#$]tu#%Zuz#$]z{#&d{!c#$]!c!d#Mz!d;'S#$];'S;=`#(W<%lO#$]V#NP_[QOX#$]XZ#%ZZ]#$]]^#%Z^p#$]pq#%Zqt#$]tu#%Zuz#$]z{#&d{!v#$]!v!w$ O!w;'S#$];'S;=`#(W<%lO#$]V$ T_[QOX#$]XZ#%ZZ]#$]]^#%Z^p#$]pq#%Zqt#$]tu#%Zuz#$]z{#&d{!c#$]!c!d#<l!d;'S#$];'S;=`#(W<%lO#$]V$!ZeSP[QOX#YXZ$WZ]#Y]^$W^p#Ypq$Wqt#Ytu$Wuz#Yz{%_{!Q#Y!Q![$!S![!c#Y!c!}$!S!}#R#Y#R#S$!S#S#T#Y#T#o$!S#o;'S#Y;'S;=`'q<%lO#Y~$#qe[QOX#YXZ$WZ]#Y]^$W^p#Ypq$Wqt#Ytu$Wuz#Yz{%_{!Q#Y!Q![$%S![!c#Y!c!}$%S!}#R#Y#R#S$%S#S#T#Y#T#o$%S#o;'S#Y;'S;=`'q<%lO#Y~$%ZeT~[QOX#YXZ$WZ]#Y]^$W^p#Ypq$Wqt#Ytu$Wuz#Yz{%_{!Q#Y!Q![$%S![!c#Y!c!}$%S!}#R#Y#R#S$%S#S#T#Y#T#o$%S#o;'S#Y;'S;=`'q<%lO#YV$&s]pP[QOX#YXZ$WZ]#Y]^$W^p#Ypq$Wqt#Ytu$Wuz#Yz{%_{;'S#Y;'S;=`'q<%lO#YU$'q_[QOX#YXZ$WZ]#Y]^$W^p#Ypq$Wqt#Ytu$Wuz#Yz{%_{#g#Y#g#h$(p#h;'S#Y;'S;=`'q<%lO#YU$(u_[QOX#YXZ$WZ]#Y]^$W^p#Ypq$Wqt#Ytu$Wuz#Yz{%_{#X#Y#X#Y$)t#Y;'S#Y;'S;=`'q<%lO#YU$)y_[QOX#YXZ$WZ]#Y]^$W^p#Ypq$Wqt#Ytu$Wuz#Yz{%_{#h#Y#h#i$*x#i;'S#Y;'S;=`'q<%lO#YU$+P]oQ[QOX#YXZ$WZ]#Y]^$W^p#Ypq$Wqt#Ytu$Wuz#Yz{%_{;'S#Y;'S;=`'q<%lO#Y",
|
|
294
|
+
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",
|
|
291
295
|
tokenizers: [
|
|
292
296
|
0,
|
|
293
297
|
1,
|
|
294
298
|
2
|
|
295
299
|
],
|
|
296
300
|
topRules: { "File": [0, 1] },
|
|
297
|
-
tokenPrec:
|
|
301
|
+
tokenPrec: 245
|
|
298
302
|
});
|
|
299
303
|
|
|
300
304
|
//#endregion
|
|
@@ -377,17 +381,40 @@ var SQLQuery = class {
|
|
|
377
381
|
return missingVars;
|
|
378
382
|
}
|
|
379
383
|
};
|
|
384
|
+
/**
|
|
385
|
+
* Represents a TABLE annotation for generating appenders.
|
|
386
|
+
* TABLE annotations specify a table name for which to generate bulk insert appenders.
|
|
387
|
+
*/
|
|
388
|
+
var TableInfo = class {
|
|
389
|
+
/** Columns introspected from the database table schema */
|
|
390
|
+
columns = [];
|
|
391
|
+
constructor(filename, id, tableName, includeColumns, hasAppender) {
|
|
392
|
+
this.filename = filename;
|
|
393
|
+
this.id = id;
|
|
394
|
+
this.tableName = tableName;
|
|
395
|
+
this.includeColumns = includeColumns;
|
|
396
|
+
this.hasAppender = hasAppender;
|
|
397
|
+
}
|
|
398
|
+
get skipGenerateFunction() {
|
|
399
|
+
return !this.hasAppender;
|
|
400
|
+
}
|
|
401
|
+
};
|
|
380
402
|
function parseSQLQueries(filePath, extraVariables) {
|
|
381
403
|
const content = readFileSync(filePath, "utf-8");
|
|
382
404
|
consola.info(`Parsing SQL file: ${filePath}`);
|
|
383
405
|
consola.debug(`File start: ${content.slice(0, 200)}`);
|
|
384
406
|
const queries = [];
|
|
407
|
+
const tables = [];
|
|
385
408
|
const cursor = parser.parse(content).cursor();
|
|
409
|
+
function getLineNumber(position) {
|
|
410
|
+
return content.slice(0, position).split("\n").length;
|
|
411
|
+
}
|
|
386
412
|
function getStr(nodeName, optional = false) {
|
|
387
413
|
const node = cursor.node.getChild(nodeName);
|
|
388
414
|
if (!node) {
|
|
389
415
|
if (optional) return;
|
|
390
|
-
|
|
416
|
+
const lineNumber = getLineNumber(cursor.node.from);
|
|
417
|
+
throw new Error(`Node '${nodeName}' not found at line ${lineNumber}`);
|
|
391
418
|
}
|
|
392
419
|
return nodeStr(node);
|
|
393
420
|
}
|
|
@@ -532,6 +559,21 @@ function parseSQLQueries(filePath, extraVariables) {
|
|
|
532
559
|
if (to > from) sql.appendSql(content.slice(from, to));
|
|
533
560
|
sql.trim();
|
|
534
561
|
}
|
|
562
|
+
if (queryType === "TABLE") {
|
|
563
|
+
const hasAppender = modifiers.includes(":appender");
|
|
564
|
+
const tableName = sqlContentStr.trim() || name;
|
|
565
|
+
const includeColumns = [];
|
|
566
|
+
for (const mod of modifiers) {
|
|
567
|
+
const match = mod.match(/:appender\(([^)]+)\)/);
|
|
568
|
+
if (match) includeColumns.push(...match[1].split(",").map((c) => c.trim()));
|
|
569
|
+
}
|
|
570
|
+
const table = new TableInfo(filePath, name, tableName, includeColumns, hasAppender);
|
|
571
|
+
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` });
|
|
572
|
+
queryNames.add(name);
|
|
573
|
+
tables.push(table);
|
|
574
|
+
consola.debug(`Added table: ${name} -> ${tableName} (appender: ${hasAppender})`);
|
|
575
|
+
continue;
|
|
576
|
+
}
|
|
535
577
|
consola.debug("Parsed query:", {
|
|
536
578
|
type: queryType,
|
|
537
579
|
name,
|
|
@@ -548,9 +590,13 @@ function parseSQLQueries(filePath, extraVariables) {
|
|
|
548
590
|
consola.debug(`Added query: ${name} (${queryType})`);
|
|
549
591
|
}
|
|
550
592
|
while (cursor.next());
|
|
551
|
-
consola.info(`Total queries parsed: ${queries.length}`);
|
|
593
|
+
consola.info(`Total queries parsed: ${queries.length}, tables: ${tables.length}`);
|
|
552
594
|
consola.info(`Query names: ${queries.map((q) => q.id).join(", ")}`);
|
|
553
|
-
|
|
595
|
+
if (tables.length > 0) consola.info(`Table names: ${tables.map((t) => t.id).join(", ")}`);
|
|
596
|
+
return {
|
|
597
|
+
queries,
|
|
598
|
+
tables
|
|
599
|
+
};
|
|
554
600
|
}
|
|
555
601
|
|
|
556
602
|
//#endregion
|
|
@@ -658,6 +704,47 @@ const duckdb = new class {
|
|
|
658
704
|
throw error;
|
|
659
705
|
}
|
|
660
706
|
}
|
|
707
|
+
async introspectTables(tables) {
|
|
708
|
+
const connection = this.connection;
|
|
709
|
+
if (!connection) throw new DatabaseError("DuckDB connection not initialized", "duckdb", "This is an internal error. Check that migrations completed successfully.");
|
|
710
|
+
for (const table of tables) {
|
|
711
|
+
consola.info(`Introspecting table schema: ${table.tableName}`);
|
|
712
|
+
try {
|
|
713
|
+
const rows = (await connection.runAndReadAll(`DESCRIBE ${table.tableName}`)).getRows();
|
|
714
|
+
function convertType(type) {
|
|
715
|
+
if (type instanceof DuckDBListType) return new ListType(convertType(type.valueType));
|
|
716
|
+
if (type instanceof DuckDBStructType) return new StructType(type.entryTypes.map((t, index) => ({
|
|
717
|
+
name: type.entryNames[index],
|
|
718
|
+
type: convertType(t),
|
|
719
|
+
nullable: true
|
|
720
|
+
})));
|
|
721
|
+
if (type instanceof DuckDBMapType) return new MapType({
|
|
722
|
+
name: "key",
|
|
723
|
+
type: convertType(type.keyType),
|
|
724
|
+
nullable: true
|
|
725
|
+
}, {
|
|
726
|
+
name: "value",
|
|
727
|
+
type: convertType(type.valueType),
|
|
728
|
+
nullable: true
|
|
729
|
+
});
|
|
730
|
+
if (type instanceof DuckDBEnumType) return new EnumType(type.values);
|
|
731
|
+
return type.toString();
|
|
732
|
+
}
|
|
733
|
+
table.columns = rows.map((row) => {
|
|
734
|
+
return {
|
|
735
|
+
name: row[0],
|
|
736
|
+
type: row[1],
|
|
737
|
+
nullable: row[2] !== "NO"
|
|
738
|
+
};
|
|
739
|
+
});
|
|
740
|
+
consola.debug(`Table ${table.tableName} columns:`, table.columns);
|
|
741
|
+
consola.success(`Introspected table: ${table.tableName} (${table.columns.length} columns)`);
|
|
742
|
+
} catch (error) {
|
|
743
|
+
consola.error(`Failed to introspect table '${table.tableName}':`, error);
|
|
744
|
+
throw error;
|
|
745
|
+
}
|
|
746
|
+
}
|
|
747
|
+
}
|
|
661
748
|
close() {
|
|
662
749
|
this.connection.closeSync();
|
|
663
750
|
}
|
|
@@ -752,6 +839,27 @@ const postgres = new class {
|
|
|
752
839
|
throw error;
|
|
753
840
|
}
|
|
754
841
|
}
|
|
842
|
+
async introspectTables(tables) {
|
|
843
|
+
const db = this.db;
|
|
844
|
+
if (!db) throw new DatabaseError("PostgreSQL database not initialized", "postgres", "This is an internal error. Check that migrations completed successfully.");
|
|
845
|
+
for (const table of tables) {
|
|
846
|
+
consola.info(`Introspecting table schema: ${table.tableName}`);
|
|
847
|
+
try {
|
|
848
|
+
table.columns = (await db.query(`SELECT column_name, data_type, is_nullable
|
|
849
|
+
FROM information_schema.columns
|
|
850
|
+
WHERE table_name = $1
|
|
851
|
+
ORDER BY ordinal_position`, [table.tableName])).rows.map((row) => ({
|
|
852
|
+
name: row.column_name,
|
|
853
|
+
type: row.data_type.toUpperCase(),
|
|
854
|
+
nullable: row.is_nullable === "YES"
|
|
855
|
+
}));
|
|
856
|
+
consola.success(`Introspected table: ${table.tableName} (${table.columns.length} columns)`);
|
|
857
|
+
} catch (error) {
|
|
858
|
+
consola.error(`Failed to introspect table '${table.tableName}':`, error);
|
|
859
|
+
throw error;
|
|
860
|
+
}
|
|
861
|
+
}
|
|
862
|
+
}
|
|
755
863
|
async close() {
|
|
756
864
|
await this.db.end();
|
|
757
865
|
await this.dbInitial.query(`DROP DATABASE "${databaseName}"`);
|
|
@@ -791,6 +899,20 @@ const sqlite = new class {
|
|
|
791
899
|
throw error;
|
|
792
900
|
}
|
|
793
901
|
}
|
|
902
|
+
introspectTables(tables) {
|
|
903
|
+
const db = this.db;
|
|
904
|
+
if (!db) throw new DatabaseError("SQLite database not initialized", "sqlite", "This is an internal error. Migrations may have failed silently.");
|
|
905
|
+
for (const table of tables) {
|
|
906
|
+
consola.info(`Introspecting table schema: ${table.tableName}`);
|
|
907
|
+
const info = this.getTableInfo(db, table.tableName);
|
|
908
|
+
table.columns = Array.from(info.values()).map((col) => ({
|
|
909
|
+
name: col.name,
|
|
910
|
+
type: col.type || "TEXT",
|
|
911
|
+
nullable: col.notnull === 0 && col.pk === 0
|
|
912
|
+
}));
|
|
913
|
+
consola.success(`Introspected table: ${table.tableName} (${table.columns.length} columns)`);
|
|
914
|
+
}
|
|
915
|
+
}
|
|
794
916
|
close() {
|
|
795
917
|
this.db.close();
|
|
796
918
|
}
|
|
@@ -1206,10 +1328,13 @@ var BaseGenerator = class {
|
|
|
1206
1328
|
listType(column) {
|
|
1207
1329
|
return this.typeMapper.listType(column);
|
|
1208
1330
|
}
|
|
1209
|
-
async beforeGenerate(_projectDir, _gen, _queries) {}
|
|
1331
|
+
async beforeGenerate(_projectDir, _gen, _queries, _tables) {}
|
|
1210
1332
|
isCompatibleWith(_engine) {
|
|
1211
1333
|
return true;
|
|
1212
1334
|
}
|
|
1335
|
+
supportsAppenders(_engine) {
|
|
1336
|
+
return false;
|
|
1337
|
+
}
|
|
1213
1338
|
functionReturnType(query) {
|
|
1214
1339
|
if (query.isOne) return this.rowType(query);
|
|
1215
1340
|
return this.typeMapper.formatListType(this.rowType(query));
|
|
@@ -1233,6 +1358,9 @@ var JavaGenerator = class extends BaseGenerator {
|
|
|
1233
1358
|
super(template, new JavaTypeMapper());
|
|
1234
1359
|
this.template = template;
|
|
1235
1360
|
}
|
|
1361
|
+
supportsAppenders(engine) {
|
|
1362
|
+
return engine === "duckdb";
|
|
1363
|
+
}
|
|
1236
1364
|
getFunctionName(id) {
|
|
1237
1365
|
return camelCase$1(id);
|
|
1238
1366
|
}
|
|
@@ -1272,7 +1400,7 @@ var JavaGenerator = class extends BaseGenerator {
|
|
|
1272
1400
|
readColumn(column, index, path) {
|
|
1273
1401
|
return this.typeMapper.parseValue(column, `rs.getObject(${index + 1})`, path);
|
|
1274
1402
|
}
|
|
1275
|
-
async beforeGenerate(_projectDir, _gen, _queries) {
|
|
1403
|
+
async beforeGenerate(_projectDir, _gen, _queries, _tables) {
|
|
1276
1404
|
Handlebars.registerHelper("partsToString", (parts) => this.partsToString(parts));
|
|
1277
1405
|
Handlebars.registerHelper("declareTypes", (queryHelper) => {
|
|
1278
1406
|
const query = queryHelper.query;
|
|
@@ -1324,7 +1452,7 @@ var JavaDuckDBArrowGenerator = class extends BaseGenerator {
|
|
|
1324
1452
|
getFunctionName(id) {
|
|
1325
1453
|
return this.javaGenerator.getFunctionName(id);
|
|
1326
1454
|
}
|
|
1327
|
-
async beforeGenerate(projectDir, gen, queries) {
|
|
1455
|
+
async beforeGenerate(projectDir, gen, queries, tables) {
|
|
1328
1456
|
const q = queries.filter((q$1) => q$1.isQuery && q$1.isOne || q$1.isMigrate);
|
|
1329
1457
|
const name = `${gen.name}-jdbc`;
|
|
1330
1458
|
writeGeneratedFile(projectDir, {
|
|
@@ -1332,11 +1460,14 @@ var JavaDuckDBArrowGenerator = class extends BaseGenerator {
|
|
|
1332
1460
|
generator: "java/jdbc",
|
|
1333
1461
|
output: gen.output,
|
|
1334
1462
|
config: gen.config
|
|
1335
|
-
}, this.javaGenerator, name, q);
|
|
1463
|
+
}, this.javaGenerator, name, q, tables, "duckdb");
|
|
1336
1464
|
}
|
|
1337
1465
|
isCompatibleWith(engine) {
|
|
1338
1466
|
return engine === "duckdb";
|
|
1339
1467
|
}
|
|
1468
|
+
supportsAppenders(_engine) {
|
|
1469
|
+
return true;
|
|
1470
|
+
}
|
|
1340
1471
|
getFilename(sqlFileName) {
|
|
1341
1472
|
return this.javaGenerator.getFilename(sqlFileName);
|
|
1342
1473
|
}
|
|
@@ -1344,25 +1475,28 @@ var JavaDuckDBArrowGenerator = class extends BaseGenerator {
|
|
|
1344
1475
|
return this.javaGenerator.getClassName(name);
|
|
1345
1476
|
}
|
|
1346
1477
|
mapType(column) {
|
|
1347
|
-
const { type
|
|
1478
|
+
const { type } = column;
|
|
1348
1479
|
if (typeof type === "string") {
|
|
1349
1480
|
const mappedType = {
|
|
1350
1481
|
INTEGER: "IntVector",
|
|
1482
|
+
BIGINT: "BigIntVector",
|
|
1351
1483
|
BOOLEAN: "BitVector",
|
|
1352
1484
|
DOUBLE: "Float8Vector",
|
|
1353
1485
|
FLOAT: "Float4Vector",
|
|
1354
1486
|
VARCHAR: "VarCharVector",
|
|
1355
|
-
TEXT: "VarCharVector"
|
|
1487
|
+
TEXT: "VarCharVector",
|
|
1488
|
+
TIMESTAMP: "TimeStampVector",
|
|
1489
|
+
DATE: "DateDayVector",
|
|
1490
|
+
TIME: "TimeMicroVector"
|
|
1356
1491
|
}[type.toUpperCase()];
|
|
1357
1492
|
if (!mappedType) consola.warn("(duckdb-arrow) Mapped type is unknown:", type);
|
|
1358
1493
|
return mappedType ?? "Object";
|
|
1359
1494
|
}
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
return this.typeMapper.getTypeName(mockColumn);
|
|
1495
|
+
if (type instanceof ListType) return "ListVector";
|
|
1496
|
+
if (type instanceof StructType) return "StructVector";
|
|
1497
|
+
if (type instanceof MapType) return "MapVector";
|
|
1498
|
+
consola.warn("(duckdb-arrow) Unknown complex type:", type);
|
|
1499
|
+
return "Object";
|
|
1366
1500
|
}
|
|
1367
1501
|
mapParameterType(type, nullable) {
|
|
1368
1502
|
return this.typeMapper.getTypeName({
|
|
@@ -1410,8 +1544,45 @@ var TsGenerator = class extends BaseGenerator {
|
|
|
1410
1544
|
getClassName(name) {
|
|
1411
1545
|
return pascalCase$1(name);
|
|
1412
1546
|
}
|
|
1413
|
-
async beforeGenerate(_projectDir, _gen, _queries) {
|
|
1547
|
+
async beforeGenerate(_projectDir, _gen, _queries, _tables) {
|
|
1414
1548
|
Handlebars.registerHelper("quote", (value) => this.quote(value));
|
|
1549
|
+
Handlebars.registerHelper("appendMethod", (column) => {
|
|
1550
|
+
const typeStr = column.type?.toString().toUpperCase() || "";
|
|
1551
|
+
if (typeStr === "INTEGER" || typeStr === "INT" || typeStr === "INT4" || typeStr === "SIGNED") return "Integer";
|
|
1552
|
+
if (typeStr === "SMALLINT" || typeStr === "INT2" || typeStr === "SHORT") return "SmallInt";
|
|
1553
|
+
if (typeStr === "TINYINT" || typeStr === "INT1") return "TinyInt";
|
|
1554
|
+
if (typeStr === "BIGINT" || typeStr === "INT8" || typeStr === "LONG") return "BigInt";
|
|
1555
|
+
if (typeStr === "HUGEINT" || typeStr === "INT128") return "HugeInt";
|
|
1556
|
+
if (typeStr === "UINTEGER" || typeStr === "UINT4") return "UInteger";
|
|
1557
|
+
if (typeStr === "USMALLINT" || typeStr === "UINT2") return "USmallInt";
|
|
1558
|
+
if (typeStr === "UTINYINT" || typeStr === "UINT1") return "UTinyInt";
|
|
1559
|
+
if (typeStr === "UBIGINT" || typeStr === "UINT8") return "UBigInt";
|
|
1560
|
+
if (typeStr === "DOUBLE" || typeStr === "FLOAT8" || typeStr === "NUMERIC" || typeStr === "DECIMAL") return "Double";
|
|
1561
|
+
if (typeStr === "FLOAT" || typeStr === "FLOAT4" || typeStr === "REAL") return "Float";
|
|
1562
|
+
if (typeStr === "BOOLEAN" || typeStr === "BOOL" || typeStr === "LOGICAL") return "Boolean";
|
|
1563
|
+
if (typeStr === "DATE") return "Date";
|
|
1564
|
+
if (typeStr === "TIMESTAMP" || typeStr.includes("TIMESTAMP")) return "Timestamp";
|
|
1565
|
+
if (typeStr === "TIME" || typeStr.includes("TIME")) return "Time";
|
|
1566
|
+
if (typeStr === "BLOB" || typeStr === "BYTEA" || typeStr === "BINARY" || typeStr === "VARBINARY") return "Blob";
|
|
1567
|
+
if (typeStr === "UUID") return "Uuid";
|
|
1568
|
+
if (typeStr === "INTERVAL") return "Interval";
|
|
1569
|
+
return "Varchar";
|
|
1570
|
+
});
|
|
1571
|
+
Handlebars.registerHelper("tsTypeForAppender", (column) => {
|
|
1572
|
+
const typeStr = column.type?.toString().toUpperCase() || "";
|
|
1573
|
+
let baseType;
|
|
1574
|
+
if (typeStr === "INTEGER" || typeStr === "INT" || typeStr === "INT4" || typeStr === "SMALLINT" || typeStr === "INT2" || typeStr === "TINYINT" || typeStr === "INT1" || typeStr === "UINTEGER" || typeStr === "UINT4" || typeStr === "USMALLINT" || typeStr === "UINT2" || typeStr === "UTINYINT" || typeStr === "UINT1" || typeStr === "DOUBLE" || typeStr === "FLOAT8" || typeStr === "FLOAT" || typeStr === "FLOAT4" || typeStr === "REAL") baseType = "number";
|
|
1575
|
+
else if (typeStr === "BIGINT" || typeStr === "INT8" || typeStr === "HUGEINT" || typeStr === "INT128" || typeStr === "UBIGINT" || typeStr === "UINT8") baseType = "bigint";
|
|
1576
|
+
else if (typeStr === "BOOLEAN" || typeStr === "BOOL") baseType = "boolean";
|
|
1577
|
+
else if (typeStr === "DATE") baseType = "DuckDBDateValue";
|
|
1578
|
+
else if (typeStr === "TIMESTAMP" || typeStr.includes("TIMESTAMP")) baseType = "DuckDBTimestampValue";
|
|
1579
|
+
else if (typeStr === "TIME" || typeStr.includes("TIME")) baseType = "DuckDBTimeValue";
|
|
1580
|
+
else if (typeStr === "BLOB" || typeStr === "BYTEA") baseType = "DuckDBBlobValue";
|
|
1581
|
+
else if (typeStr === "UUID") baseType = "string";
|
|
1582
|
+
else baseType = "string";
|
|
1583
|
+
if (column.nullable) return `${baseType} | null`;
|
|
1584
|
+
return baseType;
|
|
1585
|
+
});
|
|
1415
1586
|
Handlebars.registerHelper("tsType", (column) => {
|
|
1416
1587
|
const inlineType = (col) => {
|
|
1417
1588
|
const t = col.type;
|
|
@@ -1533,8 +1704,11 @@ var TsDuckDBGenerator = class extends TsGenerator {
|
|
|
1533
1704
|
constructor(template) {
|
|
1534
1705
|
super(template);
|
|
1535
1706
|
}
|
|
1536
|
-
|
|
1537
|
-
|
|
1707
|
+
supportsAppenders(_engine) {
|
|
1708
|
+
return true;
|
|
1709
|
+
}
|
|
1710
|
+
async beforeGenerate(projectDir, gen, queries, tables) {
|
|
1711
|
+
await super.beforeGenerate(projectDir, gen, queries, tables);
|
|
1538
1712
|
Handlebars.registerHelper("tsType", (column) => {
|
|
1539
1713
|
const inlineType = (col) => {
|
|
1540
1714
|
const t = col.type;
|
|
@@ -1595,7 +1769,7 @@ function getGenerator(generator) {
|
|
|
1595
1769
|
|
|
1596
1770
|
//#endregion
|
|
1597
1771
|
//#region src/sqltool.ts
|
|
1598
|
-
const GENERATED_FILE_COMMENT = "This file is generated by SQG. Do not edit manually.";
|
|
1772
|
+
const GENERATED_FILE_COMMENT = "This file is generated by SQG (https://sqg.dev). Do not edit manually.";
|
|
1599
1773
|
const configSchema = z.object({ result: z.record(z.string(), z.string()).optional() });
|
|
1600
1774
|
var Config = class Config {
|
|
1601
1775
|
constructor(result) {
|
|
@@ -1707,15 +1881,50 @@ var SqlQueryHelper = class {
|
|
|
1707
1881
|
return this.generator.typeMapper;
|
|
1708
1882
|
}
|
|
1709
1883
|
};
|
|
1710
|
-
|
|
1884
|
+
/** Util class to help generating appenders for tables */
|
|
1885
|
+
var TableHelper = class {
|
|
1886
|
+
constructor(table, generator) {
|
|
1887
|
+
this.table = table;
|
|
1888
|
+
this.generator = generator;
|
|
1889
|
+
}
|
|
1890
|
+
get id() {
|
|
1891
|
+
return this.table.id;
|
|
1892
|
+
}
|
|
1893
|
+
get tableName() {
|
|
1894
|
+
return this.table.tableName;
|
|
1895
|
+
}
|
|
1896
|
+
get columns() {
|
|
1897
|
+
if (this.table.includeColumns.length > 0) return this.table.columns.filter((c) => this.table.includeColumns.includes(c.name));
|
|
1898
|
+
return this.table.columns;
|
|
1899
|
+
}
|
|
1900
|
+
get skipGenerateFunction() {
|
|
1901
|
+
return this.table.skipGenerateFunction;
|
|
1902
|
+
}
|
|
1903
|
+
get functionName() {
|
|
1904
|
+
return this.generator.getFunctionName(`create_${this.table.id}_appender`);
|
|
1905
|
+
}
|
|
1906
|
+
get className() {
|
|
1907
|
+
return this.generator.getClassName(`${this.table.id}_appender`);
|
|
1908
|
+
}
|
|
1909
|
+
get rowTypeName() {
|
|
1910
|
+
return this.generator.getClassName(`${this.table.id}_row`);
|
|
1911
|
+
}
|
|
1912
|
+
get typeMapper() {
|
|
1913
|
+
return this.generator.typeMapper;
|
|
1914
|
+
}
|
|
1915
|
+
};
|
|
1916
|
+
function generateSourceFile(name, queries, tables, templatePath, generator, engine, config) {
|
|
1711
1917
|
const templateSrc = readFileSync(templatePath, "utf-8");
|
|
1712
1918
|
const template = Handlebars.compile(templateSrc);
|
|
1713
1919
|
Handlebars.registerHelper("mapType", (column) => generator.mapType(column));
|
|
1714
1920
|
Handlebars.registerHelper("plusOne", (value) => value + 1);
|
|
1921
|
+
const migrations = queries.filter((q) => q.isMigrate).map((q) => new SqlQueryHelper(q, generator, generator.getStatement(q)));
|
|
1922
|
+
const tableHelpers = generator.supportsAppenders(engine) ? tables.filter((t) => !t.skipGenerateFunction).map((t) => new TableHelper(t, generator)) : [];
|
|
1715
1923
|
return template({
|
|
1716
1924
|
generatedComment: GENERATED_FILE_COMMENT,
|
|
1717
|
-
migrations
|
|
1925
|
+
migrations,
|
|
1718
1926
|
queries: queries.map((q) => new SqlQueryHelper(q, generator, generator.getStatement(q))),
|
|
1927
|
+
tables: tableHelpers,
|
|
1719
1928
|
className: generator.getClassName(name),
|
|
1720
1929
|
config
|
|
1721
1930
|
}, {
|
|
@@ -1730,7 +1939,7 @@ const ProjectSchema = z.object({
|
|
|
1730
1939
|
version: z.number().describe("Configuration version (currently 1)"),
|
|
1731
1940
|
name: z.string().min(1, "Project name is required").describe("Project name used for generated class names"),
|
|
1732
1941
|
sql: z.array(z.object({
|
|
1733
|
-
engine: z.enum(
|
|
1942
|
+
engine: z.enum(DB_ENGINES).describe(`Database engine: ${DB_ENGINES.join(", ")}`),
|
|
1734
1943
|
files: z.array(z.string().min(1)).min(1, "At least one SQL file is required").describe("SQL files to process"),
|
|
1735
1944
|
gen: z.array(z.object({
|
|
1736
1945
|
generator: z.enum(GENERATOR_NAMES).describe(`Code generator: ${GENERATOR_NAMES.join(", ")}`),
|
|
@@ -1781,7 +1990,7 @@ function parseProjectConfig(filePath) {
|
|
|
1781
1990
|
const obj = parsed;
|
|
1782
1991
|
if (obj.sql && Array.isArray(obj.sql)) for (let i = 0; i < obj.sql.length; i++) {
|
|
1783
1992
|
const sqlConfig = obj.sql[i];
|
|
1784
|
-
if (sqlConfig.engine && !
|
|
1993
|
+
if (sqlConfig.engine && !DB_ENGINES.includes(sqlConfig.engine)) throw new InvalidEngineError(String(sqlConfig.engine), [...DB_ENGINES]);
|
|
1785
1994
|
if (sqlConfig.gen && Array.isArray(sqlConfig.gen)) for (let j = 0; j < sqlConfig.gen.length; j++) {
|
|
1786
1995
|
const genConfig = sqlConfig.gen[j];
|
|
1787
1996
|
if (genConfig.generator && !GENERATOR_NAMES.includes(genConfig.generator)) {
|
|
@@ -1830,11 +2039,11 @@ function validateQueries(queries) {
|
|
|
1830
2039
|
};
|
|
1831
2040
|
}
|
|
1832
2041
|
}
|
|
1833
|
-
async function writeGeneratedFile(projectDir, gen, generator, file, queries) {
|
|
1834
|
-
await generator.beforeGenerate(projectDir, gen, queries);
|
|
2042
|
+
async function writeGeneratedFile(projectDir, gen, generator, file, queries, tables, engine) {
|
|
2043
|
+
await generator.beforeGenerate(projectDir, gen, queries, tables);
|
|
1835
2044
|
const templatePath = join(dirname(new URL(import.meta.url).pathname), gen.template ?? generator.template);
|
|
1836
2045
|
const name = gen.name ?? basename(file, extname(file));
|
|
1837
|
-
const sourceFile = generateSourceFile(name, queries, templatePath, generator, gen.config);
|
|
2046
|
+
const sourceFile = generateSourceFile(name, queries, tables, templatePath, generator, engine, gen.config);
|
|
1838
2047
|
const outputPath = getOutputPath(projectDir, name, gen, generator);
|
|
1839
2048
|
writeFileSync(outputPath, sourceFile);
|
|
1840
2049
|
consola.success(`Generated ${outputPath}`);
|
|
@@ -1922,8 +2131,11 @@ async function processProject(projectPath) {
|
|
|
1922
2131
|
const fullPath = join(projectDir, sqlFile);
|
|
1923
2132
|
if (!existsSync(fullPath)) throw new FileNotFoundError(fullPath, projectDir);
|
|
1924
2133
|
let queries;
|
|
2134
|
+
let tables;
|
|
1925
2135
|
try {
|
|
1926
|
-
|
|
2136
|
+
const parseResult = parseSQLQueries(fullPath, extraVariables);
|
|
2137
|
+
queries = parseResult.queries;
|
|
2138
|
+
tables = parseResult.tables;
|
|
1927
2139
|
} catch (e) {
|
|
1928
2140
|
if (e instanceof SqgError) throw e;
|
|
1929
2141
|
throw SqgError.inFile(`Failed to parse SQL file: ${e.message}`, "SQL_PARSE_ERROR", sqlFile, { suggestion: "Check SQL syntax and annotation format" });
|
|
@@ -1932,6 +2144,7 @@ async function processProject(projectPath) {
|
|
|
1932
2144
|
const dbEngine = getDatabaseEngine(sql.engine);
|
|
1933
2145
|
await dbEngine.initializeDatabase(queries);
|
|
1934
2146
|
await dbEngine.executeQueries(queries);
|
|
2147
|
+
if (tables.length > 0) await dbEngine.introspectTables(tables);
|
|
1935
2148
|
validateQueries(queries);
|
|
1936
2149
|
await dbEngine.close();
|
|
1937
2150
|
} catch (e) {
|
|
@@ -1942,7 +2155,7 @@ async function processProject(projectPath) {
|
|
|
1942
2155
|
});
|
|
1943
2156
|
}
|
|
1944
2157
|
for (const gen of sql.gen) {
|
|
1945
|
-
const outputPath = await writeGeneratedFile(projectDir, gen, getGenerator(gen.generator), sqlFile, queries);
|
|
2158
|
+
const outputPath = await writeGeneratedFile(projectDir, gen, getGenerator(gen.generator), sqlFile, queries, tables, sql.engine);
|
|
1946
2159
|
files.push(outputPath);
|
|
1947
2160
|
}
|
|
1948
2161
|
}
|
|
@@ -2200,7 +2413,7 @@ sql:
|
|
|
2200
2413
|
async function initProject(options) {
|
|
2201
2414
|
const engine = options.engine || "sqlite";
|
|
2202
2415
|
const output = options.output || "./generated";
|
|
2203
|
-
if (!
|
|
2416
|
+
if (!DB_ENGINES.includes(engine)) throw new InvalidEngineError(engine, [...DB_ENGINES]);
|
|
2204
2417
|
let generator;
|
|
2205
2418
|
if (options.generator) {
|
|
2206
2419
|
if (!(options.generator in SUPPORTED_GENERATORS)) {
|
|
@@ -2242,7 +2455,7 @@ Documentation: https://sqg.dev
|
|
|
2242
2455
|
|
|
2243
2456
|
//#endregion
|
|
2244
2457
|
//#region src/sqg.ts
|
|
2245
|
-
const version = process.env.npm_package_version ?? "0.
|
|
2458
|
+
const version = process.env.npm_package_version ?? "0.4.0";
|
|
2246
2459
|
const description = process.env.npm_package_description ?? "SQG - SQL Query Generator - Type-safe code generation from SQL (https://sqg.dev)";
|
|
2247
2460
|
consola.level = LogLevels.info;
|
|
2248
2461
|
const program = new Command().name("sqg").description(`${description}
|
|
@@ -2292,7 +2505,7 @@ program.argument("<project>", "Path to the project YAML config (sqg.yaml)").hook
|
|
|
2292
2505
|
exit(1);
|
|
2293
2506
|
}
|
|
2294
2507
|
});
|
|
2295
|
-
program.command("init").description("Initialize a new SQG project with example configuration").option("-e, --engine <engine>", `Database engine (${
|
|
2508
|
+
program.command("init").description("Initialize a new SQG project with example configuration").option("-e, --engine <engine>", `Database engine (${DB_ENGINES.join(", ")})`, "sqlite").option("-g, --generator <generator>", `Code generator (${GENERATOR_NAMES.join(", ")})`).option("-o, --output <dir>", "Output directory for generated files", "./generated").option("-f, --force", "Overwrite existing files").action(async (options) => {
|
|
2296
2509
|
const parentOpts = program.opts();
|
|
2297
2510
|
try {
|
|
2298
2511
|
await initProject(options);
|
|
@@ -14,6 +14,9 @@ import org.apache.arrow.vector.complex.ListVector;
|
|
|
14
14
|
import org.apache.arrow.vector.ipc.ArrowReader;
|
|
15
15
|
import org.duckdb.DuckDBConnection;
|
|
16
16
|
import org.duckdb.DuckDBResultSet;
|
|
17
|
+
{{#if tables.length}}
|
|
18
|
+
import org.duckdb.DuckDBAppender;
|
|
19
|
+
{{/if}}
|
|
17
20
|
import {{config.package}}.{{className}}Jdbc.*;
|
|
18
21
|
|
|
19
22
|
public class {{className}} {
|
|
@@ -46,9 +49,18 @@ public class {{className}} {
|
|
|
46
49
|
{{/if}}
|
|
47
50
|
{{/unless}}
|
|
48
51
|
{{/each}}
|
|
49
|
-
}
|
|
50
52
|
|
|
53
|
+
{{#if tables.length}}
|
|
54
|
+
// ==================== Appenders ====================
|
|
55
|
+
{{#each tables}}
|
|
51
56
|
|
|
57
|
+
/** Create an appender for bulk inserts into {{tableName}} */
|
|
58
|
+
public {{className}} {{functionName}}() throws SQLException {
|
|
59
|
+
return jdbc.{{functionName}}();
|
|
60
|
+
}
|
|
61
|
+
{{/each}}
|
|
62
|
+
{{/if}}
|
|
63
|
+
}
|
|
52
64
|
|
|
53
65
|
|
|
54
66
|
{{#*inline "columnTypesRecord"}}
|
|
@@ -57,7 +69,7 @@ public class {{className}} {
|
|
|
57
69
|
public record {{rowType}}({{#each columns}}{{type}} {{name}}{{#unless @last}}, {{/unless}}{{/each}}) {}
|
|
58
70
|
{{else}}
|
|
59
71
|
public record {{rowType}}(PreparedStatement statement, RootAllocator allocator, ArrowReader reader,
|
|
60
|
-
{{#each columns}}{{mapType this}} {{name}}{{#unless @last}}, {{/unless}}{{/each}}) implements AutoCloseable {
|
|
72
|
+
{{#each columns}}{{{mapType this}}} {{name}}{{#unless @last}}, {{/unless}}{{/each}}) implements AutoCloseable {
|
|
61
73
|
public boolean loadNextBatch() throws IOException {
|
|
62
74
|
return reader.loadNextBatch();
|
|
63
75
|
}
|
|
@@ -87,7 +99,7 @@ int
|
|
|
87
99
|
{{#*inline "readVectors"}}
|
|
88
100
|
var root = reader.getVectorSchemaRoot();
|
|
89
101
|
|
|
90
|
-
return new {{rowType}}(stmt, allocator, reader, {{#each columns}}({{mapType this}})root.getVector("{{name}}"){{#unless @last}}, {{/unless}}{{/each}});
|
|
102
|
+
return new {{rowType}}(stmt, allocator, reader, {{#each columns}}({{{mapType this}}})root.getVector("{{name}}"){{#unless @last}}, {{/unless}}{{/each}});
|
|
91
103
|
|
|
92
104
|
{{/inline~}}
|
|
93
105
|
|
|
@@ -21,6 +21,10 @@ import java.util.HashMap;
|
|
|
21
21
|
import java.util.Collections;
|
|
22
22
|
import java.util.UUID;
|
|
23
23
|
import java.util.function.Function;
|
|
24
|
+
{{#if tables.length}}
|
|
25
|
+
import org.duckdb.DuckDBAppender;
|
|
26
|
+
import org.duckdb.DuckDBConnection;
|
|
27
|
+
{{/if}}
|
|
24
28
|
|
|
25
29
|
public class {{className}} {
|
|
26
30
|
private final Connection connection;
|
|
@@ -139,8 +143,72 @@ public class {{className}} {
|
|
|
139
143
|
}
|
|
140
144
|
{{/unless}}
|
|
141
145
|
{{/each}}
|
|
142
|
-
}
|
|
143
146
|
|
|
147
|
+
{{#if tables.length}}
|
|
148
|
+
// ==================== Appenders ====================
|
|
149
|
+
{{#each tables}}
|
|
150
|
+
|
|
151
|
+
/** Create an appender for bulk inserts into {{tableName}} */
|
|
152
|
+
public {{className}} {{functionName}}() throws SQLException {
|
|
153
|
+
return new {{className}}(((DuckDBConnection) connection).createAppender(DuckDBConnection.DEFAULT_SCHEMA, "{{tableName}}"));
|
|
154
|
+
}
|
|
155
|
+
{{/each}}
|
|
156
|
+
{{/if}}
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
{{#each tables}}
|
|
160
|
+
/** Row type for {{tableName}} appender */
|
|
161
|
+
public record {{rowTypeName}}({{#each columns}}{{mapType this}} {{name}}{{#unless @last}}, {{/unless}}{{/each}}) {}
|
|
162
|
+
|
|
163
|
+
/** Appender for bulk inserts into {{tableName}} */
|
|
164
|
+
public static class {{className}} implements AutoCloseable {
|
|
165
|
+
private final DuckDBAppender appender;
|
|
166
|
+
|
|
167
|
+
{{className}}(DuckDBAppender appender) {
|
|
168
|
+
this.appender = appender;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/** Get the underlying DuckDB appender for advanced operations */
|
|
172
|
+
public DuckDBAppender getAppender() {
|
|
173
|
+
return appender;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
/** Append a single row */
|
|
177
|
+
public {{className}} append({{rowTypeName}} row) throws SQLException {
|
|
178
|
+
appender.beginRow();
|
|
179
|
+
{{#each columns}}
|
|
180
|
+
appender.append(row.{{name}}());
|
|
181
|
+
{{/each}}
|
|
182
|
+
appender.endRow();
|
|
183
|
+
return this;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/** Append a single row with individual values */
|
|
187
|
+
public {{className}} append({{#each columns}}{{mapType this}} {{name}}{{#unless @last}}, {{/unless}}{{/each}}) throws SQLException {
|
|
188
|
+
appender.beginRow();
|
|
189
|
+
{{#each columns}}
|
|
190
|
+
appender.append({{name}});
|
|
191
|
+
{{/each}}
|
|
192
|
+
appender.endRow();
|
|
193
|
+
return this;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
/** Append multiple rows */
|
|
197
|
+
public {{className}} appendMany(Iterable<{{rowTypeName}}> rows) throws SQLException {
|
|
198
|
+
for (var row : rows) {
|
|
199
|
+
append(row);
|
|
200
|
+
}
|
|
201
|
+
return this;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
/** Flush and close the appender */
|
|
205
|
+
@Override
|
|
206
|
+
public void close() throws SQLException {
|
|
207
|
+
appender.close();
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
{{/each}}
|
|
211
|
+
}
|
|
144
212
|
|
|
145
213
|
{{#*inline "columnTypesRecord"}}
|
|
146
214
|
{{#if isQuery}}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// {{generatedComment}}
|
|
2
|
-
import type { DuckDBConnection, DuckDBMaterializedResult } from "@duckdb/node-api";
|
|
2
|
+
import type { DuckDBConnection, DuckDBMaterializedResult, DuckDBAppender, DuckDBDateValue, DuckDBTimeValue, DuckDBTimestampValue, DuckDBBlobValue } from "@duckdb/node-api";
|
|
3
3
|
|
|
4
4
|
export class {{className}} {
|
|
5
5
|
|
|
@@ -46,7 +46,67 @@ export class {{className}} {
|
|
|
46
46
|
{{/unless}}
|
|
47
47
|
|
|
48
48
|
{{/each}}
|
|
49
|
+
|
|
50
|
+
{{#if tables.length}}
|
|
51
|
+
// ==================== Appenders ====================
|
|
52
|
+
{{#each tables}}
|
|
53
|
+
|
|
54
|
+
async {{functionName}}(): Promise<{{className}}> {
|
|
55
|
+
return new {{className}}(await this.conn.createAppender('{{tableName}}'));
|
|
56
|
+
}
|
|
57
|
+
{{/each}}
|
|
58
|
+
{{/if}}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
{{#each tables}}
|
|
62
|
+
/** Row type for {{tableName}} appender */
|
|
63
|
+
export interface {{rowTypeName}} {
|
|
64
|
+
{{#each columns}}
|
|
65
|
+
{{name}}: {{{tsTypeForAppender this}}};
|
|
66
|
+
{{/each}}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/** Appender for bulk inserts into {{tableName}} */
|
|
70
|
+
export class {{className}} {
|
|
71
|
+
constructor(public readonly appender: DuckDBAppender) {}
|
|
72
|
+
|
|
73
|
+
/** Append a single row */
|
|
74
|
+
append(row: {{rowTypeName}}): this {
|
|
75
|
+
{{#each columns}}
|
|
76
|
+
{{#if nullable}}
|
|
77
|
+
if (row.{{name}} === null || row.{{name}} === undefined) {
|
|
78
|
+
this.appender.appendNull();
|
|
79
|
+
} else {
|
|
80
|
+
this.appender.append{{appendMethod this}}(row.{{name}});
|
|
81
|
+
}
|
|
82
|
+
{{else}}
|
|
83
|
+
this.appender.append{{appendMethod this}}(row.{{name}});
|
|
84
|
+
{{/if}}
|
|
85
|
+
{{/each}}
|
|
86
|
+
this.appender.endRow();
|
|
87
|
+
return this;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/** Append multiple rows */
|
|
91
|
+
appendMany(rows: {{rowTypeName}}[]): this {
|
|
92
|
+
for (const row of rows) {
|
|
93
|
+
this.append(row);
|
|
94
|
+
}
|
|
95
|
+
return this;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/** Flush buffered data to the table */
|
|
99
|
+
flush(): this {
|
|
100
|
+
this.appender.flushSync();
|
|
101
|
+
return this;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/** Flush and close the appender */
|
|
105
|
+
close(): void {
|
|
106
|
+
this.appender.closeSync();
|
|
107
|
+
}
|
|
49
108
|
}
|
|
109
|
+
{{/each}}
|
|
50
110
|
|
|
51
111
|
{{#*inline "params"}}{{#each parameterNames}}{{this}}{{#unless @last}}, {{/unless}}{{/each}}{{/inline}}
|
|
52
112
|
|