initial commit
This commit is contained in:
@@ -0,0 +1,173 @@
|
||||
package graphql
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/graphql-go/graphql"
|
||||
"github.com/restxlsx/restxlsx/internal/excel"
|
||||
"github.com/restxlsx/restxlsx/internal/logger"
|
||||
)
|
||||
|
||||
type Handler struct {
|
||||
schema graphql.Schema
|
||||
engine *excel.Engine
|
||||
Logger *logger.Logger
|
||||
}
|
||||
|
||||
func New(engine *excel.Engine, log *logger.Logger) (*Handler, error) {
|
||||
h := &Handler{engine: engine, Logger: log}
|
||||
schema, err := h.buildSchema()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
h.schema = schema
|
||||
return h, nil
|
||||
}
|
||||
|
||||
func (h *Handler) buildSchema() (graphql.Schema, error) {
|
||||
fields := graphql.Fields{
|
||||
"tables": &graphql.Field{
|
||||
Type: graphql.NewList(graphql.String),
|
||||
Resolve: func(p graphql.ResolveParams) (any, error) {
|
||||
return h.engine.ListTables(), nil
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, name := range h.engine.ListTables() {
|
||||
t := h.engine.GetTable(name)
|
||||
tableType := buildObjectType(name, t)
|
||||
|
||||
nameInner := name
|
||||
|
||||
fields[fmt.Sprintf("get_%s", name)] = &graphql.Field{
|
||||
Type: tableType,
|
||||
Args: graphql.FieldConfigArgument{
|
||||
"id": &graphql.ArgumentConfig{
|
||||
Type: graphql.String,
|
||||
},
|
||||
},
|
||||
Resolve: func(p graphql.ResolveParams) (any, error) {
|
||||
table := h.engine.GetTable(nameInner)
|
||||
if table == nil {
|
||||
return nil, nil
|
||||
}
|
||||
if id, ok := p.Args["id"]; ok && id != "" {
|
||||
idStr := fmt.Sprintf("%v", id)
|
||||
idColInner := h.engine.IDColumn(nameInner)
|
||||
for _, row := range table.Rows {
|
||||
if fmt.Sprintf("%v", row[idColInner]) == idStr {
|
||||
return row, nil
|
||||
}
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
return table.Rows, nil
|
||||
},
|
||||
}
|
||||
|
||||
fields[fmt.Sprintf("list_%s", name)] = &graphql.Field{
|
||||
Type: graphql.NewList(tableType),
|
||||
Resolve: func(p graphql.ResolveParams) (any, error) {
|
||||
table := h.engine.GetTable(nameInner)
|
||||
if table == nil {
|
||||
return []map[string]any{}, nil
|
||||
}
|
||||
return table.Rows, nil
|
||||
},
|
||||
}
|
||||
|
||||
fields[fmt.Sprintf("create_%s", name)] = &graphql.Field{
|
||||
Type: tableType,
|
||||
Args: buildInputArgs(t),
|
||||
Resolve: func(p graphql.ResolveParams) (any, error) {
|
||||
table := h.engine.GetTable(nameInner)
|
||||
if table == nil {
|
||||
return nil, fmt.Errorf("table not found: %s", nameInner)
|
||||
}
|
||||
rec := make(map[string]any)
|
||||
for _, col := range table.Columns {
|
||||
if v, ok := p.Args[col]; ok {
|
||||
rec[col] = v
|
||||
}
|
||||
}
|
||||
idColInner := h.engine.IDColumn(nameInner)
|
||||
if idColInner != "" {
|
||||
if _, ok := rec[idColInner]; !ok {
|
||||
rec[idColInner] = len(table.Rows) + 1
|
||||
}
|
||||
}
|
||||
table.Rows = append(table.Rows, rec)
|
||||
if err := h.engine.Flush(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return rec, nil
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
queryType := graphql.NewObject(graphql.ObjectConfig{
|
||||
Name: "Query",
|
||||
Fields: fields,
|
||||
})
|
||||
|
||||
return graphql.NewSchema(graphql.SchemaConfig{
|
||||
Query: queryType,
|
||||
})
|
||||
}
|
||||
|
||||
func buildObjectType(name string, t *excel.Table) *graphql.Object {
|
||||
fields := graphql.Fields{}
|
||||
for _, col := range t.Columns {
|
||||
colName := col
|
||||
fields[colName] = &graphql.Field{
|
||||
Type: graphql.String,
|
||||
Resolve: func(p graphql.ResolveParams) (any, error) {
|
||||
if row, ok := p.Source.(map[string]any); ok {
|
||||
return fmt.Sprintf("%v", row[colName]), nil
|
||||
}
|
||||
return nil, nil
|
||||
},
|
||||
}
|
||||
}
|
||||
return graphql.NewObject(graphql.ObjectConfig{
|
||||
Name: name,
|
||||
Fields: fields,
|
||||
})
|
||||
}
|
||||
|
||||
func buildInputArgs(t *excel.Table) graphql.FieldConfigArgument {
|
||||
args := graphql.FieldConfigArgument{}
|
||||
for _, col := range t.Columns {
|
||||
args[col] = &graphql.ArgumentConfig{
|
||||
Type: graphql.String,
|
||||
}
|
||||
}
|
||||
return args
|
||||
}
|
||||
|
||||
func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
var params struct {
|
||||
Query string `json:"query"`
|
||||
OperationName string `json:"operationName"`
|
||||
Variables map[string]any `json:"variables"`
|
||||
}
|
||||
if err := json.NewDecoder(r.Body).Decode(¶ms); err != nil {
|
||||
http.Error(w, `{"error":"invalid JSON"}`, http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
h.engine.Lock()
|
||||
result := graphql.Do(graphql.Params{
|
||||
Schema: h.schema,
|
||||
RequestString: params.Query,
|
||||
OperationName: params.OperationName,
|
||||
VariableValues: params.Variables,
|
||||
})
|
||||
h.engine.Unlock()
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
json.NewEncoder(w).Encode(result)
|
||||
}
|
||||
Reference in New Issue
Block a user