diff --git a/src/main/java/org/redis/RedisMap.java b/src/main/java/org/redis/RedisMap.java new file mode 100644 index 0000000..9ddecd7 --- /dev/null +++ b/src/main/java/org/redis/RedisMap.java @@ -0,0 +1,163 @@ +package org.redis; + +import redis.clients.jedis.Jedis; +import redis.clients.jedis.JedisPool; + +import java.util.*; + +public class RedisMap implements Map, AutoCloseable { + + private final JedisPool pool; + private final String redisKey; + + public RedisMap(JedisPool pool, String redisKey) { + Objects.requireNonNull(pool, "JedisPool не должен быть null"); + Objects.requireNonNull(redisKey, "redisKey не должен быть null"); + this.pool = pool; + this.redisKey = redisKey; + } + + private void requireNonNullKey(Object key) { + if (key == null) { + throw new NullPointerException("null ключи не поддерживаются"); + } + } + + private void requireNonNullValue(Object value) { + if (value == null) { + throw new NullPointerException("null значения не поддерживаются"); + } + } + + @Override + public void close() { + pool.close(); + } + + @Override + public int size() { + try (Jedis jedis = pool.getResource()) { + Long l = jedis.hlen(redisKey); + return l.intValue(); + } + } + + @Override + public boolean isEmpty() { + return size() == 0; + } + + @Override + public boolean containsKey(Object key) { + requireNonNullKey(key); + try (Jedis jedis = pool.getResource()) { + return jedis.hexists(redisKey, key.toString()); + } + } + + @Override + public boolean containsValue(Object value) { + requireNonNullValue(value); + try (Jedis jedis = pool.getResource()) { + List values = jedis.hvals(redisKey); + return values.contains(value.toString()); + } + } + + @Override + public String get(Object key) { + requireNonNullKey(key); + try (Jedis jedis = pool.getResource()) { + return jedis.hget(redisKey, key.toString()); + } + } + + @Override + public String put(String key, String value) { + requireNonNullKey(key); + requireNonNullValue(value); + try (Jedis jedis = pool.getResource()) { + String previous = jedis.hget(redisKey, key.toString()); + jedis.hset(redisKey, key, value); + return previous; + } + } + + @Override + public String remove(Object key) { + requireNonNullKey(key); + try (Jedis jedis = pool.getResource()) { + String previous = jedis.hget(redisKey, key.toString()); + jedis.hdel(redisKey, key.toString()); + return previous; + } + } + + @Override + public void putAll(Map m) { + Objects.requireNonNull(m, "map не должна быть null"); + if (m.isEmpty()) return; + Map toSet = new HashMap<>(); + for (Entry entry : m.entrySet()) { + if (entry.getKey() == null) throw new NullPointerException("null ключи не поддерживаются"); + if (entry.getValue() == null) throw new NullPointerException("null значения не поддерживаются"); + toSet.put(entry.getKey(), entry.getValue()); + } + try (Jedis jedis = pool.getResource()) { + jedis.hmset(redisKey, toSet); + } + + } + + @Override + public void clear() { + try (Jedis jedis = pool.getResource()) { + jedis.del(redisKey); + } + } + + @Override + public Set keySet() { + try (Jedis jedis = pool.getResource()) { + return new HashSet<>(jedis.hkeys(redisKey)); + } + } + + @Override + public Collection values() { + try (Jedis jedis = pool.getResource()) { + return new ArrayList<>(jedis.hvals(redisKey)); + } + } + + @Override + public Set> entrySet() { + try (Jedis jedis = pool.getResource()) { + Map all = jedis.hgetAll(redisKey); + Set> entries = new HashSet<>(); + for (Map.Entry entry : all.entrySet()) { + entries.add(new AbstractMap.SimpleEntry<>(entry.getKey(), entry.getValue())); + } + return entries; + } + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof Map)) return false; + Map other = (Map) o; + try (Jedis jedis = pool.getResource()) { + Map all = jedis.hgetAll(redisKey); + return all.equals(other); + } + } + + @Override + public int hashCode() { + try (Jedis j = pool.getResource()) { + Map all = j.hgetAll(redisKey); + return all.hashCode(); + } + } +} diff --git a/src/test/java/org/redis/RedisMapTest.java b/src/test/java/org/redis/RedisMapTest.java new file mode 100644 index 0000000..812ee87 --- /dev/null +++ b/src/test/java/org/redis/RedisMapTest.java @@ -0,0 +1,111 @@ +package org.redis; + +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import redis.clients.jedis.JedisPool; + +import java.util.*; + +import static org.junit.jupiter.api.Assertions.*; + +class RedisMapTest { + private JedisPool pool; + private RedisMap map; + private final String KEY = "test-map"; + + @BeforeEach + void setup() { + pool = new JedisPool("localhost", 6379); + map = new RedisMap(pool, KEY); + map.clear(); + } + + @AfterEach + void teardown() { + map.clear(); + map.close(); + } + + @Test + void testPutGetSizeIsEmpty() { + assertTrue(map.isEmpty()); + assertEquals(0, map.size()); + + assertNull(map.put("a", "1")); + assertEquals("1", map.get("a")); + assertFalse(map.isEmpty()); + assertEquals(1, map.size()); + + assertEquals("1", map.put("a", "2")); + assertEquals("2", map.get("a")); + assertEquals(1, map.size()); + } + + @Test + void testContainsKeyAndValue() { + map.put("k1", "v1"); + map.put("k2", "v2"); + assertTrue(map.containsKey("k1")); + assertTrue(map.containsValue("v2")); + assertFalse(map.containsKey("no")); + } + + @Test + void testRemove() { + map.put("x", "y"); + assertEquals("y", map.remove("x")); + assertNull(map.get("x")); + assertFalse(map.containsKey("x")); + assertFalse(map.containsValue("y")); + } + + @Test + void testPutAllAndClear() { + Map src = new HashMap<>(); + src.put("a", "1"); + src.put("b", "2"); + map.putAll(src); + assertEquals(2, map.size()); + map.clear(); + assertTrue(map.isEmpty()); + } + + @Test + void testKeySetValuesEntrySet() { + map.put("k1", "v1"); + map.put("k2", "v2"); + + Set keys = map.keySet(); + assertEquals(new HashSet<>(Arrays.asList("k1", "k2")), keys); + + Collection vals = map.values(); + assertTrue(vals.containsAll(Arrays.asList("v1", "v2"))); + + Set> entries = map.entrySet(); + assertEquals(2, entries.size()); + } + + @Test + void testEqualsHashCode() { + map.put("a", "1"); + map.put("b", "2"); + + Map other = new HashMap<>(); + other.put("a", "1"); + other.put("b", "2"); + + assertEquals(other, map); + assertEquals(other.hashCode(), map.hashCode()); + } + + @Test + void testNullKeyOrValueThrows() { + assertThrows(NullPointerException.class, () -> map.put(null, "v")); + assertThrows(NullPointerException.class, () -> map.put("k", null)); + Map m = new HashMap<>(); + m.put("k1", null); + assertThrows(NullPointerException.class, () -> map.putAll(m)); + } + +}