@upstash/redis 0.0.0-ci.babdc47f97e036e2863dfed16300cda2b97bf6ad-20240322001434 → 0.0.0-ci.bb93ac2803c2e927dc8bf1a1b3c5aa2a14034eb6-20240930061920

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (622) hide show
  1. package/.env.example +2 -0
  2. package/.github/workflows/release.yml +53 -0
  3. package/.github/workflows/tests.yaml +609 -0
  4. package/.gitignore +175 -0
  5. package/.husky/commit-msg +1 -0
  6. package/.husky/pre-commit +2 -0
  7. package/.husky/pre-push +1 -0
  8. package/.prettierignore +1 -0
  9. package/.vscode/extensions.json +3 -0
  10. package/.vscode/settings.json +20 -0
  11. package/README.md +1 -2
  12. package/bun.lockb +0 -0
  13. package/commitlint.config.js +46 -0
  14. package/dist/LICENSE +21 -0
  15. package/dist/README.md +136 -0
  16. package/dist/chunk-TEVCO3ZO.mjs +3797 -0
  17. package/dist/cloudflare.d.mts +55 -0
  18. package/dist/cloudflare.d.ts +55 -0
  19. package/dist/cloudflare.js +3907 -0
  20. package/dist/cloudflare.mjs +91 -0
  21. package/dist/fastly.d.mts +48 -0
  22. package/dist/fastly.d.ts +48 -0
  23. package/dist/fastly.js +3880 -0
  24. package/dist/fastly.mjs +64 -0
  25. package/dist/nodejs.d.mts +73 -0
  26. package/dist/nodejs.d.ts +73 -0
  27. package/dist/nodejs.js +3926 -0
  28. package/dist/nodejs.mjs +110 -0
  29. package/dist/package.json +1 -0
  30. package/{zmscore-5d82e632.d.ts → dist/zmscore-BhX8yEQc.d.mts} +249 -184
  31. package/dist/zmscore-BhX8yEQc.d.ts +3486 -0
  32. package/eslint.config.mjs +102 -0
  33. package/examples/auto-pipeline/.eslintrc.json +3 -0
  34. package/examples/auto-pipeline/README.md +77 -0
  35. package/examples/auto-pipeline/app/components/DataComponent.tsx +49 -0
  36. package/examples/auto-pipeline/app/data/getEvents.ts +18 -0
  37. package/examples/auto-pipeline/app/data/getUsers.ts +18 -0
  38. package/examples/auto-pipeline/app/data/redis.ts +12 -0
  39. package/examples/auto-pipeline/app/favicon.ico +0 -0
  40. package/examples/auto-pipeline/app/globals.css +0 -0
  41. package/examples/auto-pipeline/app/layout.tsx +22 -0
  42. package/examples/auto-pipeline/app/page.tsx +15 -0
  43. package/examples/auto-pipeline/next.config.mjs +4 -0
  44. package/examples/auto-pipeline/package.json +27 -0
  45. package/examples/auto-pipeline/postcss.config.mjs +8 -0
  46. package/examples/auto-pipeline/public/next.svg +1 -0
  47. package/examples/auto-pipeline/public/vercel.svg +1 -0
  48. package/examples/auto-pipeline/tailwind.config.ts +20 -0
  49. package/examples/auto-pipeline/tsconfig.json +26 -0
  50. package/examples/aws-cdk-python/README.md +36 -0
  51. package/examples/aws-cdk-python/cdk.json +72 -0
  52. package/examples/aws-cdk-python/jest.config.js +8 -0
  53. package/examples/aws-cdk-python/lib/api/index.py +10 -0
  54. package/examples/aws-cdk-python/lib/api/requirements.txt +1 -0
  55. package/examples/aws-cdk-python/package-lock.json +4470 -0
  56. package/examples/aws-cdk-python/package.json +27 -0
  57. package/examples/aws-cdk-python/tsconfig.json +31 -0
  58. package/examples/aws-cdk-typescript/README.md +36 -0
  59. package/examples/aws-cdk-typescript/cdk.json +72 -0
  60. package/examples/aws-cdk-typescript/jest.config.js +8 -0
  61. package/examples/aws-cdk-typescript/package-lock.json +4548 -0
  62. package/examples/aws-cdk-typescript/package.json +28 -0
  63. package/examples/aws-cdk-typescript/tsconfig.json +31 -0
  64. package/examples/aws-lambda/README.md +39 -0
  65. package/examples/aws-lambda/index.js +11 -0
  66. package/examples/aws-lambda/package-lock.json +27 -0
  67. package/examples/aws-lambda/package.json +6 -0
  68. package/examples/aws-sam/README.md +34 -0
  69. package/examples/aws-sam/__init__.py +0 -0
  70. package/examples/aws-sam/events/event.json +62 -0
  71. package/examples/aws-sam/hello_world/__init__.py +0 -0
  72. package/examples/aws-sam/hello_world/app.py +10 -0
  73. package/examples/aws-sam/hello_world/requirements.txt +2 -0
  74. package/examples/aws-sam/samconfig.toml +34 -0
  75. package/examples/aws-sam/template.yaml +52 -0
  76. package/examples/aws-sam/tests/__init__.py +0 -0
  77. package/examples/aws-sam/tests/integration/__init__.py +0 -0
  78. package/examples/aws-sam/tests/integration/test_api_gateway.py +45 -0
  79. package/examples/aws-sam/tests/requirements.txt +3 -0
  80. package/examples/aws-sam/tests/unit/__init__.py +0 -0
  81. package/examples/aws-sam/tests/unit/test_handler.py +72 -0
  82. package/examples/azure-functions/.funcignore +10 -0
  83. package/examples/azure-functions/.vscode/extensions.json +5 -0
  84. package/examples/azure-functions/README.md +67 -0
  85. package/examples/azure-functions/host.json +15 -0
  86. package/examples/azure-functions/package-lock.json +1019 -0
  87. package/examples/azure-functions/package.json +24 -0
  88. package/examples/azure-functions/src/functions/CounterFunction.ts +19 -0
  89. package/examples/azure-functions/tsconfig.json +10 -0
  90. package/examples/cloudflare-workers/README.md +26 -0
  91. package/examples/cloudflare-workers/bun.lockb +0 -0
  92. package/examples/cloudflare-workers/ci.test.ts +18 -0
  93. package/examples/cloudflare-workers/index.js +11 -0
  94. package/examples/cloudflare-workers/package.json +17 -0
  95. package/examples/cloudflare-workers/wrangler.toml +11 -0
  96. package/examples/cloudflare-workers-with-typescript/README.md +26 -0
  97. package/examples/cloudflare-workers-with-typescript/ci.test.ts +17 -0
  98. package/examples/cloudflare-workers-with-typescript/package.json +17 -0
  99. package/examples/cloudflare-workers-with-typescript/src/index.ts +16 -0
  100. package/examples/cloudflare-workers-with-typescript/tsconfig.json +105 -0
  101. package/examples/cloudflare-workers-with-typescript/wrangler.toml +9 -0
  102. package/examples/deno/main.test.ts +16 -0
  103. package/examples/deno/main.ts +9 -0
  104. package/examples/fastapi/README.md +23 -0
  105. package/examples/fastapi/main.py +12 -0
  106. package/examples/fastapi/requirements.txt +2 -0
  107. package/examples/fastly/README.md +7 -0
  108. package/examples/fastly/fastly.toml +12 -0
  109. package/examples/fastly/package.json +23 -0
  110. package/examples/fastly/src/index.js +19 -0
  111. package/examples/fastly/webpack.config.js +28 -0
  112. package/examples/google-cloud-functions/README.md +37 -0
  113. package/examples/google-cloud-functions/index.js +12 -0
  114. package/examples/google-cloud-functions/package.json +7 -0
  115. package/examples/ion/.env.example +2 -0
  116. package/examples/ion/.eslintrc.json +3 -0
  117. package/examples/ion/README.md +49 -0
  118. package/examples/ion/app/favicon.ico +0 -0
  119. package/examples/ion/app/globals.css +33 -0
  120. package/examples/ion/app/layout.tsx +22 -0
  121. package/examples/ion/app/page.tsx +12 -0
  122. package/examples/ion/next.config.mjs +4 -0
  123. package/examples/ion/package-lock.json +6709 -0
  124. package/examples/ion/package.json +28 -0
  125. package/examples/ion/postcss.config.mjs +8 -0
  126. package/examples/ion/public/next.svg +1 -0
  127. package/examples/ion/public/vercel.svg +1 -0
  128. package/examples/ion/sst-env.d.ts +12 -0
  129. package/examples/ion/sst.config.ts +19 -0
  130. package/examples/ion/tailwind.config.ts +20 -0
  131. package/examples/ion/tsconfig.json +26 -0
  132. package/examples/nextjs-app-router/.env.example +2 -0
  133. package/examples/nextjs-app-router/.eslintrc.json +3 -0
  134. package/examples/nextjs-app-router/README.md +26 -0
  135. package/examples/nextjs-app-router/app/globals.css +3 -0
  136. package/examples/nextjs-app-router/app/layout.tsx +22 -0
  137. package/examples/nextjs-app-router/app/page.tsx +12 -0
  138. package/examples/nextjs-app-router/next.config.mjs +4 -0
  139. package/examples/nextjs-app-router/package.json +27 -0
  140. package/examples/nextjs-app-router/postcss.config.mjs +8 -0
  141. package/examples/nextjs-app-router/tailwind.config.ts +20 -0
  142. package/examples/nextjs-app-router/tsconfig.json +26 -0
  143. package/examples/nextjs-pages-router/.env.example +2 -0
  144. package/examples/nextjs-pages-router/.eslintrc.json +3 -0
  145. package/examples/nextjs-pages-router/README.md +26 -0
  146. package/examples/nextjs-pages-router/next.config.mjs +6 -0
  147. package/examples/nextjs-pages-router/package.json +27 -0
  148. package/examples/nextjs-pages-router/pages/_app.tsx +6 -0
  149. package/examples/nextjs-pages-router/pages/_document.tsx +13 -0
  150. package/examples/nextjs-pages-router/pages/api/hello.ts +13 -0
  151. package/examples/nextjs-pages-router/pages/index.tsx +19 -0
  152. package/examples/nextjs-pages-router/postcss.config.mjs +8 -0
  153. package/examples/nextjs-pages-router/styles/globals.css +3 -0
  154. package/examples/nextjs-pages-router/tailwind.config.ts +20 -0
  155. package/examples/nextjs-pages-router/tsconfig.json +21 -0
  156. package/examples/nodejs/.env.example +2 -0
  157. package/examples/nodejs/README.md +24 -0
  158. package/examples/nodejs/index.js +10 -0
  159. package/examples/nodejs/package.json +10 -0
  160. package/examples/serverless-framework/counter/.env.example +2 -0
  161. package/examples/serverless-framework/counter/README.md +38 -0
  162. package/examples/serverless-framework/counter/handler.js +12 -0
  163. package/examples/serverless-framework/counter/package-lock.json +27 -0
  164. package/examples/serverless-framework/counter/package.json +6 -0
  165. package/examples/serverless-framework/counter/serverless.yml +16 -0
  166. package/examples/sst-v2/.vscode/launch.json +15 -0
  167. package/examples/sst-v2/.vscode/settings.json +5 -0
  168. package/examples/sst-v2/README.md +62 -0
  169. package/examples/sst-v2/package.json +27 -0
  170. package/examples/sst-v2/packages/core/package.json +14 -0
  171. package/examples/sst-v2/packages/core/sst-env.d.ts +1 -0
  172. package/examples/sst-v2/packages/core/tsconfig.json +7 -0
  173. package/examples/sst-v2/packages/functions/package.json +15 -0
  174. package/examples/sst-v2/packages/functions/sst-env.d.ts +1 -0
  175. package/examples/sst-v2/packages/functions/tsconfig.json +11 -0
  176. package/examples/sst-v2/packages/web/README.md +40 -0
  177. package/examples/sst-v2/packages/web/next.config.mjs +6 -0
  178. package/examples/sst-v2/packages/web/package.json +23 -0
  179. package/examples/sst-v2/packages/web/pages/_app.tsx +6 -0
  180. package/examples/sst-v2/packages/web/pages/_document.tsx +13 -0
  181. package/examples/sst-v2/packages/web/pages/api/hello.ts +16 -0
  182. package/examples/sst-v2/packages/web/pages/index.tsx +114 -0
  183. package/examples/sst-v2/packages/web/public/favicon.ico +0 -0
  184. package/examples/sst-v2/packages/web/public/next.svg +1 -0
  185. package/examples/sst-v2/packages/web/public/vercel.svg +1 -0
  186. package/examples/sst-v2/packages/web/sst-env.d.ts +1 -0
  187. package/examples/sst-v2/packages/web/styles/Home.module.css +229 -0
  188. package/examples/sst-v2/packages/web/styles/globals.css +107 -0
  189. package/examples/sst-v2/packages/web/tsconfig.json +36 -0
  190. package/examples/sst-v2/pnpm-workspace.yaml +2 -0
  191. package/examples/sst-v2/sst.config.ts +14 -0
  192. package/examples/sst-v2/stacks/Default.ts +13 -0
  193. package/examples/sst-v2/tsconfig.json +8 -0
  194. package/examples/terraform/README.md +38 -0
  195. package/examples/terraform/counter/counter.js +11 -0
  196. package/examples/terraform/counter/package.json +6 -0
  197. package/examples/terraform/main.tf +166 -0
  198. package/examples/terraform/outputs.tf +17 -0
  199. package/examples/terraform/terraform.tf +18 -0
  200. package/examples/terraform/variables.tf +6 -0
  201. package/examples/vercel-functions-app-router/.env.example +2 -0
  202. package/examples/vercel-functions-app-router/.eslintrc.json +3 -0
  203. package/examples/vercel-functions-app-router/README.md +26 -0
  204. package/examples/vercel-functions-app-router/app/api/hello/route.ts +11 -0
  205. package/examples/vercel-functions-app-router/app/globals.css +3 -0
  206. package/examples/vercel-functions-app-router/app/layout.tsx +22 -0
  207. package/examples/vercel-functions-app-router/ci.test.ts +14 -0
  208. package/examples/vercel-functions-app-router/next.config.mjs +4 -0
  209. package/examples/vercel-functions-app-router/package.json +27 -0
  210. package/examples/vercel-functions-app-router/postcss.config.mjs +8 -0
  211. package/examples/vercel-functions-app-router/tailwind.config.ts +20 -0
  212. package/examples/vercel-functions-app-router/tsconfig.json +26 -0
  213. package/examples/vercel-functions-pages-router/.env.example +2 -0
  214. package/examples/vercel-functions-pages-router/.eslintrc.json +3 -0
  215. package/examples/vercel-functions-pages-router/README.md +26 -0
  216. package/examples/vercel-functions-pages-router/ci.test.ts +14 -0
  217. package/examples/vercel-functions-pages-router/next.config.mjs +6 -0
  218. package/examples/vercel-functions-pages-router/package.json +27 -0
  219. package/examples/vercel-functions-pages-router/pages/_app.tsx +6 -0
  220. package/examples/vercel-functions-pages-router/pages/_document.tsx +13 -0
  221. package/examples/vercel-functions-pages-router/pages/api/hello.ts +12 -0
  222. package/examples/vercel-functions-pages-router/postcss.config.mjs +8 -0
  223. package/examples/vercel-functions-pages-router/styles/globals.css +3 -0
  224. package/examples/vercel-functions-pages-router/tailwind.config.ts +20 -0
  225. package/examples/vercel-functions-pages-router/tsconfig.json +21 -0
  226. package/examples/vercel-python-runtime-django/.env.example +2 -0
  227. package/examples/vercel-python-runtime-django/README.md +34 -0
  228. package/examples/vercel-python-runtime-django/api/__init__.py +0 -0
  229. package/examples/vercel-python-runtime-django/api/asgi.py +16 -0
  230. package/examples/vercel-python-runtime-django/api/settings.py +121 -0
  231. package/examples/vercel-python-runtime-django/api/urls.py +22 -0
  232. package/examples/vercel-python-runtime-django/api/wsgi.py +16 -0
  233. package/examples/vercel-python-runtime-django/example/__init__.py +0 -0
  234. package/examples/vercel-python-runtime-django/example/admin.py +3 -0
  235. package/examples/vercel-python-runtime-django/example/apps.py +6 -0
  236. package/examples/vercel-python-runtime-django/example/urls.py +9 -0
  237. package/examples/vercel-python-runtime-django/example/views.py +18 -0
  238. package/examples/vercel-python-runtime-django/manage.py +22 -0
  239. package/examples/vercel-python-runtime-django/package.json +5 -0
  240. package/examples/vercel-python-runtime-django/requirements.txt +2 -0
  241. package/examples/vercel-python-runtime-django/vercel.json +8 -0
  242. package/examples/with-sentry/index.ts +36 -0
  243. package/examples/with-sentry/package.json +17 -0
  244. package/package.json +1 -1
  245. package/pkg/auto-pipeline.test.ts +321 -0
  246. package/pkg/auto-pipeline.ts +107 -0
  247. package/pkg/commands/append.test.ts +28 -0
  248. package/pkg/commands/append.ts +11 -0
  249. package/pkg/commands/bitcount.test.ts +37 -0
  250. package/pkg/commands/bitcount.ts +29 -0
  251. package/pkg/commands/bitfield.test.ts +51 -0
  252. package/pkg/commands/bitfield.ts +50 -0
  253. package/pkg/commands/bitop.test.ts +45 -0
  254. package/pkg/commands/bitop.ts +22 -0
  255. package/pkg/commands/bitpos.test.ts +47 -0
  256. package/pkg/commands/bitpos.ts +14 -0
  257. package/pkg/commands/command.test.ts +22 -0
  258. package/pkg/commands/command.ts +98 -0
  259. package/pkg/commands/copy.test.ts +65 -0
  260. package/pkg/commands/copy.ts +22 -0
  261. package/pkg/commands/dbsize.test.ts +18 -0
  262. package/pkg/commands/dbsize.ts +11 -0
  263. package/pkg/commands/decr.test.ts +23 -0
  264. package/pkg/commands/decr.ts +11 -0
  265. package/pkg/commands/decrby.test.ts +24 -0
  266. package/pkg/commands/decrby.ts +11 -0
  267. package/pkg/commands/del.test.ts +38 -0
  268. package/pkg/commands/del.ts +11 -0
  269. package/pkg/commands/echo.test.ts +11 -0
  270. package/pkg/commands/echo.ts +11 -0
  271. package/pkg/commands/eval.test.ts +30 -0
  272. package/pkg/commands/eval.ts +14 -0
  273. package/pkg/commands/evalsha.test.ts +19 -0
  274. package/pkg/commands/evalsha.ts +14 -0
  275. package/pkg/commands/exists.test.ts +38 -0
  276. package/pkg/commands/exists.ts +11 -0
  277. package/pkg/commands/expire.test.ts +119 -0
  278. package/pkg/commands/expire.ts +12 -0
  279. package/pkg/commands/expireat.test.ts +25 -0
  280. package/pkg/commands/expireat.ts +11 -0
  281. package/pkg/commands/flushall.test.ts +18 -0
  282. package/pkg/commands/flushall.ts +14 -0
  283. package/pkg/commands/flushdb.test.ts +17 -0
  284. package/pkg/commands/flushdb.ts +14 -0
  285. package/pkg/commands/geo_add.test.ts +202 -0
  286. package/pkg/commands/geo_add.ts +54 -0
  287. package/pkg/commands/geo_dist.test.ts +79 -0
  288. package/pkg/commands/geo_dist.ts +19 -0
  289. package/pkg/commands/geo_hash.test.ts +49 -0
  290. package/pkg/commands/geo_hash.ts +23 -0
  291. package/pkg/commands/geo_pos.test.ts +60 -0
  292. package/pkg/commands/geo_pos.ts +39 -0
  293. package/pkg/commands/geo_search.test.ts +197 -0
  294. package/pkg/commands/geo_search.ts +139 -0
  295. package/pkg/commands/geo_search_store.test.ts +153 -0
  296. package/pkg/commands/geo_search_store.ts +69 -0
  297. package/pkg/commands/get.test.ts +35 -0
  298. package/pkg/commands/get.ts +11 -0
  299. package/pkg/commands/getbit.test.ts +17 -0
  300. package/pkg/commands/getbit.ts +11 -0
  301. package/pkg/commands/getdel.test.ts +39 -0
  302. package/pkg/commands/getdel.ts +11 -0
  303. package/pkg/commands/getrange.test.ts +25 -0
  304. package/pkg/commands/getrange.ts +14 -0
  305. package/pkg/commands/getset.test.ts +33 -0
  306. package/pkg/commands/getset.ts +14 -0
  307. package/pkg/commands/hdel.test.ts +45 -0
  308. package/pkg/commands/hdel.ts +11 -0
  309. package/pkg/commands/hexists.test.ts +36 -0
  310. package/pkg/commands/hexists.ts +11 -0
  311. package/pkg/commands/hget.test.ts +52 -0
  312. package/pkg/commands/hget.ts +14 -0
  313. package/pkg/commands/hgetall.test.ts +45 -0
  314. package/pkg/commands/hgetall.ts +37 -0
  315. package/pkg/commands/hincrby.test.ts +28 -0
  316. package/pkg/commands/hincrby.ts +14 -0
  317. package/pkg/commands/hincrbyfloat.test.ts +28 -0
  318. package/pkg/commands/hincrbyfloat.ts +14 -0
  319. package/pkg/commands/hkeys.test.ts +23 -0
  320. package/pkg/commands/hkeys.ts +11 -0
  321. package/pkg/commands/hlen.test.ts +25 -0
  322. package/pkg/commands/hlen.ts +11 -0
  323. package/pkg/commands/hmget.test.ts +44 -0
  324. package/pkg/commands/hmget.ts +46 -0
  325. package/pkg/commands/hmset.test.ts +23 -0
  326. package/pkg/commands/hmset.ts +14 -0
  327. package/pkg/commands/hrandfield.test.ts +59 -0
  328. package/pkg/commands/hrandfield.ts +50 -0
  329. package/pkg/commands/hscan.test.ts +44 -0
  330. package/pkg/commands/hscan.ts +30 -0
  331. package/pkg/commands/hset.test.ts +21 -0
  332. package/pkg/commands/hset.ts +14 -0
  333. package/pkg/commands/hsetnx.test.ts +37 -0
  334. package/pkg/commands/hsetnx.ts +14 -0
  335. package/pkg/commands/hstrlen.test.ts +24 -0
  336. package/pkg/commands/hstrlen.ts +11 -0
  337. package/pkg/commands/hvals.test.ts +24 -0
  338. package/pkg/commands/hvals.ts +11 -0
  339. package/pkg/commands/incr.test.ts +24 -0
  340. package/pkg/commands/incr.ts +11 -0
  341. package/pkg/commands/incrby.test.ts +24 -0
  342. package/pkg/commands/incrby.ts +11 -0
  343. package/pkg/commands/incrbyfloat.test.ts +25 -0
  344. package/pkg/commands/incrbyfloat.ts +11 -0
  345. package/pkg/commands/json_arrappend.test.ts +40 -0
  346. package/pkg/commands/json_arrappend.ts +17 -0
  347. package/pkg/commands/json_arrindex.test.ts +54 -0
  348. package/pkg/commands/json_arrindex.ts +14 -0
  349. package/pkg/commands/json_arrinsert.test.ts +49 -0
  350. package/pkg/commands/json_arrinsert.ts +17 -0
  351. package/pkg/commands/json_arrlen.test.ts +31 -0
  352. package/pkg/commands/json_arrlen.ts +14 -0
  353. package/pkg/commands/json_arrpop.test.ts +30 -0
  354. package/pkg/commands/json_arrpop.ts +14 -0
  355. package/pkg/commands/json_arrtrim.test.ts +31 -0
  356. package/pkg/commands/json_arrtrim.ts +18 -0
  357. package/pkg/commands/json_clear.test.ts +35 -0
  358. package/pkg/commands/json_clear.ts +11 -0
  359. package/pkg/commands/json_del.test.ts +29 -0
  360. package/pkg/commands/json_del.ts +11 -0
  361. package/pkg/commands/json_forget.test.ts +29 -0
  362. package/pkg/commands/json_forget.ts +11 -0
  363. package/pkg/commands/json_get.test.ts +28 -0
  364. package/pkg/commands/json_get.ts +44 -0
  365. package/pkg/commands/json_mget.test.ts +43 -0
  366. package/pkg/commands/json_mget.ts +11 -0
  367. package/pkg/commands/json_mset.test.ts +50 -0
  368. package/pkg/commands/json_mset.ts +26 -0
  369. package/pkg/commands/json_numincrby.test.ts +28 -0
  370. package/pkg/commands/json_numincrby.ts +14 -0
  371. package/pkg/commands/json_nummultby.test.ts +28 -0
  372. package/pkg/commands/json_nummultby.ts +14 -0
  373. package/pkg/commands/json_objkeys.test.ts +32 -0
  374. package/pkg/commands/json_objkeys.ts +14 -0
  375. package/pkg/commands/json_objlen.test.ts +26 -0
  376. package/pkg/commands/json_objlen.ts +14 -0
  377. package/pkg/commands/json_resp.test.ts +31 -0
  378. package/pkg/commands/json_resp.ts +11 -0
  379. package/pkg/commands/json_set.test.ts +48 -0
  380. package/pkg/commands/json_set.ts +34 -0
  381. package/pkg/commands/json_strappend.test.ts +34 -0
  382. package/pkg/commands/json_strappend.ts +14 -0
  383. package/pkg/commands/json_strlen.test.ts +27 -0
  384. package/pkg/commands/json_strlen.ts +14 -0
  385. package/pkg/commands/json_toggle.test.ts +26 -0
  386. package/pkg/commands/json_toggle.ts +11 -0
  387. package/pkg/commands/json_type.test.ts +29 -0
  388. package/pkg/commands/json_type.ts +11 -0
  389. package/pkg/commands/keys.test.ts +18 -0
  390. package/pkg/commands/keys.ts +11 -0
  391. package/pkg/commands/lindex.test.ts +33 -0
  392. package/pkg/commands/lindex.ts +11 -0
  393. package/pkg/commands/linsert.test.ts +24 -0
  394. package/pkg/commands/linsert.ts +10 -0
  395. package/pkg/commands/llen.test.ts +27 -0
  396. package/pkg/commands/llen.ts +11 -0
  397. package/pkg/commands/lmove.test.ts +48 -0
  398. package/pkg/commands/lmove.ts +19 -0
  399. package/pkg/commands/lmpop.test.ts +86 -0
  400. package/pkg/commands/lmpop.ts +19 -0
  401. package/pkg/commands/lpop.test.ts +40 -0
  402. package/pkg/commands/lpop.ts +14 -0
  403. package/pkg/commands/lpos.test.ts +56 -0
  404. package/pkg/commands/lpos.ts +25 -0
  405. package/pkg/commands/lpush.test.ts +18 -0
  406. package/pkg/commands/lpush.ts +11 -0
  407. package/pkg/commands/lpushx.test.ts +30 -0
  408. package/pkg/commands/lpushx.ts +11 -0
  409. package/pkg/commands/lrange.test.ts +21 -0
  410. package/pkg/commands/lrange.ts +11 -0
  411. package/pkg/commands/lrem.test.ts +19 -0
  412. package/pkg/commands/lrem.ts +10 -0
  413. package/pkg/commands/lset.test.ts +43 -0
  414. package/pkg/commands/lset.ts +8 -0
  415. package/pkg/commands/ltrim.test.ts +30 -0
  416. package/pkg/commands/ltrim.ts +8 -0
  417. package/pkg/commands/mget.test.ts +44 -0
  418. package/pkg/commands/mget.ts +11 -0
  419. package/pkg/commands/mod.ts +168 -0
  420. package/pkg/commands/mset.test.ts +24 -0
  421. package/pkg/commands/mset.ts +11 -0
  422. package/pkg/commands/msetnx.test.ts +46 -0
  423. package/pkg/commands/msetnx.ts +11 -0
  424. package/pkg/commands/persist.test.ts +22 -0
  425. package/pkg/commands/persist.ts +11 -0
  426. package/pkg/commands/pexpire.test.ts +24 -0
  427. package/pkg/commands/pexpire.ts +11 -0
  428. package/pkg/commands/pexpireat.test.ts +31 -0
  429. package/pkg/commands/pexpireat.ts +11 -0
  430. package/pkg/commands/pfadd.test.ts +80 -0
  431. package/pkg/commands/pfadd.ts +11 -0
  432. package/pkg/commands/pfcount.test.ts +55 -0
  433. package/pkg/commands/pfcount.ts +11 -0
  434. package/pkg/commands/pfmerge.test.ts +67 -0
  435. package/pkg/commands/pfmerge.ts +11 -0
  436. package/pkg/commands/ping.test.ts +19 -0
  437. package/pkg/commands/ping.ts +14 -0
  438. package/pkg/commands/psetex.test.ts +23 -0
  439. package/pkg/commands/psetex.ts +14 -0
  440. package/pkg/commands/pttl.test.ts +18 -0
  441. package/pkg/commands/pttl.ts +11 -0
  442. package/pkg/commands/publish.test.ts +12 -0
  443. package/pkg/commands/publish.ts +11 -0
  444. package/pkg/commands/randomkey.test.ts +16 -0
  445. package/pkg/commands/randomkey.ts +11 -0
  446. package/pkg/commands/rename.test.ts +19 -0
  447. package/pkg/commands/rename.ts +11 -0
  448. package/pkg/commands/renamenx.test.ts +33 -0
  449. package/pkg/commands/renamenx.ts +11 -0
  450. package/pkg/commands/rpop.test.ts +40 -0
  451. package/pkg/commands/rpop.ts +17 -0
  452. package/pkg/commands/rpush.test.ts +17 -0
  453. package/pkg/commands/rpush.ts +11 -0
  454. package/pkg/commands/rpushx.test.ts +30 -0
  455. package/pkg/commands/rpushx.ts +11 -0
  456. package/pkg/commands/sadd.test.ts +22 -0
  457. package/pkg/commands/sadd.ts +14 -0
  458. package/pkg/commands/scan.test.ts +91 -0
  459. package/pkg/commands/scan.ts +33 -0
  460. package/pkg/commands/scard.test.ts +16 -0
  461. package/pkg/commands/scard.ts +10 -0
  462. package/pkg/commands/script_exists.test.ts +34 -0
  463. package/pkg/commands/script_exists.ts +14 -0
  464. package/pkg/commands/script_flush.ts +21 -0
  465. package/pkg/commands/script_load.test.ts +11 -0
  466. package/pkg/commands/script_load.ts +11 -0
  467. package/pkg/commands/sdiff.test.ts +20 -0
  468. package/pkg/commands/sdiff.ts +10 -0
  469. package/pkg/commands/sdiffstore.test.ts +22 -0
  470. package/pkg/commands/sdiffstore.ts +13 -0
  471. package/pkg/commands/set.test.ts +168 -0
  472. package/pkg/commands/set.ts +51 -0
  473. package/pkg/commands/setbit.test.ts +17 -0
  474. package/pkg/commands/setbit.ts +14 -0
  475. package/pkg/commands/setex.test.ts +22 -0
  476. package/pkg/commands/setex.ts +11 -0
  477. package/pkg/commands/setnx.test.ts +27 -0
  478. package/pkg/commands/setnx.ts +11 -0
  479. package/pkg/commands/setrange.test.ts +25 -0
  480. package/pkg/commands/setrange.ts +14 -0
  481. package/pkg/commands/sinter.test.ts +37 -0
  482. package/pkg/commands/sinter.ts +10 -0
  483. package/pkg/commands/sinterstore.test.ts +22 -0
  484. package/pkg/commands/sinterstore.ts +13 -0
  485. package/pkg/commands/sismember.test.ts +31 -0
  486. package/pkg/commands/sismember.ts +10 -0
  487. package/pkg/commands/smembers.test.ts +22 -0
  488. package/pkg/commands/smembers.ts +11 -0
  489. package/pkg/commands/smismember.test.ts +22 -0
  490. package/pkg/commands/smismember.ts +16 -0
  491. package/pkg/commands/smove.test.ts +18 -0
  492. package/pkg/commands/smove.ts +13 -0
  493. package/pkg/commands/spop.test.ts +36 -0
  494. package/pkg/commands/spop.ts +17 -0
  495. package/pkg/commands/srandmember.test.ts +31 -0
  496. package/pkg/commands/srandmember.ts +17 -0
  497. package/pkg/commands/srem.test.ts +19 -0
  498. package/pkg/commands/srem.ts +10 -0
  499. package/pkg/commands/sscan.test.ts +48 -0
  500. package/pkg/commands/sscan.ts +30 -0
  501. package/pkg/commands/strlen.test.ts +17 -0
  502. package/pkg/commands/strlen.ts +11 -0
  503. package/pkg/commands/sunion.test.ts +22 -0
  504. package/pkg/commands/sunion.ts +11 -0
  505. package/pkg/commands/sunionstore.test.ts +30 -0
  506. package/pkg/commands/sunionstore.ts +14 -0
  507. package/pkg/commands/time.test.ts +12 -0
  508. package/pkg/commands/time.ts +10 -0
  509. package/pkg/commands/touch.test.ts +21 -0
  510. package/pkg/commands/touch.ts +11 -0
  511. package/pkg/commands/ttl.test.ts +17 -0
  512. package/pkg/commands/ttl.ts +11 -0
  513. package/pkg/commands/type.test.ts +72 -0
  514. package/pkg/commands/type.ts +12 -0
  515. package/pkg/commands/types.ts +150 -0
  516. package/pkg/commands/unlink.test.ts +22 -0
  517. package/pkg/commands/unlink.ts +11 -0
  518. package/pkg/commands/xack.test.ts +53 -0
  519. package/pkg/commands/xack.ts +15 -0
  520. package/pkg/commands/xadd.test.ts +128 -0
  521. package/pkg/commands/xadd.ts +64 -0
  522. package/pkg/commands/xautoclaim.test.ts +105 -0
  523. package/pkg/commands/xautoclaim.ts +30 -0
  524. package/pkg/commands/xclaim.test.ts +70 -0
  525. package/pkg/commands/xclaim.ts +55 -0
  526. package/pkg/commands/xdel.test.ts +50 -0
  527. package/pkg/commands/xdel.ts +15 -0
  528. package/pkg/commands/xgroup.test.ts +202 -0
  529. package/pkg/commands/xgroup.ts +100 -0
  530. package/pkg/commands/xinfo.test.ts +82 -0
  531. package/pkg/commands/xinfo.ts +27 -0
  532. package/pkg/commands/xlen.test.ts +29 -0
  533. package/pkg/commands/xlen.ts +11 -0
  534. package/pkg/commands/xpending.test.ts +94 -0
  535. package/pkg/commands/xpending.ts +43 -0
  536. package/pkg/commands/xrange.test.ts +69 -0
  537. package/pkg/commands/xrange.ts +48 -0
  538. package/pkg/commands/xread.test.ts +117 -0
  539. package/pkg/commands/xread.ts +51 -0
  540. package/pkg/commands/xreadgroup.test.ts +166 -0
  541. package/pkg/commands/xreadgroup.ts +66 -0
  542. package/pkg/commands/xrevrange.test.ts +48 -0
  543. package/pkg/commands/xrevrange.ts +47 -0
  544. package/pkg/commands/xtrim.test.ts +65 -0
  545. package/pkg/commands/xtrim.ts +24 -0
  546. package/pkg/commands/zadd.test.ts +242 -0
  547. package/pkg/commands/zadd.ts +53 -0
  548. package/pkg/commands/zcard.test.ts +16 -0
  549. package/pkg/commands/zcard.ts +11 -0
  550. package/pkg/commands/zcount.test.ts +16 -0
  551. package/pkg/commands/zcount.ts +13 -0
  552. package/pkg/commands/zdiffstore.test.ts +42 -0
  553. package/pkg/commands/zdiffstore.ts +14 -0
  554. package/pkg/commands/zincrby.test.ts +19 -0
  555. package/pkg/commands/zincrby.ts +13 -0
  556. package/pkg/commands/zinterstore.test.ts +297 -0
  557. package/pkg/commands/zinterstore.ts +51 -0
  558. package/pkg/commands/zlexcount.test.ts +23 -0
  559. package/pkg/commands/zlexcount.ts +10 -0
  560. package/pkg/commands/zmscore.test.ts +39 -0
  561. package/pkg/commands/zmscore.ts +15 -0
  562. package/pkg/commands/zpopmax.test.ts +46 -0
  563. package/pkg/commands/zpopmax.ts +17 -0
  564. package/pkg/commands/zpopmin.test.ts +50 -0
  565. package/pkg/commands/zpopmin.ts +17 -0
  566. package/pkg/commands/zrange.test.ts +188 -0
  567. package/pkg/commands/zrange.ts +68 -0
  568. package/pkg/commands/zrank.test.ts +23 -0
  569. package/pkg/commands/zrank.ts +14 -0
  570. package/pkg/commands/zrem.test.ts +21 -0
  571. package/pkg/commands/zrem.ts +10 -0
  572. package/pkg/commands/zremrangebylex.test.ts +24 -0
  573. package/pkg/commands/zremrangebylex.ts +10 -0
  574. package/pkg/commands/zremrangebyrank.test.ts +27 -0
  575. package/pkg/commands/zremrangebyrank.ts +13 -0
  576. package/pkg/commands/zremrangebyscore.test.ts +24 -0
  577. package/pkg/commands/zremrangebyscore.ts +10 -0
  578. package/pkg/commands/zrevrank.test.ts +23 -0
  579. package/pkg/commands/zrevrank.ts +14 -0
  580. package/pkg/commands/zscan.test.ts +48 -0
  581. package/pkg/commands/zscan.ts +30 -0
  582. package/pkg/commands/zscore.test.ts +18 -0
  583. package/pkg/commands/zscore.ts +14 -0
  584. package/pkg/commands/zunion.test.ts +251 -0
  585. package/pkg/commands/zunion.ts +54 -0
  586. package/pkg/commands/zunionstore.test.ts +274 -0
  587. package/pkg/commands/zunionstore.ts +51 -0
  588. package/pkg/error.ts +18 -0
  589. package/pkg/http.ts +349 -0
  590. package/pkg/index.ts +1 -0
  591. package/pkg/pipeline.test.ts +254 -0
  592. package/pkg/pipeline.ts +1401 -0
  593. package/pkg/read-your-writes.test.ts +115 -0
  594. package/pkg/redis.test.ts +250 -0
  595. package/pkg/redis.ts +1367 -0
  596. package/pkg/script.test.ts +58 -0
  597. package/pkg/script.ts +67 -0
  598. package/pkg/test-utils.test.ts +17 -0
  599. package/pkg/test-utils.ts +72 -0
  600. package/pkg/types.ts +35 -0
  601. package/pkg/util.ts +42 -0
  602. package/platforms/cloudflare.ts +144 -0
  603. package/platforms/fastly.ts +100 -0
  604. package/platforms/nodejs.ts +196 -0
  605. package/prettier.config.mjs +13 -0
  606. package/tsconfig.json +21 -0
  607. package/tsup.config.ts +8 -0
  608. package/version.ts +1 -0
  609. package/chunk-JD7AT2OK.js +0 -1
  610. package/chunk-XCPX3L6C.mjs +0 -1
  611. package/cloudflare.d.mts +0 -50
  612. package/cloudflare.d.ts +0 -50
  613. package/cloudflare.js +0 -1
  614. package/cloudflare.mjs +0 -1
  615. package/fastly.d.mts +0 -43
  616. package/fastly.d.ts +0 -43
  617. package/fastly.js +0 -1
  618. package/fastly.mjs +0 -1
  619. package/nodejs.d.mts +0 -85
  620. package/nodejs.d.ts +0 -85
  621. package/nodejs.js +0 -1
  622. package/nodejs.mjs +0 -1
