diff --git a/.env.example b/.env.example index e68216db..53db2cd8 100644 --- a/.env.example +++ b/.env.example @@ -5,3 +5,10 @@ MYSQL_URL= PLANETSCALE_HOST=aws.connect.psdb.cloud PLANETSCALE_USERNAME=username PLANETSCALE_PASSWORD=password + +# MSSQL +MSSQL_HOST=localhost +MSSQL_PORT=1433 +MSSQL_USERNAME=sa +MSSQL_PASSWORD=password +MSSQL_DB_NAME=test_db \ No newline at end of file diff --git a/docs/2.connectors/1.index.md b/docs/2.connectors/1.index.md index f993a907..447ba5e4 100644 --- a/docs/2.connectors/1.index.md +++ b/docs/2.connectors/1.index.md @@ -15,6 +15,7 @@ Currently supported connectors: - [PostgreSQL](/connectors/postgresql) - [MySQL](/connectors/mysql) - [SQLite](/connectors/sqlite) +- [MSSQL](/connectors/mssql) ::read-more{to="https://github.com/unjs/db0/issues/32"} See [unjs/db0#32](https://github.com/unjs/db0/issues/32) for the list of upcoming connectors. diff --git a/docs/2.connectors/mssql.md b/docs/2.connectors/mssql.md new file mode 100644 index 00000000..090c96c3 --- /dev/null +++ b/docs/2.connectors/mssql.md @@ -0,0 +1,30 @@ +--- +icon: devicon-plain:microsoftsqlserver +--- + +# MSSQL + +> Connect DB0 to MSSQL Database using `tedious` + +## Usage + +For this connector, you need to install [`tedious`](https://www.npmjs.com/package/tedious) dependency: + +:pm-install{name="tedious"} + +Use `mssql` connector: + +```js +import { createDatabase } from "db0"; +import mssql from "db0/connectors/mssql"; + +const db = createDatabase( + mssql({ + /* options */ + }), +); +``` + +## Options + +:read-more{to="https://tediousjs.github.io/tedious/api-connection.html#function_newConnection"} diff --git a/package.json b/package.json index 40d97b90..b1f00600 100644 --- a/package.json +++ b/package.json @@ -73,6 +73,7 @@ "pg": "^8.13.1", "prettier": "^3.4.2", "scule": "^1.3.0", + "tedious": "^18.6.1", "typescript": "^5.7.3", "unbuild": "^3.3.1", "vitest": "^3.0.4" @@ -83,7 +84,8 @@ "better-sqlite3": "*", "drizzle-orm": "*", "mysql2": "*", - "sqlite3": "*" + "sqlite3": "*", + "tedious": "*" }, "peerDependenciesMeta": { "@libsql/client": { @@ -98,6 +100,9 @@ "mysql2": { "optional": true }, + "tedious": { + "optional": true + }, "@electric-sql/pglite": { "optional": true }, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 6a3c4478..373dbf0f 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -78,6 +78,9 @@ importers: scule: specifier: ^1.3.0 version: 1.3.0 + tedious: + specifier: ^18.6.1 + version: 18.6.1 typescript: specifier: ^5.7.3 version: 5.7.3 @@ -109,6 +112,70 @@ packages: resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==} engines: {node: '>=6.0.0'} + '@azure/abort-controller@2.1.2': + resolution: {integrity: sha512-nBrLsEWm4J2u5LpAPjxADTlq3trDgVZZXHNKabeXZtpq3d3AbN/KGO82R87rdDz5/lYB024rtEf10/q0urNgsA==} + engines: {node: '>=18.0.0'} + + '@azure/core-auth@1.9.0': + resolution: {integrity: sha512-FPwHpZywuyasDSLMqJ6fhbOK3TqUdviZNF8OqRGA4W5Ewib2lEEZ+pBsYcBa88B2NGO/SEnYPGhyBqNlE8ilSw==} + engines: {node: '>=18.0.0'} + + '@azure/core-client@1.9.2': + resolution: {integrity: sha512-kRdry/rav3fUKHl/aDLd/pDLcB+4pOFwPPTVEExuMyaI5r+JBbMWqRbCY1pn5BniDaU3lRxO9eaQ1AmSMehl/w==} + engines: {node: '>=18.0.0'} + + '@azure/core-http-compat@2.1.2': + resolution: {integrity: sha512-5MnV1yqzZwgNLLjlizsU3QqOeQChkIXw781Fwh1xdAqJR5AA32IUaq6xv1BICJvfbHoa+JYcaij2HFkhLbNTJQ==} + engines: {node: '>=18.0.0'} + + '@azure/core-lro@2.7.2': + resolution: {integrity: sha512-0YIpccoX8m/k00O7mDDMdJpbr6mf1yWo2dfmxt5A8XVZVVMz2SSKaEbMCeJRvgQ0IaSlqhjT47p4hVIRRy90xw==} + engines: {node: '>=18.0.0'} + + '@azure/core-paging@1.6.2': + resolution: {integrity: sha512-YKWi9YuCU04B55h25cnOYZHxXYtEvQEbKST5vqRga7hWY9ydd3FZHdeQF8pyh+acWZvppw13M/LMGx0LABUVMA==} + engines: {node: '>=18.0.0'} + + '@azure/core-rest-pipeline@1.17.0': + resolution: {integrity: sha512-62Vv8nC+uPId3j86XJ0WI+sBf0jlqTqPUFCBNrGtlaUeQUIXWV/D8GE5A1d+Qx8H7OQojn2WguC8kChD6v0shA==} + engines: {node: '>=18.0.0'} + + '@azure/core-tracing@1.2.0': + resolution: {integrity: sha512-UKTiEJPkWcESPYJz3X5uKRYyOcJD+4nYph+KpfdPRnQJVrZfk0KJgdnaAWKfhsBBtAf/D58Az4AvCJEmWgIBAg==} + engines: {node: '>=18.0.0'} + + '@azure/core-util@1.11.0': + resolution: {integrity: sha512-DxOSLua+NdpWoSqULhjDyAZTXFdP/LKkqtYuxxz1SCN289zk3OG8UOpnCQAz/tygyACBtWp/BoO72ptK7msY8g==} + engines: {node: '>=18.0.0'} + + '@azure/identity@4.5.0': + resolution: {integrity: sha512-EknvVmtBuSIic47xkOqyNabAme0RYTw52BTMz8eBgU1ysTyMrD1uOoM+JdS0J/4Yfp98IBT3osqq3BfwSaNaGQ==} + engines: {node: '>=18.0.0'} + + '@azure/keyvault-common@2.0.0': + resolution: {integrity: sha512-wRLVaroQtOqfg60cxkzUkGKrKMsCP6uYXAOomOIysSMyt1/YM0eUn9LqieAWM8DLcU4+07Fio2YGpPeqUbpP9w==} + engines: {node: '>=18.0.0'} + + '@azure/keyvault-keys@4.9.0': + resolution: {integrity: sha512-ZBP07+K4Pj3kS4TF4XdkqFcspWwBHry3vJSOFM5k5ZABvf7JfiMonvaFk2nBF6xjlEbMpz5PE1g45iTMme0raQ==} + engines: {node: '>=18.0.0'} + + '@azure/logger@1.1.4': + resolution: {integrity: sha512-4IXXzcCdLdlXuCG+8UKEwLA1T1NHqUfanhXYHiQTn+6sfWCZXduqbtXDGceg3Ce5QxTGo7EqmbV6Bi+aqKuClQ==} + engines: {node: '>=18.0.0'} + + '@azure/msal-browser@3.27.0': + resolution: {integrity: sha512-+b4ZKSD8+vslCtVRVetkegEhOFMLP3rxDWJY212ct+2r6jVg6OSQKc1Qz3kCoXo0FgwaXkb+76TMZfpHp8QtgA==} + engines: {node: '>=0.8.0'} + + '@azure/msal-common@14.16.0': + resolution: {integrity: sha512-1KOZj9IpcDSwpNiQNjt0jDYZpQvNZay7QAEi/5DLubay40iGYtLzya/jbjRPLyOTZhEKyL1MzPuw2HqBCjceYA==} + engines: {node: '>=0.8.0'} + + '@azure/msal-node@2.16.0': + resolution: {integrity: sha512-oww0oJTOOvPKTVXqVyxfcFVjExQKYEkKR5KM0cTG3jnzt6u/MRMx8XaK49L/bxV35r9sCHQFjNlEShad9qGSYA==} + engines: {node: '>=16'} + '@babel/code-frame@7.26.2': resolution: {integrity: sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==} engines: {node: '>=6.9.0'} @@ -719,6 +786,9 @@ packages: '@jridgewell/trace-mapping@0.3.25': resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==} + '@js-joda/core@5.6.3': + resolution: {integrity: sha512-T1rRxzdqkEXcou0ZprN1q9yDRlvzCPLqmlNt5IIsGBzoEVgLCCYrKEwc84+TvsXuAc95VAZwtWD2zVsKPY4bcA==} + '@libsql/client@0.14.0': resolution: {integrity: sha512-/9HEKfn6fwXB5aTEEoMeFh4CtG0ZzbncBb1e++OCdVpgKZ/xyMsIVYXm0w7Pv4RUel803vE6LwniB3PqD72R0Q==} @@ -1074,6 +1144,9 @@ packages: '@types/pg@8.11.11': resolution: {integrity: sha512-kGT1qKM8wJQ5qlawUrEkXgvMSXoV213KfMGXcwfDwUIfUHXqXYXOfS1nE1LINRJVVVx5wCm70XnFlMHaIcQAfw==} + '@types/readable-stream@4.0.18': + resolution: {integrity: sha512-21jK/1j+Wg+7jVw1xnSwy/2Q1VgVjWuFssbYGTREPUBeZ+rqVFl2udq0IkxzPC0ZhOzVceUbyIACFZKLqKEBlA==} + '@types/resolve@1.20.2': resolution: {integrity: sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==} @@ -1177,6 +1250,10 @@ packages: abbrev@1.1.1: resolution: {integrity: sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==} + abort-controller@3.0.0: + resolution: {integrity: sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==} + engines: {node: '>=6.5'} + acorn-jsx@5.3.2: resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} peerDependencies: @@ -1191,6 +1268,10 @@ packages: resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==} engines: {node: '>= 6.0.0'} + agent-base@7.1.1: + resolution: {integrity: sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==} + engines: {node: '>= 14'} + agentkeepalive@4.6.0: resolution: {integrity: sha512-kja8j7PjmncONqaTsB8fQ+wE2mSU2DJ9D4XKoJ5PFWIdRMa6SLSN1ff4mOr4jCbfRSsxR4keIiySJU0N9T5hIQ==} engines: {node: '>= 8.0.0'} @@ -1271,6 +1352,9 @@ packages: bl@4.1.0: resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==} + bl@6.0.16: + resolution: {integrity: sha512-V/kz+z2Mx5/6qDfRCilmrukUXcXuCoXKg3/3hDvzKKoSUx8CJKudfIoT29XZc3UE9xBvxs5qictiHdprwtteEg==} + boolbase@1.0.0: resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==} @@ -1294,12 +1378,18 @@ packages: engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} hasBin: true + buffer-equal-constant-time@1.0.1: + resolution: {integrity: sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==} + buffer-from@1.1.2: resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} buffer@5.7.1: resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==} + buffer@6.0.3: + resolution: {integrity: sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==} + builtin-modules@3.3.0: resolution: {integrity: sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==} engines: {node: '>=6'} @@ -1589,6 +1679,10 @@ packages: resolution: {integrity: sha512-WY/3TUME0x3KPYdRRxEJJvXRHV4PyPoUsxtZa78lwItwRQRHhd2U9xOscaT/YTf8uCXIAjeJOFBVEh/7FtD8Xg==} engines: {node: '>=18'} + define-lazy-prop@2.0.0: + resolution: {integrity: sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==} + engines: {node: '>=8'} + define-lazy-prop@3.0.0: resolution: {integrity: sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==} engines: {node: '>=12'} @@ -1817,6 +1911,9 @@ packages: eastasianwidth@0.2.0: resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} + ecdsa-sig-formatter@1.0.11: + resolution: {integrity: sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==} + electron-to-chromium@1.5.74: resolution: {integrity: sha512-ck3//9RC+6oss/1Bh9tiAVFy5vfSKbRHAFh7Z3/eTRkEqJeWgymloShB17Vg3Z4nmDNp35vAd1BZ6CMW4Wt6Iw==} @@ -1975,6 +2072,14 @@ packages: event-emitter@0.3.5: resolution: {integrity: sha512-D9rRn9y7kLPnJ+hMq7S/nhvoKwwvVJahBi2BPmx3bvbsEdK3W9ii8cBSGjP+72/LnM4n6fo3+dkCX5FeTQruXA==} + event-target-shim@5.0.1: + resolution: {integrity: sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==} + engines: {node: '>=6'} + + events@3.3.0: + resolution: {integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==} + engines: {node: '>=0.8.x'} + execa@8.0.1: resolution: {integrity: sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==} engines: {node: '>=16.17'} @@ -2195,10 +2300,18 @@ packages: resolution: {integrity: sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==} engines: {node: '>= 6'} + http-proxy-agent@7.0.2: + resolution: {integrity: sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==} + engines: {node: '>= 14'} + https-proxy-agent@5.0.1: resolution: {integrity: sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==} engines: {node: '>= 6'} + https-proxy-agent@7.0.5: + resolution: {integrity: sha512-1e4Wqeblerz+tMKPIq2EMGiiWW1dIjZOksyHWSUm1rmuvw/how9hBHZ38lAGj5ID4Ik6EdkOw7NmWPy6LAwalw==} + engines: {node: '>= 14'} + human-signals@5.0.0: resolution: {integrity: sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==} engines: {node: '>=16.17.0'} @@ -2274,6 +2387,11 @@ packages: is-decimal@1.0.4: resolution: {integrity: sha512-RGdriMmQQvZ2aqaQq3awNA6dCGtKpiDFcOzrTWrDAT2MiWrKQVPmxLGHl7Y2nNu6led0kEyoX0enY0qXYsv9zw==} + is-docker@2.2.1: + resolution: {integrity: sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==} + engines: {node: '>=8'} + hasBin: true + is-docker@3.0.0: resolution: {integrity: sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} @@ -2326,6 +2444,10 @@ packages: resolution: {integrity: sha512-ZhMwEosbFJkA0YhFnNDgTM4ZxDRsS6HqTo7qsZM08fehyRYIYa0yHu5R6mgo1n/8MgaPBXiPimPD77baVFYg+A==} engines: {node: '>=12.13'} + is-wsl@2.2.0: + resolution: {integrity: sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==} + engines: {node: '>=8'} + is-wsl@3.1.0: resolution: {integrity: sha512-UcVfVfaK4Sc4m7X3dUSoHoozQGBEFeDC+zVo06t98xe8CzHSZZBekNXH+tu0NalHolcJ/QAGqS46Hef7QXBIMw==} engines: {node: '>=16'} @@ -2363,6 +2485,9 @@ packages: js-base64@3.7.7: resolution: {integrity: sha512-7rCnleh0z2CkXhH67J8K1Ytz0b2Y+yxTPL+/KOJoa20hfnVQ/3/T6W/KflYI4bRHRagNeXeU2bkNGI3v1oS/lw==} + js-md4@0.3.2: + resolution: {integrity: sha512-/GDnfQYsltsjRswQhN9fhv3EMw2sCpUdrdxyWDOUK7eyD++r3gRhzgiQgc/x4MAv2i1iuQ4lxO5mvqM3vj4bwA==} + js-tokens@4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} @@ -2403,6 +2528,22 @@ packages: engines: {node: '>=6'} hasBin: true + jsonwebtoken@9.0.2: + resolution: {integrity: sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ==} + engines: {node: '>=12', npm: '>=6'} + + jwa@1.4.1: + resolution: {integrity: sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==} + + jwa@2.0.0: + resolution: {integrity: sha512-jrZ2Qx916EA+fq9cEAeCROWPTfCwi1IVHqT2tapuqLEVVDKFDENFw1oL+MwrTvH6msKxsd1YTDVw6uKEcsrLEA==} + + jws@3.2.2: + resolution: {integrity: sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==} + + jws@4.0.0: + resolution: {integrity: sha512-KDncfTmOZoOMTFG4mBlG0qUIOlc03fmzH+ru6RgYVZhPkyiy/92Owlt/8UEN+a4TXR1FQetfIpJE8ApdvdVxTg==} + keyv@4.5.4: resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} @@ -2435,12 +2576,33 @@ packages: lodash.deburr@4.1.0: resolution: {integrity: sha512-m/M1U1f3ddMCs6Hq2tAsYThTBDaAKFDX3dwDo97GEYzamXi9SqUpjWi/Rrj/gf3X2n8ktwgZrlP1z6E3v/IExQ==} + lodash.includes@4.3.0: + resolution: {integrity: sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==} + + lodash.isboolean@3.0.3: + resolution: {integrity: sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==} + + lodash.isinteger@4.0.4: + resolution: {integrity: sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==} + + lodash.isnumber@3.0.3: + resolution: {integrity: sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==} + + lodash.isplainobject@4.0.6: + resolution: {integrity: sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==} + + lodash.isstring@4.0.1: + resolution: {integrity: sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==} + lodash.memoize@4.1.2: resolution: {integrity: sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==} lodash.merge@4.6.2: resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} + lodash.once@4.1.1: + resolution: {integrity: sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==} + lodash.throttle@4.1.1: resolution: {integrity: sha512-wIkUCfVKpVsWo3JSZlc+8MB5it+2AN5W8J7YVMST30UrvcQNZ1Okbj+rbVniijTWE6FGYy4XJq/rHkas8qJMLQ==} @@ -2642,6 +2804,9 @@ packages: napi-build-utils@2.0.0: resolution: {integrity: sha512-GEbrYkbfF7MoNaoh2iGG84Mnf/WZfB0GdGEsM8wz7Expx/LlWf5U8t9nvJKXSp3qr5IsEbK04cBGhol/KwOsWA==} + native-duplexpair@1.0.0: + resolution: {integrity: sha512-E7QQoM+3jvNtlmyfqRZ0/U75VFgCls+fSkbml2MpgWkWyz3ox8Y58gNhfuziuQYGNNQAbFZJQck55LHCnCK6CA==} + natural-compare@1.4.0: resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} @@ -2731,6 +2896,10 @@ packages: resolution: {integrity: sha512-mnkeQ1qP5Ue2wd+aivTD3NHd/lZ96Lu0jgf0pwktLPtx6cTZiH7tyeGRRHs0zX0rbrahXPnXlUnbeXyaBBuIaw==} engines: {node: '>=18'} + open@8.4.2: + resolution: {integrity: sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==} + engines: {node: '>=12'} + optionator@0.9.4: resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} engines: {node: '>= 0.8.0'} @@ -3112,6 +3281,10 @@ packages: resolution: {integrity: sha512-mQUvGU6aUFQ+rNvTIAcZuWGRT9a6f6Yrg9bHs4ImKF+HZCEK+plBvnAZYSIQztknZF2qnzNtr6F8s0+IuptdlQ==} engines: {node: ^14.13.1 || >=16.0.0} + process@0.11.10: + resolution: {integrity: sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==} + engines: {node: '>= 0.6.0'} + promise-inflight@1.0.1: resolution: {integrity: sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g==} peerDependencies: @@ -3156,6 +3329,10 @@ packages: resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==} engines: {node: '>= 6'} + readable-stream@4.5.2: + resolution: {integrity: sha512-yjavECdqeZ3GLXNgRXgeQEdz9fvDDkNKyHnbHRFtOr7/LcfgBcmct7t/ET+HaCTqfh06OzoAxrkN/IfjJBVe+g==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + readdirp@3.6.0: resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} engines: {node: '>=8.10.0'} @@ -3223,6 +3400,9 @@ packages: run-parallel@1.2.0: resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} + safe-buffer@5.1.2: + resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==} + safe-buffer@5.2.1: resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} @@ -3341,6 +3521,10 @@ packages: std-env@3.8.0: resolution: {integrity: sha512-Bc3YwwCB+OzldMxOXJIIvC6cPRWr/LxOp48CdQTOkPyk/t4JWWJbrilwBd7RJzKV8QW7tJkcgAmeuLLJugl5/w==} + stoppable@1.1.0: + resolution: {integrity: sha512-KXDYZ9dszj6bzvnEMRYvxgeTHU74QBFL54XKtP3nyMuJ81CFYtABZ3bAzL2EdFUaEwJOBOgENyFj3R7oTzDyyw==} + engines: {node: '>=4', npm: '>=6'} + string-width@4.2.3: resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} engines: {node: '>=8'} @@ -3410,6 +3594,10 @@ packages: resolution: {integrity: sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==} engines: {node: '>=10'} + tedious@18.6.1: + resolution: {integrity: sha512-9AvErXXQTd6l7TDd5EmM+nxbOGyhnmdbp/8c3pw+tjaiSXW9usME90ET/CRG1LN1Y9tPMtz/p83z4Q97B4DDpw==} + engines: {node: '>=18'} + test-exclude@7.0.1: resolution: {integrity: sha512-pFYqmTw68LXVjeWJMST4+borgQP2AyMNbg1BpZh9LbyhUeNkeaPF9gzfPGUAnSMV3qPYdWUwDIjjCLiSDOl7vg==} engines: {node: '>=18'} @@ -3450,6 +3638,9 @@ packages: peerDependencies: typescript: '>=4.8.4' + tslib@2.8.1: + resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} + tunnel-agent@0.6.0: resolution: {integrity: sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==} @@ -3533,6 +3724,10 @@ packages: util-deprecate@1.0.2: resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} + uuid@8.3.2: + resolution: {integrity: sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==} + hasBin: true + validate-npm-package-license@3.0.4: resolution: {integrity: sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==} @@ -3690,6 +3885,134 @@ snapshots: '@jridgewell/gen-mapping': 0.3.8 '@jridgewell/trace-mapping': 0.3.25 + '@azure/abort-controller@2.1.2': + dependencies: + tslib: 2.8.1 + + '@azure/core-auth@1.9.0': + dependencies: + '@azure/abort-controller': 2.1.2 + '@azure/core-util': 1.11.0 + tslib: 2.8.1 + + '@azure/core-client@1.9.2': + dependencies: + '@azure/abort-controller': 2.1.2 + '@azure/core-auth': 1.9.0 + '@azure/core-rest-pipeline': 1.17.0 + '@azure/core-tracing': 1.2.0 + '@azure/core-util': 1.11.0 + '@azure/logger': 1.1.4 + tslib: 2.8.1 + transitivePeerDependencies: + - supports-color + + '@azure/core-http-compat@2.1.2': + dependencies: + '@azure/abort-controller': 2.1.2 + '@azure/core-client': 1.9.2 + '@azure/core-rest-pipeline': 1.17.0 + transitivePeerDependencies: + - supports-color + + '@azure/core-lro@2.7.2': + dependencies: + '@azure/abort-controller': 2.1.2 + '@azure/core-util': 1.11.0 + '@azure/logger': 1.1.4 + tslib: 2.8.1 + + '@azure/core-paging@1.6.2': + dependencies: + tslib: 2.8.1 + + '@azure/core-rest-pipeline@1.17.0': + dependencies: + '@azure/abort-controller': 2.1.2 + '@azure/core-auth': 1.9.0 + '@azure/core-tracing': 1.2.0 + '@azure/core-util': 1.11.0 + '@azure/logger': 1.1.4 + http-proxy-agent: 7.0.2 + https-proxy-agent: 7.0.5 + tslib: 2.8.1 + transitivePeerDependencies: + - supports-color + + '@azure/core-tracing@1.2.0': + dependencies: + tslib: 2.8.1 + + '@azure/core-util@1.11.0': + dependencies: + '@azure/abort-controller': 2.1.2 + tslib: 2.8.1 + + '@azure/identity@4.5.0': + dependencies: + '@azure/abort-controller': 2.1.2 + '@azure/core-auth': 1.9.0 + '@azure/core-client': 1.9.2 + '@azure/core-rest-pipeline': 1.17.0 + '@azure/core-tracing': 1.2.0 + '@azure/core-util': 1.11.0 + '@azure/logger': 1.1.4 + '@azure/msal-browser': 3.27.0 + '@azure/msal-node': 2.16.0 + events: 3.3.0 + jws: 4.0.0 + open: 8.4.2 + stoppable: 1.1.0 + tslib: 2.8.1 + transitivePeerDependencies: + - supports-color + + '@azure/keyvault-common@2.0.0': + dependencies: + '@azure/abort-controller': 2.1.2 + '@azure/core-auth': 1.9.0 + '@azure/core-client': 1.9.2 + '@azure/core-rest-pipeline': 1.17.0 + '@azure/core-tracing': 1.2.0 + '@azure/core-util': 1.11.0 + '@azure/logger': 1.1.4 + tslib: 2.8.1 + transitivePeerDependencies: + - supports-color + + '@azure/keyvault-keys@4.9.0': + dependencies: + '@azure/abort-controller': 2.1.2 + '@azure/core-auth': 1.9.0 + '@azure/core-client': 1.9.2 + '@azure/core-http-compat': 2.1.2 + '@azure/core-lro': 2.7.2 + '@azure/core-paging': 1.6.2 + '@azure/core-rest-pipeline': 1.17.0 + '@azure/core-tracing': 1.2.0 + '@azure/core-util': 1.11.0 + '@azure/keyvault-common': 2.0.0 + '@azure/logger': 1.1.4 + tslib: 2.8.1 + transitivePeerDependencies: + - supports-color + + '@azure/logger@1.1.4': + dependencies: + tslib: 2.8.1 + + '@azure/msal-browser@3.27.0': + dependencies: + '@azure/msal-common': 14.16.0 + + '@azure/msal-common@14.16.0': {} + + '@azure/msal-node@2.16.0': + dependencies: + '@azure/msal-common': 14.16.0 + jsonwebtoken: 9.0.2 + uuid: 8.3.2 + '@babel/code-frame@7.26.2': dependencies: '@babel/helper-validator-identifier': 7.25.9 @@ -4122,6 +4445,8 @@ snapshots: '@jridgewell/resolve-uri': 3.1.2 '@jridgewell/sourcemap-codec': 1.5.0 + '@js-joda/core@5.6.3': {} + '@libsql/client@0.14.0': dependencies: '@libsql/core': 0.14.0 @@ -4416,6 +4741,11 @@ snapshots: pg-protocol: 1.7.0 pg-types: 4.0.2 + '@types/readable-stream@4.0.18': + dependencies: + '@types/node': 22.10.2 + safe-buffer: 5.1.2 + '@types/resolve@1.20.2': {} '@types/sqlite3@3.1.11': @@ -4570,6 +4900,10 @@ snapshots: abbrev@1.1.1: optional: true + abort-controller@3.0.0: + dependencies: + event-target-shim: 5.0.1 + acorn-jsx@5.3.2(acorn@8.14.0): dependencies: acorn: 8.14.0 @@ -4583,6 +4917,12 @@ snapshots: - supports-color optional: true + agent-base@7.1.1: + dependencies: + debug: 4.4.0 + transitivePeerDependencies: + - supports-color + agentkeepalive@4.6.0: dependencies: humanize-ms: 1.2.1 @@ -4685,6 +5025,13 @@ snapshots: inherits: 2.0.4 readable-stream: 3.6.2 + bl@6.0.16: + dependencies: + '@types/readable-stream': 4.0.18 + buffer: 6.0.3 + inherits: 2.0.4 + readable-stream: 4.5.2 + boolbase@1.0.0: {} brace-expansion@1.1.11: @@ -4714,6 +5061,8 @@ snapshots: node-releases: 2.0.19 update-browserslist-db: 1.1.2(browserslist@4.24.4) + buffer-equal-constant-time@1.0.1: {} + buffer-from@1.1.2: {} buffer@5.7.1: @@ -4721,6 +5070,11 @@ snapshots: base64-js: 1.5.1 ieee754: 1.2.1 + buffer@6.0.3: + dependencies: + base64-js: 1.5.1 + ieee754: 1.2.1 + builtin-modules@3.3.0: {} bun-types@1.2.0: @@ -5058,6 +5412,8 @@ snapshots: bundle-name: 4.1.0 default-browser-id: 5.0.0 + define-lazy-prop@2.0.0: {} + define-lazy-prop@3.0.0: {} defu@6.1.4: {} @@ -5158,6 +5514,10 @@ snapshots: eastasianwidth@0.2.0: {} + ecdsa-sig-formatter@1.0.11: + dependencies: + safe-buffer: 5.2.1 + electron-to-chromium@1.5.74: {} electron-to-chromium@1.5.87: {} @@ -5433,6 +5793,10 @@ snapshots: d: 1.0.2 es5-ext: 0.10.64 + event-target-shim@5.0.1: {} + + events@3.3.0: {} + execa@8.0.1: dependencies: cross-spawn: 7.0.6 @@ -5673,6 +6037,13 @@ snapshots: - supports-color optional: true + http-proxy-agent@7.0.2: + dependencies: + agent-base: 7.1.1 + debug: 4.4.0 + transitivePeerDependencies: + - supports-color + https-proxy-agent@5.0.1: dependencies: agent-base: 6.0.2 @@ -5681,6 +6052,13 @@ snapshots: - supports-color optional: true + https-proxy-agent@7.0.5: + dependencies: + agent-base: 7.1.1 + debug: 4.4.0 + transitivePeerDependencies: + - supports-color + human-signals@5.0.0: {} humanize-ms@1.2.1: @@ -5750,6 +6128,8 @@ snapshots: is-decimal@1.0.4: {} + is-docker@2.2.1: {} + is-docker@3.0.0: {} is-extglob@2.1.1: {} @@ -5785,6 +6165,10 @@ snapshots: is-what@4.1.16: {} + is-wsl@2.2.0: + dependencies: + is-docker: 2.2.1 + is-wsl@3.1.0: dependencies: is-inside-container: 1.0.0 @@ -5824,6 +6208,8 @@ snapshots: js-base64@3.7.7: {} + js-md4@0.3.2: {} + js-tokens@4.0.0: {} js-yaml@4.1.0: @@ -5853,6 +6239,41 @@ snapshots: json5@2.2.3: {} + jsonwebtoken@9.0.2: + dependencies: + jws: 3.2.2 + lodash.includes: 4.3.0 + lodash.isboolean: 3.0.3 + lodash.isinteger: 4.0.4 + lodash.isnumber: 3.0.3 + lodash.isplainobject: 4.0.6 + lodash.isstring: 4.0.1 + lodash.once: 4.1.1 + ms: 2.1.3 + semver: 7.6.3 + + jwa@1.4.1: + dependencies: + buffer-equal-constant-time: 1.0.1 + ecdsa-sig-formatter: 1.0.11 + safe-buffer: 5.2.1 + + jwa@2.0.0: + dependencies: + buffer-equal-constant-time: 1.0.1 + ecdsa-sig-formatter: 1.0.11 + safe-buffer: 5.2.1 + + jws@3.2.2: + dependencies: + jwa: 1.4.1 + safe-buffer: 5.2.1 + + jws@4.0.0: + dependencies: + jwa: 2.0.0 + safe-buffer: 5.2.1 + keyv@4.5.4: dependencies: json-buffer: 3.0.1 @@ -5891,10 +6312,24 @@ snapshots: lodash.deburr@4.1.0: {} + lodash.includes@4.3.0: {} + + lodash.isboolean@3.0.3: {} + + lodash.isinteger@4.0.4: {} + + lodash.isnumber@3.0.3: {} + + lodash.isplainobject@4.0.6: {} + + lodash.isstring@4.0.1: {} + lodash.memoize@4.1.2: {} lodash.merge@4.6.2: {} + lodash.once@4.1.1: {} + lodash.throttle@4.1.1: {} lodash.uniq@4.5.0: {} @@ -6127,6 +6562,8 @@ snapshots: napi-build-utils@2.0.0: {} + native-duplexpair@1.0.0: {} + natural-compare@1.4.0: {} negotiator@0.6.4: @@ -6235,6 +6672,12 @@ snapshots: is-inside-container: 1.0.0 is-wsl: 3.1.0 + open@8.4.2: + dependencies: + define-lazy-prop: 2.0.0 + is-docker: 2.2.1 + is-wsl: 2.2.0 + optionator@0.9.4: dependencies: deep-is: 0.1.4 @@ -6597,6 +7040,8 @@ snapshots: pretty-bytes@6.1.1: {} + process@0.11.10: {} + promise-inflight@1.0.1: optional: true @@ -6648,6 +7093,14 @@ snapshots: string_decoder: 1.3.0 util-deprecate: 1.0.2 + readable-stream@4.5.2: + dependencies: + abort-controller: 3.0.0 + buffer: 6.0.3 + events: 3.3.0 + process: 0.11.10 + string_decoder: 1.3.0 + readdirp@3.6.0: dependencies: picomatch: 2.3.1 @@ -6727,6 +7180,8 @@ snapshots: dependencies: queue-microtask: 1.2.3 + safe-buffer@5.1.2: {} + safe-buffer@5.2.1: {} safer-buffer@2.1.2: {} @@ -6812,8 +7267,7 @@ snapshots: split2@4.2.0: {} - sprintf-js@1.1.3: - optional: true + sprintf-js@1.1.3: {} sqlite3@5.1.7: dependencies: @@ -6838,6 +7292,8 @@ snapshots: std-env@3.8.0: {} + stoppable@1.1.0: {} + string-width@4.2.3: dependencies: emoji-regex: 8.0.0 @@ -6922,6 +7378,21 @@ snapshots: mkdirp: 1.0.4 yallist: 4.0.0 + tedious@18.6.1: + dependencies: + '@azure/core-auth': 1.9.0 + '@azure/identity': 4.5.0 + '@azure/keyvault-keys': 4.9.0 + '@js-joda/core': 5.6.3 + '@types/node': 22.10.2 + bl: 6.0.16 + iconv-lite: 0.6.3 + js-md4: 0.3.2 + native-duplexpair: 1.0.0 + sprintf-js: 1.1.3 + transitivePeerDependencies: + - supports-color + test-exclude@7.0.1: dependencies: '@istanbuljs/schema': 0.1.3 @@ -6956,6 +7427,8 @@ snapshots: dependencies: typescript: 5.7.3 + tslib@2.8.1: {} + tunnel-agent@0.6.0: dependencies: safe-buffer: 5.2.1 @@ -7068,6 +7541,8 @@ snapshots: util-deprecate@1.0.2: {} + uuid@8.3.2: {} + validate-npm-package-license@3.0.4: dependencies: spdx-correct: 3.2.0 diff --git a/scripts/gen-connectors.ts b/scripts/gen-connectors.ts index 98131082..ae8219cf 100644 --- a/scripts/gen-connectors.ts +++ b/scripts/gen-connectors.ts @@ -47,6 +47,10 @@ const connectors: { optionsTName?: string; }[] = []; +const connectorOptionsNameAliases: Record = { + "mssql": "MSSQL" +}; + for (const entry of connectorEntries) { const pathName = entry.replace(/\.ts$/, ""); const name = pathName.replace(/\/|\\/g, "-"); @@ -64,7 +68,7 @@ for (const entry of connectorEntries) { const names = [...new Set([name, ...alternativeNames])]; - const optionsTName = upperFirst(safeName) + "Options"; + const optionsTName = (connectorOptionsNameAliases[name] || upperFirst(safeName)) + "Options"; connectors.push({ name, diff --git a/src/_connectors.ts b/src/_connectors.ts index 9740135a..1dad9c37 100644 --- a/src/_connectors.ts +++ b/src/_connectors.ts @@ -7,13 +7,14 @@ import type { ConnectorOptions as LibSQLCoreOptions } from "db0/connectors/libsq import type { ConnectorOptions as LibSQLHttpOptions } from "db0/connectors/libsql/http"; import type { ConnectorOptions as LibSQLNodeOptions } from "db0/connectors/libsql/node"; import type { ConnectorOptions as LibSQLWebOptions } from "db0/connectors/libsql/web"; +import type { ConnectorOptions as MSSQLOptions } from "db0/connectors/mssql"; import type { ConnectorOptions as MySQL2Options } from "db0/connectors/mysql2"; import type { ConnectorOptions as NodeSQLite3Options } from "db0/connectors/node-sqlite3"; import type { ConnectorOptions as PgliteOptions } from "db0/connectors/pglite"; import type { ConnectorOptions as PlanetscaleOptions } from "db0/connectors/planetscale"; import type { ConnectorOptions as PostgreSQLOptions } from "db0/connectors/postgresql"; -export type ConnectorName = "better-sqlite3" | "sqlite" | "bun-sqlite" | "bun" | "cloudflare-d1" | "libsql-core" | "libsql-http" | "libsql-node" | "libsql" | "libsql-web" | "mysql2" | "node-sqlite3" | "pglite" | "planetscale" | "postgresql"; +export type ConnectorName = "better-sqlite3" | "sqlite" | "bun-sqlite" | "bun" | "cloudflare-d1" | "libsql-core" | "libsql-http" | "libsql-node" | "libsql" | "libsql-web" | "mssql" | "mysql2" | "node-sqlite3" | "pglite" | "planetscale" | "postgresql"; export type ConnectorOptions = { "better-sqlite3": BetterSQLite3Options; @@ -29,6 +30,7 @@ export type ConnectorOptions = { /** @deprecated Alias of libsql-node */ "libsql": LibSQLNodeOptions; "libsql-web": LibSQLWebOptions; + "mssql": MSSQLOptions; "mysql2": MySQL2Options; "node-sqlite3": NodeSQLite3Options; "pglite": PgliteOptions; @@ -50,6 +52,7 @@ export const connectors = Object.freeze({ /** @deprecated Alias of libsql-node */ "libsql": "db0/connectors/libsql/node", "libsql-web": "db0/connectors/libsql/web", + "mssql": "db0/connectors/mssql", "mysql2": "db0/connectors/mysql2", "node-sqlite3": "db0/connectors/node-sqlite3", "pglite": "db0/connectors/pglite", diff --git a/src/connectors/mssql.ts b/src/connectors/mssql.ts new file mode 100644 index 00000000..640efa47 --- /dev/null +++ b/src/connectors/mssql.ts @@ -0,0 +1,207 @@ +import { + Connection, + Request, + Connection as TediousConnection, + type ConnectionConfiguration, + TYPES, +} from "tedious"; +import type { DataType } from "tedious/lib/data-type"; + +import type { Connector, Statement } from "../types"; + +export type ConnectorOptions = ConnectionConfiguration; + +export default function mssqlConnector(opts: ConnectorOptions) { + let _client: undefined | TediousConnection; + async function getClient(): Promise { + if (_client && _client.state === _client.STATE.LOGGED_IN) { + return _client; + } + + return new Promise((resolve, reject) => { + const client = new Connection(opts); + client.connect((error) => { + if (error) { + reject(error); + } + + _client = client; + }); + + client.on('connect', () => resolve(_client)); + client.on('error', reject); + }); + }; + + async function _run(sql: string, parameters?: unknown[]) { + if (!sql) { + throw new Error('SQL query must be provided'); + } + + const connection = await getClient(); + const { + sql: _sql, + parameters: _parameters, + } = prepareSqlParameters(sql, parameters); + + const query = new Promise<{ rows: unknown[], success: boolean }>((resolve, reject) => { + let success = false; + const request = new Request(_sql, (error) => { + if (error) { + reject(error); + } else { + success = true; + } + }); + + const parameterKeys = Object.keys(_parameters); + for (const key of parameterKeys) { + const parameter = _parameters[key]; + + request.addParameter( + parameter.name, + parameter.type, + parameter.value + ); + } + + const rows: unknown[] = []; + request.on('row', (columns = []) => { + const currentRow = {}; + for (const column of columns) { + const { value, metadata } = column; + const { colName } = metadata; + + currentRow[colName] = value; + } + + rows.push(currentRow); + }); + + request.on('requestCompleted', () => { + connection.close(); + resolve({ rows, success }); + }); + + request.on('error', (error) => { + connection.close(); + reject(error); + }); + + connection.execSql(request); + }); + + try { + const { + rows, + success, + } = await query; + + return { + rows, + success, + }; + } catch (error) { + error.sql = _sql; + error.parameters = parameters; + console.error(error); + } + } + + return >{ + name: "mssql", + dialect: "mssql", + exec(sql: string) { + return _run(sql, []); + }, + prepare(sql: string) { + const statement = { + _sql: sql, + _params: [], + bind(...params) { + if (params.length > 0) { + this._params = params; + } + return statement; + }, + async all(...params) { + const { rows } = await _run(this._sql, params || this._params); + return rows; + }, + async run(...params) { + const { success = false } = await _run(this._sql, params || this._params) || {}; + return { + success, + }; + }, + async get(...params) { + const { rows: [ row ] } = await _run(this._sql, params || this._params); + return row; + }, + }; + + return statement; + }, + }; +}; + +// taken from the `kysely` library: https://github.com/kysely-org/kysely/blob/413a88516c20be42dc8cbebade68c27669a3ac1a/src/dialect/mssql/mssql-driver.ts#L440 +export function getTediousDataType(value: unknown): DataType { + if (value === null || value === undefined || typeof value === 'string') { + return TYPES.NVarChar; + } + + if (typeof value === 'bigint' || (typeof value === 'number' && value % 1 === 0)) { + return value < -2_147_483_648 || value > 2_147_483_647 ? TYPES.BigInt : TYPES.Int; + } + + if (typeof value === 'number') { + return TYPES.Float; + } + + if (typeof value === 'boolean') { + return TYPES.Bit; + } + + if (value instanceof Date) { + return TYPES.DateTime2; + } + + if (typeof Buffer !== 'undefined' && Buffer.isBuffer(value)) { + return TYPES.VarBinary; + } + + return TYPES.NVarChar; +}; + +// replace `?` placeholders with `@1`, `@2`, etc. +export function prepareSqlParameters(sql: string, parameters: unknown[]) { + const parameterIndexes = []; + const tokens = [...sql]; + + // find all `?` placeholders in the SQL string + for (const [i, token] of tokens.entries()) { + + if (token === '?') { + parameterIndexes.push(i); + } + }; + + const namedParameters = {}; + for (const [index, parameterIndex] of parameterIndexes.entries()) { + const incrementedIndex = index + 1; + // replace `?` placeholder with index-based parameter name + tokens[parameterIndex] = `@${incrementedIndex}`; + // store the parameter value and type with the index-based parameter name + namedParameters[`@${incrementedIndex}`] = { + name: String(incrementedIndex), + type: getTediousDataType(parameters[index]), + value: parameters[index], + }; + } + + return { + sql: tokens.join(''), // join the tokens back into a SQL string + parameters: namedParameters, + }; +}; diff --git a/src/types.ts b/src/types.ts index 978a3f6a..84305a9c 100644 --- a/src/types.ts +++ b/src/types.ts @@ -3,7 +3,7 @@ */ export type Primitive = string | number | boolean | undefined | null; -export type SQLDialect = "mysql" | "postgresql" | "sqlite" | "libsql"; +export type SQLDialect = "mysql" | "postgresql" | "sqlite" | "libsql" | "mssql"; export type Statement = { /** diff --git a/test/connectors/_tests.ts b/test/connectors/_tests.ts index 230d5472..46ae854d 100644 --- a/test/connectors/_tests.ts +++ b/test/connectors/_tests.ts @@ -36,6 +36,15 @@ export function testConnector(opts: { await db.sql`CREATE TABLE users (\`id\` VARCHAR(4) PRIMARY KEY, \`firstName\` TEXT, \`lastName\` TEXT, \`email\` TEXT)`; break; } + case "mssql": { + await db.sql`CREATE TABLE users ( + [id] NVARCHAR(4) PRIMARY KEY, + [firstName] NVARCHAR(255), + [lastName] NVARCHAR(255), + [email] NVARCHAR(255) + )`; + break; + } default: { await db.sql`CREATE TABLE users ("id" TEXT PRIMARY KEY, "firstName" TEXT, "lastName" TEXT, "email" TEXT)`; break; diff --git a/test/connectors/mssql.test.ts b/test/connectors/mssql.test.ts new file mode 100644 index 00000000..ffad5adc --- /dev/null +++ b/test/connectors/mssql.test.ts @@ -0,0 +1,122 @@ +import { describe, it, expect } from "vitest"; +import { TYPES } from "tedious"; + +import { getTediousDataType, prepareSqlParameters } from "../../src/connectors/mssql"; +import connector from "../../src/connectors/mssql"; +import { testConnector } from "./_tests"; + +describe.runIf( + process.env.MSSQL_HOST + && process.env.MSSQL_DB_NAME + && process.env.MSSQL_USERNAME + && process.env.MSSQL_PASSWORD +)( + "connectors: mssql.test", + () => { + testConnector({ + dialect: "mssql", + connector: connector({ + server: process.env.MSSQL_HOST!, + authentication: { + type: 'default', + options: { + userName: process.env.MSSQL_USERNAME!, + password: process.env.MSSQL_PASSWORD!, + }, + }, + options: { + database: process.env.MSSQL_DB_NAME!, + port: Number.parseInt(process.env.MSSQL_PORT || '1433', 10), + trustServerCertificate: true, + encrypt: false, + }, + }), + }); + }, +); + +describe("getTediousDataType", () => { + it("should return NVarChar for null", () => { + expect(getTediousDataType(null)).toBe(TYPES.NVarChar); + }); + + it("should return NVarChar for undefined", () => { + expect(getTediousDataType(undefined)).toBe(TYPES.NVarChar); + }); + + it("should return NVarChar for strings", () => { + expect(getTediousDataType("test")).toBe(TYPES.NVarChar); + }); + + it("should return Int for numbers", () => { + expect(getTediousDataType(123)).toBe(TYPES.Int); + }); + + it("should return BigInt for large integer numbers", () => { + expect(getTediousDataType(2_147_483_648)).toBe(TYPES.BigInt); + }); + + it("should return Float for floating point numbers", () => { + expect(getTediousDataType(123.45)).toBe(TYPES.Float); + }); + + it("should return Bit for boolean values", () => { + expect(getTediousDataType(true)).toBe(TYPES.Bit); + }); + + it("should return DateTime for Date objects", () => { + expect(getTediousDataType(new Date())).toBe(TYPES.DateTime2); + }); + + it("should return VarBinary for Buffer objects", () => { + expect(getTediousDataType(Buffer.from("test"))).toBe(TYPES.VarBinary); + }); + + it("should return NVarChar by default for other types", () => { + expect(getTediousDataType({})).toBe(TYPES.NVarChar); + }); +}); + +describe("prepareSqlParameters", () => { + it("should replace ? with @1, @2, etc.", () => { + const sql = "SELECT * FROM users WHERE id = ? AND name = ?"; + const parameters = [1, "John"]; + const result = prepareSqlParameters(sql, parameters); + expect(result.sql).toBe("SELECT * FROM users WHERE id = @1 AND name = @2"); + expect(result.parameters).toEqual({ + "@1": { name: "1", type: TYPES.Int, value: 1 }, + "@2": { name: "2", type: TYPES.NVarChar, value: "John" }, + }); + }); + + it("should handle no parameters", () => { + const sql = "SELECT * FROM users"; + const parameters: unknown[] = []; + const result = prepareSqlParameters(sql, parameters); + expect(result.sql).toBe("SELECT * FROM users"); + expect(result.parameters).toEqual({}); + }); + + it("should handle multiple parameters of different types", () => { + const sql = "SELECT * FROM users WHERE id = ? AND age = ? AND active = ?"; + const parameters = [1, 30, true]; + const result = prepareSqlParameters(sql, parameters); + expect(result.sql).toBe("SELECT * FROM users WHERE id = @1 AND age = @2 AND active = @3"); + expect(result.parameters).toEqual({ + "@1": { name: "1", type: TYPES.Int, value: 1 }, + "@2": { name: "2", type: TYPES.Int, value: 30 }, + "@3": { name: "3", type: TYPES.Bit, value: true }, + }); + }); + + it("should handle null and undefined parameters", () => { + const sql = "SELECT * FROM users WHERE name = ? AND email = ?"; + const parameters = [null, undefined]; + const result = prepareSqlParameters(sql, parameters); + expect(result.sql).toBe("SELECT * FROM users WHERE name = @1 AND email = @2"); + expect(result.parameters).toEqual({ + "@1": { name: "1", type: TYPES.NVarChar, value: null }, + "@2": { name: "2", type: TYPES.NVarChar, value: undefined }, + }); + }); +}); \ No newline at end of file