From 7a4e03a6e26656eb0f0f3e1ef276275f7c780f18 Mon Sep 17 00:00:00 2001 From: avichalp Date: Tue, 27 Jun 2023 21:49:20 -0700 Subject: [PATCH 1/4] Change empty /query status to 200 Signed-off-by: avichalp --- internal/router/controllers/controller.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/internal/router/controllers/controller.go b/internal/router/controllers/controller.go index 7994da9b..34fb0e80 100644 --- a/internal/router/controllers/controller.go +++ b/internal/router/controllers/controller.go @@ -282,11 +282,11 @@ func (c *Controller) runReadRequest( _ = json.NewEncoder(rw).Encode(errors.ServiceError{Message: err.Error()}) return nil, false } - if len(res.Rows) == 0 { + /* if len(res.Rows) == 0 { rw.WriteHeader(http.StatusNotFound) _ = json.NewEncoder(rw).Encode(errors.ServiceError{Message: "Row not found"}) return nil, false - } + } */ return res, true } From 13a292fc718da53be5b478c1610c5fa860ebff69 Mon Sep 17 00:00:00 2001 From: avichalp Date: Thu, 29 Jun 2023 13:52:08 -0700 Subject: [PATCH 2/4] Add unit test Signed-off-by: avichalp --- internal/router/controllers/controller.go | 6 +-- .../router/controllers/controller_test.go | 40 +++++++++++++++++++ 2 files changed, 41 insertions(+), 5 deletions(-) diff --git a/internal/router/controllers/controller.go b/internal/router/controllers/controller.go index 34fb0e80..073d256a 100644 --- a/internal/router/controllers/controller.go +++ b/internal/router/controllers/controller.go @@ -282,11 +282,7 @@ func (c *Controller) runReadRequest( _ = json.NewEncoder(rw).Encode(errors.ServiceError{Message: err.Error()}) return nil, false } - /* if len(res.Rows) == 0 { - rw.WriteHeader(http.StatusNotFound) - _ = json.NewEncoder(rw).Encode(errors.ServiceError{Message: "Row not found"}) - return nil, false - } */ + return res, true } diff --git a/internal/router/controllers/controller_test.go b/internal/router/controllers/controller_test.go index 9c917ab6..1a2cce68 100644 --- a/internal/router/controllers/controller_test.go +++ b/internal/router/controllers/controller_test.go @@ -90,6 +90,46 @@ func TestQuery(t *testing.T) { } } +func TestQueryEmptyTable(t *testing.T) { + r := mocks.NewGateway(t) + r.EXPECT().RunReadQuery(mock.Anything, mock.AnythingOfType("string")).Return( + &gateway.TableData{ + Columns: []gateway.Column{ + {Name: "id"}, + {Name: "name"}, + }, + Rows: [][]*gateway.ColumnValue{}, + }, + nil, + ) + + ctrl := NewController(r) + + router := mux.NewRouter() + router.HandleFunc("/query", ctrl.GetTableQuery) + + ctx := context.WithValue(context.Background(), middlewares.ContextIPAddress, strconv.Itoa(1)) + // Table format + req, err := http.NewRequestWithContext(ctx, "GET", "/query?statement=select%20*%20from%20foo%3B&format=table", nil) + require.NoError(t, err) + rr := httptest.NewRecorder() + router.ServeHTTP(rr, req) + require.Equal(t, http.StatusOK, rr.Code) + exp := `{"columns":[{"name":"id"},{"name":"name"}],"rows":[]}` // nolint + require.JSONEq(t, exp, rr.Body.String()) + + // Unwrapped object format + req, err = http.NewRequest("GET", "/query?statement=select%20*%20from%20foo%3B&format=objects&unwrap=true", nil) + require.NoError(t, err) + rr = httptest.NewRecorder() + router.ServeHTTP(rr, req) + require.Equal(t, http.StatusOK, rr.Code) + exp = "" + wantString := parseJSONLString(exp) + gotString := parseJSONLString(rr.Body.String()) + require.Equal(t, wantString, gotString) +} + func TestQueryExtracted(t *testing.T) { r := mocks.NewGateway(t) r.EXPECT().RunReadQuery(mock.Anything, mock.AnythingOfType("string")).Return( From f272edc9b2325c260a09e67e984c31fbfec07035 Mon Sep 17 00:00:00 2001 From: avichalp Date: Sun, 2 Jul 2023 23:27:53 -0700 Subject: [PATCH 3/4] Add readme for the tableland client Signed-off-by: avichalp --- pkg/client/v1/README.md | 85 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 85 insertions(+) create mode 100644 pkg/client/v1/README.md diff --git a/pkg/client/v1/README.md b/pkg/client/v1/README.md new file mode 100644 index 00000000..f7a98fd2 --- /dev/null +++ b/pkg/client/v1/README.md @@ -0,0 +1,85 @@ +## Tableland Client + +Tableland Client is a convenient wrapper around validator's HTTP APIs. + +### APIs +- [Create](https://github.com/tablelandnetwork/go-tableland/blob/main/pkg/client/v1/writequery.go#L39) +- [Write](https://github.com/tablelandnetwork/go-tableland/blob/main/pkg/client/v1/writequery.go#L73) +- [Version](https://github.com/tablelandnetwork/go-tableland/blob/main/pkg/client/v1/version.go#L15) +- [GetTable](https://github.com/tablelandnetwork/go-tableland/blob/main/pkg/client/v1/table.go#L19) +- [Receipt](https://github.com/tablelandnetwork/go-tableland/blob/main/pkg/client/v1/receipt.go#L29) +- [Read](https://github.com/tablelandnetwork/go-tableland/blob/main/pkg/client/v1/readquery.go#L64) +- [Validate](https://github.com/tablelandnetwork/go-tableland/blob/main/pkg/client/v1/queryhelpers.go#L19) +- [Hash](https://github.com/tablelandnetwork/go-tableland/blob/main/pkg/client/v1/queryhelpers.go#L10) +- [CheckHealth](https://github.com/tablelandnetwork/go-tableland/blob/main/pkg/client/v1/health.go#L10) + + +### Usage +Following are few example usage of these APIs. + +First, we instantiate the client: + +```go + import ( + + // ... + // ... + + clientV1 "github.com/textileio/go-tableland/pkg/client/v1" + "github.com/textileio/go-tableland/pkg/wallet" + ) + + // create the wallet from the given private key + wallet, _ := wallet.NewWallet("PRIVATE_KEY") + ctx := context.Background() + + // create the new client + client, _ := clientV1.NewClient(ctx, wallet, clientV1.[]NewClientOption{}...) +``` + +Checkout the available options [here](https://github.com/tablelandnetwork/go-tableland/blob/main/pkg/client/v1/client.go#L59). + + +The client offers the following APIs + +##### Create +Create a new table with the schema and [options](https://github.com/tablelandnetwork/go-tableland/blob/main/pkg/client/v1/writequery.go#L20). +Schema should be a valid SQL DDL as a string. + +```go + client.Create(ctx, "(id int, name text)", clientV1.WithPrefix("foo")) +``` + +##### Write +Write will execute an mutation query, returning the txn hash. Additional [options](https://github.com/tablelandnetwork/go-tableland/blob/main/pkg/client/v1/writequery.go#L99) can be passed in. + +```go + client.Write( + ctx, + "update users set name = alice where id = 1", + clientV1.WithSuggestedPriceMultiplier(1.5)) +``` + + +##### Receipt +Receipt will get the transaction receipt give the transaction hash. Additional configuration is possible with [options](https://github.com/tablelandnetwork/go-tableland/blob/main/pkg/client/v1/receipt.go#L19). + +```go + txHash := "0xfoobar" + receipt, ok, err := cp.client.Receipt(ctx, txnHash, clientV1.WaitFor(cp.receiptTimeout)) +``` + +##### Read +Read runs a read SQL query with the provided [options](https://github.com/tablelandnetwork/go-tableland/blob/main/pkg/client/v1/readquery.go#L35). + +```go + client.Read(ctx, "select counter from myTable", clientV1.ReadExtract()) +``` + +##### GetTable +The GetTable API will return the [Table](https://github.com/tablelandnetwork/go-tableland/blob/ac993505b32ccd32ad0c7b3d9552b14c0eb72823/internal/router/controllers/apiv1/model_table.go#L12) struct given the [table id](https://github.com/tablelandnetwork/go-tableland/blob/ac993505b32ccd32ad0c7b3d9552b14c0eb72823/pkg/client/v1/client.go#L206). + +```go + table, err := client.GetTable(ctx, tableID) +``` + From d5799698115c99911e902e0eda7af3a3759fca41 Mon Sep 17 00:00:00 2001 From: avichalp Date: Mon, 3 Jul 2023 12:22:33 -0700 Subject: [PATCH 4/4] Add more examples Signed-off-by: avichalp --- pkg/client/v1/README.md | 78 ++++++++++++++++++++++++++++------------- 1 file changed, 53 insertions(+), 25 deletions(-) diff --git a/pkg/client/v1/README.md b/pkg/client/v1/README.md index f7a98fd2..32886166 100644 --- a/pkg/client/v1/README.md +++ b/pkg/client/v1/README.md @@ -1,8 +1,8 @@ ## Tableland Client -Tableland Client is a convenient wrapper around validator's HTTP APIs. +Tableland Client is a convenient wrapper around validator's HTTP APIs. Here is the list of public APIs. -### APIs +#### APIs - [Create](https://github.com/tablelandnetwork/go-tableland/blob/main/pkg/client/v1/writequery.go#L39) - [Write](https://github.com/tablelandnetwork/go-tableland/blob/main/pkg/client/v1/writequery.go#L73) - [Version](https://github.com/tablelandnetwork/go-tableland/blob/main/pkg/client/v1/version.go#L15) @@ -20,66 +20,94 @@ Following are few example usage of these APIs. First, we instantiate the client: ```go - import ( +import ( - // ... - // ... +// ... +// ... - clientV1 "github.com/textileio/go-tableland/pkg/client/v1" - "github.com/textileio/go-tableland/pkg/wallet" - ) + clientV1 "github.com/textileio/go-tableland/pkg/client/v1" + "github.com/textileio/go-tableland/pkg/wallet" +) - // create the wallet from the given private key - wallet, _ := wallet.NewWallet("PRIVATE_KEY") - ctx := context.Background() +// create the wallet from the given private key +wallet, _ := wallet.NewWallet("PRIVATE_KEY") +ctx := context.Background() - // create the new client - client, _ := clientV1.NewClient(ctx, wallet, clientV1.[]NewClientOption{}...) +// create the new client +client, _ := clientV1.NewClient( + ctx, wallet, clientV1.[]NewClientOption{}...) ``` -Checkout the available options [here](https://github.com/tablelandnetwork/go-tableland/blob/main/pkg/client/v1/client.go#L59). +Checkout the available client options [here](https://github.com/tablelandnetwork/go-tableland/blob/main/pkg/client/v1/client.go#L59). -The client offers the following APIs - ##### Create Create a new table with the schema and [options](https://github.com/tablelandnetwork/go-tableland/blob/main/pkg/client/v1/writequery.go#L20). Schema should be a valid SQL DDL as a string. ```go - client.Create(ctx, "(id int, name text)", clientV1.WithPrefix("foo")) +tableID, fullTableName := client.Create( + ctx, "(id int, name text)", + clientV1.WithPrefix("foo")) ``` ##### Write Write will execute an mutation query, returning the txn hash. Additional [options](https://github.com/tablelandnetwork/go-tableland/blob/main/pkg/client/v1/writequery.go#L99) can be passed in. ```go - client.Write( - ctx, - "update users set name = alice where id = 1", - clientV1.WithSuggestedPriceMultiplier(1.5)) + // Create a new table + tableID, fullTableName := client.Create( + ctx, "(id int, name text)", + clientV1.WithPrefix("foo")) + + // Update the table + query := fmt.Sprintf( + "update %s set name = alice where id = 1", fullTableName) + hash := client.Write(ctx, query) + + // Alter table to rename a column + query := fmt.Sprintf( + "alter table %s rename name to username", fullTableName) + hash := client.Write(ctx, query) ``` ##### Receipt -Receipt will get the transaction receipt give the transaction hash. Additional configuration is possible with [options](https://github.com/tablelandnetwork/go-tableland/blob/main/pkg/client/v1/receipt.go#L19). +Receipt will get the transaction receipt given the transaction hash. Additional configuration is possible with [options](https://github.com/tablelandnetwork/go-tableland/blob/main/pkg/client/v1/receipt.go#L19). ```go - txHash := "0xfoobar" - receipt, ok, err := cp.client.Receipt(ctx, txnHash, clientV1.WaitFor(cp.receiptTimeout)) + txHash := "0xabcd" + receipt, ok, err := client.Receipt( + ctx, txnHash, clientV1.WaitFor(cp.receiptTimeout)) ``` ##### Read Read runs a read SQL query with the provided [options](https://github.com/tablelandnetwork/go-tableland/blob/main/pkg/client/v1/readquery.go#L35). ```go - client.Read(ctx, "select counter from myTable", clientV1.ReadExtract()) + // Create a new table: `myTable` + client.Create(ctx, "(counter int)", clientV1.WithPrefix("myTable")) + + // Insert a row in `myTable` + client.write(ctx, "insert into myTable (counter) values(42)") + + // Read it into the `target` struct + result := map[string]interface{}{} + client.Read( + ctx, "select counter from myTable", + result, clientV1.ReadExtract()) ``` ##### GetTable The GetTable API will return the [Table](https://github.com/tablelandnetwork/go-tableland/blob/ac993505b32ccd32ad0c7b3d9552b14c0eb72823/internal/router/controllers/apiv1/model_table.go#L12) struct given the [table id](https://github.com/tablelandnetwork/go-tableland/blob/ac993505b32ccd32ad0c7b3d9552b14c0eb72823/pkg/client/v1/client.go#L206). ```go + // create a new table + tableID, fullTableName := client.Create( + ctx, "(bar text DEFAULT 'foo',zar int, CHECK (zar>0))", + WithPrefix("foo"), WithReceiptTimeout(time.Second*10)) + + // get the table using tableID table, err := client.GetTable(ctx, tableID) ```