@@ -67,11 +67,19 @@ func (r *HashRepository[T]) FetchCache(ctx context.Context, id string, ttl time.
6767 return v , err
6868}
6969
70- func (r * HashRepository [T ]) toExec (entity * T ) (val reflect.Value , exec rueidis.LuaExec ) {
71- val = reflect .ValueOf (entity ).Elem ()
70+ func (r * HashRepository [T ]) toExec (entity * T ) (verf reflect.Value , exec rueidis.LuaExec ) {
71+ val := reflect .ValueOf (entity ).Elem ()
72+ if ! r .schema .verless {
73+ verf = val .Field (r .schema .ver .idx )
74+ } else {
75+ verf = reflect .ValueOf (int64 (0 )) // verless, set verf to a dummy value
76+ }
7277 fields := r .factory .NewConverter (val ).ToHash ()
7378 keyVal := fields [r .schema .key .name ]
74- verVal := fields [r .schema .ver .name ]
79+ var verVal string
80+ if ! r .schema .verless {
81+ verVal = fields [r .schema .ver .name ]
82+ }
7583 extVal := int64 (0 )
7684 if r .schema .ext != nil {
7785 if ext , ok := val .Field (r .schema .ext .idx ).Interface ().(time.Time ); ok && ! ext .IsZero () {
@@ -98,34 +106,42 @@ func (r *HashRepository[T]) toExec(entity *T) (val reflect.Value, exec rueidis.L
98106// Save the entity under the redis key of `{prefix}:{id}`.
99107// It also uses the `redis:",ver"` field and lua script to perform optimistic locking and prevent lost update.
100108func (r * HashRepository [T ]) Save (ctx context.Context , entity * T ) (err error ) {
101- val , exec := r .toExec (entity )
109+ verf , exec := r .toExec (entity )
102110 str , err := hashSaveScript .Exec (ctx , r .client , exec .Keys , exec .Args ).ToString ()
103111 if rueidis .IsRedisNil (err ) {
112+ if r .schema .verless {
113+ return nil
114+ }
104115 return ErrVersionMismatch
105- }
106- if err == nil {
116+ } else if err == nil {
107117 ver , _ := strconv .ParseInt (str , 10 , 64 )
108- val . Field ( r . schema . ver . idx ) .SetInt (ver )
118+ verf .SetInt (ver )
109119 }
110120 return err
111121}
112122
113123// SaveMulti batches multiple HashRepository.Save at once
114124func (r * HashRepository [T ]) SaveMulti (ctx context.Context , entities ... * T ) []error {
115125 errs := make ([]error , len (entities ))
116- vals := make ([]reflect.Value , len (entities ))
126+ verf := make ([]reflect.Value , len (entities ))
117127 exec := make ([]rueidis.LuaExec , len (entities ))
118128 for i , entity := range entities {
119- vals [i ], exec [i ] = r .toExec (entity )
129+ verf [i ], exec [i ] = r .toExec (entity )
120130 }
121131 for i , resp := range hashSaveScript .ExecMulti (ctx , r .client , exec ... ) {
122- if str , err := resp .ToString (); err != nil {
123- if errs [i ] = err ; rueidis .IsRedisNil (err ) {
124- errs [i ] = ErrVersionMismatch
132+ str , err := resp .ToString ()
133+ if rueidis .IsRedisNil (err ) {
134+ if r .schema .verless {
135+ continue
125136 }
126- } else {
137+ errs [i ] = ErrVersionMismatch
138+ continue
139+ }
140+ if err == nil {
127141 ver , _ := strconv .ParseInt (str , 10 , 64 )
128- vals [i ].Field (r .schema .ver .idx ).SetInt (ver )
142+ verf [i ].SetInt (ver )
143+ } else {
144+ errs [i ] = err
129145 }
130146 }
131147 return errs
@@ -274,6 +290,15 @@ func (r *HashRepository[T]) fromFields(fields map[string]string) (*T, error) {
274290}
275291
276292var hashSaveScript = rueidis .NewLuaScript (`
293+ if (ARGV[1] == '')
294+ then
295+ local e = (#ARGV % 2 == 1) and table.remove(ARGV) or nil
296+ if redis.call('HSET',KEYS[1],unpack(ARGV))
297+ then
298+ if e then redis.call('PEXPIREAT',KEYS[1],e) end
299+ end
300+ return nil
301+ end
277302local v = redis.call('HGET',KEYS[1],ARGV[1])
278303if (not v or v == ARGV[2])
279304then
0 commit comments