From cd597a361e74e05aeec1d10319fd875518719cc3 Mon Sep 17 00:00:00 2001 From: Timothy Carambat Date: Tue, 23 Jul 2024 12:42:53 -0700 Subject: [PATCH] OBDC Support (#1933) * add possibility to connect to SQL Base by ODBC --------- Co-authored-by: suchaudn Co-authored-by: nicho2 --- .vscode/settings.json | 1 + .../SQLConnectorSelection/DBConnection.jsx | 2 + .../NewConnectionModal.jsx | 33 +++++++++- .../SQLConnectorSelection/icons/odbc.png | Bin 0 -> 19645 bytes server/package.json | 3 +- .../plugins/sql-agent/SQLConnectors/ODBC.js | 60 ++++++++++++++++++ .../plugins/sql-agent/SQLConnectors/index.js | 5 +- server/yarn.lock | 18 +++++- 8 files changed, 116 insertions(+), 6 deletions(-) create mode 100644 frontend/src/pages/Admin/Agents/SQLConnectorSelection/icons/odbc.png create mode 100644 server/utils/agents/aibitat/plugins/sql-agent/SQLConnectors/ODBC.js diff --git a/.vscode/settings.json b/.vscode/settings.json index 5e26e477..60ff747f 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -31,6 +31,7 @@ "Mintplex", "moderations", "numpages", + "odbc", "Ollama", "Oobabooga", "openai", diff --git a/frontend/src/pages/Admin/Agents/SQLConnectorSelection/DBConnection.jsx b/frontend/src/pages/Admin/Agents/SQLConnectorSelection/DBConnection.jsx index 9d7b35b0..d7361bae 100644 --- a/frontend/src/pages/Admin/Agents/SQLConnectorSelection/DBConnection.jsx +++ b/frontend/src/pages/Admin/Agents/SQLConnectorSelection/DBConnection.jsx @@ -1,12 +1,14 @@ import PostgreSQLLogo from "./icons/postgresql.png"; import MySQLLogo from "./icons/mysql.png"; import MSSQLLogo from "./icons/mssql.png"; +import ODBCLogo from "./icons/odbc.png"; import { X } from "@phosphor-icons/react"; export const DB_LOGOS = { postgresql: PostgreSQLLogo, mysql: MySQLLogo, "sql-server": MSSQLLogo, + odbc: ODBCLogo, }; export default function DBConnection({ connection, onRemove, setHasChanges }) { diff --git a/frontend/src/pages/Admin/Agents/SQLConnectorSelection/NewConnectionModal.jsx b/frontend/src/pages/Admin/Agents/SQLConnectorSelection/NewConnectionModal.jsx index e5f4c301..f6b1c21e 100644 --- a/frontend/src/pages/Admin/Agents/SQLConnectorSelection/NewConnectionModal.jsx +++ b/frontend/src/pages/Admin/Agents/SQLConnectorSelection/NewConnectionModal.jsx @@ -11,6 +11,7 @@ function assembleConnectionString({ host = "", port = "", database = "", + driver = "", }) { if ([username, password, host, database].every((i) => !!i) === false) return `Please fill out all the fields above.`; @@ -21,6 +22,9 @@ function assembleConnectionString({ return `mysql://${username}:${password}@${host}:${port}/${database}`; case "sql-server": return `mssql://${username}:${password}@${host}:${port}/${database}`; + case "odbc": + if (!driver) return `Please fill out the driver field.`; + return `Driver={${driver}};Server=${host};Port=${port};Database=${database};UID=${username};PWD=${password}`; default: return null; } @@ -33,6 +37,7 @@ const DEFAULT_CONFIG = { host: null, port: null, database: null, + driver: null, }; export default function NewSQLConnection({ isOpen, closeModal, onSubmit }) { @@ -48,12 +53,14 @@ export default function NewSQLConnection({ isOpen, closeModal, onSubmit }) { function onFormChange() { const form = new FormData(document.getElementById("sql-connection-form")); + setConfig({ username: form.get("username").trim(), password: form.get("password"), host: form.get("host").trim(), port: form.get("port").trim(), database: form.get("database").trim(), + driver: form.get("driver")?.trim(), }); } @@ -74,7 +81,7 @@ export default function NewSQLConnection({ isOpen, closeModal, onSubmit }) { // to the parent container form so we don't have nested forms. return createPortal( -
+

@@ -114,7 +121,7 @@ export default function NewSQLConnection({ isOpen, closeModal, onSubmit }) { -
+
setEngine("sql-server")} /> + setEngine("odbc")} + />
@@ -224,6 +236,23 @@ export default function NewSQLConnection({ isOpen, closeModal, onSubmit }) { spellCheck={false} />

+ + {engine === "odbc" && ( +
+ + +
+ )}

{assembleConnectionString({ engine, ...config })}

diff --git a/frontend/src/pages/Admin/Agents/SQLConnectorSelection/icons/odbc.png b/frontend/src/pages/Admin/Agents/SQLConnectorSelection/icons/odbc.png new file mode 100644 index 0000000000000000000000000000000000000000..c287558874843bd0f534117b2cb6dea95904cb1e GIT binary patch literal 19645 zcmdtKcR1H?|36HG%m^V{J3C~{2rVlKAv2q|kr_f(G8-C7QK=*=BxTQtR6<5(D6@gg z`|+yldws9#`rh|_+{f?t`|JK3KF9UB-d^w5I?wa@e5_N9o{km+Ef*~r85zStZ4Co5 zGV)a7Um7ZWGO5ZghyU3?(l+rTBcrw^{w0?UxZX`hM)}pz(AeAf=n;7vcUMs>TX$DxOvI@Ded@kggpM6_*iU*GA;i<{!#R_JuPpbq4|$P z@&A-|ICy)L> z__w>XwUPIB^meiPj~iEY@&1obTpWofk$16jvsc>TCt_=N+Uksp_YP%U4K;Os5q?QU zG2*UV9RKBOe?Iy5Gl~7*T<_0e|MGbMi%+iV?d|Dk{m-X&^AffC^T`?Fm5E|B#jI?J z=NJFC=l}aHc~x7lf4OnuNsifh{KqGF1H>;#R-RsVhW;cwr5y%#UhZc+ZS4Ma*#B`t zbx%7hZ#!FMNpVRj5%GN@l6w`!{^M8w967~*{NjM0_d#1_8A-W)lKZUeME35LvlEfB zl9CaTm9UZ!k&=(;6p|mXwy1k(QH?lGrCFEi3-d@BI1Y z|M-fb`xzSt;<1!5l>fM)|NiX15C4A{=6`=(|8;_Yf35$A2AcFQONkieKWmg2U;F~& zyZ7J57oW+ip7C~Y_f$4?bmdpK^0acbw(?da4*suS{Kv!n?@vWkiGQ1i|GYy#E7Jd% zfjC(H&unq`G<0`&QC7Ed^ReRJX<+AOYv*a_xl2*(Kaco-yWjsRKmTzI3emsJX0d-3 zGUc6_%BYK4{s%Qw4gFFldIJqF+YM6Bh^=GXToQAKa_|21J8txhnl~;OpMEf++WYkB z&GwJC^Ls@Uu4GPlcORO)b2ad1C$DR^j;pDo!)XhawhuO*#}DOtbMPP9Z+k8@H1RXv z>a})_2>U+&w34$bqs`3reNFQdMyL9GZ_oR`e1U)VYiJBxuGmuZ3ktSYR0#+Q9?vC3 zM{BbQa|;R@tfz~LjyA0P|I5b_2@_-*@gF{Xpp30u7h4;4^(wouF#EHjqECGV#=^O# z*<)j4&xhMTe%yXmhmVhMVR6x7?wx}a4Gqon2{sN6zs6RLsS6S6qO~qE8AV0x3=9n7 zH{TSUICgAP^Xa`eZr*I`?4&8^y7=*1%s;Vl@h7FbH$SF2*bDwS8vvn)w z-Me?AFI))I%t+!%dD!u12yCPHUl<1kDec~~NB{Woh#NP!K79Q6$-*e>xQ}8c3kOGZ zbTo~Irl$2we`WN=i|389B6Kp<_4E=a{4`Q52NI=5TW*Cn+N#;v-JfiI{CIcDD@hL- zT=}h2VRUS)y0^EKw>%Gi)~#D-t0lx#TO|;Mr+xVF;eI>2k!>UIK781!a6^krmc;KZ ze{1rPc2>JuR(pEL+G>7A(oLIzL~D5k1$}dKhD(j-FI=F#c4Rw#KD4(t#%p%G%{iq) z&nZbMe~U3MFRw^NNJwa4WMrEHZ^;IB#;*HWS#)e{Y&&=DQuXkV2woVV_V)H}h(AC} zLr-7Bw>m>T_AB7ty?dB>YCc;%J%qWxUTSI4NmcY`v9q(2^%$gl{ra_^bF=#Ss3@D7 zXlCt0htv!VSnwn{!4GwfWxbEH$JQDN@6buDNKjdgo}2UO%4^s_Nkt_nA<<^Ef5V0i zGrxXa;fYPxw#u7A|f8< zToMhL-pP}(%gbknM@KWBJ-ht5I?;T2Wkn+3r^CGm53GNVwVmA_O_obiG&*r&Gwv}l zEiEBKDy<3o6kV-^+`95OB(2FH#`oNneA^Oo;Q(q>_gk8*T%t*s2FPD)9M;tO6N zUoKDkFg!Fw5ng%j;HB-Amf{ulQ3cNaIFfqo>sPgd2RC?nd3g*sFb9w8>Im@jlMU4; zXlZIvMKbY;Dlk4e7co@lq!?OW{6pWe2oPg^%6630{-%eoCN|NbHCIZRXJ)_dXm zch4@5=!wCRkq8N!y8fr7Q&rK-Lbmk+5xFEYGkg0T-@kv)wQFKuUjEUVKeTa|sDJ=@ z!Ra?uar^ojt}~c%)72j^$u^qkd$r|cvD--a^$d-RnPQpOlN@^uH&d9%4idsm5o{NcRQJo1a}~ z=vEwY2lLDMEH*bzwPsh$LDyrkdnowVr^zi=u^=rRdLlSS^+=H{9{4qCI z$G5hi)qF!bR{h~N>j7;86O$OWJw|u(^9_7h1rw4kUp}9CJAigzU?4xkZ!3E|rGoEN zO(esX=b{Wrl%b)aev9LocRRk>Y0b(CbFFDgV1k%^`+0@Z1F7$_=J*~A3-@o?e^vmC0ZZ3>xrs46@ zKXdML<6fOBF83IFMk`xi9A5bB8ULO=v3Bai_ZWHP&tKVd!qbR}ZHBf!)YQ~;=JlSO z3J0mz@oE|!iC3>iM$m2c?0iNsOIxps`jL0`x93%cq*!8xVZ3)JM4q%6kZmAdwSj@4 z0u}SG%BSX~xn83>T@pR)boJ!KGfaFcJnTa+$dVhp62QvF))+r<)mWBR0fj+%p`W5l zB3fGybJ6IDap;Q|@?H8pjC5M6zkdBPE^^`2D&1HjiwbYobhXl{@OAv45xyBPddt^R z=B8aezu@{*`7^Y9K|hlwINTy4G7@`w%tY589X{w zdZh&~?vj_6x2-4n3v(+3eQ(^cOr6y5W@YhP&RKp#a(rf-ZDirJ$v;{taPHhO-A_>w zHc>%Ka~`S6Nl_1zDRLCPyo;h=7AS}pa zD-N*L;@sY6&Q#h;HpZ)Ju;h|z{(j&gE0q)_@Ac*41dV8HgwVNfy&L^STZ9GUBZT^k zKL=mp360)rH4tqxu#x$fD%KTW%*L83=Ki4}A>za+FLYRbT@q$2bXxn%gO}6d8jh`} zq-==q&tEvDLylFm92MW7en3+bx1EpMMs={$;uqY2b#1FfG7;uhot>S{7uuLaDa?(w zpc?SXf_MhY4-fV8g`Nwu$KTP<(Db-Rn-moj9o;|aO+4s&Dyr{ATuD(S1Cd*B5=Xq- zo`7%J#91!9d;i|(tcLW=2)kOo;0mmj|!R)NImi_%p}WVLpX)1>(@N z>#jGvIdW4byMA=?Id41%d;GaQA`&aZmvjZUZq*o((io<}Te*e`U^iX->>26V4SwPf zww61psPO}8eu05msnOAwSy9zS(?WPxmgdVR_Quv$?cr7x<|Z#+ncD)061eO#+>mrl zC8X>{XtcI|tKtv(s_N>%~tRCI2#a3TGJUY?)<>&bO-S<6IFl6-!eC1z9 zG1SJ-9GEvd3wko6`_|edDEYjZJap)g-{GUgsS0VSpXZ*h+>`S%tfoeTjfFYs;j?E_ zioZS_>*#55kg9T#$x3Wc!lX3G{%DcXGFThy9~jqg(9YJjzso*tvVH6wS{m6|MlDvl zdd9%HiSc%y;NW26mwpm;aa%_FH8ehK-g~-v?ER5-r9PAE$odR6)l}tGqkO*w2+VSo z=3=-Vyy%GfSY7!jddzh3*SDzOKSpgYg%T92uG`0K-2fnyejs*nx#^USPW+@jE>K;S_kQ!Kv*fY0?=piP9K9KN|8NTM zl>AOM=3iTP?b^`Q)y1I{;GH(75WFmV=>zued65l7!i*JUxnTjy7Xi8Ma=jrAtF& zjt+LD$#OS!!#JmObdQ7tYk3|Z8fmd_Se_;s-@F-gW1J>VLF+|#F?4Le+Agu z+taCBwahb~=?k3RmHOH%kHl(VYI*@*r<=}sKb~vb$U^j~f}@+db^(keC@=1`I6Hfw z^eVmo^sD&*?wHpnoveu>JKyUIv?%hjJSRtt*RP-4*3Qlf=#6%}(06V}M@Qol&utHM zZaH;i=b-2gfB7=E!0G-dX7;P~@p%(3uf4nhV|RH~VlP}!Gcp3eSe{VUb#oI{{yn@2 zn6oQLSkSlQmE{eKoZ=F;Eh#|5A2M(YgGKstQ zDV8RT3=M^I?mgZA@uYigJdZ-+rAzO>bumQunAqBGoq9EI0f4c`ry01D=$f*=Q$5Fv zhuY(?aKnd(hxuh>jPgP_@dSwgK927n5XbP zyKK`!T7Q54SADm`scL3uwbt)3da_?jD@r|hFYt&a0H&m*Bx&refJ=7~!^p_Ug|sMb zSDU(vmFB*^5lKQ?@;?>v4FZnw1Telh7m<-1vhwZJ!>p|8R5>qhpLmaWL}(b4*|Pj;3gBN5|&z@$rV{=9)wSb?yLB^kyuKL3G#YA7w9JFjt>+TDKT*c+$GK z$CHjXWZ5HP(=XH{s=)cF+OnV}VwjG%9Na3neS4kHeYe(TvRB7Xol5Ai2xL%MTP}FJ zih^Yzn`Cb}K$DwEI!AZxo|xJ5jaF7xv=3h7W5o_F%no&y`ijMK%Y|XUj<+24mZqSh zuQ{O?3o(wf^-nG({g!X7L3SnW!b(ZwKCtX$x@1oO^#RVQ4H=uFCX{d zwO?tz$BRSCAiBJ0y9QxFp&6&1ew_wR$TCSHv&ODiu|F)%Plym5mTeB#a>en%7H zQIBUC-ObKEnrDO3O;4wF?p*|h*)^RYl!^<=TX(;9DolU)kOp&pr?BvF`27!i+S=O0 zIq0 zd%MxVQBfxv0ZQbD7ygtl=Kh8%a#6F%=35Gz z0k_U{%4rl97T&#guf}Kn@WYV1jdJ7O@_*T(CEC@@tjANW-#2dDAdn!pEUDt|DBuU) z4#|7K`~A50^XalB(ooz!`DL?okZ6y=nhlq)T)F$?34QtU_t**Tdv`iJjkj*!4r0iR zyHoS?dp@D9ly92d`QpqTPfyRcpFVw^`7wL-2G%ZFA#LVK(9AC_xAwdgExiF||GKGZ zb|^t*5Zz7u`Vq7JEeA9X91xI^VMjkEm>vrYOaJt=n8HWt$<92AE&JRI&&+wV6CIqa zkS_D4MNU12FMOanDl6D65L2kiRuYiw?&HU_ni?$vzXH_6(e>1p>;5wAS2 z(H7#A`T6hW?2jM6vb$JAQB_ZG<1PA9B^Hn#O~nnDWc>et_#cIkb=22^yu);ftNYNBSEMA@*&IBJ@no=yVb z2Wq206HDRIy0N$zASEM1khr5qk3zX|aC3`ncPf1Ksk=LHxnya2jx_~6ONxsDKa2Cz zOmUhNDk>`7OTE)))+VN>6UZs3_+@1|Dl032^3+JA++#|y_lwd(RypA#G&D7Ny*3eB z;Q2G|_9CfnkYKLKpV|FDH!Z%u-x7p60Mo;!v&eM|EiJ9BR>^Kmkv;=2b==ItL_zBe z5RKJDXWlhM|NO572Ah5v+1LopP4&hS+~m^K7h~CVW{%4%m_{B8Ggjv#BL$U|cmVx1 zj~ux;VXPs0c0nBYGdw+AuuESXbdJE;`9eRtO1wtVxx!OZxohg{h47tCJ9G@~&KyX0 z14gS~U0EVdm%>BYKSd$U9TOo`!A3V~ovE8vH~u~|&#IaV3Qhlmn{HJ{_w^1NRXa5L zV`&XweWQ}4om5m9`r0bd2=sqvZg)id2c-?8p9-BN&MuI;7q@wMctApmb#iuAx3Utz zL(la3elF?N`}Ov%UKg_&JDpadP9~JAWFB>WbQ+>%)boX0oS7kAOa@ z#BqpX0AsA|?1L!d`9rdXE-p|0QWJ<(FU$wbo|KjGmikWDP4$+NlkMvv5t7c&0HtT9 z*~8vjZ-Vqfe?kY3M4f2KU>~<3xC_mpBS&h$X7(sVIuXA^Q6oR+%6{(hWmZ(4lxzCe zCVUrvIVP(n{*N4}oWAj_E;cxE=6ySC>SpnweRut7i+qD+IdN@fto( zD4C6ycDR1yzNP4I&_2F)>-hftWHK(D{0fmxgKY74#>O1zxn=cUe;8}21HyHX8pM*I zBBP|Hwt<`x9T!*lMz6V>)RI+F(pBV>)My*l=1}wKSf*{g=b=A5D5VY%mgrlTE(s|_ zzL&W9rlGY}D>!&{+jKn!7!A^BKlC_eX69sr0N$+j3x7pB!xJZ}Q6bXP!wSUaEAbu) zM)dOj>8Mj7D{Q*Tzwb?Oh#t*o18iZJkdT0OSk!@qW~b$4GC4U3D*8-h_U)^_jVCM$ zb&ZWV2(1MKk1K~XA?`P0i5G_V)D%CM|HLTERd%ixa@pPY;~P0S9dF()UmAV*aOXkC zTUzSs6qpPiUz$0)15`n3A3lDp=IWX~;pa9!*X^FdQ#k^;KnLO<5PaSQ2k#Dk{tB5} zA@h5rq*$SLq#XUh$IU(QQ)s;9wh~=I7kxpO%SofVSkG~BaYgf})LdJ(_|qK;Lveay z@#;naeP_%GSs#qE#-T&BJNON+*II|xT33pdFTeX1R8>{wvW=CM)pn^QQ`!kj{_NSs z)f_EIdY?XhdfV3*+;u|%mAPo}`9f<^QIT?5)Q2nAuQ%rFlhJ9B&wmb4p{rjnB_;K| z*39DGQ`GK1Dhqw_TU{SAU((924x3NU90@u}u{W74eH(Ph? z5E2nN>O)^#S;ail?Otv^cN@r$UD%jkfPq;~O;1lRAwg+IVITM}`K?>Gl*-bQlf#y# zN_GD*L9v%J>+k@gfuE0Wj`yO%F+4mxD9uX2GWIRp7Gax8o|muw%F))=9-G~(Jh~Ok z{b7Fo_X}w&LwsxdQ86w!Mr-f#?eU;~aOApYZR?)hyDRE9*MdizyNaZuDA>#n*3vLC z8c8rScR8a4`z;Ja<-CY%b1>X-af|f;&5Mr#{E(&mR)3Gmr6xBVsHv;7Zc9JV(K7`| z7nPEdLL1Y=M5m?a&ij*F`K+u(@Nc_?-@hLvMn`L)feoOyz52qc4M6np>C-PF(qO2n z7{phm*7E4l7@++3ts@79AEC9*d~(ha5Eq}h(ap}z{y4EAD33G&1+6=4lK5ra7WbJ- zJ;5E9Qd2LUu<*a%QN9sHprbOTXA3AHYQog7BGYX4!&ikX&vclNR)7+oBp{|m!1y)? zsT&rqr;Z=DJETlIVO#14g6YoJ6?{bjOJ|iQ zy=K3bEi(d6)$5?uPrRQaCnxtCzn?;I2I_5s>3cTdt6SV(hBh}hD^L1@qaAk3oF(vA zy$%5Y3!P7-&EJGDxo?!at!-o%7e;;W=;ha&PUTV|gGym@Um#rU=P0Y!DpcVE{9iKn* zwW_Qsf>8-X9Annk(4f33cFL_I;CR-FoU#d}KV((EVQ#Y91Vj~=~O1_J5u`}>Gb_7!G6zJ!Shm*$)MayrzdW5x`C z9sPj8X2voSKK-irh3+vs5XHCq+C`AU#a|t#@~mrVOB42beL3>PIBy-Q?Qwp#B>S29 z`TCv`uRPC@Lw7^TH}Adq#yH=$kxgav4mr?f1RE=BfBD)8t4L5*h9)*j}adOpP1e0?u9#PSO~KPHPm7rog@+Qu!#9~m*k-;^R&4?GSbH?v`u zfY(@p$;m7(pPp@i>!3IMT;pjSh)r>?&z94zx3eAE$Tm}L06yK{X7g?>m&84mwzj;( zB5+drz^LwF9UVl?moS!zS4~wGcVEKia6rA2=Aw`xOvbJi$!~*eu@OV5~ zj%e^wyFCift6;b7@QrfH7I#A@<4L~%@+J4peeQK_8CpD^X9c^$!otK|KS>=)Q|1Aq zAvMUA{rlRIADcss8A){( zC+d6^xDUcF$ef@S3Qff=-@cgHp?Za7Gro{z3FWorAIj6kj_bNw zap9sx>D8hlnTf6fYKSsw5HYJ;wQO@@HtqOx2W$7AbSq513@3z#$tFVUV7Am9AgjRf z9uW8UTpRnUb4xzrRp9&}`V%0W(d0{wj^xC|a~M(^(6GlM)qQW@o`X95NxDC>_(Khf zTIWewGI4+sVUR*pE!z8EZ>dKy3W$j%gwt!^K=HPFVwlOmqdU$v#5Gu;1aK($2t#L-0F2(n35h$3 zN5N;Or|_ReOr!Uh^x|lmviaBVl=iK+YkfZlMG=P4!-v|YjGkgiNlD<22b`RC{|tEb zj2j@h;q_~@eZz@sf7#LbQNHdjO zWfsx|7sZckt-%(pc<#!_$FnAG)V|sw{158J-CreAM9u40@w7Jm@@Xk9ePiQjAS>93 zDI0+K(Ix)?r&n(;+=zeM*%|%oTgOm;WjLdpGM!fQ8aWx++S+8VzaguAnevR*`O}{r z^}6&`H4g0W39m6UOOZ*t~(?vc(_SQoUoVNyWO{Lt39_gC(o5@ z90#N}YS+c_WRPprKG-0*@#<-3@x`U;Q}bk4q`0c`cG1H~$qpu#?HX{p560 z1#^XIXvSWj31h{jiGuJ!u^NRlK0fJScf=dmwQIoTMfHc8m`%*^Tfp<+7B-pd@Da8k zIzjd#Hy4E#2UR@TM@H^jgyc|3&4)vx+PhiQ?i&ysakMo}%g$~ay8f_e%oBprY}$SV zJ(Awq#)f)w@Eo8iigwD@a7$T-{lu9J)-#gH%E<{xOS1t7l-suMqB(xzL=3N5l-6k7Ff z-Y{Tlfp~{rx^(HD>&bN3%T9${C!U&x9=acP=)PJ|(5oIhhQOAV7J{6SNaB!`H?pvV z&CJZGu4%ow^}$J+;0o_Ebr1K+1j<&4lPD8~NZviYz2MYRpPedkX_fn zDJ$>h=0>pXT$e7%=PzEoHjOn#hJf_z>+y%}PQGaPylNcq>|&%gC|Y^48Ib33_{b`vTEz z5O06}{COuclNyb4ZE?1q?~Pjsu^R zaLV(dbtg@A1!ow<5`8nXi=art#<^sWeG=NQe&M0@CRhFb=*bfeXrZu$@3uRQh}!Qj zcI&ksqp3LTv<}9)C4^ni6sxP~CIWJDoX{pbQ`9K?=YH-5JB6Em{tW~Dz)oqa&T8fg z*z8j*%|2-RgbxP88n%LHa&j`&$g{0d&+rTc*++HTDI#*ElslP&LhBr)zt`qrmLeh| z1k+^XQ@#k53EiKmz`ixIyu7^Ue%nSP1A{R1DO%LH1McoQJtM}p&zZjDQeu(^F5R8A zIhNJlSzymZ&{RNlLXc5b<^^u>Owp9l0r!BU1#=!3EsR-`eBkNpn^H=7Q(7w6>rit` z3*({tESL_SDS|hkfI&Zo+|8RegY&W%7W^2Cc~29u4JaFUeFD9)BH|u*+^CJWi&T8 z_e|MZ+FR=TqeLVWgS1mpk_FSTdR3(#Ws5ZaZre&nSy>svBUL!dulId{{{D@|0@okE zc)_*%3T=CPJ0cw%MM~FJF)6QG*^pDkuP6KmNHL~Ul2lh7JlKwC#rLO$!?+YPFK>Kq zZf@y=#?cTne<sEjMd`g934Kjk=WA7O!H@7n9E~-M)?2t3QzD?$RiIM=*k#P|? zjUHzF>hh>clX+e4z~p4yxpU`AAAB$Oy2Wwg#EF%TqJT!7;*SY#2iNyX(!OZz?(S|w z^M_nja+t@6_#V@v^^?ODyzvoV-rS73c#(e2bL+dFo{L|;oW9iet-t@ReGsSmx3->= z%jc%N4)gjya%RcROK%}OqI9q-lealQl-JpmUPj;d1!Rfl;aR0cx_I_Y!VtC zPEq9kxkX@2F!z;X0`*Q}9q^KOQ3b6v{)GX|~Ms*2cySIWND{ z@@*8#*9X`zE;t?6wt_h$q}$FtvkT3!SlLsP|Fu;#kM|}2k-4)=|Jf*G&1_m8^52PI}~a_+owmgf^EgeZP`}^xoX%3VFx0#v(oYRD|%344+?#p8lIYpKYCNf3Pt+k zt_#tNdb_XqEln0D-M;NMmlwszqh@cPx#~PeI&ak<{fEAJ_XN%NM#03XXl>OUz7Rd8 zgWg_WT~!0{R40FL`6lRJW&MC6{LBvZb{O{qMdC~ zn6_+8-WJxXZ)Eg<@4DtyoBrr~rKMY7_1!)&3Y=1jy3jE>$!U;SY>or7>6R533>j3JHXp?g1)9HoMWWdKvod2G`?*k|bB{tP$n^E~JD)jT z>bECbeBad-1JXPYD^@1%_=r;Qq_oGN22o3(F+V=ua?0F1Zf$jXO%s*t;Iuu{AISTK zl97x6o;k1PxKeN3$~Mq-cNfbqDDZ&22bsY5K7*hf(S;!jqbwLXXTXwhe>odzlJbc2 z4|EdWM>^M?vJSZ^hhNvzb#E)iKv3X@9&6+p)nLj>yFU5Sr6h!X5XUen%my`Ho?ctc z=?eGoJ9w0+Kx*r#pDQKy7j{@wUz4zTqSxLliuY6<#RT{2^H*2qn9A<%EwP)$>XNq| z?w^`+`!$EVBVt~3@>l<2P8tSoGLnx^-C?m;=XV`@5N&qFDmyzHV!JwU81iph9WOO- z1A-9T8dk?vXRp@VN((>V>#pZ(<&76dr4-)4eG9oW#npu&!Q-|!5RioFOo*;BzrXBE zlD^2N!h7)GL4*s#Vq;@%CuO9it>9b`iszW(pEb<9{~~6A3ePLIUU}e5=Est{s;cCO zz(J!s*Vkv!*qu3Gk7&yC(c6KEsj2iKAt8<3DuHvtaMG3ZS39l$4u)`jv;q508UFVI7i1_d^@-4M*xQ-NQa3~@Kw7Y^z2L}wXDy?HHT4~eiR?({mm6^ zxKZYnR5ilf`tKlPDR;gqOtb@PYU==nY{y@Hegx!vvd9GzYvIGuk!{ihcsCXzkrCVm z=`>Ys?dY*l_VlMu83_g@EUaN-a=mBdE&qMP-Gr#r5dLujr@^W!@Uz?> z0#Jj(bFPqrnhdshu2cK&=2W@&k0)u4BW{_WFG&~+NLjs{-&+G1Xaz1$Un}#Uo6K1@3{Om4 zY-rHNsu$e7o0gd4H?JO~S5i_Ua%jpcKaVv=E*1Qfh1o*^A)d>QXWS+p7c+Ymz_$C! z*QcA));P@w3d6#Z9s*nlUbBBH|A-H~ZEi)sjex|-MNOD&X0z`#$3#!n*3}K(jpF6{ zSviEuqdff_zb*|r12=p3l|yU#ph%gSS`Q9IQQtR+K>-3B`lb>Y5z%OV)$#@JQ7^9o z;mN%&C?cKL-n}!peD$g|Dy6ort`=n5o^96&D;+p6=)v`zoScp*y`x7NJ~$PQshdO* zZWT@@^q0&nretJf^xQXj0xkll2hq{Ui6)Pp7iVJc3XxINYhJm0`Odw2lt`7 zgN0FYIA0rP1#-fRXZhetAyZlb1puk$Xrvx9{?aix{g)n@{sv7G0=>hHpp)ST8R>J- zukn^fL|bdv(JqOnJ^5siJ%rcnRopsw)Ix*7*W(KNdgO{Io zHBlRH!8Nc*EXAqf;}a5?AlBvj%?_$6V9fg5~i!N!it>9QZ;WC%9FDxxpAcQzZG($On|T$z2BcZWv|Nf;*9b31FC7B3eXn zt+n(Asw0Rq5h-V#+lq2yVu5{)?7`IZny6S46BA$%!YN{>>Hz;{Ay`;`d}2bB7nk5f z@~)@Au0+5@OpFOq5iZUGl49u$l8Y)Z@Zr%hlCN()2wWo4qtN4;%-I<{@D61Czi&m+ zA`MinFKNn)28HR_)+vl4JvUdhX7k=bifB)#PjAQ4+=wDjQ&XedTEB5aJK!`zR>)u8 zMTBt5Q=_`+T~*hryAJ0?ZaEgn0SF1Cl(Oo>Sry!~ht9;r1XQ=?@~&gVNzR|A{KMyY zyAtU(i{62I4RK8`3p~|^4FcGIF*9Ld`p>~j**$jAI$7<4V1eLaWNsm8;IOCwTYhee zPW}o0uV-j@Z@Sjo$LFTXylVsJam(5TfE38nQxZ9hjOD^*w02 z9^LM_->e`C+zjO5PakINoEM;RFSwgylqqjWIVSgPYtY%(_Mio9Mk09G58(hJ0fW?j zVxBw;VK;-D!Q3Q7CQ*x*(P$YZOFpE;_C)n-G=F_ZA4(GF%kap^ zcyS!(Ud{5BLqM(&c_VvMEyLSxePaXRGAr?1zx#@laZh-jhMHO!22u+680Jw$1!n~` zsRYD;d70~RK^B8jEf(3Vekc4mYU9C_P^`Xb+Vr&Gsi~>p zj?vqo1n1f7)^N-y-rc;3CnqmYlpq*G zS4&x|CIi`DtnWH9Lh!&_ToGyl4zwAFtoIf^Xu0)mI&m^!FlNWFsFk*5f3ziR56H4r zD2OAX5tL(-laM&XQpC20gZRtVoZ4EXFgeTr14jO9^L5NI&9$}bVY6HBm3-|Q z2V9FraK@Oi#vN(H;kN~?`=iG|>NG7a@ATMhOrimlk^t*1Y2q*dqKCv(l@qe!44tvj zoR-np!yJptWolf8?RLZY^ z0*=cD&OIS+iyy zW@nPLsj!V?A!lt-Ovglsf-3$98p%w($|^G^5Y#LwmnTTCA>jx9>>@$3y^3TVlghFl zab77j(^D&7PtY(irIcQ_iVNLKL#z@41|fvfbAKa)96_LvPLQh~;Kw@IO2pEUhEdK@ z-^xNwO%2DG3s4l(VsVW_HXNpq{R}vX=YH~}^?0wd&3jw-KQer6PTL!bbHly1nxE>$ zj7TnJ6}&k(J|5Gab;1VrF7A^`oJ1vo<$+K)Y3r6YveeX6B(pA{nE$YN!(UgCM@}e1 zC0;uq9bqy#yghjIXzc~IJ^f$4Z1>$IMMf3RuxrnrYUJMZ5Z3nHrIGJRB2`pH&=DRQ zgw@yPjMt+>ZNiC~)Ect7=}*&9+qw%+LA0c`Irp`?J9(<~+*^EBm;Hg6i1hcALG+W? zn3Z@&O;b}Y@R?!JC`#*odUB}DmB{mXAnj0cSb*h9X66oTUdcn^Q&vHt$(+$7I&|-O zL}C9hFvu~8RrHK(+`x{VNgqBK!c)}8E`b7B{B&fk{}|spaWm{&spKFn*nnA z5!=FS7Djad#@)!u$r%HzLnxOB$l!XC*8PcnwXvHCFQlqU4LJ!sa@S6jKM;Juzkqz` z^4@#(6$0Tz=#S`xFcD#sse{b*Y-{6ZXJtJP%#3@pf`^1thO<&c9WgL6iUcDf4lgP) zn)1{>t)ruJP0Eo4>DLR$gI0EQoR~^(z+7o?0fZ!AIMi!cIZ^TPj3tK!H=G9s2J#~^ zMA+4X2Xxs;5hZMdE(ghQ(o>v%!$7cboB>-Ny*^?6WWM%#K~!C-%%4{;pId3 zAr6bzSKL*7R8X)9Q21}5&sZHoG4+`IBwf;U=@#~?Tt2i7KY*Y8qodSdQA7#|&YEY6 zmMxy##Q-}EfC3QKqlIdZNJgmz(uU|(Y=BtA&b&!A9tLr zt+;EYp3!y(7e+#23<>}m1z`ZZe;|W9vB!XD=S-3SxJt^ zz>||aJjQ?EB|oe3JuI~#PV9|j@$uZeUqhpsf&#lEw^mjln0D~*FX*vpGMVy!`Qy$e zb20`dg5RRi5cLOnsR4{LaB*&NF-$9JVhDJ6;*d%pOzXM1s#V7?U%sRxpmc8@!btV| z_nVZJm1nTA2!_}IHe@_BzXiOpJgyre`Ry9v55j4Jkd8pFD)=JyKRD|1sGK3Hgq__0 zjQHp9XRw^!wzsd}w{IW769Hw24N`yeoicpj9VhDCdvpwI}C z)Iy4ig{My=U;j`)BlpZVBgMH+o9%oy2m6;l5E|h3CNZ1wclWpR32F9^;gJS(Ll!p? zqH95d2-GPeRRDxrIhlFyo+V=bL}%*v+SnU2Ptx{QS)QRljyV#d8ZF}%vgbaNTtqtA zrRO=b=d$_bn>S;z#b^MnSPh29@FX^7^rOGmK!9wPpMqjljT;cA-9knX&M&QL3BUxV z-n@c5RE#l)fOP>yN=i!7Zy~w;xn^y-buHRQ*~=AyMqntAmgM5z?(SG(H^)BrKB@7Q zQ^CKt89g=Ifb8R;CFI5l{Rx~#LynKZom*;ux+xlR+3KQm#!`4#7~#>OgjKb+G9dwj z=*a@|53?gFr?CI+eZL2M0eNUwp$B5wH#~+aV1iM8ZQhL>CsF0V+tZ&td-l1n6Ge3f z`}~H)LVm~Ind9N+Cao-<311@cIP4x+*_)9|37R`$WF)wE?>QOZatIx{zQ9ssvgklB2Eqx#+<%70V`R_OG^pSBlZ*C!+ z$1~qPax!coL%pm6mJY*CkhcC+1ki1uGN-o(?$FiMU0y0*Q~3Vl$1LV0ZtSLenPXef zqgBwUcVqKUjk1=MitgO0aOfn$3K(#^aw`h5`My9xxMSwx3h3}bYf}8tyq82Gjm`U| zhl-Q5SvQNCi3fNELOU{kPP*GTN^Er_b_;|r^@Xejss6g|L}a)?bBF|W_|l#|d-9+( zW)<=w8cZt9%5pBRhe{JjRlEcf0Jpk*{s_ivDj?ngDljauI=r0$RGoKn(HE`y6L(^R zfjcP>UU6Ibr?|X=f@=JpVG1cSHGlt-u3y)`6_>AwY(IL#mh>4NE&JosyuSD7G;zG| zQFlSoxO$3lBNw@(Uq9i(ZihcIHIW*T+`AXqUb~O88g;~DMY{P=RH!p4Z5=Z>0)Y>b zF#XhC?*w%hMn=Yk*0p8b@Fj#n>kVaj|hc+=IziOmV(0nOOl5&rSxN9AtJ*XDr8 zaUBJpiHeK_<=tb(f;Jqowt4UkxPrb^ryh3n#e1!W?8Gp&_smzW!%9Ejs#6s^OL1j= zAfYu8TRVb^u*cvB6b|u#)V#DHqHZSeikJpzTpi4H$j8>x!nT3tI?=<|iQNhPbC}+h zqf$`@k80r4c_2rpyab>oj^NX!R!k2OZh7y9er2o!paWu$ELNuP)v+p4AL;L>`$yU+7jSq{B2jjF^(l( zYzfQ$^i=Kc{=mS}Hu3UHd1>Y7Go5zKCg(%d*}sjAi9hds7eyJzlhfv~_2$Vp#{H-Y z#)Z8|@DMR5n71GS=H>6daxDF3lDd3D+lih#|5{$5voKGi-2}*gVB>=~`(zaMhZOKc zKZ1imq{0s!y3n>{TNk{F=vs#KVIfJVH;J_u%@^SZ6^y<7_`=Yh(dKh_adEN9s0RqF zzJ5~M3fec(oRBN>n&>XhX}!pR;26|BiKq_TgM`xaaNa)!gUyf$9c0MuhGQSp0&kmj0G`Fm{M%kv&L2v-l7oS2yD@oF_O za}I&ua{-|UM17k3SFyX=c!k#h=5^&jE7_v(rR;)$UrrgD&cf&9qGsgg$nAvyU^P@1 zM-}LUV1#km+27|z`Ttz=2MYGQiHN}{f@cJfhuyNu1R@wTw|VpCAz*;2XO8blBd^)Q zNBzD&%1lg50Icq!b~>I3Vs1r3)DQVi`=lb%1c}y2mwYs8tRc5;0u-;fJVTv7p|U{+p0+ zaw`0E&ubA)XKi&QS$W2P2iOI&5;hgNoJiWl_uC-*oafqI6rA~!XftRg1YroLD;XaP z@Ox0Sgn-Rn7j4#;_cYT_0($yP^=!ak#I^z)MIefDsHo5!+|%Rx@WCf$B?edLLc5z3 zCwfXYVHY0f%qu8JfZCGIyC`j-E|dBz$ceq6gI>(!sA9=$3khqeJkB>M`d>=$@bV&-hw|c>P~|t~UZjs;SydxT zO39;ZOM`0HP9$61LzcE+o0hfrelpThvYxfIAkhmy9MiP|6+T^T*P_IY0*XIFQU#|Q z>fJSQt967MiY*=1*fe&!nBiv#ll>i2aA+bL0saR!&l*CNrq=!IfR}?rf(uJ1@z$;0 zX>CpMH|c~M%5)klkg`s=GWRkR<75&lbqW?DJ_w;0g>5gPUX^(3=vWWU~S@Sf;a S${_y0*ueuj8c)?M!~QRV4(|;B literal 0 HcmV?d00001 diff --git a/server/package.json b/server/package.json index 4f07e68b..0b998240 100644 --- a/server/package.json +++ b/server/package.json @@ -66,6 +66,7 @@ "mysql2": "^3.9.8", "node-html-markdown": "^1.3.0", "node-llama-cpp": "^2.8.0", + "odbc": "^2.4.8", "ollama": "^0.5.0", "openai": "4.38.5", "pg": "^8.11.5", @@ -101,4 +102,4 @@ "nodemon": "^2.0.22", "prettier": "^3.0.3" } -} +} \ No newline at end of file diff --git a/server/utils/agents/aibitat/plugins/sql-agent/SQLConnectors/ODBC.js b/server/utils/agents/aibitat/plugins/sql-agent/SQLConnectors/ODBC.js new file mode 100644 index 00000000..d4f58464 --- /dev/null +++ b/server/utils/agents/aibitat/plugins/sql-agent/SQLConnectors/ODBC.js @@ -0,0 +1,60 @@ +const odbc = require("odbc"); +const UrlPattern = require("url-pattern"); + +class ODBCConnector { + #connected = false; + database_id = ""; + constructor( + config = { + connectionString: null, + } + ) { + this.connectionString = config.connectionString; + this._client = null; + this.database_id = this.#parseDatabase(); + } + + #parseDatabase() { + const regex = /Database=([^;]+)/; + const match = this.connectionString.match(regex); + return match ? match[1] : null; + } + + async connect() { + this._client = await odbc.connect(this.connectionString); + this.#connected = true; + return this._client; + } + + /** + * + * @param {string} queryString the SQL query to be run + * @returns {import(".").QueryResult} + */ + async runQuery(queryString = "") { + const result = { rows: [], count: 0, error: null }; + try { + if (!this.#connected) await this.connect(); + const query = await this._client.query(queryString); + result.rows = query; + result.count = query.length; + } catch (err) { + console.log(this.constructor.name, err); + result.error = err.message; + } finally { + await this._client.close(); + this.#connected = false; + } + return result; + } + + getTablesSql() { + return `SELECT table_name FROM information_schema.tables WHERE table_schema = '${this.database_id}'`; + } + + getTableSchemaSql(table_name) { + return `SHOW COLUMNS FROM ${this.database_id}.${table_name};`; + } +} + +module.exports.ODBCConnector = ODBCConnector; diff --git a/server/utils/agents/aibitat/plugins/sql-agent/SQLConnectors/index.js b/server/utils/agents/aibitat/plugins/sql-agent/SQLConnectors/index.js index 9cf1e1ff..2e153b7e 100644 --- a/server/utils/agents/aibitat/plugins/sql-agent/SQLConnectors/index.js +++ b/server/utils/agents/aibitat/plugins/sql-agent/SQLConnectors/index.js @@ -2,7 +2,7 @@ const { SystemSettings } = require("../../../../../../models/systemSettings"); const { safeJsonParse } = require("../../../../../http"); /** - * @typedef {('postgresql'|'mysql'|'sql-server')} SQLEngine + * @typedef {('postgresql'|'mysql'|'sql-server'|'odbc')} SQLEngine */ /** @@ -36,6 +36,9 @@ function getDBClient(identifier = "", connectionConfig = {}) { case "sql-server": const { MSSQLConnector } = require("./MSSQL"); return new MSSQLConnector(connectionConfig); + case "odbc": + const { ODBCConnector } = require("./ODBC"); + return new ODBCConnector(connectionConfig); default: throw new Error( `There is no supported database connector for ${identifier}` diff --git a/server/yarn.lock b/server/yarn.lock index 3c5484d4..96df39c4 100644 --- a/server/yarn.lock +++ b/server/yarn.lock @@ -673,7 +673,7 @@ "@langchain/core" "~0.1" js-tiktoken "^1.0.11" -"@mapbox/node-pre-gyp@^1.0.11": +"@mapbox/node-pre-gyp@^1.0.11", "@mapbox/node-pre-gyp@^1.0.5": version "1.0.11" resolved "https://registry.yarnpkg.com/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.11.tgz#417db42b7f5323d79e93b34a6d7a2a12c0df43fa" integrity sha512-Yhlar6v9WQgUp/He7BdgzOz8lqMQ8sU+jkCq7Wx8Myc5YFJLbEe7lgui/V7G1qB1DJykHSGwreceSaD60Y0PUQ== @@ -1588,7 +1588,7 @@ arrify@^2.0.0: resolved "https://registry.yarnpkg.com/arrify/-/arrify-2.0.1.tgz#c9655e9331e0abcd588d2a7cad7e9956f66701fa" integrity sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug== -async@^3.2.3, async@^3.2.4: +async@^3.0.1, async@^3.2.3, async@^3.2.4: version "3.2.5" resolved "https://registry.yarnpkg.com/async/-/async-3.2.5.tgz#ebd52a8fdaf7a2289a24df399f8d8485c8a46b66" integrity sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg== @@ -4813,6 +4813,11 @@ node-abort-controller@^3.1.1: resolved "https://registry.yarnpkg.com/node-abort-controller/-/node-abort-controller-3.1.1.tgz#a94377e964a9a37ac3976d848cb5c765833b8548" integrity sha512-AGK2yQKIjRuqnc6VkX2Xj5d+QW8xZ87pa1UK6yA6ouUyuxfHuMP6umE5QK7UmTeOAymo+Zx1Fxiuw9rVx8taHQ== +node-addon-api@^3.0.2: + version "3.2.1" + resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-3.2.1.tgz#81325e0a2117789c0128dab65e7e38f07ceba161" + integrity sha512-mmcei9JghVNDYydghQmeDX8KoAm0FAiYyIcUt/N4nhyAipB17pllZQDOJD2fotxABnt4Mdz+dKTO7eftLg4d0A== + node-addon-api@^5.0.0: version "5.1.0" resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-5.1.0.tgz#49da1ca055e109a23d537e9de43c09cca21eb762" @@ -5065,6 +5070,15 @@ octokit@^3.1.0: "@octokit/request-error" "^5.0.0" "@octokit/types" "^12.0.0" +odbc@^2.4.8: + version "2.4.8" + resolved "https://registry.yarnpkg.com/odbc/-/odbc-2.4.8.tgz#56e34a1cafbaf1c2c53eec229b3a7604f890e3bf" + integrity sha512-W4VkBcr8iSe8hqpp2GoFPybCAJefC7eK837XThJkYCW4tBzyQisqkciwt1UYidU1OpKy1589y9dMN0tStiVB1Q== + dependencies: + "@mapbox/node-pre-gyp" "^1.0.5" + async "^3.0.1" + node-addon-api "^3.0.2" + ollama@^0.5.0: version "0.5.0" resolved "https://registry.yarnpkg.com/ollama/-/ollama-0.5.0.tgz#cb9bc709d4d3278c9f484f751b0d9b98b06f4859"