allow multiple where condition joining by "and"
This commit is contained in:
parent
ff90e37965
commit
3056d81fcc
16
README.md
16
README.md
@ -120,17 +120,20 @@ The above is nearly like REDIS keys command
|
||||
|
||||
Each record is exactly a hash, you could use raw REDIS commands ``hget, hmget or hgetall`` to retrieve the same content
|
||||
|
||||
#### Where in Select Statement
|
||||
This module supports =, >, <, >=, <=, <>, != and like conditions. Only single condition is allowed.
|
||||
#### Where Clause in Select Statement
|
||||
Your could specify =, >, <, >=, <=, <>, != or like conditions in where clause. Now the module only support "and" to join multiple conditions.
|
||||
```bash
|
||||
127.0.0.1:6379> dbx.select tel from phonebook where name like Son
|
||||
1) 1) tel
|
||||
2) "1-888-3333-1412"
|
||||
2) 1) tel
|
||||
2) "1-456-1246-3421"
|
||||
127.0.0.1:6379> dbx.select tel from phonebook where name like Son and pos = 4
|
||||
1) 1) tel
|
||||
2) "1-888-3333-1412"
|
||||
```
|
||||
|
||||
#### Order in Select Statement
|
||||
#### Order Clause in Select Statement
|
||||
Ordering can be ascending or descending. All sortings are alpha-sort.
|
||||
```bash
|
||||
127.0.0.1:6379> dbx.select * from phonebook order by pos asc
|
||||
@ -140,7 +143,7 @@ Ordering can be ascending or descending. All sortings are alpha-sort.
|
||||
```
|
||||
|
||||
#### Delete Statement
|
||||
You may also use Insert and Delete statement to operate the hash
|
||||
You may also use Insert and Delete statement to operate the hash. If you does not provide the where clause, it will delete all the records of the specified key prefix. (i.e. phonebook)
|
||||
```bash
|
||||
127.0.0.1:6379> dbx.delete from phonebook where gender = F
|
||||
(integer) 2
|
||||
@ -149,6 +152,7 @@ You may also use Insert and Delete statement to operate the hash
|
||||
```
|
||||
|
||||
#### Insert Statement
|
||||
The module provide simple Insert statement which same as the function of the REDIS command hmset. It will append a random string to your provided key (i.e. phonebook). If operation is successful, it will return the key name.
|
||||
```bash
|
||||
127.0.0.1:6379> dbx.insert into phonebook (name,tel,birth,pos,gender) values ('Peter Nelson' ,1-456-1246-3421, 2019-10-01, 3, M)
|
||||
"phonebook:1588298418-551514504"
|
||||
@ -159,7 +163,7 @@ You may also use Insert and Delete statement to operate the hash
|
||||
127.0.0.1:6379> dbx.insert into phonebook (name,tel,birth,pos,gender) values ('Mattias Swensson' ,1-888-3333-1412, 2017-06-30, 4, M)
|
||||
"phonebook:1588299202-1052597574"
|
||||
```
|
||||
Please be noted that Redis requires at least one space after the single and double quoted arguments.
|
||||
Note that Redis requires at least one space after the single and double quoted arguments.
|
||||
Or you may quote the whole SQL statement as below:
|
||||
```bash
|
||||
127.0.0.1:6379> dbx.insert "into phonebook (name,tel,birth,pos,gender) values ('Peter Nelson','1-456-1246-3421','2019-10-01',3, 'M')"
|
||||
@ -204,4 +208,4 @@ REDIS v4.0
|
||||
MIT
|
||||
|
||||
## Status
|
||||
Now the Select statement only supports single where condition and single order sequence. I will add more useful features in the future. Simple Insert, Update and Delete statement will be included finally. This project is in an early stage of development. Any contribution is welcome :D
|
||||
This project is in an early stage of development. Any contribution is welcome :D
|
||||
|
137
src/dbx.c
137
src/dbx.c
@ -41,50 +41,52 @@ int whereRecord(RedisModuleCtx *ctx, RedisModuleString *key, Vector *vWhere) {
|
||||
int match = 1;
|
||||
|
||||
// If where statement is defined, get the specified hash content and do comparison
|
||||
if (Vector_Size(vWhere) == 3) {
|
||||
Vector_Get(vWhere, 0, &field);
|
||||
Vector_Get(vWhere, 1, &condition);
|
||||
Vector_Get(vWhere, 2, &w);
|
||||
size_t n = Vector_Size(vWhere);
|
||||
if (n == 0) return 1;
|
||||
if (n % 3 != 0) return 0;
|
||||
for (size_t i = 0; i < n; i += 3) {
|
||||
Vector_Get(vWhere, i, &field);
|
||||
Vector_Get(vWhere, i+1, &condition);
|
||||
Vector_Get(vWhere, i+2, &w);
|
||||
if (condition == 7)
|
||||
toLower(w);
|
||||
if (strlen(w) == 0)
|
||||
match = 0;
|
||||
else {
|
||||
RedisModuleCallReply *tags = RedisModule_Call(ctx, "HGET", "sc", key, field);
|
||||
if (RedisModule_CallReplyLength(tags) > 0) {
|
||||
RedisModuleString *rms = RedisModule_CreateStringFromCallReply(tags);
|
||||
size_t l;
|
||||
const char *s = RedisModule_StringPtrLen(rms, &l);
|
||||
switch(condition) {
|
||||
case 0:
|
||||
match = strcmp(s, w) >= 0? 1: 0;
|
||||
break;
|
||||
case 1:
|
||||
match = strcmp(s, w) <= 0? 1: 0;
|
||||
break;
|
||||
case 2:
|
||||
case 3:
|
||||
match = strcmp(s, w) != 0? 1: 0;
|
||||
break;
|
||||
case 4:
|
||||
match = strcmp(s, w) > 0? 1: 0;
|
||||
break;
|
||||
case 5:
|
||||
match = strcmp(s, w) < 0? 1: 0;
|
||||
break;
|
||||
case 6:
|
||||
match = strcmp(s, w) == 0? 1: 0;
|
||||
break;
|
||||
case 7:
|
||||
match = strstr(toLower((char*)s), w)? 1: 0;
|
||||
break;
|
||||
}
|
||||
RedisModule_FreeString(ctx, rms);
|
||||
RedisModule_FreeCallReply(tags);
|
||||
}
|
||||
else
|
||||
match = 0;
|
||||
if (strlen(w) == 0) return 0;
|
||||
|
||||
RedisModuleCallReply *tags = RedisModule_Call(ctx, "HGET", "sc", key, field);
|
||||
if (RedisModule_CallReplyLength(tags) == 0) {
|
||||
RedisModule_FreeCallReply(tags);
|
||||
return 0;
|
||||
}
|
||||
RedisModuleString *rms = RedisModule_CreateStringFromCallReply(tags);
|
||||
size_t l;
|
||||
const char *s = RedisModule_StringPtrLen(rms, &l);
|
||||
switch(condition) {
|
||||
case 0:
|
||||
match = strcmp(s, w) >= 0? 1: 0;
|
||||
break;
|
||||
case 1:
|
||||
match = strcmp(s, w) <= 0? 1: 0;
|
||||
break;
|
||||
case 2:
|
||||
case 3:
|
||||
match = strcmp(s, w) != 0? 1: 0;
|
||||
break;
|
||||
case 4:
|
||||
match = strcmp(s, w) > 0? 1: 0;
|
||||
break;
|
||||
case 5:
|
||||
match = strcmp(s, w) < 0? 1: 0;
|
||||
break;
|
||||
case 6:
|
||||
match = strcmp(s, w) == 0? 1: 0;
|
||||
break;
|
||||
case 7:
|
||||
match = strstr(toLower((char*)s), w)? 1: 0;
|
||||
break;
|
||||
}
|
||||
RedisModule_FreeString(ctx, rms);
|
||||
RedisModule_FreeCallReply(tags);
|
||||
if (match == 0) return 0;
|
||||
}
|
||||
return match;
|
||||
}
|
||||
@ -154,20 +156,24 @@ Vector* splitStringByChar(char *s, char* d) {
|
||||
|
||||
Vector* splitWhereString(char *s) {
|
||||
Vector *v = NewVector(void *, 16);
|
||||
static char chk[8][3] = {">=", "<=", "!=", "<>", ">", "<", "=", "~"};
|
||||
char *p = s;
|
||||
while(*p++) {
|
||||
for(int i=0; i<8; i++) {
|
||||
char *c = chk[i];
|
||||
if (strncmp(c, p, strlen(c)) == 0) {
|
||||
*p = 0;
|
||||
p += strlen(c);
|
||||
Vector_Push(v, s);
|
||||
Vector_Push(v, i);
|
||||
Vector_Push(v, p);
|
||||
break;
|
||||
char *token = strtok(s, "&&");
|
||||
while (token != NULL) {
|
||||
static char chk[8][3] = {">=", "<=", "!=", "<>", ">", "<", "=", "~"};
|
||||
char *p = token;
|
||||
while(*p++) {
|
||||
for(int i=0; i<8; i++) {
|
||||
char *c = chk[i];
|
||||
if (strncmp(c, p, strlen(c)) == 0) {
|
||||
*p = 0;
|
||||
p += strlen(c);
|
||||
Vector_Push(v, token);
|
||||
Vector_Push(v, i);
|
||||
Vector_Push(v, p);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
token = strtok(NULL, "&&");
|
||||
}
|
||||
return v;
|
||||
}
|
||||
@ -283,7 +289,7 @@ int SelectCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
|
||||
}
|
||||
break;
|
||||
case -1:
|
||||
// parse from statement
|
||||
// parse from clause
|
||||
fromKeys = RMUtil_CreateFormattedString(ctx, token);
|
||||
step = 2;
|
||||
break;
|
||||
@ -299,9 +305,11 @@ int SelectCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
|
||||
break;
|
||||
case -3:
|
||||
case 4:
|
||||
// parse where statement
|
||||
// parse where clause
|
||||
if (strcmp("order", token) == 0)
|
||||
step = -5;
|
||||
else if (strcmp("and", token) == 0)
|
||||
strcat(stmWhere, "&&");
|
||||
else {
|
||||
if (strlen(stmWhere) + strlen(token) > 512) {
|
||||
RedisModule_ReplyWithError(ctx, "where arguments are too long");
|
||||
@ -323,7 +331,7 @@ int SelectCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
|
||||
break;
|
||||
case -6:
|
||||
case 7:
|
||||
// parse order statement
|
||||
// parse order clause
|
||||
if (strlen(stmOrder) + strlen(token) > 512) {
|
||||
RedisModule_ReplyWithError(ctx, "order arguments are too long");
|
||||
return REDISMODULE_ERR;
|
||||
@ -471,7 +479,7 @@ int InsertCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
|
||||
}
|
||||
break;
|
||||
case -1:
|
||||
// parse into key, assume time+rand always is new key
|
||||
// parse into clause, assume time+rand always is new key
|
||||
intoKey = RMUtil_CreateFormattedString(ctx, "%s:%u-%i", token, (unsigned)time(NULL), rand());
|
||||
step = -2;
|
||||
break;
|
||||
@ -615,7 +623,7 @@ int DeleteCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
|
||||
}
|
||||
break;
|
||||
case -1:
|
||||
// parse from statement
|
||||
// parse from clause
|
||||
fromKeys = RMUtil_CreateFormattedString(ctx, token);
|
||||
step = 2;
|
||||
break;
|
||||
@ -629,14 +637,19 @@ int DeleteCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
|
||||
break;
|
||||
case -3:
|
||||
case 4:
|
||||
// parse where clause
|
||||
if (strlen(stmWhere) + strlen(token) > 512) {
|
||||
RedisModule_ReplyWithError(ctx, "where arguments are too long");
|
||||
return REDISMODULE_ERR;
|
||||
}
|
||||
char *p = token;
|
||||
while (*p++) *p = *p == 7? 32: *p;
|
||||
strcat(stmWhere, token);
|
||||
step = 4;
|
||||
if (strcmp("and", token) == 0)
|
||||
strcat(stmWhere, "&&");
|
||||
else {
|
||||
char *p = token;
|
||||
while (*p++) *p = *p == 7? 32: *p;
|
||||
strcat(stmWhere, token);
|
||||
step = 4;
|
||||
}
|
||||
break;
|
||||
}
|
||||
token = strtok(NULL, " ");
|
||||
|
Loading…
x
Reference in New Issue
Block a user