Skip to content

Commit 30f3dde

Browse files
committed
static query
1 parent fc37683 commit 30f3dde

File tree

3 files changed

+109
-64
lines changed

3 files changed

+109
-64
lines changed

README.md

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,9 @@ curl "http://$ADDRESS:$PORT/query" -d "$PARAM_1,$PARAM_2,...,$PARAM_N"
7575
- Request body must not have a CSV header.
7676
- Each request body line is a different query.
7777
- Each param in a line corresponds to a query param (a question mark in the query string).
78+
- Static query (without any query params):
79+
- The request must be a HTTP GET to "http://$ADDRESS:$PORT/query".
80+
- The query executes only once.
7881

7982
## Getting a response
8083

@@ -109,3 +112,30 @@ echo -e "github.com\none.one.one.one\ngoogle-public-dns-a.google.com" | curl "ht
109112
- Has an "headers" field which is an array of headers of the SQL query result.
110113
- Has an "out" field which is an array of arrays of results. Each inner array is a result row.
111114
- Element #1 is the result of query #1, Element #2 is the result of query #2, and so forth.
115+
- Static query (without any query params):
116+
- The response JSON has only one element.
117+
118+
## Static query
119+
120+
```bash
121+
SQLiteQueryServer --db ./test_db/ip_dns.db --query "SELECT * FROM ip_dns" --port 8080
122+
```
123+
124+
```bash
125+
curl "http://localhost:8080/query"
126+
```
127+
128+
```json
129+
[
130+
{
131+
"in": [],
132+
"headers": ["ip", "dns"],
133+
"out": [
134+
["1.1.1.1", "one.one.one.one"],
135+
["8.8.8.8", "google-public-dns-a.google.com"],
136+
["192.30.253.112", "github.com"],
137+
["192.30.253.113", "github.com"]
138+
]
139+
}
140+
]
141+
```

main.go

Lines changed: 35 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111
"os"
1212
"regexp"
1313
"strconv"
14+
"strings"
1415

