@sqg/sqg 0.2.2 → 0.3.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
@@ -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 Return single row (or null) instead of array
76
- :pluck Return single column value (requires exactly 1 column)
77
- :all Return all rows (default)
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
@@ -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'#CvOnQQO'#C^OOQO'#Cn'#CnQVQPOOO!SQSO,59cO!_QPO,59fOOQO'#Cp'#CpO!gQQO,59bOOQO'#C}'#C}O#RQQO'#CiOOQO,58x,58xOOQO-E6l-E6lOOQO'#Co'#CoO!SQSO1G.}O!VQSO1G.}OOQO'#Cb'#CbOOQO1G.}1G.}O#cQPO1G/QOOQO-E6n-E6nO#kQPO'#CdOOQO'#Cq'#CqO#pQQO1G.|OOQO'#Cm'#CmOOQO'#Cr'#CrO$XQQO,59TOOQO-E6m-E6mO!VQSO7+$iOOQO7+$i7+$iO$iQPO,59OOOQO-E6o-E6oOOQO-E6p-E6pOOQO<<HT<<HTO$nQQO1G.jOOQO'#Ce'#CeOiQPO7+$UO$yQQO<<Gp",
284
- stateData: "%r~OiOS~ORPOVQO~OSVO~OSWO~OlXO~OYZOZZO[ZO^ZO_ZO`ZO~OT_OlXOmbO~OT_Olna~OlXOofOYjaZja[ja^ja_ja`ja~OliOR]XV]Xg]X~PnOT_Olni~OSoO~OofOYjiZji[ji^ji_ji`ji~OliOR]aV]ag]a~PnOpsO~OYtOZtO[tO~OlXOYWyZWy[Wy^Wy_Wy`WyoWy~OR`o^iZTmYV_[~",
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: 205
301
+ tokenPrec: 245
298
302
  });
299
303
 
300
304
  //#endregion
