@@ -12,7 +12,7 @@ import { RedisValue } from "./command";
1212export 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