@@ -65,11 +65,19 @@ func (r *HashRepository[T]) FetchCache(ctx context.Context, id string, ttl time.
6565 return v , err
6666}
6767
68- func (r * HashRepository [T ]) toExec (entity * T ) (val reflect.Value , exec rueidis.LuaExec ) {
69- val = reflect .ValueOf (entity ).Elem ()
68+ func (r * HashRepository [T ]) toExec (entity * T ) (verf reflect.Value , exec rueidis.LuaExec ) {
69+ val := reflect .ValueOf (entity ).Elem ()
70+ if ! r .schema .verless {
71+ verf = val .Field (r .schema .ver .idx )
72+ } else {
73+ verf = reflect .ValueOf (int64 (0 )) // verless, set verf to a dummy value
74+ }
7075 fields := r .factory .NewConverter (val ).ToHash ()
7176 keyVal := fields [r .schema .key .name ]
72- verVal := fields [r .schema .ver .name ]
77+ var verVal string
78+ if ! r .schema .verless {
79+ verVal = fields [r .schema .ver .name ]
80+ }
7381 extVal := int64 (0 )
7482 if r .schema .ext != nil {
7583 if ext , ok := val .Field (r .schema .ext .idx ).Interface ().(time.Time ); ok && ! ext .IsZero () {
@@ -96,34 +104,42 @@ func (r *HashRepository[T]) toExec(entity *T) (val reflect.Value, exec rueidis.L
96104// Save the entity under the redis key of `{prefix}:{id}`.
97105// It also uses the `redis:",ver"` field and lua script to perform optimistic locking and prevent lost update.
98106func (r * HashRepository [T ]) Save (ctx context.Context , entity * T ) (err error ) {
99- val , exec := r .toExec (entity )
107+ verf , exec := r .toExec (entity )
100108 str , err := hashSaveScript .Exec (ctx , r .client , exec .Keys , exec .Args ).ToString ()
101109 if rueidis .IsRedisNil (err ) {
110+ if r .schema .verless {
111+ return nil
112+ }
102113 return ErrVersionMismatch
103- }
104- if err == nil {
114+ } else if err == nil {
105115 ver , _ := strconv .ParseInt (str , 10 , 64 )
106- val . Field ( r . schema . ver . idx ) .SetInt (ver )
116+ verf .SetInt (ver )
107117 }
108118 return err
109119}
110120
111121// SaveMulti batches multiple HashRepository.Save at once
112122func (r * HashRepository [T ]) SaveMulti (ctx context.Context , entities ... * T ) []error {
113123 errs := make ([]error , len (entities ))
114- vals := make ([]reflect.Value , len (entities ))
124+ verf := make ([]reflect.Value , len (entities ))
115125 exec := make ([]rueidis.LuaExec , len (entities ))
116126 for i , entity := range entities {
117- vals [i ], exec [i ] = r .toExec (entity )
127+ verf [i ], exec [i ] = r .toExec (entity )
118128 }
119129 for i , resp := range hashSaveScript .ExecMulti (ctx , r .client , exec ... ) {
120- if str , err := resp .ToString (); err != nil {
121- if errs [i ] = err ; rueidis .IsRedisNil (err ) {
122- errs [i ] = ErrVersionMismatch
130+ str , err := resp .ToString ()
131+ if rueidis .IsRedisNil (err ) {
132+ if r .schema .verless {
133+ continue
123134 }
124- } else {
135+ errs [i ] = ErrVersionMismatch
136+ continue
137+ }
138+ if err == nil {
125139 ver , _ := strconv .ParseInt (str , 10 , 64 )
126- vals [i ].Field (r .schema .ver .idx ).SetInt (ver )
140+ verf [i ].SetInt (ver )
141+ } else {
142+ errs [i ] = err
127143 }
128144 }
129145 return errs
@@ -200,6 +216,15 @@ func (r *HashRepository[T]) fromFields(fields map[string]string) (*T, error) {
200216}
201217
202218var hashSaveScript = rueidis .NewLuaScript (`
219+ if (ARGV[1] == '')
220+ then
221+ local e = (#ARGV % 2 == 1) and table.remove(ARGV) or nil
222+ if redis.call('HSET',KEYS[1],unpack(ARGV))
223+ then
224+ if e then redis.call('PEXPIREAT',KEYS[1],e) end
225+ end
226+ return nil
227+ end
203228local v = redis.call('HGET',KEYS[1],ARGV[1])
204229if (not v or v == ARGV[2])
205230then
0 commit comments