Skip to content

Commit

Permalink
feat(redis): add saveRawAsBinary driver option (#559)
Browse files Browse the repository at this point in the history
  • Loading branch information
cjpearson committed Jan 2, 2025
1 parent 9e15ab9 commit de592c8
Show file tree
Hide file tree
Showing 4 changed files with 89 additions and 40 deletions.
38 changes: 0 additions & 38 deletions src/_utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,41 +45,3 @@ export function stringify(value: any): string {

throw new Error("[unstorage] Cannot stringify value!");
}

export const BASE64_PREFIX = "base64:";

export function serializeRaw(value: any) {
if (typeof value === "string") {
return value;
}
return BASE64_PREFIX + base64Encode(value);
}

export function deserializeRaw(value: any) {
if (typeof value !== "string") {
// Return non-strings as-is
return value;
}
if (!value.startsWith(BASE64_PREFIX)) {
// Return unknown strings as-is
return value;
}
return base64Decode(value.slice(BASE64_PREFIX.length));
}

function base64Decode(input: string) {
if (globalThis.Buffer) {
return Buffer.from(input, "base64");
}
return Uint8Array.from(
globalThis.atob(input),
(c) => c.codePointAt(0) as number
);
}

function base64Encode(input: Uint8Array) {
if (globalThis.Buffer) {
return Buffer.from(input).toString("base64");
}
return globalThis.btoa(String.fromCodePoint(...input));
}
50 changes: 49 additions & 1 deletion src/drivers/redis.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
import { defineDriver, joinKeys } from "./utils";
import {
defineDriver,
joinKeys,
createError,
serializeRaw,
deserializeRaw,
} from "./utils";
// TODO: use named import in v2
import Redis, {
Cluster,
Expand Down Expand Up @@ -32,6 +38,12 @@ export interface RedisOptions extends _RedisOptions {
* Default TTL for all items in seconds.
*/
ttl?: number;

/**
* Whether to save Buffer/Uint8Arry as binary data or a base64-encoded string
* This option applies to the experimental getItemRaw/setItemRaw methods
*/
saveRawAsBinary?: boolean;
}

const DRIVER_NAME = "redis";
Expand Down Expand Up @@ -75,6 +87,42 @@ export default defineDriver((opts: RedisOptions) => {
await getRedisClient().set(p(key), value);
}
},
async getItemRaw(key) {
if (opts.saveRawAsBinary) {
const value = await getRedisClient().getBuffer(p(key));
return value ?? null;

Check warning on line 93 in src/drivers/redis.ts

View check run for this annotation

Codecov / codecov/patch

src/drivers/redis.ts#L92-L93

Added lines #L92 - L93 were not covered by tests
} else {
const value = await getRedisClient().get(p(key));
return deserializeRaw(value);
}
},
async setItemRaw(key, value, tOptions) {
let valueToSave: any;
if (opts.saveRawAsBinary) {
if (value instanceof Uint8Array) {
if (value instanceof Buffer) {
valueToSave = value;
} else {
valueToSave = Buffer.copyBytesFrom(
value,
value.byteOffset,
value.byteLength
);
}
} else {
throw createError(DRIVER_NAME, "Expected Buffer or Uint8Array");
}

Check warning on line 114 in src/drivers/redis.ts

View check run for this annotation

Codecov / codecov/patch

src/drivers/redis.ts#L102-L114

Added lines #L102 - L114 were not covered by tests
} else {
valueToSave = serializeRaw(value);
}

const ttl = tOptions?.ttl ?? opts.ttl;
if (ttl) {
await getRedisClient().set(p(key), valueToSave, "EX", ttl);

Check warning on line 121 in src/drivers/redis.ts

View check run for this annotation

Codecov / codecov/patch

src/drivers/redis.ts#L121

Added line #L121 was not covered by tests
} else {
await getRedisClient().set(p(key), valueToSave);
}
},
async removeItem(key) {
await getRedisClient().del(p(key));
},
Expand Down
38 changes: 38 additions & 0 deletions src/drivers/utils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,3 +51,41 @@ export function createRequiredError(driver: string, name: string | string[]) {
}
return createError(driver, `Missing required option \`${name}\`.`);
}

export const BASE64_PREFIX = "base64:";

export function serializeRaw(value: any) {
if (typeof value === "string") {
return value;
}

Check warning on line 60 in src/drivers/utils/index.ts

View check run for this annotation

Codecov / codecov/patch

src/drivers/utils/index.ts#L59-L60

Added lines #L59 - L60 were not covered by tests
return BASE64_PREFIX + base64Encode(value);
}

export function deserializeRaw(value: any) {
if (typeof value !== "string") {
// Return non-strings as-is
return value;
}

Check warning on line 68 in src/drivers/utils/index.ts

View check run for this annotation

Codecov / codecov/patch

src/drivers/utils/index.ts#L67-L68

Added lines #L67 - L68 were not covered by tests
if (!value.startsWith(BASE64_PREFIX)) {
// Return unknown strings as-is
return value;
}

Check warning on line 72 in src/drivers/utils/index.ts

View check run for this annotation

Codecov / codecov/patch

src/drivers/utils/index.ts#L71-L72

Added lines #L71 - L72 were not covered by tests
return base64Decode(value.slice(BASE64_PREFIX.length));
}

function base64Decode(input: string) {
if (globalThis.Buffer) {
return Buffer.from(input, "base64");
}
return Uint8Array.from(
globalThis.atob(input),
(c) => c.codePointAt(0) as number
);
}

Check warning on line 84 in src/drivers/utils/index.ts

View check run for this annotation

Codecov / codecov/patch

src/drivers/utils/index.ts#L80-L84

Added lines #L80 - L84 were not covered by tests

function base64Encode(input: Uint8Array) {
if (globalThis.Buffer) {
return Buffer.from(input).toString("base64");
}
return globalThis.btoa(String.fromCodePoint(...input));
}

Check warning on line 91 in src/drivers/utils/index.ts

View check run for this annotation

Codecov / codecov/patch

src/drivers/utils/index.ts#L90-L91

Added lines #L90 - L91 were not covered by tests
3 changes: 2 additions & 1 deletion src/storage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ import type {
TransactionOptions,
} from "./types";
import memory from "./drivers/memory";
import { asyncCall, deserializeRaw, serializeRaw, stringify } from "./_utils";
import { serializeRaw, deserializeRaw } from "./drivers/utils";
import { asyncCall, stringify } from "./_utils";
import {
normalizeKey,
normalizeBaseKey,
Expand Down

0 comments on commit de592c8

Please sign in to comment.