This is an automated email from the ASF dual-hosted git repository.
ako pushed a commit to branch ageviewer_go
in repository https://gitbox.apache.org/repos/asf/age.git
The following commit(s) were added to refs/heads/ageviewer_go by this push:
new 8a3406a9 [Ageviewer_go_Desktop] Added functionalities to read query
response dynamically (#836)
8a3406a9 is described below
commit 8a3406a99b418c79a6647b90765eaf3088555631
Author: Kamlesh Kumar <[email protected]>
AuthorDate: Fri Apr 28 09:19:15 2023 +0500
[Ageviewer_go_Desktop] Added functionalities to read query response
dynamically (#836)
* Function to disconnect database add to backend
* Added functionalities to read query response dynamically
---
backend/miscellaneous/cypher.go | 40 ++++++++++++++++++++++++++++
backend/miscellaneous/results.go | 7 +++++
backend/models/graph.go | 14 +++++++---
backend/routes/query.go | 56 ++++++++++++++++++----------------------
4 files changed, 82 insertions(+), 35 deletions(-)
diff --git a/backend/miscellaneous/cypher.go b/backend/miscellaneous/cypher.go
new file mode 100644
index 00000000..2bad06bc
--- /dev/null
+++ b/backend/miscellaneous/cypher.go
@@ -0,0 +1,40 @@
+package miscellaneous
+
+import (
+ "database/sql"
+)
+
+func CypherCall(db *sql.DB, q map[string]string, c chan<- ChannelResults) {
+ data := ChannelResults{}
+ results := []interface{}{}
+ rows, err := db.Query(q["query"])
+ if err != nil {
+ data.Err = err
+ c <- data
+ return
+ }
+ cols, _ := rows.ColumnTypes()
+ if len(cols) == 1 && cols[0].DatabaseTypeName() == "VOID" {
+ data.Msg = map[string]string{
+ "status": "success",
+ }
+ c <- data
+ return
+ }
+
+ for rows.Next() {
+ rawData := make([]any, len(cols))
+ for i := 0; i < len(cols); i++ {
+ rawData[i] = new(string)
+ }
+
+ err := rows.Scan(rawData...)
+ if err != nil {
+ data.Err = err
+ break
+ }
+ results = append(results, rawData)
+ }
+ data.Res = results
+ c <- data
+}
diff --git a/backend/miscellaneous/results.go b/backend/miscellaneous/results.go
new file mode 100644
index 00000000..963fd404
--- /dev/null
+++ b/backend/miscellaneous/results.go
@@ -0,0 +1,7 @@
+package miscellaneous
+
+type ChannelResults struct {
+ Res any
+ Msg map[string]string
+ Err error
+}
diff --git a/backend/models/graph.go b/backend/models/graph.go
index 61380faf..cb5df677 100644
--- a/backend/models/graph.go
+++ b/backend/models/graph.go
@@ -15,15 +15,21 @@ type Graph struct {
GetMetaData returns the metadata for a given graph instance g, based on the
version of the database.
and returns a set of rows and an error (if any)
*/
-func (g *Graph) GetMetaData(conn *sql.DB, v int) (*sql.Rows, error) {
+func (g *Graph) GetMetaData(conn *sql.DB, v int, dataChan chan<- *sql.Rows,
errorChan chan<- error) {
defer conn.Close()
+ var data *sql.Rows
+ var err error
+
switch v {
case 11:
- return conn.Query(db.META_DATA_11, g.Name)
+ data, err = conn.Query(db.META_DATA_11, g.Name)
case 12:
- return conn.Query(db.META_DATA_12, g.Name)
+ data, err = conn.Query(db.META_DATA_12, g.Name)
default:
- return nil, errors.New("unsupported version")
+ err = errors.New("unsupported version")
}
+
+ errorChan <- err
+ dataChan <- data
}
diff --git a/backend/routes/query.go b/backend/routes/query.go
index dea66cb9..39aedf3b 100644
--- a/backend/routes/query.go
+++ b/backend/routes/query.go
@@ -32,19 +32,19 @@ func CypherMiddleWare(next echo.HandlerFunc)
echo.HandlerFunc {
if err != nil {
return echo.NewHTTPError(400, err.Error())
}
- if err = conn.Ping(); err != nil { // check if the connection
is still valid
+ if err = conn.Ping(); err != nil {
return echo.NewHTTPError(400, err.Error())
}
if !user.GraphInit {
- _, err = conn.Exec(db.INIT_EXTENSION) // initialize the
AGE extension, if it is not already
+ _, err = conn.Exec(db.INIT_EXTENSION)
if err != nil {
msg := fmt.Sprintf("could not communicate with
db\nerror: %s", err.Error())
return echo.NewHTTPError(400, msg)
}
- user.GraphInit = true // set the flag to true, so that
the extension is not initialized again
+ user.GraphInit = true
}
if user.Version == 0 {
- rows, err := conn.Query(db.PG_VERSION) // get the
version of the database, if Version in User connection struct is 0.
+ rows, err := conn.Query(db.PG_VERSION)
if err != nil {
fmt.Print(err.Error())
}
@@ -65,17 +65,15 @@ func CypherMiddleWare(next echo.HandlerFunc)
echo.HandlerFunc {
}
/*
- Cypher function processes Cypher queries in a context object, The function
extracts
- the query from the context object, executes it on a database connection, and
returns
- the results as a JSON response. It also handles errors that may arise during
the query execution.
+Cypher function processes Cypher queries in a context object, The function
extracts
+the query from the context object, executes it on a database connection, and
returns
+the results as a JSON response. It also handles errors that may arise during
the query execution.
*/
-
func Cypher(ctx echo.Context) error {
q := map[string]string{}
- results := []interface{}{}
var err error
- err = ctx.Bind(&q) // extract the query from the request body
+ err = ctx.Bind(&q)
if err != nil {
e := m.ErrorHandle{
Msg: "unable to parse query",
@@ -83,28 +81,22 @@ func Cypher(ctx echo.Context) error {
}
return ctx.JSON(400, e.JSON())
}
- conn := ctx.Get("conn").(*sql.DB) // get the database connection from
the context object
- rows, err := conn.Query(q["query"]) // execute the query on the database
-
+ conn := ctx.Get("conn").(*sql.DB)
+ c := make(chan m.ChannelResults, 1)
+ m.CypherCall(conn, q, c)
+ data := <-c
+ err = data.Err
+ res := data.Res
+ msg := data.Msg
if err != nil {
return echo.NewHTTPError(400, fmt.Sprintf("unable to process
query. error: %s", err.Error()))
}
- cols, _ := rows.ColumnTypes()
- if len(cols) == 1 && cols[0].DatabaseTypeName() == "VOID" { // if the
query is a DDL query(Data Definition Language), return a 204 status code
- return ctx.JSON(204, map[string]string{
- "status": "success",
- })
- }
- for rows.Next() { // iterate over the rows returned by the query
- data := []any{}
- err := rows.Scan(&data)
- if err != nil {
- print(fmt.Sprintf("\n\nerror: %s", err.Error()))
- }
- results = append(results, data)
+ if _, ok := msg["status"]; ok {
+ return ctx.JSON(204, msg)
}
- return ctx.JSON(200, results)
+
+ return ctx.JSON(200, res)
}
/*
@@ -113,20 +105,22 @@ which graph to query, and the user object to determine
the database version. The
then organized into two lists: one for nodes and one for edges, before being
returned as a JSON response.
*/
func GraphMetaData(c echo.Context) error {
+ dataChan := make(chan *sql.Rows, 1)
+ errChan := make(chan error, 1)
- user := c.Get("user").(models.Connection) // get the user object from
the context object
+ user := c.Get("user").(models.Connection)
conn := c.Get("conn").(*sql.DB)
graph := models.Graph{}
- c.Bind(&graph) // extract the graph object from the request body
+ c.Bind(&graph)
conn.Exec(db.ANALYZE)
- data, err := graph.GetMetaData(conn, user.Version) // get the metadata
for the graph according to the version.
+ go graph.GetMetaData(conn, user.Version, dataChan, errChan)
+ data, err := <-dataChan, <-errChan
if err != nil {
return echo.NewHTTPError(400, err.Error())
}
results := models.MetaDataContainer{}
- // organize the metadata into two lists: one for nodes and one for edges
for data.Next() {
row := models.MetaData{}
err := data.Scan(&row.Label, &row.Cnt, &row.Kind)