Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 15 additions & 4 deletions .github/workflows/tests.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
name: Tests
on:
push:
branches:
- main
pull_request:
schedule:
- cron: "0 0 * * *" # daily
Expand Down Expand Up @@ -466,8 +469,12 @@ jobs:
pnpm add -g wrangler
working-directory: examples/cloudflare-workers

- name: Add account ID
run: echo 'account_id = "${{ secrets.CLOUDFLARE_ACCOUNT_ID }}"' >> wrangler.toml
- name: Add environment
run: |
echo 'account_id = "${{ secrets.CLOUDFLARE_ACCOUNT_ID }}"' >> wrangler.toml
echo '[vars]' >> wrangler.toml
echo 'UPSTASH_REDIS_REST_URL = "${{ secrets.UPSTASH_REDIS_REST_URL }}"' >> ./wrangler.toml
echo 'UPSTASH_REDIS_REST_TOKEN = "${{ secrets.UPSTASH_REDIS_REST_TOKEN }}"' >> ./wrangler.toml
working-directory: examples/cloudflare-workers

- name: Start example
Expand Down Expand Up @@ -554,8 +561,12 @@ jobs:

working-directory: examples/cloudflare-workers-with-typescript

- name: Add account ID
run: echo 'account_id = "${{ secrets.CLOUDFLARE_ACCOUNT_ID }}"' >> wrangler.toml
- name: Add environment
run: |
echo 'account_id = "${{ secrets.CLOUDFLARE_ACCOUNT_ID }}"' >> wrangler.toml
echo '[vars]' >> wrangler.toml
echo 'UPSTASH_REDIS_REST_URL = "${{ secrets.UPSTASH_REDIS_REST_URL }}"' >> ./wrangler.toml
echo 'UPSTASH_REDIS_REST_TOKEN = "${{ secrets.UPSTASH_REDIS_REST_TOKEN }}"' >> ./wrangler.toml
working-directory: examples/cloudflare-workers-with-typescript

- name: Start example
Expand Down
2 changes: 1 addition & 1 deletion cmd/build.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ const outDir = "./dist";

await dnt.emptyDir(outDir);

const version = Deno.args.length > 0 ? Deno.args[0] : "development";
const version = Deno.args.length > 0 ? Deno.args[0] : "v0.0.0";
Deno.writeFileSync(
"version.ts",
new TextEncoder().encode(`export const VERSION = "${version}"`),
Expand Down
2 changes: 1 addition & 1 deletion examples/cloudflare-workers-with-typescript/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,6 @@
"publish": "wrangler publish"
},
"dependencies": {
"@upstash/redis": "latest"
"@upstash/redis": "../../dist"
}
}
4 changes: 2 additions & 2 deletions examples/cloudflare-workers/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@
"publish": "wrangler publish"
},
"devDependencies": {
"wrangler": "^2.4.4"
"wrangler": "^2.20.0"
},
"dependencies": {
"@upstash/redis": "latest"
"@upstash/redis": "link:../../dist"
}
}
30 changes: 0 additions & 30 deletions examples/nextjs_edge/middleware.ts

This file was deleted.

4 changes: 2 additions & 2 deletions examples/nextjs_edge/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@
"start": "next start"
},
"dependencies": {
"@upstash/redis": "latest",
"next": "^13.0.5",
"@upstash/redis": "../../dist",
"next": "^13.4.4",
"react": "^18.2.0",
"react-dom": "^18.2.0"
},
Expand Down
15 changes: 11 additions & 4 deletions examples/nextjs_edge/pages/api/counter.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
import { NextApiRequest, NextApiResponse } from "next";
import { Redis } from "@upstash/redis";
import { NextRequest, NextResponse } from "next/server";

export default (_req: NextApiRequest, res: NextApiResponse) => {
res.status(200);
res.send("OK");
export const config = {
runtime: "edge",
};

const redis = Redis.fromEnv();

export default async (_req: NextRequest) => {
const counter = await redis.incr("vercel_edge_counter");
return NextResponse.json({ counter });
};
4 changes: 1 addition & 3 deletions examples/nextjs_edge/test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,6 @@ Deno.test("works", async () => {

const res = await fetch(url);
assertEquals(res.status, 200);
const counterString = res.headers.get("Counter");
const counter = parseInt(counterString!);
const { counter } = await res.json() as { counter: number };
assertEquals("number", typeof counter);
assertEquals("OK", await res.text());
});
3 changes: 2 additions & 1 deletion pkg/commands/set.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,8 @@ Deno.test("get with xx", async (t) => {
const value = randomID();
await new SetCommand([key, old]).exec(client);

const res = await new SetCommand([key, value, { get: true, xx: true }]).exec(client);
const res = await new SetCommand([key, value, { get: true, xx: true }])
.exec(client);
assertEquals(res, old);
});
});
Expand Down
67 changes: 28 additions & 39 deletions pkg/pipeline.ts
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,10 @@ import { ZMScoreCommand } from "./commands/zmscore.ts";
import { HRandFieldCommand } from "./commands/hrandfield.ts";
import { ZDiffStoreCommand } from "./commands/zdiffstore.ts";

type Chain = <T>(command: Command<any, T>) => Pipeline;
// Given a tuple of commands, returns a tuple of the response data of each command
type InferResponseData<T extends unknown[]> = {
[K in keyof T]: T[K] extends Command<any, infer TData> ? TData : unknown;
};