@@ -377,11 +381,30 @@ 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();
386
409
  function getStr(nodeName, optional = false) {
387
410
  const node = cursor.node.getChild(nodeName);
@@ -532,6 +555,21 @@ function parseSQLQueries(filePath, extraVariables) {
532
555
  if (to > from) sql.appendSql(content.slice(from, to));
533
556
  sql.trim();
534
557
  }
558
+ if (queryType === "TABLE") {
559
+ const hasAppender = modifiers.includes(":appender");
560
+ const tableName = sqlContentStr.trim() || name;
561
+ const includeColumns = [];
562
+ for (const mod of modifiers) {
563
+ const match = mod.match(/:appender\(([^)]+)\)/);
564
+ if (match) includeColumns.push(...match[1].split(",").map((c) => c.trim()));
565
+ }
566
+ const table = new TableInfo(filePath, name, tableName, includeColumns, hasAppender);
567
+ 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` });
568
+ queryNames.add(name);
569
+ tables.push(table);
570
+ consola.debug(`Added table: ${name} -> ${tableName} (appender: ${hasAppender})`);
571
+ continue;
572
+ }
535
573
  consola.debug("Parsed query:", {
536
574
  type: queryType,
537
575
  name,
@@ -548,9 +586,13 @@ function parseSQLQueries(filePath, extraVariables) {
548
586
  consola.debug(`Added query: ${name} (${queryType})`);
549
587
  }
550
588
  while (cursor.next());
551
- consola.info(`Total queries parsed: ${queries.length}`);
589
+ consola.info(`Total queries parsed: ${queries.length}, tables: ${tables.length}`);
552
590
  consola.info(`Query names: ${queries.map((q) => q.id).join(", ")}`);
553
- return queries;
591
+ if (tables.length > 0) consola.info(`Table names: ${tables.map((t) => t.id).join(", ")}`);
592
+ return {
593
+ queries,
594
+ tables
595
+ };
554
596
  }
555
597
 
556
598
  //#endregion
@@ -658,6 +700,47 @@ const duckdb = new class {
658
700
  throw error;
659
701
  }
660
702
  }
703
+ async introspectTables(tables) {
704
+ const connection = this.connection;
705
+ if (!connection) throw new DatabaseError("DuckDB connection not initialized", "duckdb", "This is an internal error. Check that migrations completed successfully.");
706
+ for (const table of tables) {
707
+ consola.info(`Introspecting table schema: ${table.tableName}`);
708
+ try {
709
+ const rows = (await connection.runAndReadAll(`DESCRIBE ${table.tableName}`)).getRows();
710
+ function convertType(type) {
711
+ if (type instanceof DuckDBListType) return new ListType(convertType(type.valueType));
712
+ if (type instanceof DuckDBStructType) return new StructType(type.entryTypes.map((t, index) => ({
713
+ name: type.entryNames[index],
714
+ type: convertType(t),
715
+ nullable: true
716
+ })));
717
+ if (type instanceof DuckDBMapType) return new MapType({
718
+ name: "key",
719
+ type: convertType(type.keyType),
720
+ nullable: true
721
+ }, {
722
+ name: "value",
723
+ type: convertType(type.valueType),
724
+ nullable: true
725
+ });
726
+ if (type instanceof DuckDBEnumType) return new EnumType(type.values);
727
+ return type.toString();
728
+ }
729
+ table.columns = rows.map((row) => {
730
+ return {
731
+ name: row[0],
732
+ type: row[1],
733
+ nullable: row[2] !== "NO"
734
+ };
735
+ });
736
+ consola.debug(`Table ${table.tableName} columns:`, table.columns);
737
+ consola.success(`Introspected table: ${table.tableName} (${table.columns.length} columns)`);
738
+ } catch (error) {
739
+ consola.error(`Failed to introspect table '${table.tableName}':`, error);
740
+ throw error;
741
+ }
742
+ }
743
+ }
661
744
  close() {
662
745
  this.connection.closeSync();
663
746
  }
@@ -752,6 +835,27 @@ const postgres = new class {
752
835
  throw error;
753
836
  }
754
837
  }
838
+ async introspectTables(tables) {
839
+ const db = this.db;
840
+ if (!db) throw new DatabaseError("PostgreSQL database not initialized", "postgres", "This is an internal error. Check that migrations completed successfully.");
841
+ for (const table of tables) {
842
+ consola.info(`Introspecting table schema: ${table.tableName}`);
843
+ try {
844
+ table.columns = (await db.query(`SELECT column_name, data_type, is_nullable
845
+ FROM information_schema.columns
846
+ WHERE table_name = $1
847
+ ORDER BY ordinal_position`, [table.tableName])).rows.map((row) => ({
848
+ name: row.column_name,
849
+ type: row.data_type.toUpperCase(),
850
+ nullable: row.is_nullable === "YES"
851
+ }));
852
+ consola.success(`Introspected table: ${table.tableName} (${table.columns.length} columns)`);
853
+ } catch (error) {
854
+ consola.error(`Failed to introspect table '${table.tableName}':`, error);
855
+ throw error;
856
+ }
857
+ }
858
+ }
755
859
  async close() {
756
860
  await this.db.end();
757
861
  await this.dbInitial.query(`DROP DATABASE "${databaseName}"`);
@@ -791,6 +895,20 @@ const sqlite = new class {
791
895
  throw error;
792
896
  }
793
897
  }
898
+ introspectTables(tables) {
899
+ const db = this.db;
900
+ if (!db) throw new DatabaseError("SQLite database not initialized", "sqlite", "This is an internal error. Migrations may have failed silently.");
901
+ for (const table of tables) {
902
+ consola.info(`Introspecting table schema: ${table.tableName}`);
903
+ const info = this.getTableInfo(db, table.tableName);
904
+ table.columns = Array.from(info.values()).map((col) => ({
905
+ name: col.name,
906
+ type: col.type || "TEXT",
907
+ nullable: col.notnull === 0 && col.pk === 0
908
+ }));
909
+ consola.success(`Introspected table: ${table.tableName} (${table.columns.length} columns)`);
910
+ }
911
+ }
794
912
  close() {
795
913
  this.db.close();
796
914
  }
@@ -1206,7 +1324,7 @@ var BaseGenerator = class {
1206
1324
  listType(column) {
1207
1325
  return this.typeMapper.listType(column);
1208
1326
  }
1209
- async beforeGenerate(_projectDir, _gen, _queries) {}
1327
+ async beforeGenerate(_projectDir, _gen, _queries, _tables) {}
1210
1328
  isCompatibleWith(_engine) {
1211
1329
  return true;
1212
1330
  }
@@ -1272,7 +1390,7 @@ var JavaGenerator = class extends BaseGenerator {
1272
1390
  readColumn(column, index, path) {
1273
1391
  return this.typeMapper.parseValue(column, `rs.getObject(${index + 1})`, path);
1274
1392
  }
1275
- async beforeGenerate(_projectDir, _gen, _queries) {
1393
+ async beforeGenerate(_projectDir, _gen, _queries, _tables) {
1276
1394
  Handlebars.registerHelper("partsToString", (parts) => this.partsToString(parts));
1277
1395
  Handlebars.registerHelper("declareTypes", (queryHelper) => {
1278
1396
  const query = queryHelper.query;
@@ -1324,7 +1442,7 @@ var JavaDuckDBArrowGenerator = class extends BaseGenerator {
1324
1442
  getFunctionName(id) {
1325
1443
  return this.javaGenerator.getFunctionName(id);
1326
1444
  }
1327
- async beforeGenerate(projectDir, gen, queries) {
1445
+ async beforeGenerate(projectDir, gen, queries, tables) {
1328
1446
  const q = queries.filter((q$1) => q$1.isQuery && q$1.isOne || q$1.isMigrate);
1329
1447
  const name = `${gen.name}-jdbc`;
1330
1448
  writeGeneratedFile(projectDir, {
@@ -1332,7 +1450,7 @@ var JavaDuckDBArrowGenerator = class extends BaseGenerator {
1332
1450
  generator: "java/jdbc",
1333
1451
  output: gen.output,
1334
1452
  config: gen.config
1335
- }, this.javaGenerator, name, q);
1453
+ }, this.javaGenerator, name, q, tables);
1336
1454
  }
1337
1455
  isCompatibleWith(engine) {
1338
1456
  return engine === "duckdb";
@@ -1410,8 +1528,45 @@ var TsGenerator = class extends BaseGenerator {
1410
1528
  getClassName(name) {
1411
1529
  return pascalCase$1(name);
1412
1530
  }
1413
- async beforeGenerate(_projectDir, _gen, _queries) {
1531
+ async beforeGenerate(_projectDir, _gen, _queries, _tables) {
1414
1532
  Handlebars.registerHelper("quote", (value) => this.quote(value));
1533
+ Handlebars.registerHelper("appendMethod", (column) => {
1534
+ const typeStr = column.type?.toString().toUpperCase() || "";
1535
+ if (typeStr === "INTEGER" || typeStr === "INT" || typeStr === "INT4" || typeStr === "SIGNED") return "Integer";
1536
+ if (typeStr === "SMALLINT" || typeStr === "INT2" || typeStr === "SHORT") return "SmallInt";
1537
+ if (typeStr === "TINYINT" || typeStr === "INT1") return "TinyInt";
1538
+ if (typeStr === "BIGINT" || typeStr === "INT8" || typeStr === "LONG") return "BigInt";
1539
+ if (typeStr === "HUGEINT" || typeStr === "INT128") return "HugeInt";
1540
+ if (typeStr === "UINTEGER" || typeStr === "UINT4") return "UInteger";
1541
+ if (typeStr === "USMALLINT" || typeStr === "UINT2") return "USmallInt";
1542
+ if (typeStr === "UTINYINT" || typeStr === "UINT1") return "UTinyInt";
1543
+ if (typeStr === "UBIGINT" || typeStr === "UINT8") return "UBigInt";
1544
+ if (typeStr === "DOUBLE" || typeStr === "FLOAT8" || typeStr === "NUMERIC" || typeStr === "DECIMAL") return "Double";
1545
+ if (typeStr === "FLOAT" || typeStr === "FLOAT4" || typeStr === "REAL") return "Float";
1546
+ if (typeStr === "BOOLEAN" || typeStr === "BOOL" || typeStr === "LOGICAL") return "Boolean";
1547
+ if (typeStr === "DATE") return "Date";
1548
+ if (typeStr === "TIMESTAMP" || typeStr.includes("TIMESTAMP")) return "Timestamp";
1549
+ if (typeStr === "TIME" || typeStr.includes("TIME")) return "Time";
1550
+ if (typeStr === "BLOB" || typeStr === "BYTEA" || typeStr === "BINARY" || typeStr === "VARBINARY") return "Blob";
1551
+ if (typeStr === "UUID") return "Uuid";
1552
+ if (typeStr === "INTERVAL") return "Interval";
1553
+ return "Varchar";
1554
+ });
1555
+ Handlebars.registerHelper("tsTypeForAppender", (column) => {
1556
+ const typeStr = column.type?.toString().toUpperCase() || "";
1557
+ let baseType;
1558
+ 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";
1559
+ else if (typeStr === "BIGINT" || typeStr === "INT8" || typeStr === "HUGEINT" || typeStr === "INT128" || typeStr === "UBIGINT" || typeStr === "UINT8") baseType = "bigint";
1560
+ else if (typeStr === "BOOLEAN" || typeStr === "BOOL") baseType = "boolean";
1561
+ else if (typeStr === "DATE") baseType = "DuckDBDateValue";
1562
+ else if (typeStr === "TIMESTAMP" || typeStr.includes("TIMESTAMP")) baseType = "DuckDBTimestampValue";
1563
+ else if (typeStr === "TIME" || typeStr.includes("TIME")) baseType = "DuckDBTimeValue";
1564
+ else if (typeStr === "BLOB" || typeStr === "BYTEA") baseType = "DuckDBBlobValue";
1565
+ else if (typeStr === "UUID") baseType = "string";
1566
+ else baseType = "string";
1567
+ if (column.nullable) return `${baseType} | null`;
1568
+ return baseType;
1569
+ });
1415
1570
  Handlebars.registerHelper("tsType", (column) => {
1416
1571
  const inlineType = (col) => {
1417
1572
  const t = col.type;
@@ -1533,8 +1688,8 @@ var TsDuckDBGenerator = class extends TsGenerator {
1533
1688
  constructor(template) {
1534
1689
  super(template);
1535
1690
  }
1536
- async beforeGenerate(projectDir, gen, queries) {
1537
- await super.beforeGenerate(projectDir, gen, queries);
1691
+ async beforeGenerate(projectDir, gen, queries, tables) {
1692
+ await super.beforeGenerate(projectDir, gen, queries, tables);
1538
1693
  Handlebars.registerHelper("tsType", (column) => {
1539
1694
  const inlineType = (col) => {
1540
1695
  const t = col.type;
@@ -1707,15 +1862,50 @@ var SqlQueryHelper = class {
1707
1862
  return this.generator.typeMapper;
1708
1863
  }
1709
1864
  };
1710
- function generateSourceFile(name, queries, templatePath, generator, config) {
1865
+ /** Util class to help generating appenders for tables */
1866
+ var TableHelper = class {
1867
+ constructor(table, generator) {
1868
+ this.table = table;
1869
+ this.generator = generator;
1870
+ }
1871
+ get id() {
1872
+ return this.table.id;
1873
+ }
1874
+ get tableName() {
1875
+ return this.table.tableName;
1876
+ }
1877
+ get columns() {
1878
+ if (this.table.includeColumns.length > 0) return this.table.columns.filter((c) => this.table.includeColumns.includes(c.name));
1879
+ return this.table.columns;
1880
+ }
1881
+ get skipGenerateFunction() {
1882
+ return this.table.skipGenerateFunction;
1883
+ }
1884
+ get functionName() {
1885
+ return this.generator.getFunctionName(`create_${this.table.id}_appender`);
1886
+ }
1887
+ get className() {
1888
+ return this.generator.getClassName(`${this.table.id}_appender`);
1889
+ }
1890
+ get rowTypeName() {
1891
+ return this.generator.getClassName(`${this.table.id}_row`);
1892
+ }
1893
+ get typeMapper() {
1894
+ return this.generator.typeMapper;
1895
+ }
1896
+ };
1897
+ function generateSourceFile(name, queries, tables, templatePath, generator, config) {
1711
1898
  const templateSrc = readFileSync(templatePath, "utf-8");
1712
1899
  const template = Handlebars.compile(templateSrc);
1713
1900
  Handlebars.registerHelper("mapType", (column) => generator.mapType(column));
1714
1901
  Handlebars.registerHelper("plusOne", (value) => value + 1);
1902
+ const migrations = queries.filter((q) => q.isMigrate).map((q) => new SqlQueryHelper(q, generator, generator.getStatement(q)));
1903
+ const tableHelpers = tables.filter((t) => !t.skipGenerateFunction).map((t) => new TableHelper(t, generator));
1715
1904
  return template({
1716
1905
  generatedComment: GENERATED_FILE_COMMENT,
1717
- migrations: queries.filter((q) => q.isMigrate).map((q) => new SqlQueryHelper(q, generator, generator.getStatement(q))),
1906
+ migrations,
1718
1907
  queries: queries.map((q) => new SqlQueryHelper(q, generator, generator.getStatement(q))),
1908
+ tables: tableHelpers,
1719
1909
  className: generator.getClassName(name),
1720
1910
  config
1721
1911
  }, {
@@ -1830,11 +2020,11 @@ function validateQueries(queries) {
1830
2020
  };
1831
2021
  }
1832
2022
  }
1833
- async function writeGeneratedFile(projectDir, gen, generator, file, queries) {
1834
- await generator.beforeGenerate(projectDir, gen, queries);
2023
+ async function writeGeneratedFile(projectDir, gen, generator, file, queries, tables = []) {
2024
+ await generator.beforeGenerate(projectDir, gen, queries, tables);
1835
2025
  const templatePath = join(dirname(new URL(import.meta.url).pathname), gen.template ?? generator.template);
1836
2026
  const name = gen.name ?? basename(file, extname(file));
1837
- const sourceFile = generateSourceFile(name, queries, templatePath, generator, gen.config);
2027
+ const sourceFile = generateSourceFile(name, queries, tables, templatePath, generator, gen.config);
1838
2028
  const outputPath = getOutputPath(projectDir, name, gen, generator);
1839
2029
  writeFileSync(outputPath, sourceFile);
1840
2030
  consola.success(`Generated ${outputPath}`);
@@ -1922,8 +2112,11 @@ async function processProject(projectPath) {
1922
2112
  const fullPath = join(projectDir, sqlFile);
1923
2113
  if (!existsSync(fullPath)) throw new FileNotFoundError(fullPath, projectDir);
1924
2114
  let queries;
2115
+ let tables;
1925
2116
  try {
1926
- queries = parseSQLQueries(fullPath, extraVariables);
2117
+ const parseResult = parseSQLQueries(fullPath, extraVariables);
2118
+ queries = parseResult.queries;
2119
+ tables = parseResult.tables;
1927
2120
  } catch (e) {
1928
2121
  if (e instanceof SqgError) throw e;
1929
2122
  throw SqgError.inFile(`Failed to parse SQL file: ${e.message}`, "SQL_PARSE_ERROR", sqlFile, { suggestion: "Check SQL syntax and annotation format" });
@@ -1932,6 +2125,7 @@ async function processProject(projectPath) {
1932
2125
  const dbEngine = getDatabaseEngine(sql.engine);
1933
2126
  await dbEngine.initializeDatabase(queries);
1934
2127
  await dbEngine.executeQueries(queries);
2128
+ if (tables.length > 0) await dbEngine.introspectTables(tables);
1935
2129
  validateQueries(queries);
1936
2130
  await dbEngine.close();
1937
2131
  } catch (e) {
@@ -1942,7 +2136,7 @@ async function processProject(projectPath) {
1942
2136
  });
1943
2137
  }
1944
2138
  for (const gen of sql.gen) {
1945
- const outputPath = await writeGeneratedFile(projectDir, gen, getGenerator(gen.generator), sqlFile, queries);
2139
+ const outputPath = await writeGeneratedFile(projectDir, gen, getGenerator(gen.generator), sqlFile, queries, tables);
1946
2140
  files.push(outputPath);
1947
2141
  }
1948
2142
  }
@@ -2242,7 +2436,7 @@ Documentation: https://sqg.dev
2242
2436
 
2243
2437
  //#endregion
2244
2438
  //#region src/sqg.ts
2245
- const version = process.env.npm_package_version ?? "0.2.2";
2439
+ const version = process.env.npm_package_version ?? "0.3.0";
2246
2440
  const description = process.env.npm_package_description ?? "SQG - SQL Query Generator - Type-safe code generation from SQL (https://sqg.dev)";
2247
2441
  consola.level = LogLevels.info;
2248
2442
  const program = new Command().name("sqg").description(`${description}
@@ -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"}}
@@ -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
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sqg/sqg",
3
- "version": "0.2.2",
3
+ "version": "0.3.0",
4
4
  "description": "SQG - SQL Query Generator - Type-safe code generation from SQL (https://sqg.dev)",
5
5
  "type": "module",
6
6
  "bin": {