diff --git a/src/drizzle.config.ts b/drizzle.config.ts similarity index 62% rename from src/drizzle.config.ts rename to drizzle.config.ts index 6ef01d1..d7980e8 100644 --- a/src/drizzle.config.ts +++ b/drizzle.config.ts @@ -1,9 +1,9 @@ import type { Config } from "drizzle-kit"; export default { - schema: "./schema.ts", - out: "./drizzle", - driver: "better-sqlite", + schema: "./src/schema.ts", + out: "./src/drizzle", + dialect: "sqlite", dbCredentials: { url: "data.db", }, diff --git a/package.json b/package.json index bfc1f91..e633806 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,7 @@ "name": "liteque", "description": "A sqlite-based job queue for Node.js", "author": "Mohamed Bassem ", - "version": "0.1.3", + "version": "0.2.0", "type": "module", "main": "dist/index.js", "types": "dist/index.d.ts", @@ -32,7 +32,7 @@ "devDependencies": { "@tsconfig/node21": "^21.0.3", "@types/better-sqlite3": "^7.6.11", - "drizzle-kit": "^0.20.14", + "drizzle-kit": "^0.24.02", "typescript": "^5.6.3", "vitest": "^1.3.1" }, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 80218bf..f297639 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -28,8 +28,8 @@ importers: specifier: ^7.6.11 version: 7.6.11 drizzle-kit: - specifier: ^0.20.14 - version: 0.20.18 + specifier: ^0.24.02 + version: 0.24.2 typescript: specifier: ^5.6.3 version: 5.6.3 @@ -39,6 +39,9 @@ importers: packages: + '@drizzle-team/brocli@0.10.2': + resolution: {integrity: sha512-z33Il7l5dKjUgGULTqBsQBQwckHh5AbIuxhdsIxDDiZAzBOrZO6q9ogcWC65kU382AfynTfgNumVcNIjuIua6w==} + '@esbuild-kit/core-utils@3.3.2': resolution: {integrity: sha512-sPRAnw9CdSsRmEtnsl2WXWdyquogVpB3yZ3dgwJfe8zrOzTsV7cJvmwrKVa+0ma5BoiGJ+BoqkMvawbayKUsqQ==} deprecated: 'Merged into tsx: https://tsx.is' @@ -455,18 +458,6 @@ packages: cpu: [x64] os: [win32] - '@hono/node-server@1.13.2': - resolution: {integrity: sha512-0w8nEmAyx0Ul0CQp8BL2VtAG4YVdpzXd/mvvM+l0G5Oq22pUyHS+KeFFPSY+czLOF5NAiV3MUNPD1n14Ol5svg==} - engines: {node: '>=18.14.1'} - peerDependencies: - hono: ^4 - - '@hono/zod-validator@0.2.2': - resolution: {integrity: sha512-dSDxaPV70Py8wuIU2QNpoVEIOSzSXZ/6/B/h4xA7eOMz7+AarKTSGV8E6QwrdcCbBLkpqfJ4Q2TmBO0eP1tCBQ==} - peerDependencies: - hono: '>=3.9.0' - zod: ^3.19.1 - '@jest/schemas@29.6.3': resolution: {integrity: sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} @@ -613,9 +604,6 @@ packages: async-mutex@0.4.1: resolution: {integrity: sha512-WfoBo4E/TbCX1G95XTjbWTE3X2XLG0m1Xbv2cwOtuPdyH9CZvnaA5nCt1ucjaKEgW2A5IF71hxrRhr83Je5xjA==} - balanced-match@1.0.2: - resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} - base64-js@1.5.1: resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} @@ -628,9 +616,6 @@ packages: bl@4.1.0: resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==} - brace-expansion@2.0.1: - resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==} - buffer-from@1.1.2: resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} @@ -641,47 +626,23 @@ packages: resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==} engines: {node: '>=8'} - camelcase@7.0.1: - resolution: {integrity: sha512-xlx1yCK2Oc1APsPXDL2LdlNP6+uu8OCDdhOBSVT279M/S+y75O30C2VuD8T2ogdePBBl7PfPF4504tnLgX3zfw==} - engines: {node: '>=14.16'} - chai@4.5.0: resolution: {integrity: sha512-RITGBfijLkBddZvnn8jdqoTypxvqbOLYQkGGxXzeFjVHvudaPw0HNFD9x928/eUwYWd2dPCugVqspGALTZZQKw==} engines: {node: '>=4'} - chalk@5.3.0: - resolution: {integrity: sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==} - engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} - check-error@1.0.3: resolution: {integrity: sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==} chownr@1.1.4: resolution: {integrity: sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==} - cli-color@2.0.4: - resolution: {integrity: sha512-zlnpg0jNcibNrO7GG9IeHH7maWFeCz+Ja1wx/7tZNU5ASSSSZ+/qZciM0/LHCYxSdqv5h2sdbQ/PXYdOuetXvA==} - engines: {node: '>=0.10'} - - commander@9.5.0: - resolution: {integrity: sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==} - engines: {node: ^12.20.0 || >=14} - confbox@0.1.8: resolution: {integrity: sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==} - copy-anything@3.0.5: - resolution: {integrity: sha512-yCEafptTtb4bk7GLEQoM8KVJpxAfdBJYaXyzQEgQQQgYrZiDp8SJmGKlYza6CYjEDNstAdNdKA3UuoULlEbS6w==} - engines: {node: '>=12.13'} - cross-spawn@7.0.3: resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==} engines: {node: '>= 8'} - d@1.0.2: - resolution: {integrity: sha512-MOqHvMWF9/9MX6nza0KgvFH4HpMU0EF5uUDXqX/BtxtU8NfB0QzRtJ8Oe/6SuS4kbhyzVJwjd97EA4PKrzJ8bw==} - engines: {node: '>=0.12'} - debug@4.3.7: resolution: {integrity: sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==} engines: {node: '>=6.0'} @@ -711,15 +672,8 @@ packages: resolution: {integrity: sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - difflib@0.2.4: - resolution: {integrity: sha512-9YVwmMb0wQHQNr5J9m6BSj6fk4pfGITGQOOs+D9Fl+INODWFOfvhIU1hNv6GgR1RBoC/9NJcwu77zShxV0kT7w==} - - dreamopt@0.8.0: - resolution: {integrity: sha512-vyJTp8+mC+G+5dfgsY+r3ckxlz+QMX40VjPQsZc5gxVAxLmi64TBoVkP54A/pRAXMXsbu2GMMBrZPxNv23waMg==} - engines: {node: '>=0.4.0'} - - drizzle-kit@0.20.18: - resolution: {integrity: sha512-fLTwcnLqtBxGd+51H/dEm9TC0FW6+cIX/RVPyNcitBO77X9+nkogEfMAJebpd/8Yl4KucmePHRYRWWvUlW0rqg==} + drizzle-kit@0.24.2: + resolution: {integrity: sha512-nXOaTSFiuIaTMhS8WJC2d4EBeIcN9OSt2A2cyFbQYBAZbi7lRsVGJNqDpEwPqYfJz38yxbY/UtbvBBahBfnExQ==} hasBin: true drizzle-orm@0.33.0: @@ -814,24 +768,6 @@ packages: end-of-stream@1.4.4: resolution: {integrity: sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==} - env-paths@3.0.0: - resolution: {integrity: sha512-dtJUTepzMW3Lm/NPxRf3wP4642UWhjL2sQxc+ym2YMj1m/H2zDNQOlezafzkHwn6sMstjHTwG6iQQsctDW/b1A==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - - es5-ext@0.10.64: - resolution: {integrity: sha512-p2snDhiLaXe6dahss1LddxqEm+SkuDvV8dnIQG0MWjyHpcMNfXKPE+/Cc0y+PhxJX3A4xGNeFCj5oc0BUh6deg==} - engines: {node: '>=0.10'} - - es6-iterator@2.0.3: - resolution: {integrity: sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g==} - - es6-symbol@3.1.4: - resolution: {integrity: sha512-U9bFFjX8tFiATgtkJ1zg25+KviIXpgRvRHS8sau3GfhVzThRQrOeksPeT0BWW2MNZs1OEWJ1DPXOQMn0KKRkvg==} - engines: {node: '>=0.12'} - - es6-weak-map@2.0.3: - resolution: {integrity: sha512-p5um32HOTO1kP+w7PRnB+5lQ43Z6muuMuIMffvDN8ZB4GcnjLBV6zGStpbASIMk4DCAvEaamhe2zhyCb/QXXsA==} - esbuild-register@3.6.0: resolution: {integrity: sha512-H2/S7Pm8a9CL1uhp9OvjwrBh5Pvx0H8qVOxNu8Wed9Y7qv56MPtq+GGM8RJpq6glYJn9Wspr8uw7l55uyinNeg==} peerDependencies: @@ -852,16 +788,9 @@ packages: engines: {node: '>=12'} hasBin: true - esniff@2.0.1: - resolution: {integrity: sha512-kTUIGKQ/mDPFoJ0oVfcmyJn4iBDRptjNVIzwIFR7tqWXdVI9xfA2RMwY/gbSpJG3lkdWNEjLap/NqVHZiJsdfg==} - engines: {node: '>=0.10'} - estree-walker@3.0.3: resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==} - event-emitter@0.3.5: - resolution: {integrity: sha512-D9rRn9y7kLPnJ+hMq7S/nhvoKwwvVJahBi2BPmx3bvbsEdK3W9ii8cBSGjP+72/LnM4n6fo3+dkCX5FeTQruXA==} - execa@8.0.1: resolution: {integrity: sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==} engines: {node: '>=16.17'} @@ -870,18 +799,12 @@ packages: resolution: {integrity: sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==} engines: {node: '>=6'} - ext@1.7.0: - resolution: {integrity: sha512-6hxeJYaL110a9b5TEJSj0gojyHQAmA2ch5Os+ySCiA1QGdS697XWY1pzsrSjqA9LDEEgdB/KypIlR59RcLuHYw==} - file-uri-to-path@1.0.0: resolution: {integrity: sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==} fs-constants@1.0.0: resolution: {integrity: sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==} - fs.realpath@1.0.0: - resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} - fsevents@2.3.3: resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} @@ -900,21 +823,6 @@ packages: github-from-package@0.0.0: resolution: {integrity: sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==} - glob@8.1.0: - resolution: {integrity: sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==} - engines: {node: '>=12'} - deprecated: Glob versions prior to v9 are no longer supported - - hanji@0.0.5: - resolution: {integrity: sha512-Abxw1Lq+TnYiL4BueXqMau222fPSPMFtya8HdpWsz/xVAhifXou71mPh/kY2+08RgFcVccjG3uZHs6K5HAe3zw==} - - heap@0.2.7: - resolution: {integrity: sha512-2bsegYkkHO+h/9MGbn6KWcE45cHZgPANo5LXF7EvWdT0yT2EguSVO1nDgU5c8+ZOPwp2vMNa7YFsJhVcDR9Sdg==} - - hono@4.6.7: - resolution: {integrity: sha512-wX4ZbOnzfNO61hUjuQbJ7OPGs1fWXXVVJ8VTPDb2Ls/x9HjCbVTm80Je6VTHMz5n5RGDtBgV9d9ZFZxBqx56ng==} - engines: {node: '>=16.9.0'} - human-signals@5.0.0: resolution: {integrity: sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==} engines: {node: '>=16.17.0'} @@ -922,57 +830,32 @@ packages: ieee754@1.2.1: resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} - inflight@1.0.6: - resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} - deprecated: This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful. - inherits@2.0.4: resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} ini@1.3.8: resolution: {integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==} - is-promise@2.2.2: - resolution: {integrity: sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ==} - is-stream@3.0.0: resolution: {integrity: sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - is-what@4.1.16: - resolution: {integrity: sha512-ZhMwEosbFJkA0YhFnNDgTM4ZxDRsS6HqTo7qsZM08fehyRYIYa0yHu5R6mgo1n/8MgaPBXiPimPD77baVFYg+A==} - engines: {node: '>=12.13'} - isexe@2.0.0: resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} js-tokens@9.0.0: resolution: {integrity: sha512-WriZw1luRMlmV3LGJaR6QOJjWwgLUTf89OwT2lUOyjX2dJGBwgmIkbcz+7WFZjrZM635JOIR517++e/67CP9dQ==} - json-diff@0.9.0: - resolution: {integrity: sha512-cVnggDrVkAAA3OvFfHpFEhOnmcsUpleEKq4d4O8sQWWSH40MBrWstKigVB1kGrgLWzuom+7rRdaCsnBD6VyObQ==} - hasBin: true - local-pkg@0.5.0: resolution: {integrity: sha512-ok6z3qlYyCDS4ZEU27HaU6x/xZa9Whf8jD4ptH5UZTQYZVYeb9bnZ3ojVhiJNLiXK1Hfc0GNbLXcmZ5plLDDBg==} engines: {node: '>=14'} - lodash.throttle@4.1.1: - resolution: {integrity: sha512-wIkUCfVKpVsWo3JSZlc+8MB5it+2AN5W8J7YVMST30UrvcQNZ1Okbj+rbVniijTWE6FGYy4XJq/rHkas8qJMLQ==} - loupe@2.3.7: resolution: {integrity: sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA==} - lru-queue@0.1.0: - resolution: {integrity: sha512-BpdYkt9EvGl8OfWHDQPISVpcl5xZthb+XPsbELj5AQXxIC8IriDZIQYjBJPEm5rS420sjZ0TLEzRcq5KdBhYrQ==} - magic-string@0.30.12: resolution: {integrity: sha512-Ea8I3sQMVXr8JhN4z+H/d8zwo+tYDgHE9+5G4Wnrwhs0gaK9fXTKx0Tw5Xwsd/bCPTTZNRAdpyzvoeORe9LYpw==} - memoizee@0.4.17: - resolution: {integrity: sha512-DGqD7Hjpi/1or4F/aYAspXKNm5Yili0QDAFAY4QYvpqpgiY6+1jOfqpmByzjxbWd/T9mChbCArXAbDAsTm5oXA==} - engines: {node: '>=0.12'} - merge-stream@2.0.0: resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} @@ -984,14 +867,6 @@ packages: resolution: {integrity: sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==} engines: {node: '>=10'} - minimatch@5.1.6: - resolution: {integrity: sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==} - engines: {node: '>=10'} - - minimatch@7.4.6: - resolution: {integrity: sha512-sBz8G/YjVniEz6lKPNpKxXwazJe4c19fEfV2GDMX6AjFz+MX9uDWIZW8XreVhkFW3fkIdTv/gxWr/Kks5FFAVw==} - engines: {node: '>=10'} - minimist@1.2.8: resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} @@ -1012,9 +887,6 @@ packages: napi-build-utils@1.0.2: resolution: {integrity: sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==} - next-tick@1.1.0: - resolution: {integrity: sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==} - node-abi@3.71.0: resolution: {integrity: sha512-SZ40vRiy/+wRTf21hxkkEjPJZpARzUMVcJoQse2EF8qkUWbbO2z7vd5oA/H6bVH6SZQ5STGcu0KRDS7biNRfxw==} engines: {node: '>=10'} @@ -1118,9 +990,6 @@ packages: simple-get@4.0.1: resolution: {integrity: sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==} - sisteransi@1.0.5: - resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==} - source-map-js@1.2.1: resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} engines: {node: '>=0.10.0'} @@ -1152,10 +1021,6 @@ packages: strip-literal@2.1.0: resolution: {integrity: sha512-Op+UycaUt/8FbN/Z2TWPBLge3jWrP3xj10f3fnYxf052bKuS3EKs1ZQcVGjnEMdsNVAM+plXRdmjrZ/KgG3Skw==} - superjson@2.2.1: - resolution: {integrity: sha512-8iGv75BYOa0xRJHK5vRLEjE2H/i4lulTjzpUXic3Eg8akftYjkmQDa8JARQ42rlczXyFR3IeRoeFCc7RxHsYZA==} - engines: {node: '>=16'} - tar-fs@2.1.1: resolution: {integrity: sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==} @@ -1163,10 +1028,6 @@ packages: resolution: {integrity: sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==} engines: {node: '>=6'} - timers-ext@0.1.8: - resolution: {integrity: sha512-wFH7+SEAcKfJpfLPkrgMPvvwnEtj8W4IurvEyrKsDleXnKLCDw71w8jltvfLa8Rm4qQxxT4jmDBYbJG/z7qoww==} - engines: {node: '>=0.12'} - tinybench@2.9.0: resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==} @@ -1188,9 +1049,6 @@ packages: resolution: {integrity: sha512-Acylog8/luQ8L7il+geoSxhEkazvkslg7PSNKOX59mbB9cOveP5aq9h74Y7YU8yDpJwetzQQrfIwtf4Wp4LKcw==} engines: {node: '>=4'} - type@2.7.3: - resolution: {integrity: sha512-8j+1QmAbPvLZow5Qpi6NCaN8FB60p/6x8/vfNqOk/hC+HuvFZhL4+WfekuhQLiqFZXOgQdrs3B+XxEmCc6b3FQ==} - typescript@5.6.3: resolution: {integrity: sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw==} engines: {node: '>=14.17'} @@ -1276,9 +1134,6 @@ packages: engines: {node: '>=8'} hasBin: true - wordwrap@1.0.0: - resolution: {integrity: sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==} - wrappy@1.0.2: resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} @@ -1291,6 +1146,8 @@ packages: snapshots: + '@drizzle-team/brocli@0.10.2': {} + '@esbuild-kit/core-utils@3.3.2': dependencies: esbuild: 0.18.20 @@ -1505,15 +1362,6 @@ snapshots: '@esbuild/win32-x64@0.21.5': optional: true - '@hono/node-server@1.13.2(hono@4.6.7)': - dependencies: - hono: 4.6.7 - - '@hono/zod-validator@0.2.2(hono@4.6.7)(zod@3.23.8)': - dependencies: - hono: 4.6.7 - zod: 3.23.8 - '@jest/schemas@29.6.3': dependencies: '@sinclair/typebox': 0.27.8 @@ -1631,8 +1479,6 @@ snapshots: dependencies: tslib: 2.8.0 - balanced-match@1.0.2: {} - base64-js@1.5.1: {} better-sqlite3@11.5.0: @@ -1650,10 +1496,6 @@ snapshots: inherits: 2.0.4 readable-stream: 3.6.2 - brace-expansion@2.0.1: - dependencies: - balanced-match: 1.0.2 - buffer-from@1.1.2: {} buffer@5.7.1: @@ -1663,8 +1505,6 @@ snapshots: cac@6.7.14: {} - camelcase@7.0.1: {} - chai@4.5.0: dependencies: assertion-error: 1.1.0 @@ -1675,41 +1515,20 @@ snapshots: pathval: 1.1.1 type-detect: 4.1.0 - chalk@5.3.0: {} - check-error@1.0.3: dependencies: get-func-name: 2.0.2 chownr@1.1.4: {} - cli-color@2.0.4: - dependencies: - d: 1.0.2 - es5-ext: 0.10.64 - es6-iterator: 2.0.3 - memoizee: 0.4.17 - timers-ext: 0.1.8 - - commander@9.5.0: {} - confbox@0.1.8: {} - copy-anything@3.0.5: - dependencies: - is-what: 4.1.16 - cross-spawn@7.0.3: dependencies: path-key: 3.1.1 shebang-command: 2.0.0 which: 2.0.2 - d@1.0.2: - dependencies: - es5-ext: 0.10.64 - type: 2.7.3 - debug@4.3.7: dependencies: ms: 2.1.3 @@ -1728,33 +1547,12 @@ snapshots: diff-sequences@29.6.3: {} - difflib@0.2.4: - dependencies: - heap: 0.2.7 - - dreamopt@0.8.0: - dependencies: - wordwrap: 1.0.0 - - drizzle-kit@0.20.18: + drizzle-kit@0.24.2: dependencies: + '@drizzle-team/brocli': 0.10.2 '@esbuild-kit/esm-loader': 2.6.5 - '@hono/node-server': 1.13.2(hono@4.6.7) - '@hono/zod-validator': 0.2.2(hono@4.6.7)(zod@3.23.8) - camelcase: 7.0.1 - chalk: 5.3.0 - commander: 9.5.0 - env-paths: 3.0.0 esbuild: 0.19.12 esbuild-register: 3.6.0(esbuild@0.19.12) - glob: 8.1.0 - hanji: 0.0.5 - hono: 4.6.7 - json-diff: 0.9.0 - minimatch: 7.4.6 - semver: 7.6.3 - superjson: 2.2.1 - zod: 3.23.8 transitivePeerDependencies: - supports-color @@ -1767,33 +1565,6 @@ snapshots: dependencies: once: 1.4.0 - env-paths@3.0.0: {} - - es5-ext@0.10.64: - dependencies: - es6-iterator: 2.0.3 - es6-symbol: 3.1.4 - esniff: 2.0.1 - next-tick: 1.1.0 - - es6-iterator@2.0.3: - dependencies: - d: 1.0.2 - es5-ext: 0.10.64 - es6-symbol: 3.1.4 - - es6-symbol@3.1.4: - dependencies: - d: 1.0.2 - ext: 1.7.0 - - es6-weak-map@2.0.3: - dependencies: - d: 1.0.2 - es5-ext: 0.10.64 - es6-iterator: 2.0.3 - es6-symbol: 3.1.4 - esbuild-register@3.6.0(esbuild@0.19.12): dependencies: debug: 4.3.7 @@ -1878,22 +1649,10 @@ snapshots: '@esbuild/win32-ia32': 0.21.5 '@esbuild/win32-x64': 0.21.5 - esniff@2.0.1: - dependencies: - d: 1.0.2 - es5-ext: 0.10.64 - event-emitter: 0.3.5 - type: 2.7.3 - estree-walker@3.0.3: dependencies: '@types/estree': 1.0.6 - event-emitter@0.3.5: - dependencies: - d: 1.0.2 - es5-ext: 0.10.64 - execa@8.0.1: dependencies: cross-spawn: 7.0.3 @@ -1908,16 +1667,10 @@ snapshots: expand-template@2.0.3: {} - ext@1.7.0: - dependencies: - type: 2.7.3 - file-uri-to-path@1.0.0: {} fs-constants@1.0.0: {} - fs.realpath@1.0.0: {} - fsevents@2.3.3: optional: true @@ -1931,96 +1684,39 @@ snapshots: github-from-package@0.0.0: {} - glob@8.1.0: - dependencies: - fs.realpath: 1.0.0 - inflight: 1.0.6 - inherits: 2.0.4 - minimatch: 5.1.6 - once: 1.4.0 - - hanji@0.0.5: - dependencies: - lodash.throttle: 4.1.1 - sisteransi: 1.0.5 - - heap@0.2.7: {} - - hono@4.6.7: {} - human-signals@5.0.0: {} ieee754@1.2.1: {} - inflight@1.0.6: - dependencies: - once: 1.4.0 - wrappy: 1.0.2 - inherits@2.0.4: {} ini@1.3.8: {} - is-promise@2.2.2: {} - is-stream@3.0.0: {} - is-what@4.1.16: {} - isexe@2.0.0: {} js-tokens@9.0.0: {} - json-diff@0.9.0: - dependencies: - cli-color: 2.0.4 - difflib: 0.2.4 - dreamopt: 0.8.0 - local-pkg@0.5.0: dependencies: mlly: 1.7.2 pkg-types: 1.2.1 - lodash.throttle@4.1.1: {} - loupe@2.3.7: dependencies: get-func-name: 2.0.2 - lru-queue@0.1.0: - dependencies: - es5-ext: 0.10.64 - magic-string@0.30.12: dependencies: '@jridgewell/sourcemap-codec': 1.5.0 - memoizee@0.4.17: - dependencies: - d: 1.0.2 - es5-ext: 0.10.64 - es6-weak-map: 2.0.3 - event-emitter: 0.3.5 - is-promise: 2.2.2 - lru-queue: 0.1.0 - next-tick: 1.1.0 - timers-ext: 0.1.8 - merge-stream@2.0.0: {} mimic-fn@4.0.0: {} mimic-response@3.1.0: {} - minimatch@5.1.6: - dependencies: - brace-expansion: 2.0.1 - - minimatch@7.4.6: - dependencies: - brace-expansion: 2.0.1 - minimist@1.2.8: {} mkdirp-classic@0.5.3: {} @@ -2038,8 +1734,6 @@ snapshots: napi-build-utils@1.0.2: {} - next-tick@1.1.0: {} - node-abi@3.71.0: dependencies: semver: 7.6.3 @@ -2171,8 +1865,6 @@ snapshots: once: 1.4.0 simple-concat: 1.0.1 - sisteransi@1.0.5: {} - source-map-js@1.2.1: {} source-map-support@0.5.21: @@ -2198,10 +1890,6 @@ snapshots: dependencies: js-tokens: 9.0.0 - superjson@2.2.1: - dependencies: - copy-anything: 3.0.5 - tar-fs@2.1.1: dependencies: chownr: 1.1.4 @@ -2217,11 +1905,6 @@ snapshots: inherits: 2.0.4 readable-stream: 3.6.2 - timers-ext@0.1.8: - dependencies: - es5-ext: 0.10.64 - next-tick: 1.1.0 - tinybench@2.9.0: {} tinypool@0.8.4: {} @@ -2236,8 +1919,6 @@ snapshots: type-detect@4.1.0: {} - type@2.7.3: {} - typescript@5.6.3: {} ufo@1.5.4: {} @@ -2316,8 +1997,6 @@ snapshots: siginfo: 2.0.0 stackback: 0.0.2 - wordwrap@1.0.0: {} - wrappy@1.0.2: {} yocto-queue@1.1.1: {} diff --git a/src/drizzle/0001_wandering_giant_man.sql b/src/drizzle/0001_wandering_giant_man.sql new file mode 100644 index 0000000..c0c3a35 --- /dev/null +++ b/src/drizzle/0001_wandering_giant_man.sql @@ -0,0 +1,2 @@ +ALTER TABLE `tasks` ADD `idempotencyKey` text;--> statement-breakpoint +CREATE UNIQUE INDEX `tasks_queue_idempotencyKey_unique` ON `tasks` (`queue`,`idempotencyKey`); \ No newline at end of file diff --git a/src/drizzle/meta/0000_snapshot.json b/src/drizzle/meta/0000_snapshot.json index 57c7c2f..4b75197 100644 --- a/src/drizzle/meta/0000_snapshot.json +++ b/src/drizzle/meta/0000_snapshot.json @@ -1,8 +1,6 @@ { - "version": "5", + "version": "6", "dialect": "sqlite", - "id": "3094773c-0138-46b2-b617-4b10093b0f53", - "prevId": "00000000-0000-0000-0000-000000000000", "tables": { "tasks": { "name": "tasks", @@ -123,8 +121,9 @@ }, "enums": {}, "_meta": { - "schemas": {}, "tables": {}, "columns": {} - } + }, + "id": "3094773c-0138-46b2-b617-4b10093b0f53", + "prevId": "00000000-0000-0000-0000-000000000000" } \ No newline at end of file diff --git a/src/drizzle/meta/0001_snapshot.json b/src/drizzle/meta/0001_snapshot.json new file mode 100644 index 0000000..c21ecf0 --- /dev/null +++ b/src/drizzle/meta/0001_snapshot.json @@ -0,0 +1,148 @@ +{ + "version": "6", + "dialect": "sqlite", + "id": "0f918c72-5b27-4e4c-9027-631ead290bf2", + "prevId": "3094773c-0138-46b2-b617-4b10093b0f53", + "tables": { + "tasks": { + "name": "tasks", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "queue": { + "name": "queue", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "payload": { + "name": "payload", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "createdAt": { + "name": "createdAt", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'pending'" + }, + "expireAt": { + "name": "expireAt", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "allocationId": { + "name": "allocationId", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "numRunsLeft": { + "name": "numRunsLeft", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "maxNumRuns": { + "name": "maxNumRuns", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "idempotencyKey": { + "name": "idempotencyKey", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": { + "tasks_queue_idx": { + "name": "tasks_queue_idx", + "columns": [ + "queue" + ], + "isUnique": false + }, + "tasks_status_idx": { + "name": "tasks_status_idx", + "columns": [ + "status" + ], + "isUnique": false + }, + "tasks_expire_at_idx": { + "name": "tasks_expire_at_idx", + "columns": [ + "expireAt" + ], + "isUnique": false + }, + "tasks_num_runs_left_idx": { + "name": "tasks_num_runs_left_idx", + "columns": [ + "numRunsLeft" + ], + "isUnique": false + }, + "tasks_max_num_runs_idx": { + "name": "tasks_max_num_runs_idx", + "columns": [ + "maxNumRuns" + ], + "isUnique": false + }, + "tasks_allocation_id_idx": { + "name": "tasks_allocation_id_idx", + "columns": [ + "allocationId" + ], + "isUnique": false + }, + "tasks_queue_idempotencyKey_unique": { + "name": "tasks_queue_idempotencyKey_unique", + "columns": [ + "queue", + "idempotencyKey" + ], + "isUnique": true + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + } + }, + "enums": {}, + "_meta": { + "schemas": {}, + "tables": {}, + "columns": {} + }, + "internal": { + "indexes": {} + } +} \ No newline at end of file diff --git a/src/drizzle/meta/_journal.json b/src/drizzle/meta/_journal.json index 2b14f89..87902ec 100644 --- a/src/drizzle/meta/_journal.json +++ b/src/drizzle/meta/_journal.json @@ -8,6 +8,13 @@ "when": 1720992922192, "tag": "0000_wonderful_talisman", "breakpoints": true + }, + { + "idx": 1, + "version": "6", + "when": 1730656128884, + "tag": "0001_wandering_giant_man", + "breakpoints": true } ] } \ No newline at end of file diff --git a/src/options.ts b/src/options.ts index 18f8e52..f375444 100644 --- a/src/options.ts +++ b/src/options.ts @@ -8,6 +8,11 @@ export interface SqliteQueueOptions { }; } +export interface EnqueueOptions { + numRetries?: number; + idempotencyKey?: string; +} + export interface RunnerFuncs { run: (job: DequeuedJob) => Promise; onComplete?: (job: DequeuedJob) => Promise; diff --git a/src/queue.ts b/src/queue.ts index ad48646..0544238 100644 --- a/src/queue.ts +++ b/src/queue.ts @@ -2,7 +2,7 @@ import assert from "node:assert"; import { and, asc, count, eq, gt, lt, or } from "drizzle-orm"; import { buildDBClient } from "./db"; -import { SqliteQueueOptions } from "./options"; +import { EnqueueOptions, SqliteQueueOptions } from "./options"; import { Job, tasksTable } from "./schema"; // generate random id @@ -29,19 +29,27 @@ export class SqliteQueue { return this.queueName; } - async enqueue(payload: T): Promise { - const job = await this.db + /** + * Enqueue a job into the queue. + * If a job with the same idempotency key is already enqueued, it will be ignored and undefined will be returned. + */ + async enqueue(payload: T, options?: EnqueueOptions): Promise { + const opts = options ?? {}; + const numRetries = opts.numRetries ?? this.options.defaultJobArgs.numRetries; + const [job] = await this.db .insert(tasksTable) .values({ queue: this.queueName, payload: JSON.stringify(payload), - numRunsLeft: this.options.defaultJobArgs.numRetries + 1, - maxNumRuns: this.options.defaultJobArgs.numRetries + 1, + numRunsLeft: numRetries + 1, + maxNumRuns: numRetries + 1, allocationId: generateAllocationId(), + idempotencyKey: opts.idempotencyKey, }) + .onConflictDoNothing({target: [tasksTable.queue, tasksTable.idempotencyKey]}) .returning(); - return job[0]; + return job; } async stats() { diff --git a/src/runner.test.ts b/src/runner.test.ts index 7777b42..176f34a 100644 --- a/src/runner.test.ts +++ b/src/runner.test.ts @@ -288,7 +288,7 @@ describe("SqiteQueueRunner", () => { await queue.db .update(tasksTable) .set({ payload: "{}" }) - .where(eq(tasksTable.id, job.id)); + .where(eq(tasksTable.id, job!.id)); const barrier = new Barrier(1); barrier.allowParticipantsToProceed(); @@ -437,4 +437,30 @@ describe("SqiteQueueRunner", () => { expect(results.numCompleted).toEqual(1000); expect(results.numFailed).toEqual(0); }); + + test("idempotency keys", async () => { + const queue = new SqliteQueue( + "queue1", + buildDBClient(":memory:", true), + { + defaultJobArgs: { + numRetries: 0, + }, + }, + ); + + await queue.enqueue({ increment: 1 }); + await queue.enqueue({ increment: 2 }, { idempotencyKey: "2" }); + await queue.enqueue({ increment: 2 }, { idempotencyKey: "2" }); + await queue.enqueue({ increment: 2 }, { idempotencyKey: "2" }); + await queue.enqueue({ increment: 3 }, { idempotencyKey: "3" }); + + expect(await queue.stats()).toEqual({ + pending: 3, + running: 0, + pending_retry: 0, + failed: 0, + }); + + }); }); diff --git a/src/schema.ts b/src/schema.ts index 377c6b1..090644c 100644 --- a/src/schema.ts +++ b/src/schema.ts @@ -1,4 +1,4 @@ -import { index, integer, sqliteTable, text } from "drizzle-orm/sqlite-core"; +import { index, integer, sqliteTable, text, unique } from "drizzle-orm/sqlite-core"; function createdAtField() { return integer("createdAt", { mode: "timestamp" }) @@ -22,6 +22,7 @@ export const tasksTable = sqliteTable( allocationId: text("allocationId").notNull(), numRunsLeft: integer("numRunsLeft").notNull(), maxNumRuns: integer("maxNumRuns").notNull(), + idempotencyKey: text("idempotencyKey"), }, (tasks) => ({ queueIdx: index("tasks_queue_idx").on(tasks.queue), @@ -30,6 +31,7 @@ export const tasksTable = sqliteTable( numRunsLeftIdx: index("tasks_num_runs_left_idx").on(tasks.numRunsLeft), maxNumRunsIdx: index("tasks_max_num_runs_idx").on(tasks.maxNumRuns), allocationIdIdx: index("tasks_allocation_id_idx").on(tasks.allocationId), + idempotencyKeyIdx: unique().on(tasks.queue, tasks.idempotencyKey), }), );