@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.
- package/.env.example +2 -0
- package/.github/workflows/release.yml +53 -0
- package/.github/workflows/tests.yaml +609 -0
- package/.gitignore +175 -0
- package/.husky/commit-msg +1 -0
- package/.husky/pre-commit +2 -0
- package/.husky/pre-push +1 -0
- package/.prettierignore +1 -0
- package/.vscode/extensions.json +3 -0
- package/.vscode/settings.json +20 -0
- package/README.md +1 -2
- package/bun.lockb +0 -0
- package/commitlint.config.js +46 -0
- package/dist/LICENSE +21 -0
- package/dist/README.md +136 -0
- package/dist/chunk-TEVCO3ZO.mjs +3797 -0
- package/dist/cloudflare.d.mts +55 -0
- package/dist/cloudflare.d.ts +55 -0
- package/dist/cloudflare.js +3907 -0
- package/dist/cloudflare.mjs +91 -0
- package/dist/fastly.d.mts +48 -0
- package/dist/fastly.d.ts +48 -0
- package/dist/fastly.js +3880 -0
- package/dist/fastly.mjs +64 -0
- package/dist/nodejs.d.mts +73 -0
- package/dist/nodejs.d.ts +73 -0
- package/dist/nodejs.js +3926 -0
- package/dist/nodejs.mjs +110 -0
- package/dist/package.json +1 -0
- package/{zmscore-5d82e632.d.ts → dist/zmscore-BhX8yEQc.d.mts} +249 -184
- package/dist/zmscore-BhX8yEQc.d.ts +3486 -0
- package/eslint.config.mjs +102 -0
- package/examples/auto-pipeline/.eslintrc.json +3 -0
- package/examples/auto-pipeline/README.md +77 -0
- package/examples/auto-pipeline/app/components/DataComponent.tsx +49 -0
- package/examples/auto-pipeline/app/data/getEvents.ts +18 -0
- package/examples/auto-pipeline/app/data/getUsers.ts +18 -0
- package/examples/auto-pipeline/app/data/redis.ts +12 -0
- package/examples/auto-pipeline/app/favicon.ico +0 -0
- package/examples/auto-pipeline/app/globals.css +0 -0
- package/examples/auto-pipeline/app/layout.tsx +22 -0
- package/examples/auto-pipeline/app/page.tsx +15 -0
- package/examples/auto-pipeline/next.config.mjs +4 -0
- package/examples/auto-pipeline/package.json +27 -0
- package/examples/auto-pipeline/postcss.config.mjs +8 -0
- package/examples/auto-pipeline/public/next.svg +1 -0
- package/examples/auto-pipeline/public/vercel.svg +1 -0
- package/examples/auto-pipeline/tailwind.config.ts +20 -0
- package/examples/auto-pipeline/tsconfig.json +26 -0
- package/examples/aws-cdk-python/README.md +36 -0
- package/examples/aws-cdk-python/cdk.json +72 -0
- package/examples/aws-cdk-python/jest.config.js +8 -0
- package/examples/aws-cdk-python/lib/api/index.py +10 -0
- package/examples/aws-cdk-python/lib/api/requirements.txt +1 -0
- package/examples/aws-cdk-python/package-lock.json +4470 -0
- package/examples/aws-cdk-python/package.json +27 -0
- package/examples/aws-cdk-python/tsconfig.json +31 -0
- package/examples/aws-cdk-typescript/README.md +36 -0
- package/examples/aws-cdk-typescript/cdk.json +72 -0
- package/examples/aws-cdk-typescript/jest.config.js +8 -0
- package/examples/aws-cdk-typescript/package-lock.json +4548 -0
- package/examples/aws-cdk-typescript/package.json +28 -0
- package/examples/aws-cdk-typescript/tsconfig.json +31 -0
- package/examples/aws-lambda/README.md +39 -0
- package/examples/aws-lambda/index.js +11 -0
- package/examples/aws-lambda/package-lock.json +27 -0
- package/examples/aws-lambda/package.json +6 -0
- package/examples/aws-sam/README.md +34 -0
- package/examples/aws-sam/__init__.py +0 -0
- package/examples/aws-sam/events/event.json +62 -0
- package/examples/aws-sam/hello_world/__init__.py +0 -0
- package/examples/aws-sam/hello_world/app.py +10 -0
- package/examples/aws-sam/hello_world/requirements.txt +2 -0
- package/examples/aws-sam/samconfig.toml +34 -0
- package/examples/aws-sam/template.yaml +52 -0
- package/examples/aws-sam/tests/__init__.py +0 -0
- package/examples/aws-sam/tests/integration/__init__.py +0 -0
- package/examples/aws-sam/tests/integration/test_api_gateway.py +45 -0
- package/examples/aws-sam/tests/requirements.txt +3 -0
- package/examples/aws-sam/tests/unit/__init__.py +0 -0
- package/examples/aws-sam/tests/unit/test_handler.py +72 -0
- package/examples/azure-functions/.funcignore +10 -0
- package/examples/azure-functions/.vscode/extensions.json +5 -0
- package/examples/azure-functions/README.md +67 -0
- package/examples/azure-functions/host.json +15 -0
- package/examples/azure-functions/package-lock.json +1019 -0
- package/examples/azure-functions/package.json +24 -0
- package/examples/azure-functions/src/functions/CounterFunction.ts +19 -0
- package/examples/azure-functions/tsconfig.json +10 -0
- package/examples/cloudflare-workers/README.md +26 -0
- package/examples/cloudflare-workers/bun.lockb +0 -0
- package/examples/cloudflare-workers/ci.test.ts +18 -0
- package/examples/cloudflare-workers/index.js +11 -0
- package/examples/cloudflare-workers/package.json +17 -0
- package/examples/cloudflare-workers/wrangler.toml +11 -0
- package/examples/cloudflare-workers-with-typescript/README.md +26 -0
- package/examples/cloudflare-workers-with-typescript/ci.test.ts +17 -0
- package/examples/cloudflare-workers-with-typescript/package.json +17 -0
- package/examples/cloudflare-workers-with-typescript/src/index.ts +16 -0
- package/examples/cloudflare-workers-with-typescript/tsconfig.json +105 -0
- package/examples/cloudflare-workers-with-typescript/wrangler.toml +9 -0
- package/examples/deno/main.test.ts +16 -0
- package/examples/deno/main.ts +9 -0
- package/examples/fastapi/README.md +23 -0
- package/examples/fastapi/main.py +12 -0
- package/examples/fastapi/requirements.txt +2 -0
- package/examples/fastly/README.md +7 -0
- package/examples/fastly/fastly.toml +12 -0
- package/examples/fastly/package.json +23 -0
- package/examples/fastly/src/index.js +19 -0
- package/examples/fastly/webpack.config.js +28 -0
- package/examples/google-cloud-functions/README.md +37 -0
- package/examples/google-cloud-functions/index.js +12 -0
- package/examples/google-cloud-functions/package.json +7 -0
- package/examples/ion/.env.example +2 -0
- package/examples/ion/.eslintrc.json +3 -0
- package/examples/ion/README.md +49 -0
- package/examples/ion/app/favicon.ico +0 -0
- package/examples/ion/app/globals.css +33 -0
- package/examples/ion/app/layout.tsx +22 -0
- package/examples/ion/app/page.tsx +12 -0
- package/examples/ion/next.config.mjs +4 -0
- package/examples/ion/package-lock.json +6709 -0
- package/examples/ion/package.json +28 -0
- package/examples/ion/postcss.config.mjs +8 -0
- package/examples/ion/public/next.svg +1 -0
- package/examples/ion/public/vercel.svg +1 -0
- package/examples/ion/sst-env.d.ts +12 -0
- package/examples/ion/sst.config.ts +19 -0
- package/examples/ion/tailwind.config.ts +20 -0
- package/examples/ion/tsconfig.json +26 -0
- package/examples/nextjs-app-router/.env.example +2 -0
- package/examples/nextjs-app-router/.eslintrc.json +3 -0
- package/examples/nextjs-app-router/README.md +26 -0
- package/examples/nextjs-app-router/app/globals.css +3 -0
- package/examples/nextjs-app-router/app/layout.tsx +22 -0
- package/examples/nextjs-app-router/app/page.tsx +12 -0
- package/examples/nextjs-app-router/next.config.mjs +4 -0
- package/examples/nextjs-app-router/package.json +27 -0
- package/examples/nextjs-app-router/postcss.config.mjs +8 -0
- package/examples/nextjs-app-router/tailwind.config.ts +20 -0
- package/examples/nextjs-app-router/tsconfig.json +26 -0
- package/examples/nextjs-pages-router/.env.example +2 -0
- package/examples/nextjs-pages-router/.eslintrc.json +3 -0
- package/examples/nextjs-pages-router/README.md +26 -0
- package/examples/nextjs-pages-router/next.config.mjs +6 -0
- package/examples/nextjs-pages-router/package.json +27 -0
- package/examples/nextjs-pages-router/pages/_app.tsx +6 -0
- package/examples/nextjs-pages-router/pages/_document.tsx +13 -0
- package/examples/nextjs-pages-router/pages/api/hello.ts +13 -0
- package/examples/nextjs-pages-router/pages/index.tsx +19 -0
- package/examples/nextjs-pages-router/postcss.config.mjs +8 -0
- package/examples/nextjs-pages-router/styles/globals.css +3 -0
- package/examples/nextjs-pages-router/tailwind.config.ts +20 -0
- package/examples/nextjs-pages-router/tsconfig.json +21 -0
- package/examples/nodejs/.env.example +2 -0
- package/examples/nodejs/README.md +24 -0
- package/examples/nodejs/index.js +10 -0
- package/examples/nodejs/package.json +10 -0
- package/examples/serverless-framework/counter/.env.example +2 -0
- package/examples/serverless-framework/counter/README.md +38 -0
- package/examples/serverless-framework/counter/handler.js +12 -0
- package/examples/serverless-framework/counter/package-lock.json +27 -0
- package/examples/serverless-framework/counter/package.json +6 -0
- package/examples/serverless-framework/counter/serverless.yml +16 -0
- package/examples/sst-v2/.vscode/launch.json +15 -0
- package/examples/sst-v2/.vscode/settings.json +5 -0
- package/examples/sst-v2/README.md +62 -0
- package/examples/sst-v2/package.json +27 -0
- package/examples/sst-v2/packages/core/package.json +14 -0
- package/examples/sst-v2/packages/core/sst-env.d.ts +1 -0
- package/examples/sst-v2/packages/core/tsconfig.json +7 -0
- package/examples/sst-v2/packages/functions/package.json +15 -0
- package/examples/sst-v2/packages/functions/sst-env.d.ts +1 -0
- package/examples/sst-v2/packages/functions/tsconfig.json +11 -0
- package/examples/sst-v2/packages/web/README.md +40 -0
- package/examples/sst-v2/packages/web/next.config.mjs +6 -0
- package/examples/sst-v2/packages/web/package.json +23 -0
- package/examples/sst-v2/packages/web/pages/_app.tsx +6 -0
- package/examples/sst-v2/packages/web/pages/_document.tsx +13 -0
- package/examples/sst-v2/packages/web/pages/api/hello.ts +16 -0
- package/examples/sst-v2/packages/web/pages/index.tsx +114 -0
- package/examples/sst-v2/packages/web/public/favicon.ico +0 -0
- package/examples/sst-v2/packages/web/public/next.svg +1 -0
- package/examples/sst-v2/packages/web/public/vercel.svg +1 -0
- package/examples/sst-v2/packages/web/sst-env.d.ts +1 -0
- package/examples/sst-v2/packages/web/styles/Home.module.css +229 -0
- package/examples/sst-v2/packages/web/styles/globals.css +107 -0
- package/examples/sst-v2/packages/web/tsconfig.json +36 -0
- package/examples/sst-v2/pnpm-workspace.yaml +2 -0
- package/examples/sst-v2/sst.config.ts +14 -0
- package/examples/sst-v2/stacks/Default.ts +13 -0
- package/examples/sst-v2/tsconfig.json +8 -0
- package/examples/terraform/README.md +38 -0
- package/examples/terraform/counter/counter.js +11 -0
- package/examples/terraform/counter/package.json +6 -0
- package/examples/terraform/main.tf +166 -0
- package/examples/terraform/outputs.tf +17 -0
- package/examples/terraform/terraform.tf +18 -0
- package/examples/terraform/variables.tf +6 -0
- package/examples/vercel-functions-app-router/.env.example +2 -0
- package/examples/vercel-functions-app-router/.eslintrc.json +3 -0
- package/examples/vercel-functions-app-router/README.md +26 -0
- package/examples/vercel-functions-app-router/app/api/hello/route.ts +11 -0
- package/examples/vercel-functions-app-router/app/globals.css +3 -0
- package/examples/vercel-functions-app-router/app/layout.tsx +22 -0
- package/examples/vercel-functions-app-router/ci.test.ts +14 -0
- package/examples/vercel-functions-app-router/next.config.mjs +4 -0
- package/examples/vercel-functions-app-router/package.json +27 -0
- package/examples/vercel-functions-app-router/postcss.config.mjs +8 -0
- package/examples/vercel-functions-app-router/tailwind.config.ts +20 -0
- package/examples/vercel-functions-app-router/tsconfig.json +26 -0
- package/examples/vercel-functions-pages-router/.env.example +2 -0
- package/examples/vercel-functions-pages-router/.eslintrc.json +3 -0
- package/examples/vercel-functions-pages-router/README.md +26 -0
- package/examples/vercel-functions-pages-router/ci.test.ts +14 -0
- package/examples/vercel-functions-pages-router/next.config.mjs +6 -0
- package/examples/vercel-functions-pages-router/package.json +27 -0
- package/examples/vercel-functions-pages-router/pages/_app.tsx +6 -0
- package/examples/vercel-functions-pages-router/pages/_document.tsx +13 -0
- package/examples/vercel-functions-pages-router/pages/api/hello.ts +12 -0
- package/examples/vercel-functions-pages-router/postcss.config.mjs +8 -0
- package/examples/vercel-functions-pages-router/styles/globals.css +3 -0
- package/examples/vercel-functions-pages-router/tailwind.config.ts +20 -0
- package/examples/vercel-functions-pages-router/tsconfig.json +21 -0
- package/examples/vercel-python-runtime-django/.env.example +2 -0
- package/examples/vercel-python-runtime-django/README.md +34 -0
- package/examples/vercel-python-runtime-django/api/__init__.py +0 -0
- package/examples/vercel-python-runtime-django/api/asgi.py +16 -0
- package/examples/vercel-python-runtime-django/api/settings.py +121 -0
- package/examples/vercel-python-runtime-django/api/urls.py +22 -0
- package/examples/vercel-python-runtime-django/api/wsgi.py +16 -0
- package/examples/vercel-python-runtime-django/example/__init__.py +0 -0
- package/examples/vercel-python-runtime-django/example/admin.py +3 -0
- package/examples/vercel-python-runtime-django/example/apps.py +6 -0
- package/examples/vercel-python-runtime-django/example/urls.py +9 -0
- package/examples/vercel-python-runtime-django/example/views.py +18 -0
- package/examples/vercel-python-runtime-django/manage.py +22 -0
- package/examples/vercel-python-runtime-django/package.json +5 -0
- package/examples/vercel-python-runtime-django/requirements.txt +2 -0
- package/examples/vercel-python-runtime-django/vercel.json +8 -0
- package/examples/with-sentry/index.ts +36 -0
- package/examples/with-sentry/package.json +17 -0
- package/package.json +1 -1
- package/pkg/auto-pipeline.test.ts +321 -0
- package/pkg/auto-pipeline.ts +107 -0
- package/pkg/commands/append.test.ts +28 -0
- package/pkg/commands/append.ts +11 -0
- package/pkg/commands/bitcount.test.ts +37 -0
- package/pkg/commands/bitcount.ts +29 -0
- package/pkg/commands/bitfield.test.ts +51 -0
- package/pkg/commands/bitfield.ts +50 -0
- package/pkg/commands/bitop.test.ts +45 -0
- package/pkg/commands/bitop.ts +22 -0
- package/pkg/commands/bitpos.test.ts +47 -0
- package/pkg/commands/bitpos.ts +14 -0
- package/pkg/commands/command.test.ts +22 -0
- package/pkg/commands/command.ts +98 -0
- package/pkg/commands/copy.test.ts +65 -0
- package/pkg/commands/copy.ts +22 -0
- package/pkg/commands/dbsize.test.ts +18 -0
- package/pkg/commands/dbsize.ts +11 -0
- package/pkg/commands/decr.test.ts +23 -0
- package/pkg/commands/decr.ts +11 -0
- package/pkg/commands/decrby.test.ts +24 -0
- package/pkg/commands/decrby.ts +11 -0
- package/pkg/commands/del.test.ts +38 -0
- package/pkg/commands/del.ts +11 -0
- package/pkg/commands/echo.test.ts +11 -0
- package/pkg/commands/echo.ts +11 -0
- package/pkg/commands/eval.test.ts +30 -0
- package/pkg/commands/eval.ts +14 -0
- package/pkg/commands/evalsha.test.ts +19 -0
- package/pkg/commands/evalsha.ts +14 -0
- package/pkg/commands/exists.test.ts +38 -0
- package/pkg/commands/exists.ts +11 -0
- package/pkg/commands/expire.test.ts +119 -0
- package/pkg/commands/expire.ts +12 -0
- package/pkg/commands/expireat.test.ts +25 -0
- package/pkg/commands/expireat.ts +11 -0
- package/pkg/commands/flushall.test.ts +18 -0
- package/pkg/commands/flushall.ts +14 -0
- package/pkg/commands/flushdb.test.ts +17 -0
- package/pkg/commands/flushdb.ts +14 -0
- package/pkg/commands/geo_add.test.ts +202 -0
- package/pkg/commands/geo_add.ts +54 -0
- package/pkg/commands/geo_dist.test.ts +79 -0
- package/pkg/commands/geo_dist.ts +19 -0
- package/pkg/commands/geo_hash.test.ts +49 -0
- package/pkg/commands/geo_hash.ts +23 -0
- package/pkg/commands/geo_pos.test.ts +60 -0
- package/pkg/commands/geo_pos.ts +39 -0
- package/pkg/commands/geo_search.test.ts +197 -0
- package/pkg/commands/geo_search.ts +139 -0
- package/pkg/commands/geo_search_store.test.ts +153 -0
- package/pkg/commands/geo_search_store.ts +69 -0
- package/pkg/commands/get.test.ts +35 -0
- package/pkg/commands/get.ts +11 -0
- package/pkg/commands/getbit.test.ts +17 -0
- package/pkg/commands/getbit.ts +11 -0
- package/pkg/commands/getdel.test.ts +39 -0
- package/pkg/commands/getdel.ts +11 -0
- package/pkg/commands/getrange.test.ts +25 -0
- package/pkg/commands/getrange.ts +14 -0
- package/pkg/commands/getset.test.ts +33 -0
- package/pkg/commands/getset.ts +14 -0
- package/pkg/commands/hdel.test.ts +45 -0
- package/pkg/commands/hdel.ts +11 -0
- package/pkg/commands/hexists.test.ts +36 -0
- package/pkg/commands/hexists.ts +11 -0
- package/pkg/commands/hget.test.ts +52 -0
- package/pkg/commands/hget.ts +14 -0
- package/pkg/commands/hgetall.test.ts +45 -0
- package/pkg/commands/hgetall.ts +37 -0
- package/pkg/commands/hincrby.test.ts +28 -0
- package/pkg/commands/hincrby.ts +14 -0
- package/pkg/commands/hincrbyfloat.test.ts +28 -0
- package/pkg/commands/hincrbyfloat.ts +14 -0
- package/pkg/commands/hkeys.test.ts +23 -0
- package/pkg/commands/hkeys.ts +11 -0
- package/pkg/commands/hlen.test.ts +25 -0
- package/pkg/commands/hlen.ts +11 -0
- package/pkg/commands/hmget.test.ts +44 -0
- package/pkg/commands/hmget.ts +46 -0
- package/pkg/commands/hmset.test.ts +23 -0
- package/pkg/commands/hmset.ts +14 -0
- package/pkg/commands/hrandfield.test.ts +59 -0
- package/pkg/commands/hrandfield.ts +50 -0
- package/pkg/commands/hscan.test.ts +44 -0
- package/pkg/commands/hscan.ts +30 -0
- package/pkg/commands/hset.test.ts +21 -0
- package/pkg/commands/hset.ts +14 -0
- package/pkg/commands/hsetnx.test.ts +37 -0
- package/pkg/commands/hsetnx.ts +14 -0
- package/pkg/commands/hstrlen.test.ts +24 -0
- package/pkg/commands/hstrlen.ts +11 -0
- package/pkg/commands/hvals.test.ts +24 -0
- package/pkg/commands/hvals.ts +11 -0
- package/pkg/commands/incr.test.ts +24 -0
- package/pkg/commands/incr.ts +11 -0
- package/pkg/commands/incrby.test.ts +24 -0
- package/pkg/commands/incrby.ts +11 -0
- package/pkg/commands/incrbyfloat.test.ts +25 -0
- package/pkg/commands/incrbyfloat.ts +11 -0
- package/pkg/commands/json_arrappend.test.ts +40 -0
- package/pkg/commands/json_arrappend.ts +17 -0
- package/pkg/commands/json_arrindex.test.ts +54 -0
- package/pkg/commands/json_arrindex.ts +14 -0
- package/pkg/commands/json_arrinsert.test.ts +49 -0
- package/pkg/commands/json_arrinsert.ts +17 -0
- package/pkg/commands/json_arrlen.test.ts +31 -0
- package/pkg/commands/json_arrlen.ts +14 -0
- package/pkg/commands/json_arrpop.test.ts +30 -0
- package/pkg/commands/json_arrpop.ts +14 -0
- package/pkg/commands/json_arrtrim.test.ts +31 -0
- package/pkg/commands/json_arrtrim.ts +18 -0
- package/pkg/commands/json_clear.test.ts +35 -0
- package/pkg/commands/json_clear.ts +11 -0
- package/pkg/commands/json_del.test.ts +29 -0
- package/pkg/commands/json_del.ts +11 -0
- package/pkg/commands/json_forget.test.ts +29 -0
- package/pkg/commands/json_forget.ts +11 -0
- package/pkg/commands/json_get.test.ts +28 -0
- package/pkg/commands/json_get.ts +44 -0
- package/pkg/commands/json_mget.test.ts +43 -0
- package/pkg/commands/json_mget.ts +11 -0
- package/pkg/commands/json_mset.test.ts +50 -0
- package/pkg/commands/json_mset.ts +26 -0
- package/pkg/commands/json_numincrby.test.ts +28 -0
- package/pkg/commands/json_numincrby.ts +14 -0
- package/pkg/commands/json_nummultby.test.ts +28 -0
- package/pkg/commands/json_nummultby.ts +14 -0
- package/pkg/commands/json_objkeys.test.ts +32 -0
- package/pkg/commands/json_objkeys.ts +14 -0
- package/pkg/commands/json_objlen.test.ts +26 -0
- package/pkg/commands/json_objlen.ts +14 -0
- package/pkg/commands/json_resp.test.ts +31 -0
- package/pkg/commands/json_resp.ts +11 -0
- package/pkg/commands/json_set.test.ts +48 -0
- package/pkg/commands/json_set.ts +34 -0
- package/pkg/commands/json_strappend.test.ts +34 -0
- package/pkg/commands/json_strappend.ts +14 -0
- package/pkg/commands/json_strlen.test.ts +27 -0
- package/pkg/commands/json_strlen.ts +14 -0
- package/pkg/commands/json_toggle.test.ts +26 -0
- package/pkg/commands/json_toggle.ts +11 -0
- package/pkg/commands/json_type.test.ts +29 -0
- package/pkg/commands/json_type.ts +11 -0
- package/pkg/commands/keys.test.ts +18 -0
- package/pkg/commands/keys.ts +11 -0
- package/pkg/commands/lindex.test.ts +33 -0
- package/pkg/commands/lindex.ts +11 -0
- package/pkg/commands/linsert.test.ts +24 -0
- package/pkg/commands/linsert.ts +10 -0
- package/pkg/commands/llen.test.ts +27 -0
- package/pkg/commands/llen.ts +11 -0
- package/pkg/commands/lmove.test.ts +48 -0
- package/pkg/commands/lmove.ts +19 -0
- package/pkg/commands/lmpop.test.ts +86 -0
- package/pkg/commands/lmpop.ts +19 -0
- package/pkg/commands/lpop.test.ts +40 -0
- package/pkg/commands/lpop.ts +14 -0
- package/pkg/commands/lpos.test.ts +56 -0
- package/pkg/commands/lpos.ts +25 -0
- package/pkg/commands/lpush.test.ts +18 -0
- package/pkg/commands/lpush.ts +11 -0
- package/pkg/commands/lpushx.test.ts +30 -0
- package/pkg/commands/lpushx.ts +11 -0
- package/pkg/commands/lrange.test.ts +21 -0
- package/pkg/commands/lrange.ts +11 -0
- package/pkg/commands/lrem.test.ts +19 -0
- package/pkg/commands/lrem.ts +10 -0
- package/pkg/commands/lset.test.ts +43 -0
- package/pkg/commands/lset.ts +8 -0
- package/pkg/commands/ltrim.test.ts +30 -0
- package/pkg/commands/ltrim.ts +8 -0
- package/pkg/commands/mget.test.ts +44 -0
- package/pkg/commands/mget.ts +11 -0
- package/pkg/commands/mod.ts +168 -0
- package/pkg/commands/mset.test.ts +24 -0
- package/pkg/commands/mset.ts +11 -0
- package/pkg/commands/msetnx.test.ts +46 -0
- package/pkg/commands/msetnx.ts +11 -0
- package/pkg/commands/persist.test.ts +22 -0
- package/pkg/commands/persist.ts +11 -0
- package/pkg/commands/pexpire.test.ts +24 -0
- package/pkg/commands/pexpire.ts +11 -0
- package/pkg/commands/pexpireat.test.ts +31 -0
- package/pkg/commands/pexpireat.ts +11 -0
- package/pkg/commands/pfadd.test.ts +80 -0
- package/pkg/commands/pfadd.ts +11 -0
- package/pkg/commands/pfcount.test.ts +55 -0
- package/pkg/commands/pfcount.ts +11 -0
- package/pkg/commands/pfmerge.test.ts +67 -0
- package/pkg/commands/pfmerge.ts +11 -0
- package/pkg/commands/ping.test.ts +19 -0
- package/pkg/commands/ping.ts +14 -0
- package/pkg/commands/psetex.test.ts +23 -0
- package/pkg/commands/psetex.ts +14 -0
- package/pkg/commands/pttl.test.ts +18 -0
- package/pkg/commands/pttl.ts +11 -0
- package/pkg/commands/publish.test.ts +12 -0
- package/pkg/commands/publish.ts +11 -0
- package/pkg/commands/randomkey.test.ts +16 -0
- package/pkg/commands/randomkey.ts +11 -0
- package/pkg/commands/rename.test.ts +19 -0
- package/pkg/commands/rename.ts +11 -0
- package/pkg/commands/renamenx.test.ts +33 -0
- package/pkg/commands/renamenx.ts +11 -0
- package/pkg/commands/rpop.test.ts +40 -0
- package/pkg/commands/rpop.ts +17 -0
- package/pkg/commands/rpush.test.ts +17 -0
- package/pkg/commands/rpush.ts +11 -0
- package/pkg/commands/rpushx.test.ts +30 -0
- package/pkg/commands/rpushx.ts +11 -0
- package/pkg/commands/sadd.test.ts +22 -0
- package/pkg/commands/sadd.ts +14 -0
- package/pkg/commands/scan.test.ts +91 -0
- package/pkg/commands/scan.ts +33 -0
- package/pkg/commands/scard.test.ts +16 -0
- package/pkg/commands/scard.ts +10 -0
- package/pkg/commands/script_exists.test.ts +34 -0
- package/pkg/commands/script_exists.ts +14 -0
- package/pkg/commands/script_flush.ts +21 -0
- package/pkg/commands/script_load.test.ts +11 -0
- package/pkg/commands/script_load.ts +11 -0
- package/pkg/commands/sdiff.test.ts +20 -0
- package/pkg/commands/sdiff.ts +10 -0
- package/pkg/commands/sdiffstore.test.ts +22 -0
- package/pkg/commands/sdiffstore.ts +13 -0
- package/pkg/commands/set.test.ts +168 -0
- package/pkg/commands/set.ts +51 -0
- package/pkg/commands/setbit.test.ts +17 -0
- package/pkg/commands/setbit.ts +14 -0
- package/pkg/commands/setex.test.ts +22 -0
- package/pkg/commands/setex.ts +11 -0
- package/pkg/commands/setnx.test.ts +27 -0
- package/pkg/commands/setnx.ts +11 -0
- package/pkg/commands/setrange.test.ts +25 -0
- package/pkg/commands/setrange.ts +14 -0
- package/pkg/commands/sinter.test.ts +37 -0
- package/pkg/commands/sinter.ts +10 -0
- package/pkg/commands/sinterstore.test.ts +22 -0
- package/pkg/commands/sinterstore.ts +13 -0
- package/pkg/commands/sismember.test.ts +31 -0
- package/pkg/commands/sismember.ts +10 -0
- package/pkg/commands/smembers.test.ts +22 -0
- package/pkg/commands/smembers.ts +11 -0
- package/pkg/commands/smismember.test.ts +22 -0
- package/pkg/commands/smismember.ts +16 -0
- package/pkg/commands/smove.test.ts +18 -0
- package/pkg/commands/smove.ts +13 -0
- package/pkg/commands/spop.test.ts +36 -0
- package/pkg/commands/spop.ts +17 -0
- package/pkg/commands/srandmember.test.ts +31 -0
- package/pkg/commands/srandmember.ts +17 -0
- package/pkg/commands/srem.test.ts +19 -0
- package/pkg/commands/srem.ts +10 -0
- package/pkg/commands/sscan.test.ts +48 -0
- package/pkg/commands/sscan.ts +30 -0
- package/pkg/commands/strlen.test.ts +17 -0
- package/pkg/commands/strlen.ts +11 -0
- package/pkg/commands/sunion.test.ts +22 -0
- package/pkg/commands/sunion.ts +11 -0
- package/pkg/commands/sunionstore.test.ts +30 -0
- package/pkg/commands/sunionstore.ts +14 -0
- package/pkg/commands/time.test.ts +12 -0
- package/pkg/commands/time.ts +10 -0
- package/pkg/commands/touch.test.ts +21 -0
- package/pkg/commands/touch.ts +11 -0
- package/pkg/commands/ttl.test.ts +17 -0
- package/pkg/commands/ttl.ts +11 -0
- package/pkg/commands/type.test.ts +72 -0
- package/pkg/commands/type.ts +12 -0
- package/pkg/commands/types.ts +150 -0
- package/pkg/commands/unlink.test.ts +22 -0
- package/pkg/commands/unlink.ts +11 -0
- package/pkg/commands/xack.test.ts +53 -0
- package/pkg/commands/xack.ts +15 -0
- package/pkg/commands/xadd.test.ts +128 -0
- package/pkg/commands/xadd.ts +64 -0
- package/pkg/commands/xautoclaim.test.ts +105 -0
- package/pkg/commands/xautoclaim.ts +30 -0
- package/pkg/commands/xclaim.test.ts +70 -0
- package/pkg/commands/xclaim.ts +55 -0
- package/pkg/commands/xdel.test.ts +50 -0
- package/pkg/commands/xdel.ts +15 -0
- package/pkg/commands/xgroup.test.ts +202 -0
- package/pkg/commands/xgroup.ts +100 -0
- package/pkg/commands/xinfo.test.ts +82 -0
- package/pkg/commands/xinfo.ts +27 -0
- package/pkg/commands/xlen.test.ts +29 -0
- package/pkg/commands/xlen.ts +11 -0
- package/pkg/commands/xpending.test.ts +94 -0
- package/pkg/commands/xpending.ts +43 -0
- package/pkg/commands/xrange.test.ts +69 -0
- package/pkg/commands/xrange.ts +48 -0
- package/pkg/commands/xread.test.ts +117 -0
- package/pkg/commands/xread.ts +51 -0
- package/pkg/commands/xreadgroup.test.ts +166 -0
- package/pkg/commands/xreadgroup.ts +66 -0
- package/pkg/commands/xrevrange.test.ts +48 -0
- package/pkg/commands/xrevrange.ts +47 -0
- package/pkg/commands/xtrim.test.ts +65 -0
- package/pkg/commands/xtrim.ts +24 -0
- package/pkg/commands/zadd.test.ts +242 -0
- package/pkg/commands/zadd.ts +53 -0
- package/pkg/commands/zcard.test.ts +16 -0
- package/pkg/commands/zcard.ts +11 -0
- package/pkg/commands/zcount.test.ts +16 -0
- package/pkg/commands/zcount.ts +13 -0
- package/pkg/commands/zdiffstore.test.ts +42 -0
- package/pkg/commands/zdiffstore.ts +14 -0
- package/pkg/commands/zincrby.test.ts +19 -0
- package/pkg/commands/zincrby.ts +13 -0
- package/pkg/commands/zinterstore.test.ts +297 -0
- package/pkg/commands/zinterstore.ts +51 -0
- package/pkg/commands/zlexcount.test.ts +23 -0
- package/pkg/commands/zlexcount.ts +10 -0
- package/pkg/commands/zmscore.test.ts +39 -0
- package/pkg/commands/zmscore.ts +15 -0
- package/pkg/commands/zpopmax.test.ts +46 -0
- package/pkg/commands/zpopmax.ts +17 -0
- package/pkg/commands/zpopmin.test.ts +50 -0
- package/pkg/commands/zpopmin.ts +17 -0
- package/pkg/commands/zrange.test.ts +188 -0
- package/pkg/commands/zrange.ts +68 -0
- package/pkg/commands/zrank.test.ts +23 -0
- package/pkg/commands/zrank.ts +14 -0
- package/pkg/commands/zrem.test.ts +21 -0
- package/pkg/commands/zrem.ts +10 -0
- package/pkg/commands/zremrangebylex.test.ts +24 -0
- package/pkg/commands/zremrangebylex.ts +10 -0
- package/pkg/commands/zremrangebyrank.test.ts +27 -0
- package/pkg/commands/zremrangebyrank.ts +13 -0
- package/pkg/commands/zremrangebyscore.test.ts +24 -0
- package/pkg/commands/zremrangebyscore.ts +10 -0
- package/pkg/commands/zrevrank.test.ts +23 -0
- package/pkg/commands/zrevrank.ts +14 -0
- package/pkg/commands/zscan.test.ts +48 -0
- package/pkg/commands/zscan.ts +30 -0
- package/pkg/commands/zscore.test.ts +18 -0
- package/pkg/commands/zscore.ts +14 -0
- package/pkg/commands/zunion.test.ts +251 -0
- package/pkg/commands/zunion.ts +54 -0
- package/pkg/commands/zunionstore.test.ts +274 -0
- package/pkg/commands/zunionstore.ts +51 -0
- package/pkg/error.ts +18 -0
- package/pkg/http.ts +349 -0
- package/pkg/index.ts +1 -0
- package/pkg/pipeline.test.ts +254 -0
- package/pkg/pipeline.ts +1401 -0
- package/pkg/read-your-writes.test.ts +115 -0
- package/pkg/redis.test.ts +250 -0
- package/pkg/redis.ts +1367 -0
- package/pkg/script.test.ts +58 -0
- package/pkg/script.ts +67 -0
- package/pkg/test-utils.test.ts +17 -0
- package/pkg/test-utils.ts +72 -0
- package/pkg/types.ts +35 -0
- package/pkg/util.ts +42 -0
- package/platforms/cloudflare.ts +144 -0
- package/platforms/fastly.ts +100 -0
- package/platforms/nodejs.ts +196 -0
- package/prettier.config.mjs +13 -0
- package/tsconfig.json +21 -0
- package/tsup.config.ts +8 -0
- package/version.ts +1 -0
- package/chunk-JD7AT2OK.js +0 -1
- package/chunk-XCPX3L6C.mjs +0 -1
- package/cloudflare.d.mts +0 -50
- package/cloudflare.d.ts +0 -50
- package/cloudflare.js +0 -1
- package/cloudflare.mjs +0 -1
- package/fastly.d.mts +0 -43
- package/fastly.d.ts +0 -43
- package/fastly.js +0 -1
- package/fastly.mjs +0 -1
- package/nodejs.d.mts +0 -85
- package/nodejs.d.ts +0 -85
- package/nodejs.js +0 -1
- package/nodejs.mjs +0 -1
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
/* eslint-disable unicorn/consistent-function-scoping */
|
|
2
|
+
import { addNewItemToStream, keygen, newHttpClient } from "../test-utils";
|
|
3
|
+
|
|
4
|
+
import { afterAll, describe, expect, test } from "bun:test";
|
|
5
|
+
import { UNBALANCED_XREAD_ERR, XReadCommand } from "./xread";
|
|
6
|
+
|
|
7
|
+
const client = newHttpClient();
|
|
8
|
+
|
|
9
|
+
const { newKey, cleanup } = keygen();
|
|
10
|
+
afterAll(cleanup);
|
|
11
|
+
|
|
12
|
+
describe("COUNT", () => {
|
|
13
|
+
test("should return successfully", async () => {
|
|
14
|
+
const streamKey = newKey();
|
|
15
|
+
const { member1: xmember1, member2: xmember2 } = await addNewItemToStream(streamKey, client);
|
|
16
|
+
|
|
17
|
+
const res = (await new XReadCommand([streamKey, "0-0"]).exec(client)) as string[];
|
|
18
|
+
|
|
19
|
+
//@ts-expect-error to silence compiler
|
|
20
|
+
expect(res[0][1][0][1]).toEqual(["field1", xmember1, "field2", xmember2]);
|
|
21
|
+
});
|
|
22
|
+
test("should return multiple items", async () => {
|
|
23
|
+
const wantedLength = 3;
|
|
24
|
+
const streamKey = newKey();
|
|
25
|
+
await addNewItemToStream(streamKey, client);
|
|
26
|
+
await addNewItemToStream(streamKey, client);
|
|
27
|
+
await addNewItemToStream(streamKey, client);
|
|
28
|
+
|
|
29
|
+
const res = (await new XReadCommand([streamKey, "0-0", { count: wantedLength }]).exec(
|
|
30
|
+
client
|
|
31
|
+
)) as any[];
|
|
32
|
+
|
|
33
|
+
expect(res[0][1].length).toBe(wantedLength);
|
|
34
|
+
});
|
|
35
|
+
test("should return desired amount of items", async () => {
|
|
36
|
+
const wantedLength = 2;
|
|
37
|
+
const streamKey = newKey();
|
|
38
|
+
await addNewItemToStream(streamKey, client);
|
|
39
|
+
await addNewItemToStream(streamKey, client);
|
|
40
|
+
await addNewItemToStream(streamKey, client);
|
|
41
|
+
|
|
42
|
+
const res = (await new XReadCommand([streamKey, "0-0", { count: wantedLength }]).exec(
|
|
43
|
+
client
|
|
44
|
+
)) as any[];
|
|
45
|
+
|
|
46
|
+
expect(res[0][1].length).toBe(wantedLength);
|
|
47
|
+
});
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
describe("IDs", () => {
|
|
51
|
+
test(
|
|
52
|
+
"should return items with given id",
|
|
53
|
+
async () => {
|
|
54
|
+
const streamKey = newKey();
|
|
55
|
+
await addNewItemToStream(streamKey, client);
|
|
56
|
+
|
|
57
|
+
const res = (await new XReadCommand([streamKey, `${Date.now() - 15_000}-0`]).exec(
|
|
58
|
+
client
|
|
59
|
+
)) as string[];
|
|
60
|
+
expect(res).toBeInstanceOf(Array);
|
|
61
|
+
},
|
|
62
|
+
{ retry: 3 }
|
|
63
|
+
);
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
describe("Multiple stream", () => {
|
|
67
|
+
test(
|
|
68
|
+
"should return items with multiple streams and ids",
|
|
69
|
+
async () => {
|
|
70
|
+
const wantedLength = 2;
|
|
71
|
+
|
|
72
|
+
const streamKey1 = newKey();
|
|
73
|
+
await addNewItemToStream(streamKey1, client);
|
|
74
|
+
const streamKey2 = newKey();
|
|
75
|
+
await addNewItemToStream(streamKey2, client);
|
|
76
|
+
|
|
77
|
+
const res = (await new XReadCommand([
|
|
78
|
+
[streamKey1, streamKey2],
|
|
79
|
+
["0-0", "0-0"],
|
|
80
|
+
]).exec(client)) as string[];
|
|
81
|
+
expect(res.length).toBe(wantedLength);
|
|
82
|
+
},
|
|
83
|
+
{ retry: 3 }
|
|
84
|
+
);
|
|
85
|
+
|
|
86
|
+
test(
|
|
87
|
+
"should return only 1 stream",
|
|
88
|
+
async () => {
|
|
89
|
+
const wantedLength = 1;
|
|
90
|
+
|
|
91
|
+
const streamKey1 = newKey();
|
|
92
|
+
await addNewItemToStream(streamKey1, client);
|
|
93
|
+
|
|
94
|
+
const res = (await new XReadCommand([
|
|
95
|
+
[streamKey1, newKey()],
|
|
96
|
+
["0-0", "0-0"],
|
|
97
|
+
]).exec(client)) as string[];
|
|
98
|
+
expect(res.length).toBe(wantedLength);
|
|
99
|
+
},
|
|
100
|
+
{ retry: 3 }
|
|
101
|
+
);
|
|
102
|
+
|
|
103
|
+
test(
|
|
104
|
+
"should throw when unbalanced is array passed",
|
|
105
|
+
() => {
|
|
106
|
+
const throwable = async () => {
|
|
107
|
+
const streamKey1 = newKey();
|
|
108
|
+
await addNewItemToStream(streamKey1, client);
|
|
109
|
+
|
|
110
|
+
await new XReadCommand([[streamKey1, newKey()], ["0-0"]]).exec(client);
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
expect(throwable).toThrow(UNBALANCED_XREAD_ERR);
|
|
114
|
+
},
|
|
115
|
+
{ retry: 3 }
|
|
116
|
+
);
|
|
117
|
+
});
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import type { CommandOptions } from "./command";
|
|
2
|
+
import { Command } from "./command";
|
|
3
|
+
|
|
4
|
+
export const UNBALANCED_XREAD_ERR =
|
|
5
|
+
"ERR Unbalanced XREAD list of streams: for each stream key an ID or '$' must be specified";
|
|
6
|
+
|
|
7
|
+
type XReadCommandOptions = [
|
|
8
|
+
key: string | string[],
|
|
9
|
+
id: string | string[],
|
|
10
|
+
options?: { count?: number; blockMS?: number },
|
|
11
|
+
];
|
|
12
|
+
|
|
13
|
+
//This type ensures users have balanced stream keys and stream ids otherwise redis server will throw an error.
|
|
14
|
+
type XReadOptions = XReadCommandOptions extends [infer K, infer I, ...any[]]
|
|
15
|
+
? K extends string
|
|
16
|
+
? I extends string
|
|
17
|
+
? [key: string, id: string, options?: { count?: number; blockMS?: number }]
|
|
18
|
+
: never
|
|
19
|
+
: K extends string[]
|
|
20
|
+
? I extends string[]
|
|
21
|
+
? [key: string[], id: string[], options?: { count?: number; blockMS?: number }]
|
|
22
|
+
: never
|
|
23
|
+
: never
|
|
24
|
+
: never;
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* @see https://redis.io/commands/xread
|
|
28
|
+
*/
|
|
29
|
+
export class XReadCommand extends Command<number, unknown[]> {
|
|
30
|
+
constructor([key, id, options]: XReadOptions, opts?: CommandOptions<number, unknown[]>) {
|
|
31
|
+
if (Array.isArray(key) && Array.isArray(id) && key.length !== id.length) {
|
|
32
|
+
throw new Error(UNBALANCED_XREAD_ERR);
|
|
33
|
+
}
|
|
34
|
+
const commands: unknown[] = [];
|
|
35
|
+
|
|
36
|
+
if (typeof options?.count === "number") {
|
|
37
|
+
commands.push("COUNT", options.count);
|
|
38
|
+
}
|
|
39
|
+
if (typeof options?.blockMS === "number") {
|
|
40
|
+
commands.push("BLOCK", options.blockMS);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
commands.push(
|
|
44
|
+
"STREAMS",
|
|
45
|
+
...(Array.isArray(key) ? [...key] : [key]),
|
|
46
|
+
...(Array.isArray(id) ? [...id] : [id])
|
|
47
|
+
);
|
|
48
|
+
|
|
49
|
+
super(["XREAD", ...commands], opts);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
import { addNewItemToStream, keygen, newHttpClient } from "../test-utils";
|
|
2
|
+
|
|
3
|
+
import { afterAll, describe, expect, test } from "bun:test";
|
|
4
|
+
import { XGroupCommand } from "./xgroup";
|
|
5
|
+
import { XInfoCommand } from "./xinfo";
|
|
6
|
+
import { UNBALANCED_XREADGROUP_ERR, XReadGroupCommand } from "./xreadgroup";
|
|
7
|
+
|
|
8
|
+
const client = newHttpClient();
|
|
9
|
+
|
|
10
|
+
const { newKey, cleanup } = keygen();
|
|
11
|
+
afterAll(cleanup);
|
|
12
|
+
|
|
13
|
+
describe("COUNT", () => {
|
|
14
|
+
test("should read everything into given xreadgroup and mark them as pending", async () => {
|
|
15
|
+
const wantedAmount = 3;
|
|
16
|
+
const streamKey = newKey();
|
|
17
|
+
const group = newKey();
|
|
18
|
+
const consumer = newKey();
|
|
19
|
+
|
|
20
|
+
for (let i = 0; i < wantedAmount; i++) {
|
|
21
|
+
await addNewItemToStream(streamKey, client);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
await new XGroupCommand([streamKey, { type: "CREATE", group, id: "0" }]).exec(client);
|
|
25
|
+
|
|
26
|
+
const res = (await new XReadGroupCommand([group, consumer, streamKey, ">"]).exec(
|
|
27
|
+
client
|
|
28
|
+
)) as string[];
|
|
29
|
+
const listOfStreams = res[0][1];
|
|
30
|
+
|
|
31
|
+
expect(listOfStreams.length).toEqual(wantedAmount);
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
test("should read given amount of streams into given xreadgroup and mark them as pending", async () => {
|
|
35
|
+
const wantedAmount = 2;
|
|
36
|
+
const streamKey = newKey();
|
|
37
|
+
const group = newKey();
|
|
38
|
+
const consumer = newKey();
|
|
39
|
+
|
|
40
|
+
for (let i = 0; i < wantedAmount; i++) {
|
|
41
|
+
await addNewItemToStream(streamKey, client);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
await new XGroupCommand([streamKey, { type: "CREATE", group, id: "0" }]).exec(client);
|
|
45
|
+
|
|
46
|
+
const res = (await new XReadGroupCommand([
|
|
47
|
+
group,
|
|
48
|
+
consumer,
|
|
49
|
+
streamKey,
|
|
50
|
+
">",
|
|
51
|
+
{ count: wantedAmount },
|
|
52
|
+
]).exec(client)) as string[];
|
|
53
|
+
const listOfStreams = res[0][1];
|
|
54
|
+
|
|
55
|
+
expect(listOfStreams.length).toEqual(wantedAmount);
|
|
56
|
+
});
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
describe("NOACK", () => {
|
|
60
|
+
test("should return 0 items in PEL", async () => {
|
|
61
|
+
const streamKey = newKey();
|
|
62
|
+
const group = newKey();
|
|
63
|
+
const consumer = newKey();
|
|
64
|
+
|
|
65
|
+
await addNewItemToStream(streamKey, client);
|
|
66
|
+
|
|
67
|
+
await new XGroupCommand([streamKey, { type: "CREATE", group, id: "0" }]).exec(client);
|
|
68
|
+
|
|
69
|
+
await new XReadGroupCommand([group, consumer, streamKey, ">", { NOACK: true }]).exec(client);
|
|
70
|
+
|
|
71
|
+
const xinfoRes = (await new XInfoCommand([streamKey, { type: "CONSUMERS", group }]).exec(
|
|
72
|
+
client
|
|
73
|
+
)) as string[];
|
|
74
|
+
expect(xinfoRes).toEqual([]);
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
test("should return desired amount of items in PEL", async () => {
|
|
78
|
+
const wantedCount = 5;
|
|
79
|
+
const streamKey = newKey();
|
|
80
|
+
const group = newKey();
|
|
81
|
+
const consumer = newKey();
|
|
82
|
+
|
|
83
|
+
for (let i = 0; i < wantedCount; i++) {
|
|
84
|
+
await addNewItemToStream(streamKey, client);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
await new XGroupCommand([streamKey, { type: "CREATE", group, id: "0" }]).exec(client);
|
|
88
|
+
|
|
89
|
+
await new XReadGroupCommand([group, consumer, streamKey, ">", { NOACK: false }]).exec(client);
|
|
90
|
+
|
|
91
|
+
const xinfoRes = (await new XInfoCommand([streamKey, { type: "CONSUMERS", group }]).exec(
|
|
92
|
+
client
|
|
93
|
+
)) as string[];
|
|
94
|
+
|
|
95
|
+
const pendingCount = Number(xinfoRes[0][3]);
|
|
96
|
+
|
|
97
|
+
expect(pendingCount).toBe(wantedCount);
|
|
98
|
+
});
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
describe("Multiple Stream", () => {
|
|
102
|
+
test("should read given amount of streams into given xreadgroup and mark them as pending", async () => {
|
|
103
|
+
const streamKey1 = newKey();
|
|
104
|
+
const streamKey2 = newKey();
|
|
105
|
+
const group = newKey();
|
|
106
|
+
const consumer = newKey();
|
|
107
|
+
|
|
108
|
+
await addNewItemToStream(streamKey1, client);
|
|
109
|
+
await addNewItemToStream(streamKey1, client);
|
|
110
|
+
await addNewItemToStream(streamKey2, client);
|
|
111
|
+
await addNewItemToStream(streamKey2, client);
|
|
112
|
+
|
|
113
|
+
await new XGroupCommand([streamKey1, { type: "CREATE", group, id: "0" }]).exec(client);
|
|
114
|
+
await new XGroupCommand([streamKey2, { type: "CREATE", group, id: "0" }]).exec(client);
|
|
115
|
+
|
|
116
|
+
const res = (await new XReadGroupCommand([
|
|
117
|
+
group,
|
|
118
|
+
consumer,
|
|
119
|
+
[streamKey1, streamKey2],
|
|
120
|
+
[">", ">"],
|
|
121
|
+
{ count: 1 },
|
|
122
|
+
]).exec(client)) as string[];
|
|
123
|
+
expect(res.length).toEqual(2);
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
test("should read everything into given xreadgroup and mark them as pending", async () => {
|
|
127
|
+
const wantedAmount = 4;
|
|
128
|
+
const streamKey = newKey();
|
|
129
|
+
const group = newKey();
|
|
130
|
+
const consumer = newKey();
|
|
131
|
+
|
|
132
|
+
for (let i = 0; i < wantedAmount; i++) {
|
|
133
|
+
await addNewItemToStream(streamKey, client);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
await new XGroupCommand([streamKey, { type: "CREATE", group, id: "0" }]).exec(client);
|
|
137
|
+
|
|
138
|
+
const res = (await new XReadGroupCommand([
|
|
139
|
+
group,
|
|
140
|
+
consumer,
|
|
141
|
+
streamKey,
|
|
142
|
+
">",
|
|
143
|
+
{ count: wantedAmount },
|
|
144
|
+
]).exec(client)) as string[];
|
|
145
|
+
const listOfStreams = res[0][1];
|
|
146
|
+
|
|
147
|
+
expect(listOfStreams.length).toEqual(wantedAmount);
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
test("should throw when unbalanced is array passed", () => {
|
|
151
|
+
// eslint-disable-next-line unicorn/consistent-function-scoping
|
|
152
|
+
const throwable = async () => {
|
|
153
|
+
const streamKey = newKey();
|
|
154
|
+
const group = newKey();
|
|
155
|
+
const consumer = newKey();
|
|
156
|
+
|
|
157
|
+
await addNewItemToStream(streamKey, client);
|
|
158
|
+
|
|
159
|
+
await new XGroupCommand([streamKey, { type: "CREATE", group, id: "0" }]).exec(client);
|
|
160
|
+
|
|
161
|
+
await new XReadGroupCommand([group, consumer, [streamKey, newKey()], ["0-0"]]).exec(client);
|
|
162
|
+
};
|
|
163
|
+
|
|
164
|
+
expect(throwable).toThrow(UNBALANCED_XREADGROUP_ERR);
|
|
165
|
+
});
|
|
166
|
+
});
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import type { CommandOptions } from "./command";
|
|
2
|
+
import { Command } from "./command";
|
|
3
|
+
|
|
4
|
+
export const UNBALANCED_XREADGROUP_ERR =
|
|
5
|
+
"ERR Unbalanced XREADGROUP list of streams: for each stream key an ID or '$' must be specified";
|
|
6
|
+
|
|
7
|
+
type Options = { count?: number; blockMS?: number; NOACK?: boolean };
|
|
8
|
+
type XReadGroupCommandOptions = [
|
|
9
|
+
group: string,
|
|
10
|
+
consumer: string,
|
|
11
|
+
key: string | string[],
|
|
12
|
+
id: string | string[],
|
|
13
|
+
options?: Options,
|
|
14
|
+
];
|
|
15
|
+
|
|
16
|
+
//This type ensures users have balanced stream keys and stream ids otherwise redis server will throw an error.
|
|
17
|
+
type XReadGroupOptions = XReadGroupCommandOptions extends [
|
|
18
|
+
string,
|
|
19
|
+
string,
|
|
20
|
+
infer TKey,
|
|
21
|
+
infer TId,
|
|
22
|
+
...any[],
|
|
23
|
+
]
|
|
24
|
+
? TKey extends string
|
|
25
|
+
? TId extends string
|
|
26
|
+
? [group: string, consumer: string, key: string, id: string, options?: Options]
|
|
27
|
+
: never
|
|
28
|
+
: TKey extends string[]
|
|
29
|
+
? TId extends string[]
|
|
30
|
+
? [group: string, consumer: string, key: string[], id: string[], options?: Options]
|
|
31
|
+
: never
|
|
32
|
+
: never
|
|
33
|
+
: never;
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* @see https://redis.io/commands/xreadgroup
|
|
37
|
+
*/
|
|
38
|
+
export class XReadGroupCommand extends Command<number, unknown[]> {
|
|
39
|
+
constructor(
|
|
40
|
+
[group, consumer, key, id, options]: XReadGroupOptions,
|
|
41
|
+
opts?: CommandOptions<number, unknown[]>
|
|
42
|
+
) {
|
|
43
|
+
if (Array.isArray(key) && Array.isArray(id) && key.length !== id.length) {
|
|
44
|
+
throw new Error(UNBALANCED_XREADGROUP_ERR);
|
|
45
|
+
}
|
|
46
|
+
const commands: unknown[] = [];
|
|
47
|
+
|
|
48
|
+
if (typeof options?.count === "number") {
|
|
49
|
+
commands.push("COUNT", options.count);
|
|
50
|
+
}
|
|
51
|
+
if (typeof options?.blockMS === "number") {
|
|
52
|
+
commands.push("BLOCK", options.blockMS);
|
|
53
|
+
}
|
|
54
|
+
if (typeof options?.NOACK === "boolean" && options.NOACK) {
|
|
55
|
+
commands.push("NOACK");
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
commands.push(
|
|
59
|
+
"STREAMS",
|
|
60
|
+
...(Array.isArray(key) ? [...key] : [key]),
|
|
61
|
+
...(Array.isArray(id) ? [...id] : [id])
|
|
62
|
+
);
|
|
63
|
+
|
|
64
|
+
super(["XREADGROUP", "GROUP", group, consumer, ...commands], opts);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { keygen, newHttpClient } from "../test-utils";
|
|
2
|
+
|
|
3
|
+
import { afterAll, beforeEach, describe, expect, test } from "bun:test";
|
|
4
|
+
import { XAddCommand } from "./xadd";
|
|
5
|
+
import { XRevRangeCommand } from "./xrevrange";
|
|
6
|
+
|
|
7
|
+
const client = newHttpClient();
|
|
8
|
+
const { newKey, cleanup } = keygen();
|
|
9
|
+
const key = newKey();
|
|
10
|
+
afterAll(cleanup);
|
|
11
|
+
|
|
12
|
+
beforeEach(async () => {
|
|
13
|
+
await new XAddCommand([key, "*", { name: "Virginia", surname: "Woolf" }]).exec(client);
|
|
14
|
+
|
|
15
|
+
await new XAddCommand([key, "*", { name: "Jane", surname: "Austen" }]).exec(client);
|
|
16
|
+
|
|
17
|
+
await new XAddCommand([key, "*", { name: "Toni", surname: "Morrison" }]).exec(client);
|
|
18
|
+
|
|
19
|
+
await new XAddCommand([key, "*", { name: "Agatha", surname: "Christie" }]).exec(client);
|
|
20
|
+
|
|
21
|
+
await new XAddCommand([key, "*", { name: "Ngozi", surname: "Adichie" }]).exec(client);
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
describe("without options", () => {
|
|
25
|
+
test("should return stream in a reverse order", async () => {
|
|
26
|
+
const res = await new XRevRangeCommand([key, "+", "-"]).exec(client);
|
|
27
|
+
|
|
28
|
+
expect(Object.keys(res).length).toBe(5);
|
|
29
|
+
expect(Object.values(res)[0]).toEqual({
|
|
30
|
+
name: "Ngozi",
|
|
31
|
+
surname: "Adichie",
|
|
32
|
+
});
|
|
33
|
+
});
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
describe("LIMIT", () => {
|
|
37
|
+
test("should return only last two", async () => {
|
|
38
|
+
const res = await new XRevRangeCommand([key, "+", "-", 2]).exec(client);
|
|
39
|
+
expect(Object.keys(res).length).toBe(2);
|
|
40
|
+
expect(Object.values(res)).toEqual([
|
|
41
|
+
{
|
|
42
|
+
name: "Ngozi",
|
|
43
|
+
surname: "Adichie",
|
|
44
|
+
},
|
|
45
|
+
{ name: "Agatha", surname: "Christie" },
|
|
46
|
+
]);
|
|
47
|
+
});
|
|
48
|
+
});
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import type { CommandOptions } from "./command";
|
|
2
|
+
import { Command } from "./command";
|
|
3
|
+
|
|
4
|
+
export class XRevRangeCommand<
|
|
5
|
+
TData extends Record<string, Record<string, unknown>>,
|
|
6
|
+
> extends Command<string[][], TData> {
|
|
7
|
+
constructor(
|
|
8
|
+
[key, end, start, count]: [key: string, end: string, start: string, count?: number],
|
|
9
|
+
opts?: CommandOptions<unknown[], TData[]>
|
|
10
|
+
) {
|
|
11
|
+
const command: unknown[] = ["XREVRANGE", key, end, start];
|
|
12
|
+
if (typeof count === "number") {
|
|
13
|
+
command.push("COUNT", count);
|
|
14
|
+
}
|
|
15
|
+
super(command, {
|
|
16
|
+
deserialize: (result) => deserialize<any>(result as any),
|
|
17
|
+
...opts,
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function deserialize<TData extends Record<string, Record<string, unknown>>>(
|
|
23
|
+
result: [string, string[]][]
|
|
24
|
+
): TData {
|
|
25
|
+
const obj: Record<string, Record<string, unknown>> = {};
|
|
26
|
+
for (const e of result) {
|
|
27
|
+
while (e.length >= 2) {
|
|
28
|
+
const streamId = e.shift() as string;
|
|
29
|
+
const entries = e.shift()!;
|
|
30
|
+
|
|
31
|
+
if (!(streamId in obj)) {
|
|
32
|
+
obj[streamId] = {};
|
|
33
|
+
}
|
|
34
|
+
while (entries.length >= 2) {
|
|
35
|
+
const field = (entries as string[]).shift()!;
|
|
36
|
+
const value = (entries as string[]).shift()!;
|
|
37
|
+
|
|
38
|
+
try {
|
|
39
|
+
obj[streamId][field] = JSON.parse(value);
|
|
40
|
+
} catch {
|
|
41
|
+
obj[streamId][field] = value;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
return obj as TData;
|
|
47
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { keygen, newHttpClient, randomID } from "../test-utils";
|
|
2
|
+
|
|
3
|
+
import { afterAll, describe, expect, test } from "bun:test";
|
|
4
|
+
import { XAddCommand } from "./xadd";
|
|
5
|
+
import { XLenCommand } from "./xlen";
|
|
6
|
+
import { XTrimCommand } from "./xtrim";
|
|
7
|
+
|
|
8
|
+
const client = newHttpClient();
|
|
9
|
+
|
|
10
|
+
const { newKey, cleanup } = keygen();
|
|
11
|
+
afterAll(cleanup);
|
|
12
|
+
|
|
13
|
+
describe("XLEN", () => {
|
|
14
|
+
test(
|
|
15
|
+
"should approximately trim stream to 30 items",
|
|
16
|
+
async () => {
|
|
17
|
+
const key = newKey();
|
|
18
|
+
const promises = [];
|
|
19
|
+
for (let i = 1; i <= 1000; i++) {
|
|
20
|
+
promises.push(new XAddCommand([key, "*", { [randomID()]: randomID() }]).exec(client));
|
|
21
|
+
}
|
|
22
|
+
await Promise.all(promises);
|
|
23
|
+
await new XTrimCommand([key, { strategy: "MAXLEN", threshold: 30, exactness: "~" }]).exec(
|
|
24
|
+
client
|
|
25
|
+
);
|
|
26
|
+
const len = await new XLenCommand([key]).exec(client);
|
|
27
|
+
expect(len).toBeGreaterThanOrEqual(29);
|
|
28
|
+
expect(len).toBeLessThanOrEqual(31);
|
|
29
|
+
},
|
|
30
|
+
{ timeout: 1000 * 60 }
|
|
31
|
+
);
|
|
32
|
+
|
|
33
|
+
test("should trim with zero threshold and remove everything", async () => {
|
|
34
|
+
const key = newKey();
|
|
35
|
+
const promises = [];
|
|
36
|
+
for (let i = 1; i <= 50; i++) {
|
|
37
|
+
promises.push(new XAddCommand([key, "*", { [randomID()]: randomID() }]).exec(client));
|
|
38
|
+
}
|
|
39
|
+
await Promise.all(promises);
|
|
40
|
+
await new XTrimCommand([key, { strategy: "MAXLEN", threshold: 0, exactness: "=" }]).exec(
|
|
41
|
+
client
|
|
42
|
+
);
|
|
43
|
+
const len = await new XLenCommand([key]).exec(client);
|
|
44
|
+
expect(len).toBeLessThanOrEqual(1);
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
test(
|
|
48
|
+
"should trim with MINID and a limit and only remove 2 items that satisfies MINID",
|
|
49
|
+
async () => {
|
|
50
|
+
const key = newKey();
|
|
51
|
+
const baseTimestamp = Date.now();
|
|
52
|
+
for (let i = 0; i < 20; i++) {
|
|
53
|
+
const id = `${baseTimestamp}-${i}`;
|
|
54
|
+
await new XAddCommand([key, id, { data: `value${i}` }]).exec(client);
|
|
55
|
+
}
|
|
56
|
+
const midRangeId = `${baseTimestamp}-10`;
|
|
57
|
+
await new XTrimCommand([key, { strategy: "MINID", threshold: midRangeId, limit: 2 }]).exec(
|
|
58
|
+
client
|
|
59
|
+
);
|
|
60
|
+
const len = await new XLenCommand([key]).exec(client);
|
|
61
|
+
expect(len).toBeLessThanOrEqual(20);
|
|
62
|
+
},
|
|
63
|
+
{ timeout: 20_000 }
|
|
64
|
+
);
|
|
65
|
+
});
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { CommandOptions } from "./command";
|
|
2
|
+
import { Command } from "./command";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* @see https://redis.io/commands/xtrim
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
type XTrimOptions = {
|
|
9
|
+
strategy: "MAXLEN" | "MINID";
|
|
10
|
+
exactness?: "~" | "=";
|
|
11
|
+
threshold: number | string;
|
|
12
|
+
limit?: number;
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
export class XTrimCommand extends Command<number, number> {
|
|
16
|
+
constructor(
|
|
17
|
+
[key, options]: [key: string, options: XTrimOptions],
|
|
18
|
+
opts?: CommandOptions<number, number>
|
|
19
|
+
) {
|
|
20
|
+
const { limit, strategy, threshold, exactness = "~" } = options;
|
|
21
|
+
|
|
22
|
+
super(["XTRIM", key, strategy, exactness, threshold, ...(limit ? ["LIMIT", limit] : [])], opts);
|
|
23
|
+
}
|
|
24
|
+
}
|