1516
json "github.com/json-iterator/go"
1617
_ "github.com/mattn/go-sqlite3"
@@ -26,6 +27,7 @@ func main() {
2627

2728
func cmd(cmdArgs []string) error {
2829
log.Printf("SQLiteQueryServer v%s\n", version)
30+
log.Println("https://github.com/assafmo/SQLiteQueryServer")
2931

3032
// Parse cmd args
3133
var flagSet = flag.NewFlagSet("cmd flags", flag.ContinueOnError)
@@ -102,26 +104,38 @@ func initQueryHandler(dbPath string, queryString string, serverPort uint) (func(
102104
http.Error(w, helpMessage, http.StatusNotFound)
103105
return
104106
}
105-
if r.Method != "POST" {
107+
if r.Method != "POST" && r.Method != "GET" {
106108
http.Error(w, helpMessage, http.StatusMethodNotAllowed)
107109
return
108110
}
109111

110112
// Init fullResponse
111113
fullResponse := []queryResult{}
112114

113-
reqCsvReader := csv.NewReader(r.Body)
115+
var reqCsvReader *csv.Reader
116+
if r.Method == "GET" {
117+
// Static query
118+
reqCsvReader = csv.NewReader(strings.NewReader(""))
119+
} else {
120+
// Parameterized query
121+
reqCsvReader = csv.NewReader(r.Body)
122+
}
114123
reqCsvReader.FieldsPerRecord = -1
115124

116125
// Iterate over each query
117126
for {
118127
csvRecord, err := reqCsvReader.Read()
119-
if err == io.EOF || err == http.ErrBodyReadAfterClose {
120-
// EOF || last line is without \n
121-
break
122-
} else if err != nil {
123-
http.Error(w, fmt.Sprintf("\n\nError reading request body: %v\n\n%s", err, helpMessage), http.StatusInternalServerError)
124-
return
128+
if r.Method == "POST" {
129+
// Parameterized query
130+
if err == io.EOF || err == http.ErrBodyReadAfterClose {
131+
// EOF || last line is without \n
132+
break
133+
} else if err != nil {
134+
http.Error(w, fmt.Sprintf("\n\nError reading request body: %v\n\n%s", err, helpMessage), http.StatusInternalServerError)
135+
return
136+
}
137+
} else {
138+
csvRecord = make([]string, 0)
125139
}
126140

127141
// Init queryResponse
@@ -177,6 +191,11 @@ func initQueryHandler(dbPath string, queryString string, serverPort uint) (func(
177191
}
178192

179193
fullResponse = append(fullResponse, queryResponse)
194+
195+
if r.Method == "GET" {
196+
// Static query - execute only once
197+
break
198+
}
180199
}
181200

182201
// Return json
@@ -221,8 +240,11 @@ func buildHelpMessage(helpMessage string, queryString string, queryStmt *sql.Stm
221240
- Request body must not have a CSV header.
222241
- Each request body line is a different query.
223242
- Each param in a line corresponds to a query param (a question mark in the query string).
243+
- Static query (without any query params):
244+
- The request must be a HTTP GET to "http://$ADDRESS:%d/query".
245+
- The query executes only once.
224246
225-
`, serverPort, serverPort, serverPort)
247+
`, serverPort, serverPort, serverPort, serverPort)
226248

227249
helpMessage += fmt.Sprintf(`Response example:
228250
$ echo -e "github.com\none.one.one.one\ngoogle-public-dns-a.google.com" | curl "http://$ADDRESS:%d/query" --data-binary @-
@@ -258,6 +280,10 @@ func buildHelpMessage(helpMessage string, queryString string, queryStmt *sql.Stm
258280
- Has an "headers" fields which is an array of headers of the SQL query result.
259281
- Has an "out" field which is an array of arrays of results. Each inner array is a result row.
260282
- Element #1 is the result of query #1, Element #2 is the result of query #2, and so forth.
283+
- Static query (without any query params):
284+
- The response JSON has only one element.
285+
286+
For more info visit https://github.com/assafmo/SQLiteQueryServer
261287
`, serverPort)
262288

263289
return helpMessage

main_test.go

Lines changed: 44 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -252,60 +252,49 @@ func TestMoreThanOneParam(t *testing.T) {
252252
compare(t, fullResponse, expectedResponse)
253253
}
254254

255-
// func TestZeroParams(t *testing.T) {
256-
// log.SetOutput(&bytes.Buffer{})
257-
258-
// reqString := "\n"
259-
260-
// req := httptest.NewRequest("POST",
261-
// "http://example.org/query",
262-
// strings.NewReader(reqString))
263-
// w := httptest.NewRecorder()
264-
// queryHandler, err := initQueryHandler(testDbPath,
265-
// "SELECT * FROM ip_dns",
266-
// 0)
267-
// if err != nil {
268-
// t.Fatal(err)
269-
// }
270-
// queryHandler(w, req)
271-
272-
// resp := w.Result()
273-
// defer resp.Body.Close()
274-
275-
// if resp.StatusCode != http.StatusOK {
276-
// t.Fatalf(`resp.StatusCode (%d) != http.StatusOK (%d)`, resp.StatusCode, http.StatusOK)
277-
// }
278-
279-
// if resp.Header.Get("Content-Type") != "application/json" {
280-
// t.Fatalf(`resp.Header.Get("Content-Type") (%s) != "application/json"`, resp.Header.Get("Content-Type"))
281-
// }
282-
283-
// var answer []httpAnswer
284-
// decoder := json.NewDecoder(resp.Body)
285-
// err = decoder.Decode(&answer)
286-
// if err != nil {
287-
// t.Fatal(err)
288-
// }
289-
290-
// expectedResponse := []httpAnswer{
291-
// httpAnswer{
292-
// Out: [][]interface{}{
293-
// []interface{}{"1.1.1.1", "one.one.one.one"},
294-
// []interface{}{"8.8.8.8", "google-public-dns-a.google.com"},
295-
// []interface{}{"192.30.253.112", "github.com"},
296-
// []interface{}{"192.30.253.113", "github.com"},
297-
// }},
298-
// httpAnswer{
299-
// Out: [][]interface{}{
300-
// []interface{}{"1.1.1.1", "one.one.one.one"},
301-
// []interface{}{"8.8.8.8", "google-public-dns-a.google.com"},
302-
// []interface{}{"192.30.253.112", "github.com"},
303-
// []interface{}{"192.30.253.113", "github.com"},
304-
// }},
305-
// }
306-
307-
// compare(t, answer, expectedResponse)
308-
// }
255+
func TestZeroParams(t *testing.T) {
256+
log.SetOutput(&bytes.Buffer{})
257+
258+
req := httptest.NewRequest("GET",
259+
"http://example.org/query",
260+
nil)
261+
w := httptest.NewRecorder()
262+
queryHandler, err := initQueryHandler(testDbPath, "SELECT * FROM ip_dns", 0)
263+
if err != nil {
264+
t.Fatal(err)
265+
}
266+
queryHandler(w, req)
267+
268+
resp := w.Result()
269+
defer resp.Body.Close()
270+
271+
if resp.StatusCode != http.StatusOK {
272+
t.Fatalf(`resp.StatusCode (%d) != http.StatusOK (%d)`, resp.StatusCode, http.StatusOK)
273+
}
274+
275+
if resp.Header.Get("Content-Type") != "application/json" {
276+
t.Fatalf(`resp.Header.Get("Content-Type") (%s) != "application/json"`, resp.Header.Get("Content-Type"))
277+
}
278+
279+
var answer []queryResult
280+
decoder := json.NewDecoder(resp.Body)
281+
err = decoder.Decode(&answer)
282+
if err != nil {
283+
t.Fatal(err)
284+
}
285+
286+
expectedResponse := []queryResult{
287+
queryResult{
288+
Out: [][]interface{}{
289+
[]interface{}{"1.1.1.1", "one.one.one.one"},
290+
[]interface{}{"8.8.8.8", "google-public-dns-a.google.com"},
291+
[]interface{}{"192.30.253.112", "github.com"},
292+
[]interface{}{"192.30.253.113", "github.com"},
293+
}},
294+
}
295+
296+
compare(t, answer, expectedResponse)
297+
}
309298

310299
func compare(t *testing.T, answer []queryResult, expectedResponse []queryResult) {
311300
for i, v := range expectedResponse {
@@ -386,7 +375,7 @@ func TestBadPathRequest(t *testing.T) {
386375
func TestBadMethodRequest(t *testing.T) {
387376
log.SetOutput(&bytes.Buffer{})
388377

389-
req := httptest.NewRequest("GET",
378+
req := httptest.NewRequest("PUT",
390379
"http://example.org/query",
391380
nil)
392381
w := httptest.NewRecorder()

0 commit comments

Comments
 (0)