@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,119 @@
1
+ import { keygen, newHttpClient, randomID } from "../test-utils";
2
+
3
+ import { afterAll, describe, expect, test } from "bun:test";
4
+ import { ExpireCommand } from "./expire";
5
+ import { GetCommand } from "./get";
6
+ import { SetCommand } from "./set";
7
+ const client = newHttpClient();
8
+
9
+ const { newKey, cleanup } = keygen();
10
+ afterAll(cleanup);
11
+
12
+ test("expires a key correctly", async () => {
13
+ const key = newKey();
14
+ const value = randomID();
15
+ await new SetCommand([key, value]).exec(client);
16
+ const res = await new ExpireCommand([key, 1]).exec(client);
17
+ expect(res).toEqual(1);
18
+ await new Promise((res) => setTimeout(res, 2000));
19
+ const res2 = await new GetCommand([key]).exec(client);
20
+
21
+ expect(res2).toEqual(null);
22
+ });
23
+
24
+ describe("NX", () => {
25
+ test("should set expiry only when the key has no expiry", async () => {
26
+ const key = newKey();
27
+ const value = randomID();
28
+ await new SetCommand([key, value]).exec(client);
29
+ const res = await new ExpireCommand([key, 1, "NX"]).exec(client);
30
+ expect(res).toEqual(1);
31
+ await new Promise((res) => setTimeout(res, 2000));
32
+ const res2 = await new GetCommand([key]).exec(client);
33
+
34
+ expect(res2).toEqual(null);
35
+ });
36
+
37
+ test("should not set expiry when the key has expiry", async () => {
38
+ const key = newKey();
39
+ const value = randomID();
40
+ await new SetCommand([key, value, { ex: 1000 }]).exec(client);
41
+ const res = await new ExpireCommand([key, 1, "NX"]).exec(client);
42
+ expect(res).toEqual(0);
43
+ });
44
+ });
45
+
46
+ describe("XX", () => {
47
+ test(
48
+ "should set expiry only when the key has an existing expiry",
49
+ async () => {
50
+ const key = newKey();
51
+ const value = randomID();
52
+ await new SetCommand([key, value, { ex: 1 }]).exec(client);
53
+ const res = await new ExpireCommand([key, 5, "XX"]).exec(client);
54
+ expect(res).toEqual(1);
55
+ await new Promise((res) => setTimeout(res, 6000));
56
+ const res2 = await new GetCommand([key]).exec(client);
57
+ expect(res2).toEqual(null);
58
+ },
59
+ { timeout: 10_000 }
60
+ );
61
+
62
+ test("should not set expiry when the key does not have an existing expiry", async () => {
63
+ const key = newKey();
64
+ const value = randomID();
65
+ await new SetCommand([key, value]).exec(client);
66
+ const res = await new ExpireCommand([key, 5, "XX"]).exec(client);
67
+ expect(res).toEqual(0);
68
+ });
69
+ });
70
+
71
+ describe("GT", () => {
72
+ test(
73
+ "should set expiry only when the new expiry is greater than current one",
74
+ async () => {
75
+ const key = newKey();
76
+ const value = randomID();
77
+ await new SetCommand([key, value, { ex: 1 }]).exec(client);
78
+ const res = await new ExpireCommand([key, 5, "GT"]).exec(client);
79
+ expect(res).toEqual(1);
80
+ await new Promise((res) => setTimeout(res, 6000));
81
+ const res2 = await new GetCommand([key]).exec(client);
82
+ expect(res2).toEqual(null);
83
+ },
84
+ { timeout: 10_000 }
85
+ );
86
+
87
+ test("should not set expiry when the new expiry is not greater than current one", async () => {
88
+ const key = newKey();
89
+ const value = randomID();
90
+ await new SetCommand([key, value, { ex: 10 }]).exec(client);
91
+ const res = await new ExpireCommand([key, 5, "GT"]).exec(client);
92
+ expect(res).toEqual(0);
93
+ });
94
+ });
95
+
96
+ describe("LT", () => {
97
+ test(
98
+ "should set expiry only when the new expiry is less than current one",
99
+ async () => {
100
+ const key = newKey();
101
+ const value = randomID();
102
+ await new SetCommand([key, value, { ex: 5 }]).exec(client);
103
+ const res = await new ExpireCommand([key, 3, "LT"]).exec(client);
104
+ expect(res).toEqual(1);
105
+ await new Promise((res) => setTimeout(res, 4000));
106
+ const res2 = await new GetCommand([key]).exec(client);
107
+ expect(res2).toEqual(null);
108
+ },
109
+ { timeout: 10_000 }
110
+ );
111
+
112
+ test("should not set expiry when the new expiry is not less than current one", async () => {
113
+ const key = newKey();
114
+ const value = randomID();
115
+ await new SetCommand([key, value, { ex: 10 }]).exec(client);
116
+ const res = await new ExpireCommand([key, 20, "LT"]).exec(client);
117
+ expect(res).toEqual(0);
118
+ });
119
+ });
@@ -0,0 +1,12 @@
1
+ import type { CommandOptions } from "./command";
2
+ import { Command } from "./command";
3
+
4
+ type ExpireOptions = "NX" | "nx" | "XX" | "xx" | "GT" | "gt" | "LT" | "lt";
5
+ export class ExpireCommand extends Command<"0" | "1", 0 | 1> {
6
+ constructor(
7
+ cmd: [key: string, seconds: number, option?: ExpireOptions],
8
+ opts?: CommandOptions<"0" | "1", 0 | 1>
9
+ ) {
10
+ super(["expire", ...cmd.filter(Boolean)], opts);
11
+ }
12
+ }
@@ -0,0 +1,25 @@
1
+ import { keygen, newHttpClient, randomID } from "../test-utils";
2
+
3
+ import { afterAll, describe, expect, test } from "bun:test";
4
+ import { SetCommand } from "./set";
5
+
6
+ import { ExpireAtCommand } from "./expireat";
7
+ import { GetCommand } from "./get";
8
+ const client = newHttpClient();
9
+
10
+ const { newKey, cleanup } = keygen();
11
+ afterAll(cleanup);
12
+
13
+ describe("without options", () => {
14
+ test("expires the key", async () => {
15
+ const key = newKey();
16
+ const value = randomID();
17
+ await new SetCommand([key, value]).exec(client);
18
+
19
+ const res = await new ExpireAtCommand([key, 1]).exec(client);
20
+ expect(res).toEqual(1);
21
+ await new Promise((res) => setTimeout(res, 2000));
22
+ const res2 = await new GetCommand([key]).exec(client);
23
+ expect(res2).toEqual(null);
24
+ });
25
+ });
@@ -0,0 +1,11 @@
1
+ import type { CommandOptions } from "./command";
2
+ import { Command } from "./command";
3
+
4
+ /**
5
+ * @see https://redis.io/commands/expireat
6
+ */
7
+ export class ExpireAtCommand extends Command<"0" | "1", 0 | 1> {
8
+ constructor(cmd: [key: string, unix: number], opts?: CommandOptions<"0" | "1", 0 | 1>) {
9
+ super(["expireat", ...cmd], opts);
10
+ }
11
+ }
@@ -0,0 +1,18 @@
1
+ import { newHttpClient } from "../test-utils";
2
+ import { FlushAllCommand } from "./flushall";
3
+
4
+ import { describe, expect, test } from "bun:test";
5
+ const client = newHttpClient();
6
+
7
+ describe("without options", () => {
8
+ test("flushes the db", async () => {
9
+ const res = await new FlushAllCommand().exec(client);
10
+ expect(res).toEqual("OK");
11
+ });
12
+ });
13
+ describe("async", () => {
14
+ test("flushes the db", async () => {
15
+ const res = await new FlushAllCommand([{ async: true }]).exec(client);
16
+ expect(res).toEqual("OK");
17
+ });
18
+ });
@@ -0,0 +1,14 @@
1
+ import type { CommandOptions } from "./command";
2
+ import { Command } from "./command";
3
+ /**
4
+ * @see https://redis.io/commands/flushall
5
+ */
6
+ export class FlushAllCommand extends Command<"OK", "OK"> {
7
+ constructor(args?: [{ async?: boolean }], opts?: CommandOptions<"OK", "OK">) {
8
+ const command = ["flushall"];
9
+ if (args && args.length > 0 && args[0].async) {
10
+ command.push("async");
11
+ }
12
+ super(command, opts);
13
+ }
14
+ }
@@ -0,0 +1,17 @@
1
+ import { describe, expect, test } from "bun:test";
2
+ import { newHttpClient } from "../test-utils";
3
+ import { FlushDBCommand } from "./flushdb";
4
+ const client = newHttpClient();
5
+
6
+ describe("without options", () => {
7
+ test("flushes the db", async () => {
8
+ const res = await new FlushDBCommand([]).exec(client);
9
+ expect(res).toEqual("OK");
10
+ });
11
+ });
12
+ describe("async", () => {
13
+ test("flushes the db", async () => {
14
+ const res = await new FlushDBCommand([{ async: true }]).exec(client);
15
+ expect(res).toEqual("OK");
16
+ });
17
+ });
@@ -0,0 +1,14 @@
1
+ import type { CommandOptions } from "./command";
2
+ import { Command } from "./command";
3
+ /**
4
+ * @see https://redis.io/commands/flushdb
5
+ */
6
+ export class FlushDBCommand extends Command<"OK", "OK"> {
7
+ constructor([opts]: [opts?: { async?: boolean }], cmdOpts?: CommandOptions<"OK", "OK">) {
8
+ const command = ["flushdb"];
9
+ if (opts?.async) {
10
+ command.push("async");
11
+ }
12
+ super(command, cmdOpts);
13
+ }
14
+ }
@@ -0,0 +1,202 @@
1
+ import { keygen, newHttpClient, randomID } from "../test-utils";
2
+
3
+ import { afterAll, describe, expect, test } from "bun:test";
4
+
5
+ import type { GeoMember } from "./geo_add";
6
+ import { GeoAddCommand } from "./geo_add";
7
+
8
+ const client = newHttpClient();
9
+
10
+ const { newKey, cleanup } = keygen();
11
+ afterAll(cleanup);
12
+
13
+ type Coordinate = {
14
+ latitude: number;
15
+ longitude: number;
16
+ };
17
+
18
+ function generateRandomPoint(radius = 100): Coordinate {
19
+ const center = { lat: 14.23, lng: 23.12 };
20
+
21
+ const x0 = center.lng;
22
+ const y0 = center.lat;
23
+ // Convert Radius from meters to degrees.
24
+ const rd = radius / 111_300;
25
+
26
+ const u = Math.random();
27
+ const v = Math.random();
28
+
29
+ const w = rd * Math.sqrt(u);
30
+ const t = 2 * Math.PI * v;
31
+ const x = w * Math.cos(t);
32
+ const y = w * Math.sin(t);
33
+
34
+ const xp = x / Math.cos(y0);
35
+
36
+ // Resulting point.
37
+ return { latitude: y + y0, longitude: xp + x0 };
38
+ }
39
+
40
+ function getTestMember(): GeoMember<Record<string, number>> {
41
+ const member = randomID();
42
+
43
+ return {
44
+ ...generateRandomPoint(),
45
+ member: { [member]: Math.random() * 1000 },
46
+ };
47
+ }
48
+
49
+ describe("without options", () => {
50
+ test("adds the geo member", async () => {
51
+ const key = newKey();
52
+ const member = randomID();
53
+
54
+ const res = await new GeoAddCommand([key, { ...generateRandomPoint(), member }]).exec(client);
55
+ expect(res).toEqual(1);
56
+ });
57
+
58
+ test("adds multiple members", async () => {
59
+ const key = newKey();
60
+
61
+ const res = await new GeoAddCommand([
62
+ key,
63
+ { ...generateRandomPoint(), member: randomID() },
64
+ { ...generateRandomPoint(), member: randomID() },
65
+ { ...generateRandomPoint(), member: randomID() },
66
+ { ...generateRandomPoint(), member: randomID() },
67
+ ]).exec(client);
68
+
69
+ expect(res).toEqual(4);
70
+ });
71
+
72
+ test("adds the geo member with member as object", async () => {
73
+ const key = newKey();
74
+
75
+ const res = await new GeoAddCommand<Record<string, number>>([
76
+ key,
77
+ getTestMember(),
78
+ getTestMember(),
79
+ getTestMember(),
80
+ getTestMember(),
81
+ getTestMember(),
82
+ getTestMember(),
83
+ getTestMember(),
84
+ ]).exec(client);
85
+
86
+ expect(res).toEqual(7);
87
+ });
88
+ });
89
+
90
+ describe("xx", () => {
91
+ describe("when the member exists", () => {
92
+ test("updates the member", async () => {
93
+ const key = newKey();
94
+ const member = getTestMember();
95
+
96
+ // Create member.
97
+ await new GeoAddCommand<Record<string, number>>([key, member]).exec(client);
98
+
99
+ const updatedMember = { ...generateRandomPoint(), member: member.member };
100
+
101
+ const response = await new GeoAddCommand<Record<string, number>>([
102
+ key,
103
+ { xx: true },
104
+ updatedMember,
105
+ ]).exec(client);
106
+
107
+ expect(response).toEqual(0);
108
+ });
109
+ });
110
+ describe("when the member does not exist", () => {
111
+ test("does nothing", async () => {
112
+ const key = newKey();
113
+ const member = getTestMember();
114
+
115
+ // Create member.
116
+ await new GeoAddCommand<Record<string, number>>([key, { xx: true }, member]).exec(client);
117
+
118
+ const { result } = await client.request({
119
+ body: ["geopos", key, JSON.stringify(member.member)],
120
+ });
121
+
122
+ expect(result).toEqual([null]);
123
+ });
124
+ });
125
+ });
126
+
127
+ describe("nx", () => {
128
+ describe("when the member exists", () => {
129
+ test("does not update the member", async () => {
130
+ const key = newKey();
131
+ const member = getTestMember();
132
+
133
+ // Create member.
134
+ await new GeoAddCommand<Record<string, number>>([key, member]).exec(client);
135
+
136
+ // Get member position
137
+ const { result } = await client.request({
138
+ body: ["geopos", key, JSON.stringify(member.member)],
139
+ });
140
+
141
+ const updatedMember = { ...generateRandomPoint(), member: member.member };
142
+
143
+ // Update member with nx command.
144
+ const response = await new GeoAddCommand<Record<string, number>>([
145
+ key,
146
+ { nx: true },
147
+ updatedMember,
148
+ ]).exec(client);
149
+
150
+ expect(response).toEqual(0);
151
+
152
+ // Get member position again. And assert it didn't change
153
+ const { result: updatedResult } = await client.request({
154
+ body: ["geopos", key, JSON.stringify(member.member)],
155
+ });
156
+
157
+ expect(result).toEqual(updatedResult);
158
+ });
159
+ });
160
+
161
+ describe("when the member does not exist", () => {
162
+ test("adds new member", async () => {
163
+ const key = newKey();
164
+ const member = getTestMember();
165
+
166
+ // Create member.
167
+ const response = await new GeoAddCommand<Record<string, number>>([
168
+ key,
169
+ { nx: true },
170
+ member,
171
+ ]).exec(client);
172
+
173
+ expect(response).toEqual(1);
174
+ });
175
+ });
176
+ });
177
+
178
+ describe("ch", () => {
179
+ test("returns the number of changed elements", async () => {
180
+ const key = newKey();
181
+ const member = getTestMember();
182
+ const member2 = getTestMember();
183
+ const member3 = getTestMember();
184
+
185
+ // Create member.
186
+ await new GeoAddCommand<Record<string, number>>([key, member, member2, member3]).exec(client);
187
+
188
+ const updatedMember2 = { ...member2, ...generateRandomPoint() };
189
+ const updatedMember3 = { ...member3, ...generateRandomPoint() };
190
+
191
+ // Create members again, but this time change members 2 and 3
192
+ const response = await new GeoAddCommand<Record<string, number>>([
193
+ key,
194
+ { ch: true },
195
+ member,
196
+ updatedMember2,
197
+ updatedMember3,
198
+ ]).exec(client);
199
+
200
+ expect(response).toEqual(2);
201
+ });
202
+ });
@@ -0,0 +1,54 @@
1
+ import type { CommandOptions } from "./command";
2
+ import { Command } from "./command";
3
+
4
+ export type GeoAddCommandOptions =
5
+ | {
6
+ nx?: boolean;
7
+ xx?: never;
8
+ }
9
+ | ({
10
+ nx?: never;
11
+ xx?: boolean;
12
+ } & { ch?: boolean });
13
+
14
+ export type GeoMember<TMemberType> = {
15
+ latitude: number;
16
+ longitude: number;
17
+ member: TMemberType;
18
+ };
19
+
20
+ /**
21
+ * @see https://redis.io/commands/geoadd
22
+ */
23
+ export class GeoAddCommand<TMemberType = string> extends Command<number | null, number | null> {
24
+ constructor(
25
+ [key, arg1, ...arg2]: [
26
+ string,
27
+ GeoMember<TMemberType> | GeoAddCommandOptions,
28
+ ...GeoMember<TMemberType>[],
29
+ ],
30
+ opts?: CommandOptions<number | null, number | null>
31
+ ) {
32
+ const command: unknown[] = ["geoadd", key];
33
+
34
+ if ("nx" in arg1 && arg1.nx) {
35
+ command.push("nx");
36
+ } else if ("xx" in arg1 && arg1.xx) {
37
+ command.push("xx");
38
+ }
39
+
40
+ if ("ch" in arg1 && arg1.ch) {
41
+ command.push("ch");
42
+ }
43
+
44
+ if ("latitude" in arg1 && arg1.latitude) {
45
+ command.push(arg1.longitude, arg1.latitude, arg1.member);
46
+ }
47
+
48
+ command.push(
49
+ ...arg2.flatMap(({ latitude, longitude, member }) => [longitude, latitude, member])
50
+ );
51
+
52
+ super(command, opts);
53
+ }
54
+ }
@@ -0,0 +1,79 @@
1
+ import { expect, test } from "bun:test";
2
+ import { newHttpClient } from "../test-utils";
3
+
4
+ import { GeoAddCommand } from "./geo_add";
5
+ import { GeoDistCommand } from "./geo_dist";
6
+
7
+ const client = newHttpClient();
8
+
9
+ test("should return distance successfully in meters", async () => {
10
+ await new GeoAddCommand([
11
+ "Sicily",
12
+ { longitude: 13.361_389, latitude: 38.115_556, member: "Palermo" },
13
+ { longitude: 15.087_269, latitude: 37.502_669, member: "Catania" },
14
+ ]).exec(client);
15
+
16
+ const res = await new GeoDistCommand(["Sicily", "Palermo", "Catania"]).exec(client);
17
+
18
+ expect(res).toEqual(166_274.1516);
19
+ });
20
+
21
+ test("should return distance for object members", async () => {
22
+ await new GeoAddCommand([
23
+ "Sicily",
24
+ { longitude: 13.361_389, latitude: 38.115_556, member: { name: "Palermo" } },
25
+ { longitude: 15.087_269, latitude: 37.502_669, member: { name: "Catania" } },
26
+ ]).exec(client);
27
+
28
+ const res = await new GeoDistCommand([
29
+ "Sicily",
30
+ { name: "Palermo" },
31
+ {
32
+ name: "Catania",
33
+ },
34
+ ]).exec(client);
35
+
36
+ expect(res).toEqual(166_274.1516);
37
+ });
38
+
39
+ test("should return distance successfully in kilometers", async () => {
40
+ await new GeoAddCommand([
41
+ "Sicily",
42
+ { longitude: 13.361_389, latitude: 38.115_556, member: "Palermo" },
43
+ { longitude: 15.087_269, latitude: 37.502_669, member: "Catania" },
44
+ ]).exec(client);
45
+
46
+ const res = await new GeoDistCommand(["Sicily", "Palermo", "Catania", "KM"]).exec(client);
47
+
48
+ expect(res).toEqual(166.2742);
49
+ });
50
+
51
+ test("should return distance successfully in miles", async () => {
52
+ await new GeoAddCommand([
53
+ "Sicily",
54
+ { longitude: 13.361_389, latitude: 38.115_556, member: "Palermo" },
55
+ { longitude: 15.087_269, latitude: 37.502_669, member: "Catania" },
56
+ ]).exec(client);
57
+
58
+ const res = await new GeoDistCommand(["Sicily", "Palermo", "Catania", "MI"]).exec(client);
59
+
60
+ expect(res).toEqual(103.3182);
61
+ });
62
+
63
+ test("should return distance successfully in feet", async () => {
64
+ await new GeoAddCommand([
65
+ "Sicily",
66
+ { longitude: 13.361_389, latitude: 38.115_556, member: "Palermo" },
67
+ { longitude: 15.087_269, latitude: 37.502_669, member: "Catania" },
68
+ ]).exec(client);
69
+
70
+ const res = await new GeoDistCommand(["Sicily", "Palermo", "Catania", "FT"]).exec(client);
71
+
72
+ expect(res?.toString()).toEqual("545518.8700");
73
+ });
74
+
75
+ test("should return null if members doesn't exist", async () => {
76
+ const res = await new GeoDistCommand(["Sicily", "FOO", "BAR"]).exec(client);
77
+
78
+ expect(res).toEqual(null);
79
+ });
@@ -0,0 +1,19 @@
1
+ import type { CommandOptions } from "./command";
2
+ import { Command } from "./command";
3
+
4
+ /**
5
+ * @see https://redis.io/commands/geodist
6
+ */
7
+ export class GeoDistCommand<TMemberType = string> extends Command<number | null, number | null> {
8
+ constructor(
9
+ [key, member1, member2, unit = "M"]: [
10
+ key: string,
11
+ member1: TMemberType,
12
+ member2: TMemberType,
13
+ unit?: "M" | "KM" | "FT" | "MI",
14
+ ],
15
+ opts?: CommandOptions<number | null, number | null>
16
+ ) {
17
+ super(["GEODIST", key, member1, member2, unit], opts);
18
+ }
19
+ }
@@ -0,0 +1,49 @@
1
+ import { describe, expect, test } from "bun:test";
2
+ import { newHttpClient } from "../test-utils.ts";
3
+
4
+ import { GeoAddCommand } from "./geo_add.ts";
5
+ import { GeoHashCommand } from "./geo_hash.ts";
6
+
7
+ const client = newHttpClient();
8
+
9
+ describe("GEOHASH tests", () => {
10
+ test("should accept two member array and return valid hash", async () => {
11
+ const key = "Sicily";
12
+ const members = ["Palermo", "Catania"];
13
+ await new GeoAddCommand([
14
+ key,
15
+ { longitude: 13.361_389, latitude: 38.115_556, member: members[0] },
16
+ { longitude: 15.087_269, latitude: 37.502_669, member: members[1] },
17
+ ]).exec(client);
18
+
19
+ const response = await new GeoHashCommand([key, members]).exec(client);
20
+ expect(response.length).toEqual(2);
21
+ });
22
+
23
+ test("should accept three different string members and return valid hash", async () => {
24
+ const key = "Sicily";
25
+ const members = ["Palermo", "Catania", "Marsala"];
26
+ await new GeoAddCommand([
27
+ key,
28
+ { longitude: 13.361_389, latitude: 38.115_556, member: members[0] },
29
+ { longitude: 15.087_269, latitude: 37.502_669, member: members[1] },
30
+ { longitude: 12.4372, latitude: 37.7981, member: members[2] },
31
+ ]).exec(client);
32
+
33
+ const response = await new GeoHashCommand([key, "Palermo", "Catania", "Marsala"]).exec(client);
34
+ expect(response.length).toEqual(3);
35
+ });
36
+
37
+ test("should accept two objects as members", async () => {
38
+ const key = "Sicily";
39
+ const members = [{ name: "Palermo" }, { name: "Catania" }];
40
+ await new GeoAddCommand([
41
+ key,
42
+ { longitude: 13.361_389, latitude: 38.115_556, member: members[0] },
43
+ { longitude: 15.087_269, latitude: 37.502_669, member: members[1] },
44
+ ]).exec(client);
45
+
46
+ const response = await new GeoHashCommand([key, members]).exec(client);
47
+ expect(response.length).toBe(2);
48
+ });
49
+ });
@@ -0,0 +1,23 @@
1
+ import type { CommandOptions } from "./command.ts";
2
+ import { Command } from "./command.ts";
3
+
4
+ /**
5
+ * @see https://redis.io/commands/geohash
6
+ */
7
+ export class GeoHashCommand<TMember = string> extends Command<
8
+ (string | null)[],
9
+ (string | null)[]
10
+ > {
11
+ constructor(
12
+ cmd: [string, ...TMember[]],
13
+ opts?: CommandOptions<(string | null)[], (string | null)[]>
14
+ ) {
15
+ const [key] = cmd;
16
+ // Check if the second argument is an array of strings (members).
17
+ // If it is, use it directly; if not, it means the members were passed individually,
18
+ // so we slice the cmd from the second element onwards to get the members.
19
+ const members = Array.isArray(cmd[1]) ? cmd[1] : cmd.slice(1);
20
+
21
+ super(["GEOHASH", key, ...members], opts);
22
+ }
23
+ }