Skip to content

Commit 17f037d

Browse files
committed
fix: prevent double-wrapping of typebox schemas
1 parent 31a18c2 commit 17f037d

File tree

1 file changed

+26
-14
lines changed

1 file changed

+26
-14
lines changed

src/transform.ts

Lines changed: 26 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import { RedisValue } from "./command";
1212
export abstract class RedisTransform<T extends TSchema = TSchema> {
1313
readonly schema: T;
1414
constructor(schema: T) {
15-
this.schema = createRedisTransform(schema, this.constructor.name) as any;
15+
this.schema = wrapSchemaForRedis(schema, this.constructor.name) as any;
1616
}
1717

1818
/**
@@ -34,37 +34,49 @@ export abstract class RedisTransform<T extends TSchema = TSchema> {
3434
}
3535
}
3636

37+
const wrappedSchemas = new WeakSet<TSchema>();
38+
3739
/**
3840
* Wrap the JavaScript types with Redis-targeted transform types.
3941
*
4042
* Note: The encode/decode methods are flipped, because TypeBox expects
4143
* transform types to operate on input values, not output values.
4244
*/
43-
function createRedisTransform(schema: TSchema, instanceType?: string) {
45+
function wrapSchemaForRedis(schema: TSchema, instanceType?: string) {
46+
if (wrappedSchemas.has(schema)) {
47+
return schema;
48+
}
49+
4450
if (instanceType === "RedisHash") {
4551
if (schema.type !== "object" || !schema.properties) {
4652
throw new Error("RedisHash must have an object schema with properties");
4753
}
4854
const newSchema = { ...schema.properties };
4955
for (const field in schema.properties) {
50-
newSchema[field] = createRedisTransform(schema.properties[field]) as any;
56+
newSchema[field] = wrapSchemaForRedis(schema.properties[field]) as any;
5157
}
52-
return Type.Object(newSchema);
53-
}
54-
if (schema.type !== "string" && schema.type !== "uint8array") {
58+
schema = Type.Object(newSchema);
59+
} else if (schema.type !== "string" && schema.type !== "uint8array") {
5560
if (schema.type === "number") {
56-
return Transform(schema as TNumber)
61+
schema = Transform(schema as TNumber)
5762
.Decode((value) => String(value))
5863
.Encode((value) => Number(value));
59-
}
60-
if (schema.type === "boolean") {
61-
return Transform(schema as TBoolean)
64+
} else if (schema.type === "boolean") {
65+
schema = Transform(schema as TBoolean)
6266
.Decode((value) => (value ? "1" : "0"))
63-
.Encode((value) => value === "1");
67+
.Encode((value) => {
68+
console.trace("TBoolean.encode:", value);
69+
if (value === "1") return true;
70+
if (value === "0") return false;
71+
throw new Error("Invalid boolean value");
72+
});
73+
} else {
74+
schema = Transform(schema)
75+
.Decode((value) => JSON.stringify(value))
76+
.Encode((value) => JSON.parse(value));
6477
}
65-
return Transform(schema)
66-
.Decode((value) => JSON.stringify(value))
67-
.Encode((value) => JSON.parse(value));
6878
}
79+
80+
wrappedSchemas.add(schema);
6981
return schema;
7082
}

0 commit comments

Comments
 (0)