diff --git a/sources/Redis.Client.pas b/sources/Redis.Client.pas index 8a8bcdc..a0fa4b6 100644 --- a/sources/Redis.Client.pas +++ b/sources/Redis.Client.pas @@ -2,7 +2,7 @@ // // Delphi REDIS Client // -// Copyright (c) 2015-2023 Daniele Teti +// Copyright (c) 2015-2024 Daniele Teti // // https://github.com/danieleteti/delphiredisclient // @@ -218,6 +218,7 @@ TRedisClient = class(TRedisClientBase, IRedisClient) function MOVE(const aKey: string; const aDB: Byte): boolean; function PERSIST(const aKey: string): boolean; function RANDOMKEY: TRedisString; + procedure SCAN(aPattern: string; aCallback: TProc>); // non system function InTransaction: boolean; // transations @@ -265,6 +266,34 @@ function TRedisClient.SADD(const aKey, aValue: string): Integer; Result := SADD(BytesOfUnicode(aKey), BytesOfUnicode(aValue)); end; +procedure TRedisClient.SCAN(aPattern: string; aCallback: TProc>); +var + lCmd: IRedisCommand; + aCursor: integer; + AResp: TRedisRESPArray; + AKey: string; + Values: TArray; +begin + aCursor := 0; +{$HINTS OFF} // H2443 - about inline function + repeat + lCmd := NewRedisCommand('SCAN'); + lCmd.Add(aCursor); + lCmd.Add('MATCH'); + lCmd.Add(Apattern); + AResp := ExecuteAndGetRESPArray(lCmd); + try + ACursor := AResp.I[0]; + SetLength(Values, 0); + for AKey in AResp[1].ArrayValue do + Values := Values + [AKey]; + finally + AResp.Free; + end; + aCallback(Values); + until aCursor = 0; +end; + function TRedisClient.SCARD(const aKey: string): Integer; begin FNextCMD := GetCmdList('SCARD').Add(aKey); diff --git a/sources/Redis.Command.pas b/sources/Redis.Command.pas index 60ffc34..6ea8185 100644 --- a/sources/Redis.Command.pas +++ b/sources/Redis.Command.pas @@ -2,7 +2,7 @@ // // Delphi REDIS Client // -// Copyright (c) 2015-2023 Daniele Teti +// Copyright (c) 2015-2024 Daniele Teti // // https://github.com/danieleteti/delphiredisclient // diff --git a/sources/Redis.Commons.pas b/sources/Redis.Commons.pas index 03bcd68..67ac458 100644 --- a/sources/Redis.Commons.pas +++ b/sources/Redis.Commons.pas @@ -2,7 +2,7 @@ // // Delphi REDIS Client // -// Copyright (c) 2015-2023 Daniele Teti +// Copyright (c) 2015-2024 Daniele Teti // // https://github.com/danieleteti/delphiredisclient // @@ -38,6 +38,8 @@ interface REDIS_NETLIB_INDY = 'indy'; type + TRedisKeyList = TArray; + ERedisException = class(Exception) end; @@ -230,6 +232,7 @@ TRedisClientBase = class abstract(TInterfacedObject) procedure AUTH(const aPassword: string); overload; procedure AUTH(const aUsername, aPassword: string); overload; function MOVE(const aKey: string; const aDB: Byte): boolean; + procedure SCAN(aPattern: string; aCallback: TProc>); // raw execute function ExecuteAndGetRESPArray(const RedisCommand: IRedisCommand): TRedisRESPArray; diff --git a/sources/Redis.NetLib.Factory.pas b/sources/Redis.NetLib.Factory.pas index b30e750..68a89d6 100644 --- a/sources/Redis.NetLib.Factory.pas +++ b/sources/Redis.NetLib.Factory.pas @@ -2,7 +2,7 @@ // // Delphi REDIS Client // -// Copyright (c) 2015-2023 Daniele Teti +// Copyright (c) 2015-2024 Daniele Teti // // https://github.com/danieleteti/delphiredisclient // diff --git a/sources/Redis.NetLib.INDY.pas b/sources/Redis.NetLib.INDY.pas index 51523f4..38aea3a 100644 --- a/sources/Redis.NetLib.INDY.pas +++ b/sources/Redis.NetLib.INDY.pas @@ -2,7 +2,7 @@ // // Delphi REDIS Client // -// Copyright (c) 2015-2023 Daniele Teti +// Copyright (c) 2015-2024 Daniele Teti // // https://github.com/danieleteti/delphiredisclient // diff --git a/sources/Redis.Values.pas b/sources/Redis.Values.pas index f60f110..9c6bb19 100644 --- a/sources/Redis.Values.pas +++ b/sources/Redis.Values.pas @@ -2,7 +2,7 @@ // // Delphi REDIS Client // -// Copyright (c) 2015-2023 Daniele Teti +// Copyright (c) 2015-2024 Daniele Teti // // https://github.com/danieleteti/delphiredisclient // diff --git a/sources/RedisMQ.pas b/sources/RedisMQ.pas index b056e6e..e09d4db 100644 --- a/sources/RedisMQ.pas +++ b/sources/RedisMQ.pas @@ -2,7 +2,7 @@ // // Delphi REDIS Client // -// Copyright (c) 2015-2023 Daniele Teti +// Copyright (c) 2015-2024 Daniele Teti // // https://github.com/danieleteti/delphiredisclient // diff --git a/tests/RedisClientTests.dproj b/tests/RedisClientTests.dproj index 608164a..0f9ca2e 100644 --- a/tests/RedisClientTests.dproj +++ b/tests/RedisClientTests.dproj @@ -1,7 +1,7 @@  {7843B265-EF0B-481C-9CF2-1FD021717D89} - 19.5 + 20.1 None True Debug @@ -303,6 +303,16 @@ 1 + + + res\drawable-anydpi-v21 + 1 + + + res\drawable-anydpi-v21 + 1 + + res\values @@ -323,6 +333,66 @@ 1 + + + res\values-v31 + 1 + + + res\values-v31 + 1 + + + + + res\drawable-anydpi-v26 + 1 + + + res\drawable-anydpi-v26 + 1 + + + + + res\drawable + 1 + + + res\drawable + 1 + + + + + res\drawable + 1 + + + res\drawable + 1 + + + + + res\drawable + 1 + + + res\drawable + 1 + + + + + res\drawable-anydpi-v33 + 1 + + + res\drawable-anydpi-v33 + 1 + + res\values @@ -333,6 +403,16 @@ 1 + + + res\values-night-v21 + 1 + + + res\values-night-v21 + 1 + + res\drawable @@ -503,6 +583,56 @@ 1 + + + res\drawable-anydpi-v24 + 1 + + + res\drawable-anydpi-v24 + 1 + + + + + res\drawable + 1 + + + res\drawable + 1 + + + + + res\drawable-night-anydpi-v21 + 1 + + + res\drawable-night-anydpi-v21 + 1 + + + + + res\drawable-anydpi-v31 + 1 + + + res\drawable-anydpi-v31 + 1 + + + + + res\drawable-night-anydpi-v31 + 1 + + + res\drawable-night-anydpi-v31 + 1 + + 1 diff --git a/tests/TestRedisClientU.pas b/tests/TestRedisClientU.pas index 0cf7cdc..2131482 100644 --- a/tests/TestRedisClientU.pas +++ b/tests/TestRedisClientU.pas @@ -2,7 +2,7 @@ // // Delphi REDIS Client // -// Copyright (c) 2015-2021 Daniele Teti +// Copyright (c) 2015-2024 Daniele Teti // // https://github.com/danieleteti/delphiredisclient // @@ -122,6 +122,8 @@ TestRedisClient = class(TTestCase) procedure TestZREVRANGE; procedure TestZRANGE; + procedure TestSCAN; + // test Redis 3.2+ commands procedure TestGEODIST; procedure TestGEOPOS; @@ -1123,6 +1125,27 @@ procedure TestRedisClient.TestRPUSH_RPOP; CheckEquals(False, FRedis.RPOP('mylist', Value)); end; +procedure TestRedisClient.TestSCAN; +begin + FRedis.&SET('A1','v1'); + FRedis.&SET('A2','v1'); + FRedis.&SET('A3','v1'); + CheckTrue(FRedis.EXISTS('A1')); + CheckTrue(FRedis.EXISTS('A2')); + CheckTrue(FRedis.EXISTS('A3')); + FRedis.SCAN('A*', + procedure(Topics: TArray) + begin + if Length(Topics) > 0 then + begin + FRedis.DEL(Topics); + end; + end); + CheckFalse(FRedis.EXISTS('A1')); + CheckFalse(FRedis.EXISTS('A2')); + CheckFalse(FRedis.EXISTS('A3')); +end; + procedure TestRedisClient.TestSDIFF; var lRes: TRedisArray; diff --git a/tests/TestRedisMQ.pas b/tests/TestRedisMQ.pas index 80e501b..7666569 100644 --- a/tests/TestRedisMQ.pas +++ b/tests/TestRedisMQ.pas @@ -2,7 +2,7 @@ // // Delphi REDIS Client // -// Copyright (c) 2015-2021 Daniele Teti +// Copyright (c) 2015-2024 Daniele Teti // // https://github.com/danieleteti/delphiredisclient // diff --git a/tests/TestRedisValuesU.pas b/tests/TestRedisValuesU.pas index 8319075..7b21e64 100644 --- a/tests/TestRedisValuesU.pas +++ b/tests/TestRedisValuesU.pas @@ -2,7 +2,7 @@ // // Delphi REDIS Client // -// Copyright (c) 2015-2021 Daniele Teti +// Copyright (c) 2015-2024 Daniele Teti // // https://github.com/danieleteti/delphiredisclient //