@@ -0,0 +1,321 @@
1
+ import { Redis } from "../platforms/nodejs";
2
+ import { keygen, newHttpClient } from "./test-utils";
3
+
4
+ import { afterEach, describe, expect, test } from "bun:test";
5
+ import { ScriptLoadCommand } from "./commands/script_load";
6
+
7
+ const client = newHttpClient();
8
+
9
+ const { newKey, cleanup } = keygen();
10
+ afterEach(cleanup);
11
+
12
+ describe("Auto pipeline", () => {
13
+ test("should execute all commands inside a Promise.all in a single pipeline", async () => {
14
+ const persistentKey = newKey();
15
+ const persistentKey2 = newKey();
16
+ const persistentKey3 = newKey();
17
+ const scriptHash = await new ScriptLoadCommand(["return 1"]).exec(client);
18
+
19
+ const redis = Redis.fromEnv({
20
+ latencyLogging: false,
21
+ enableAutoPipelining: true,
22
+ });
23
+ // @ts-expect-error pipelineCounter is not in type but accessible
24
+ expect(redis.pipelineCounter).toBe(0);
25
+
26
+ // all the following commands are in a single pipeline call
27
+ const result = await Promise.all([
28
+ redis.append(newKey(), "hello"),
29
+ redis.bitcount(newKey(), 0, 1),
30
+ redis.bitop("and", newKey(), newKey()),
31
+ redis.bitpos(newKey(), 1, 0),
32
+ redis.dbsize(),
33
+ redis.decr(newKey()),
34
+ redis.decrby(newKey(), 1),
35
+ redis.del(newKey()),
36
+ redis.echo("hello"),
37
+ redis.eval("return ARGV[1]", [], ["Hello"]),
38
+ redis.evalsha(scriptHash, [], ["Hello"]),
39
+ redis.exists(newKey()),
40
+ redis.expire(newKey(), 5),
41
+ redis.expireat(newKey(), Math.floor(Date.now() / 1000) + 60),
42
+ redis.flushall(),
43
+ redis.flushdb(),
44
+ redis.get(newKey()),
45
+ redis.getbit(newKey(), 0),
46
+ redis.getdel(newKey()),
47
+ redis.getset(newKey(), "hello"),
48
+ redis.hdel(newKey(), "field"),
49
+ redis.hexists(newKey(), "field"),
50
+ redis.hget(newKey(), "field"),
51
+ redis.hgetall(newKey()),
52
+ redis.hincrby(newKey(), "field", 1),
53
+ redis.hincrbyfloat(newKey(), "field", 1.5),
54
+ redis.hkeys(newKey()),
55
+ redis.hlen(newKey()),
56
+ redis.hmget(newKey(), newKey()),
57
+ redis.hmset(newKey(), { field: "field", value: "value" }),
58
+ redis.hscan(newKey(), 0),
59
+ redis.hset(newKey(), { field: "value" }),
60
+ redis.hsetnx(newKey(), "field", "value"),
61
+ redis.hstrlen(newKey(), "field"),
62
+ redis.hvals(newKey()),
63
+ redis.incr(newKey()),
64
+ redis.incrby(newKey(), 1),
65
+ redis.incrbyfloat(newKey(), 1.5),
66
+ redis.keys("*"),
67
+ redis.lindex(newKey(), 0),
68
+ redis.linsert(newKey(), "before", "pivot", "value"),
69
+ redis.llen(newKey()),
70
+ redis.lmove(newKey(), newKey(), "left", "right"),
71
+ redis.lpop(newKey()),
72
+ redis.lpos(newKey(), "value"),
73
+ redis.lpush(persistentKey, "element"),
74
+ redis.lpushx(newKey(), "element1", "element2"),
75
+ redis.lrange(newKey(), 0, 1),
76
+ redis.lrem(newKey(), 1, "value"),
77
+ redis.lset(persistentKey, 0, "value"),
78
+ redis.ltrim(newKey(), 0, 1),
79
+ redis.hrandfield(newKey()),
80
+ redis.hrandfield(newKey(), 2),
81
+ redis.hrandfield(newKey(), 3, true),
82
+ redis.mget<[string, string]>(newKey(), newKey()),
83
+ redis.mset({ key1: "value", key2: "value" }),
84
+ redis.msetnx({ key3: "value", key4: "value" }),
85
+ redis.persist(newKey()),
86
+ redis.pexpire(newKey(), 1000),
87
+ redis.pexpireat(newKey(), Date.now() + 1000),
88
+ redis.ping(),
89
+ redis.psetex(newKey(), 1, "value"),
90
+ redis.pttl(newKey()),
91
+ redis.publish("test", "hello"),
92
+ redis.randomkey(),
93
+ redis.rename(persistentKey, persistentKey2),
94
+ redis.renamenx(persistentKey2, newKey()),
95
+ redis.rpop(newKey()),
96
+ redis.rpush(newKey(), "element1", "element2"),
97
+ redis.rpushx(newKey(), "element1", "element2"),
98
+ redis.sadd(newKey(), "memeber1", "member2"),
99
+ redis.scan(0),
100
+ redis.scard(newKey()),
101
+ redis.sdiff(newKey()),
102
+ redis.sdiffstore(newKey(), newKey()),
103
+ redis.set(newKey(), "value"),
104
+ redis.setbit(newKey(), 1, 1),
105
+ redis.setex(newKey(), 1, "value"),
106
+ redis.setnx(newKey(), "value"),
107
+ redis.setrange(newKey(), 1, "value"),
108
+ redis.sinter(newKey(), newKey()),
109
+ redis.sinterstore(newKey(), newKey()),
110
+ redis.sismember(newKey(), "member"),
111
+ redis.smembers(newKey()),
112
+ redis.smove(newKey(), newKey(), "member"),
113
+ redis.spop(newKey()),
114
+ redis.srandmember(newKey()),
115
+ redis.srem(newKey(), "member"),
116
+ redis.sscan(newKey(), 0),
117
+ redis.strlen(newKey()),
118
+ redis.sunion(newKey()),
119
+ redis.sunionstore(newKey(), newKey()),
120
+ redis.time(),
121
+ redis.touch(newKey()),
122
+ redis.ttl(newKey()),
123
+ redis.type(newKey()),
124
+ redis.unlink(newKey()),
125
+ redis.zadd(newKey(), { score: 0, member: "member" }),
126
+ redis.zcard(newKey()),
127
+ redis.scriptExists(scriptHash),
128
+ redis.scriptFlush({ async: true }),
129
+ redis.scriptLoad("return 1"),
130
+ redis.zcount(newKey(), 0, 1),
131
+ redis.zincrby(newKey(), 1, "member"),
132
+ redis.zinterstore(newKey(), 1, [newKey()]),
133
+ redis.zlexcount(newKey(), "-", "+"),
134
+ redis.zpopmax(newKey()),
135
+ redis.zpopmin(newKey()),
136
+ redis.zrange(newKey(), 0, 1),
137
+ redis.zrank(newKey(), "member"),
138
+ redis.zrem(newKey(), "member"),
139
+ redis.zremrangebylex(newKey(), "-", "+"),
140
+ redis.zremrangebyrank(newKey(), 0, 1),
141
+ redis.zremrangebyscore(newKey(), 0, 1),
142
+ redis.zrevrank(newKey(), "member"),
143
+ redis.zscan(newKey(), 0),
144
+ redis.zscore(newKey(), "member"),
145
+ redis.zunionstore(newKey(), 1, [newKey()]),
146
+ redis.zunion(1, [newKey()]),
147
+ redis.json.set(persistentKey3, "$", { log: ["one", "two"] }),
148
+ redis.json.arrappend(persistentKey3, "$.log", '"three"'),
149
+ ]);
150
+ expect(result).toBeTruthy();
151
+ expect(result.length).toBe(121); // returns
152
+ // @ts-expect-error pipelineCounter is not in type but accessible120 results
153
+ expect(redis.pipelineCounter).toBe(1);
154
+ });
155
+
156
+ test("should group async requests with sync requests", async () => {
157
+ const redis = Redis.fromEnv({
158
+ latencyLogging: false,
159
+ enableAutoPipelining: true,
160
+ });
161
+ // @ts-expect-error pipelineCounter is not in type but accessible
162
+ expect(redis.pipelineCounter).toBe(0);
163
+
164
+ // following five commands are added to the pipeline
165
+ void redis.flushdb();
166
+ void redis.incr("baz");
167
+ void redis.incr("baz");
168
+ void redis.set("foo", "bar");
169
+ void redis.incr("baz");
170
+
171
+ // two get calls are added to the pipeline and pipeline
172
+ // is executed since we called await
173
+ const [fooValue, bazValue] = await Promise.all([redis.get("foo"), redis.get("baz")]);
174
+
175
+ expect(fooValue).toBe("bar");
176
+ expect(bazValue).toBe(3);
177
+ // @ts-expect-error pipelineCounter is not in type but accessible
178
+ expect(redis.pipelineCounter).toBe(1);
179
+ });
180
+
181
+ test("should execute a pipeline for each consecutive awaited command", async () => {
182
+ const redis = Redis.fromEnv({
183
+ latencyLogging: false,
184
+ enableAutoPipelining: true,
185
+ });
186
+ // @ts-expect-error pipelineCounter is not in type but accessible
187
+ expect(redis.pipelineCounter).toBe(0);
188
+
189
+ void redis.flushdb();
190
+
191
+ const res1 = await redis.incr("baz");
192
+ // @ts-expect-error pipelineCounter is not in type but accessible
193
+ expect(redis.pipelineCounter).toBe(1);
194
+
195
+ const res2 = await redis.incr("baz");
196
+ // @ts-expect-error pipelineCounter is not in type but accessible
197
+ expect(redis.pipelineCounter).toBe(2);
198
+
199
+ const res3 = await redis.set("foo", "bar");
200
+ // @ts-expect-error pipelineCounter is not in type but accessible
201
+ expect(redis.pipelineCounter).toBe(3);
202
+
203
+ expect([res1, res2, res3]).toEqual([1, 2, "OK"]);
204
+ });
205
+
206
+ test("should execute a single pipeline for several commands inside Promise.all", async () => {
207
+ const redis = Redis.fromEnv({
208
+ latencyLogging: false,
209
+ enableAutoPipelining: true,
210
+ });
211
+ // @ts-expect-error pipelineCounter is not in type but accessible
212
+ expect(redis.pipelineCounter).toBe(0);
213
+
214
+ const resArray = await Promise.all([
215
+ redis.flushdb(),
216
+ redis.incr("baz"),
217
+ redis.incr("baz"),
218
+ redis.set("foo", "bar"),
219
+ redis.get("foo"),
220
+ ]);
221
+ // @ts-expect-error pipelineCounter is not in type but accessible
222
+ expect(redis.pipelineCounter).toBe(1);
223
+ expect(resArray).toEqual(["OK", 1, 2, "OK", "bar"]);
224
+ });
225
+
226
+ test("should be able to utilize only redis functions 'use' like usual", async () => {
227
+ const redis = Redis.fromEnv({
228
+ latencyLogging: false,
229
+ enableAutoPipelining: true,
230
+ });
231
+ // @ts-expect-error pipelineCounter is not in type but accessible
232
+ expect(redis.pipelineCounter).toBe(0);
233
+
234
+ let state = false;
235
+ redis.use(async (req, next) => {
236
+ state = true;
237
+ return await next(req);
238
+ });
239
+
240
+ // @ts-expect-error pipelineCounter is not in type but accessible
241
+ expect(redis.pipelineCounter).toBe(0);
242
+
243
+ const a = await redis.incr("aeroplane");
244
+ expect(a).toEqual(1);
245
+ expect(state).toEqual(true);
246
+
247
+ // @ts-expect-error pipelineCounter is not in type but accessible
248
+ expect(redis.pipelineCounter).toBe(1);
249
+ });
250
+
251
+ test("should be able to utilize only redis functions 'multi' and 'pipeline' like usual", async () => {
252
+ const redis = Redis.fromEnv({
253
+ latencyLogging: false,
254
+ enableAutoPipelining: true,
255
+ });
256
+ // @ts-expect-error pipelineCounter is not in type but accessible
257
+ expect(redis.pipelineCounter).toBe(0);
258
+
259
+ const pipe = redis.pipeline();
260
+ pipe.incr("voila");
261
+ pipe.incr("voila");
262
+ const result = await pipe.exec();
263
+ expect(result).toEqual([1, 2]);
264
+
265
+ // @ts-expect-error pipelineCounter is not in type but accessible
266
+ expect(redis.pipelineCounter).toBe(0);
267
+
268
+ const transaction = redis.multi();
269
+ transaction.incr("et voila");
270
+ transaction.incr("et voila");
271
+ const result_2 = await transaction.exec();
272
+ expect(result_2).toEqual([1, 2]);
273
+
274
+ // @ts-expect-error pipelineCounter is not in type but accessible
275
+ expect(redis.pipelineCounter).toBe(0);
276
+ });
277
+
278
+ test("should be able to utilize only redis functions 'createScript' like usual", async () => {
279
+ const redis = Redis.fromEnv({
280
+ latencyLogging: false,
281
+ enableAutoPipelining: true,
282
+ });
283
+ // @ts-expect-error pipelineCounter is not in type but accessible
284
+ expect(redis.pipelineCounter).toBe(0);
285
+
286
+ const script = redis.createScript("return ARGV[1];");
287
+
288
+ // @ts-expect-error pipelineCounter is not in type but accessible
289
+ expect(redis.pipelineCounter).toBe(0);
290
+
291
+ const res = await script.eval([], ["Hello World"]);
292
+ expect(res).toEqual("Hello World");
293
+
294
+ // @ts-expect-error pipelineCounter is not in type but accessible
295
+ expect(redis.pipelineCounter).toBe(1);
296
+ });
297
+
298
+ test("should handle JSON commands correctly", async () => {
299
+ const redis = Redis.fromEnv({
300
+ latencyLogging: false,
301
+ enableAutoPipelining: true,
302
+ });
303
+
304
+ // @ts-expect-error pipelineCounter is not in type but accessible
305
+ expect(redis.pipelineCounter).toBe(0);
306
+
307
+ const res = await Promise.all([
308
+ redis.set("foo1", "bar"),
309
+ redis.json.set("baz1", "$", { hello: "world" }),
310
+ redis.get("foo1"),
311
+ redis.json.get("baz1"),
312
+ redis.json.del("baz1"),
313
+ redis.json.get("baz1"),
314
+ ]);
315
+
316
+ // @ts-expect-error pipelineCounter is not in type but accessible
317
+ expect(redis.pipelineCounter).toBe(1);
318
+
319
+ expect(res).toEqual(["OK", "OK", "bar", { hello: "world" }, 1, null]);
320
+ });
321
+ });
@@ -0,0 +1,107 @@
1
+ import type { Command } from "./commands/command";
2
+ import type { Pipeline } from "./pipeline";
3
+ import type { Redis } from "./redis";
4
+ import type { CommandArgs } from "./types";
5
+
6
+ // properties which are only available in redis
7
+ type redisOnly = Exclude<keyof Redis, keyof Pipeline>;
8
+
9
+ export function createAutoPipelineProxy(_redis: Redis, json?: boolean): Redis {
10
+ const redis = _redis as Redis & {
11
+ autoPipelineExecutor: AutoPipelineExecutor;
12
+ };
13
+
14
+ if (!redis.autoPipelineExecutor) {
15
+ redis.autoPipelineExecutor = new AutoPipelineExecutor(redis);
16
+ }
17
+
18
+ return new Proxy(redis, {
19
+ get: (redis, command: "pipelineCounter" | keyof Pipeline | redisOnly) => {
20
+ // return pipelineCounter of autoPipelineExecutor
21
+ if (command === "pipelineCounter") {
22
+ return redis.autoPipelineExecutor.pipelineCounter;
23
+ }
24
+
25
+ if (command === "json") {
26
+ return createAutoPipelineProxy(redis, true);
27
+ }
28
+
29
+ const commandInRedisButNotPipeline =
30
+ command in redis && !(command in redis.autoPipelineExecutor.pipeline);
31
+
32
+ if (commandInRedisButNotPipeline) {
33
+ return redis[command as redisOnly];
34
+ }
35
+
36
+ // If the method is a function on the pipeline, wrap it with the executor logic
37
+ const isFunction = json
38
+ ? typeof redis.autoPipelineExecutor.pipeline.json[command as keyof Pipeline["json"]] ===
39
+ "function"
40
+ : typeof redis.autoPipelineExecutor.pipeline[command as keyof Pipeline] === "function";
41
+ if (isFunction) {
42
+ return (...args: CommandArgs<typeof Command>) => {
43
+ // pass the function as a callback
44
+ return redis.autoPipelineExecutor.withAutoPipeline((pipeline) => {
45
+ if (json) {
46
+ (pipeline.json[command as keyof Pipeline["json"]] as (...args: any) => unknown)(
47
+ ...args
48
+ );
49
+ } else {
50
+ (pipeline[command as keyof Pipeline] as (...args: any) => unknown)(...args);
51
+ }
52
+ });
53
+ };
54
+ }
55
+
56
+ // if the property is not a function, a property of redis or "pipelineCounter"
57
+ // simply return it from pipeline
58
+ return redis.autoPipelineExecutor.pipeline[command as keyof Pipeline];
59
+ },
60
+ }) as Redis;
61
+ }
62
+
63
+ class AutoPipelineExecutor {
64
+ private pipelinePromises = new WeakMap<Pipeline, Promise<unknown[]>>();
65
+ private activePipeline: Pipeline | null = null;
66
+ private indexInCurrentPipeline = 0;
67
+ private redis: Redis;
68
+ pipeline: Pipeline; // only to make sure that proxy can work
69
+ pipelineCounter = 0; // to keep track of how many times a pipeline was executed
70
+
71
+ constructor(redis: Redis) {
72
+ this.redis = redis;
73
+ this.pipeline = redis.pipeline();
74
+ }
75
+
76
+ async withAutoPipeline<T>(executeWithPipeline: (pipeline: Pipeline) => unknown): Promise<T> {
77
+ const pipeline = this.activePipeline ?? this.redis.pipeline();
78
+
79
+ if (!this.activePipeline) {
80
+ this.activePipeline = pipeline;
81
+ this.indexInCurrentPipeline = 0;
82
+ }
83
+
84
+ const index = this.indexInCurrentPipeline++;
85
+ executeWithPipeline(pipeline);
86
+
87
+ const pipelineDone = this.deferExecution().then(() => {
88
+ if (!this.pipelinePromises.has(pipeline)) {
89
+ const pipelinePromise = pipeline.exec();
90
+ this.pipelineCounter += 1;
91
+
92
+ this.pipelinePromises.set(pipeline, pipelinePromise);
93
+ this.activePipeline = null;
94
+ }
95
+
96
+ return this.pipelinePromises.get(pipeline)!;
97
+ });
98
+
99
+ const results = await pipelineDone;
100
+ return results[index] as T;
101
+ }
102
+
103
+ private async deferExecution() {
104
+ await Promise.resolve();
105
+ await Promise.resolve();
106
+ }
107
+ }
@@ -0,0 +1,28 @@
1
+ import { keygen, newHttpClient, randomID } from "../test-utils";
2
+ import { AppendCommand } from "./append";
3
+
4
+ import { afterAll, describe, expect, test } from "bun:test";
5
+ const client = newHttpClient();
6
+
7
+ const { newKey, cleanup } = keygen();
8
+ afterAll(cleanup);
9
+
10
+ describe("when key is not set", () => {
11
+ test("appends to empty value", async () => {
12
+ const key = newKey();
13
+ const value = randomID();
14
+ const res = await new AppendCommand([key, value]).exec(client);
15
+ expect(res).toEqual(value.length);
16
+ });
17
+ });
18
+
19
+ describe("when key is set", () => {
20
+ test("appends to existing value", async () => {
21
+ const key = newKey();
22
+ const value = randomID();
23
+ const res = await new AppendCommand([key, value]).exec(client);
24
+ expect(res).toEqual(value.length);
25
+ const res2 = await new AppendCommand([key, "_"]).exec(client);
26
+ expect(res2).toEqual(value.length + 1);
27
+ });
28
+ });
@@ -0,0 +1,11 @@
1
+ import type { CommandOptions } from "./command";
2
+ import { Command } from "./command";
3
+
4
+ /**
5
+ * @see https://redis.io/commands/append
6
+ */
7
+ export class AppendCommand extends Command<number, number> {
8
+ constructor(cmd: [key: string, value: string], opts?: CommandOptions<number, number>) {
9
+ super(["append", ...cmd], opts);
10
+ }
11
+ }
@@ -0,0 +1,37 @@
1
+ import { afterAll, describe, expect, test } from "bun:test";
2
+ import { keygen, newHttpClient } from "../test-utils";
3
+ import { BitCountCommand } from "./bitcount";
4
+
5
+ import { SetCommand } from "./set";
6
+ const client = newHttpClient();
7
+
8
+ const { newKey, cleanup } = keygen();
9
+ afterAll(cleanup);
10
+
11
+ describe("when key is not set", () => {
12
+ test("returns 0", async () => {
13
+ const key = newKey();
14
+ const res = await new BitCountCommand([key]).exec(client);
15
+ expect(res).toEqual(0);
16
+ });
17
+ });
18
+
19
+ describe("when key is set", () => {
20
+ test("returns bitcount", async () => {
21
+ const key = newKey();
22
+ const value = "Hello World";
23
+ await new SetCommand([key, value]).exec(client);
24
+ const res = await new BitCountCommand([key]).exec(client);
25
+ expect(res).toEqual(43);
26
+ });
27
+
28
+ test("with start and end", () => {
29
+ test("returns bitcount", async () => {
30
+ const key = newKey();
31
+ const value = "Hello World";
32
+ await new SetCommand([key, value]).exec(client);
33
+ const res = await new BitCountCommand([key, 4, 8]).exec(client);
34
+ expect(res).toEqual(22);
35
+ });
36
+ });
37
+ });
@@ -0,0 +1,29 @@
1
+ import type { CommandOptions } from "./command";
2
+ import { Command } from "./command";
3
+
4
+ /**
5
+ * @see https://redis.io/commands/bitcount
6
+ */
7
+ export class BitCountCommand extends Command<number, number> {
8
+ constructor(
9
+ cmd: [key: string, start?: never, end?: never],
10
+ opts?: CommandOptions<number, number>
11
+ );
12
+ constructor(
13
+ cmd: [key: string, start: number, end: number],
14
+ opts?: CommandOptions<number, number>
15
+ );
16
+ constructor(
17
+ [key, start, end]: [key: string, start?: number, end?: number],
18
+ opts?: CommandOptions<number, number>
19
+ ) {
20
+ const command: unknown[] = ["bitcount", key];
21
+ if (typeof start === "number") {
22
+ command.push(start);
23
+ }
24
+ if (typeof end === "number") {
25
+ command.push(end);
26
+ }
27
+ super(command, opts);
28
+ }
29
+ }
@@ -0,0 +1,51 @@
1
+ import { afterAll, describe, expect, test } from "bun:test";
2
+ import { keygen, newHttpClient } from "../test-utils";
3
+ import { BitFieldCommand } from "./bitfield";
4
+
5
+ const client = newHttpClient();
6
+
7
+ const { newKey, cleanup } = keygen();
8
+ afterAll(cleanup);
9
+
10
+ describe("when key is not set", () => {
11
+ test("returns 0", async () => {
12
+ const key = newKey();
13
+ const res = await new BitFieldCommand([key], client).get("u4", "#0").exec();
14
+ expect(res).toEqual([0]);
15
+ });
16
+ });
17
+
18
+ describe("when key is set", () => {
19
+ test("sets / gets value", async () => {
20
+ const key = newKey();
21
+ const value = 42;
22
+ const res = await new BitFieldCommand([key], client)
23
+ .set("u8", "#0", value)
24
+ .get("u8", "#0")
25
+ .exec();
26
+ expect(res).toEqual([0, value]);
27
+ });
28
+
29
+ test("increments value", async () => {
30
+ const key = newKey();
31
+ const value = 42;
32
+ const increment = 10;
33
+ const res = await new BitFieldCommand([key], client)
34
+ .set("u8", "#0", value)
35
+ .incrby("u8", "#0", increment)
36
+ .exec();
37
+ expect(res).toEqual([0, value + increment]);
38
+ });
39
+
40
+ test("overflows", async () => {
41
+ const key = newKey();
42
+ const value = 255;
43
+ const bitWidth = 8;
44
+ const res = await new BitFieldCommand([key], client)
45
+ .set(`u${bitWidth}`, "#0", value)
46
+ .incrby(`u${bitWidth}`, "#0", 10)
47
+ .overflow("WRAP")
48
+ .exec();
49
+ expect(res).toEqual([0, (value + 10) % 2 ** bitWidth]);
50
+ });
51
+ });
@@ -0,0 +1,50 @@
1
+ import { type Requester } from "../http";
2
+ import { Command, type CommandOptions } from "./command";
3
+
4
+ type SubCommandArgs<TRest extends unknown[] = []> = [
5
+ encoding: string, // u1 - u63 | i1 - i64
6
+ offset: number | string, // <int> | #<int>
7
+ ...rest: TRest,
8
+ ];
9
+
10
+ /**
11
+ * @see https://redis.io/commands/bitfield
12
+ */
13
+ export class BitFieldCommand<T = Promise<number[]>> {
14
+ private command: (string | number)[];
15
+
16
+ constructor(
17
+ args: [key: string],
18
+ private client: Requester,
19
+ private opts?: CommandOptions<number[], number[]>,
20
+ private execOperation = (command: Command<number[], number[]>) => command.exec(this.client) as T
21
+ ) {
22
+ this.command = ["bitfield", ...args];
23
+ }
24
+
25
+ private chain(...args: typeof this.command) {
26
+ this.command.push(...args);
27
+ return this;
28
+ }
29
+
30
+ get(...args: SubCommandArgs) {
31
+ return this.chain("get", ...args);
32
+ }
33
+
34
+ set(...args: SubCommandArgs<[value: number]>) {
35
+ return this.chain("set", ...args);
36
+ }
37
+
38
+ incrby(...args: SubCommandArgs<[increment: number]>) {
39
+ return this.chain("incrby", ...args);
40
+ }
41
+
42
+ overflow(overflow: "WRAP" | "SAT" | "FAIL") {
43
+ return this.chain("overflow", overflow);
44
+ }
45
+
46
+ exec() {
47
+ const command = new Command(this.command, this.opts);
48
+ return this.execOperation(command);
49
+ }
50
+ }
@@ -0,0 +1,45 @@
1
+ import { BitOpCommand } from "./bitop";
2
+
3
+ import { afterAll, describe, expect, test } from "bun:test";
4
+ import { keygen, newHttpClient } from "../test-utils";
5
+ import { SetCommand } from "./set";
6
+ const client = newHttpClient();
7
+
8
+ const { newKey, cleanup } = keygen();
9
+ afterAll(cleanup);
10
+
11
+ describe("when key is not set", () => {
12
+ test("returns 0", async () => {
13
+ const source = newKey();
14
+ const dest = newKey();
15
+ const res = await new BitOpCommand(["and", dest, source]).exec(client);
16
+ expect(res).toEqual(0);
17
+ });
18
+ });
19
+
20
+ describe("when key is set", () => {
21
+ describe("not", () => {
22
+ test("inverts all bits", async () => {
23
+ const source = newKey();
24
+ const sourcevalue = "Hello World";
25
+ const dest = newKey();
26
+ const destValue = "foo: bar";
27
+ await new SetCommand([source, sourcevalue]).exec(client);
28
+ await new SetCommand([dest, destValue]).exec(client);
29
+ const res = await new BitOpCommand(["not", dest, source]).exec(client);
30
+ expect(res).toEqual(11);
31
+ });
32
+ });
33
+ describe("and", () => {
34
+ test("works", async () => {
35
+ const source = newKey();
36
+ const sourcevalue = "Hello World";
37
+ const dest = newKey();
38
+ const destValue = "foo: bar";
39
+ await new SetCommand([source, sourcevalue]).exec(client);
40
+ await new SetCommand([dest, destValue]).exec(client);
41
+ const res = await new BitOpCommand(["and", dest, source]).exec(client);
42
+ expect(res).toEqual(11);
43
+ });
44
+ });
45
+ });