/**
* Upstash REST API supports command pipelining to send multiple commands in
Expand Down Expand Up @@ -182,7 +185,7 @@ type Chain = <T>(command: Command<any, T>) => Pipeline;
* const res = await p.set("key","value").get("key").exec()
* ```
*
* It's not possible to infer correct types with a dynamic pipeline, so you can
* Return types are inferred if all commands are chained, but you can still
* override the response type manually:
* ```ts
* redis.pipeline()
Expand All @@ -192,9 +195,9 @@ type Chain = <T>(command: Command<any, T>) => Pipeline;
*
* ```
*/
export class Pipeline {
export class Pipeline<TCommands extends Command<any, any>[] = []> {
private client: Requester;
private commands: Command<unknown, unknown>[];
private commands: TCommands;
private commandOptions?: CommandOptions<any, any>;
private multiExec: boolean;
constructor(opts: {
Expand All @@ -204,7 +207,7 @@ export class Pipeline {
}) {
this.client = opts.client;

this.commands = [];
this.commands = ([] as unknown) as TCommands; // the TCommands generic in the class definition is only used for carrying through chained command types and should never be explicitly set when instantiating the class
this.commandOptions = opts.commandOptions;
this.multiExec = opts.multiExec ?? false;
}
Expand All @@ -214,13 +217,16 @@ export class Pipeline {
*
* Returns an array with the results of all pipelined commands.
*
* You can define a return type manually to make working in typescript easier
* If all commands are statically chained from start to finish, types are inferred. You can still define a return type manually if necessary though:
* ```ts
* redis.pipeline().get("key").exec<[{ greeting: string }]>()
* const p = redis.pipeline()
* p.get("key")
* const result = p.exec<[{ greeting: string }]>()
* ```
*/
exec = async <
TCommandResults extends unknown[] = unknown[],
TCommandResults extends unknown[] = [] extends TCommands ? unknown[]
: InferResponseData<TCommands>,
>(): Promise<TCommandResults> => {
if (this.commands.length === 0) {
throw new Error("Pipeline is empty");
Expand All @@ -245,12 +251,14 @@ export class Pipeline {
};

/**
* Pushes a command into the pipelien and returns a chainable instance of the
* Pushes a command into the pipeline and returns a chainable instance of the
* pipeline
*/
private chain<T>(command: Command<any, T>): this {
private chain<T>(
command: Command<any, T>,
): Pipeline<[...TCommands, Command<any, T>]> {
this.commands.push(command);
return this;
return this as any; // TS thinks we're returning Pipeline<[]> here, because we're not creating a new instance of the class, hence the cast
}

/**
Expand All @@ -274,14 +282,18 @@ export class Pipeline {
destinationKey: string,
sourceKey: string,
...sourceKeys: string[]
): Pipeline;
(op: "not", destinationKey: string, sourceKey: string): Pipeline;
): Pipeline<[...TCommands, BitOpCommand]>;
(
op: "not",
destinationKey: string,
sourceKey: string,
): Pipeline<[...TCommands, BitOpCommand]>;
} = (
op: "and" | "or" | "xor" | "not",
destinationKey: string,
sourceKey: string,
...sourceKeys: string[]
): Pipeline =>
) =>
this.chain(
new BitOpCommand(
[op as any, destinationKey, sourceKey, ...sourceKeys],
Expand Down Expand Up @@ -549,7 +561,7 @@ export class Pipeline {
direction: "before" | "after",
pivot: TData,
value: TData,
): Pipeline =>
) =>
this.chain(
new LInsertCommand<TData>(
[key, direction, pivot, value],
Expand Down Expand Up @@ -1070,30 +1082,7 @@ export class Pipeline {
/**
* @see https://redis.io/commands/?group=json
*/
get json(): {
arrappend: (...args: CommandArgs<typeof JsonArrAppendCommand>) => Pipeline;
arrindex: (...args: CommandArgs<typeof JsonArrIndexCommand>) => Pipeline;
arrinsert: (...args: CommandArgs<typeof JsonArrInsertCommand>) => Pipeline;
arrlen: (...args: CommandArgs<typeof JsonArrLenCommand>) => Pipeline;
arrpop: (...args: CommandArgs<typeof JsonArrPopCommand>) => Pipeline;
arrtrim: (...args: CommandArgs<typeof JsonArrTrimCommand>) => Pipeline;
clear: (...args: CommandArgs<typeof JsonClearCommand>) => Pipeline;
del: (...args: CommandArgs<typeof JsonDelCommand>) => Pipeline;
forget: (...args: CommandArgs<typeof JsonForgetCommand>) => Pipeline;
get: (...args: CommandArgs<typeof JsonGetCommand>) => Pipeline;
mget: (...args: CommandArgs<typeof JsonMGetCommand>) => Pipeline;
numincrby: (...args: CommandArgs<typeof JsonNumIncrByCommand>) => Pipeline;
nummultby: (...args: CommandArgs<typeof JsonNumMultByCommand>) => Pipeline;
objkeys: (...args: CommandArgs<typeof JsonObjKeysCommand>) => Pipeline;
objlen: (...args: CommandArgs<typeof JsonObjLenCommand>) => Pipeline;
resp: (...args: CommandArgs<typeof JsonRespCommand>) => Pipeline;
set: (...args: CommandArgs<typeof JsonSetCommand>) => Pipeline;
strappend: (...args: CommandArgs<typeof JsonStrAppendCommand>) => Pipeline;
strlen: (...args: CommandArgs<typeof JsonStrLenCommand>) => Pipeline;
toggle: (...args: CommandArgs<typeof JsonToggleCommand>) => Pipeline;
type: (...args: CommandArgs<typeof JsonTypeCommand>) => Pipeline;
} {
// For some reason we needed to define the types manually, otherwise Deno wouldn't build it
get json() {
return {
/**
* @see https://redis.io/commands/json.arrappend
Expand Down
2 changes: 1 addition & 1 deletion version.ts
Original file line number Diff line number Diff line change
@@ -1 +1 @@
export const VERSION = "development"
export const VERSION = "v0.0.0";