Skip to content

Commit c4a6f99

Browse files
committed
Add MGET, move commands description to a separate file
1 parent e9c6396 commit c4a6f99

File tree

3 files changed

+63
-10
lines changed

3 files changed

+63
-10
lines changed

COMMANDS.md

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# Commands
2+
3+
This is a list of supported Redis commands and how they are implemented.
4+
5+
The statuses are one of these:
6+
7+
- `stable` - it works as expected, can be used in production
8+
- `limited-stable` - only parts of the Redis implementation are available, but they work as expected and can be used in production
9+
- `beta` - it has been tested, but use with caution
10+
- `alpha` - experimental, only for developers
11+
12+
| Command | Status | Comment |
13+
|:-------:|:----------------:|:----------------------------------------------------------------------------------------------------------------------------------------------------|
14+
| `DEL` | `stable` | `DELETE FROM ... WHERE key = ...` |
15+
| `GET` | `stable` | `SELECT value FROM ... WHERE key = ...` |
16+
| `KEYS` | `limited-stable` | although, only `*`-globs are supported with `ILIKE` and `%`, because it is the most common scenario for me (to select keys starting with something) |
17+
| `MGET` | `alpha` | `SELECT value FROM ... WHERE key in (...)`, it might be slow for thousands of keys |
18+
| `PING` | `stable` | `SELECT 1` |
19+
| `QUIT` | `stable` | N/A (provided by `redcon`) |
20+
| `SET` | `stable` | `INSERT` or `UPDATE`, i.e. ["UPSERT" method](https://www.postgresql.org/docs/14/sql-insert.html) |

README.md

+3-8
Original file line numberDiff line numberDiff line change
@@ -47,14 +47,9 @@ So I decided to implement PostgreSQL backend for Redis' interface.
4747

4848
When you first start postgredis, it will create a table with two columns: unique `key` and `value`. They both are in [text](https://www.postgresql.org/docs/14/datatype-character.html) format. Unique `key` helps with concise "upsert" queries. Thanks to [pgx](https://github.com/jackc/pgx) I don't have think about how to maintain a connection, I just start a [pool](https://github.com/jackc/pgx/tree/master/pgxpool). There is also a logging of sql queries, which is good for debugging.
4949

50-
These Redis commands are supported:
51-
52-
- `SET` - `INSERT` or `UPDATE`, i.e. ["UPSERT" method](https://www.postgresql.org/docs/14/sql-insert.html)
53-
- `GET` - `SELECT value FROM ... WHERE key = ...`
54-
- `DEL` - `DELETE FROM ... WHERE key = ...`
55-
- `KEYS` - although, only `*`-globs are supported with `ILIKE` and `%`, because it is the most common scenario for me (to select keys starting with something)
56-
- `PING` - `SELECT 1`
57-
- `QUIT`
50+
## Supported commands
51+
52+
See COMMANDS.md.
5853

5954
## Future plans
6055

main.go

+40-2
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ func (s *Server) Handler(conn redcon.Conn, cmd redcon.Command) {
6868
),
6969
)
7070
if err != nil {
71-
fmt.Println(err)
71+
log.Println(err)
7272
conn.WriteError(err.Error())
7373
return
7474
}
@@ -81,11 +81,49 @@ func (s *Server) Handler(conn redcon.Conn, cmd redcon.Command) {
8181
var val string
8282
err := s.pool.QueryRow(context.Background(), fmt.Sprintf("SELECT value FROM %s WHERE key = '%s'", *table, cmd.Args[1])).Scan(&val)
8383
if err != nil {
84-
fmt.Println(err)
84+
log.Println(err)
8585
conn.WriteNull()
8686
} else {
8787
conn.WriteBulk([]byte(val))
8888
}
89+
case "mget":
90+
if len(cmd.Args) < 2 {
91+
conn.WriteError("ERR wrong number of arguments for '" + string(cmd.Args[0]) + "' command")
92+
return
93+
}
94+
quotedKeys := make([]string, len(cmd.Args[1:]))
95+
for i, arg := range cmd.Args[1:] {
96+
quotedKeys[i] = fmt.Sprintf("'%s'", arg)
97+
}
98+
query := fmt.Sprintf("SELECT key, value FROM %s WHERE key in (%s)", *table, strings.Join(quotedKeys, ","))
99+
log.Println(query)
100+
rows, err := s.pool.Query(context.Background(), query)
101+
if err != nil {
102+
conn.WriteError(err.Error())
103+
return
104+
}
105+
conn.WriteArray(len(cmd.Args[1:]))
106+
keysFromDb := make(map[string]string)
107+
for rows.Next() {
108+
var (
109+
key string
110+
value string
111+
)
112+
err = rows.Scan(&key, &value)
113+
if err != nil {
114+
conn.WriteError(err.Error())
115+
return
116+
}
117+
keysFromDb[key] = value
118+
}
119+
for _, key := range cmd.Args[1:] {
120+
value, ok := keysFromDb[string(key)]
121+
if !ok {
122+
conn.WriteNull()
123+
continue
124+
}
125+
conn.WriteAny(value)
126+
}
89127
case "del":
90128
if len(cmd.Args) != 2 {
91129
conn.WriteError("ERR wrong number of arguments for '" + string(cmd.Args[0]) + "' command")

0 commit comments

Comments
 (0)