124 lines
3 KiB
Go
124 lines
3 KiB
Go
package cmdpacks
|
|
|
|
import (
|
|
"context"
|
|
"github.com/aws/aws-sdk-go-v2/service/dynamodb/types"
|
|
"github.com/lmika/dynamo-browse/internal/dynamo-browse/controllers"
|
|
"github.com/lmika/dynamo-browse/internal/dynamo-browse/models"
|
|
"github.com/lmika/dynamo-browse/internal/dynamo-browse/models/queryexpr"
|
|
"github.com/lmika/dynamo-browse/internal/dynamo-browse/services/tables"
|
|
"github.com/pkg/errors"
|
|
"ucl.lmika.dev/repl"
|
|
"ucl.lmika.dev/ucl"
|
|
)
|
|
|
|
type rsModule struct {
|
|
tableService *tables.Service
|
|
state *controllers.State
|
|
}
|
|
|
|
var rsNewDoc = repl.Doc{
|
|
Brief: "Creates a new, empty result set",
|
|
}
|
|
|
|
func (rs *rsModule) rsNew(ctx context.Context, args ucl.CallArgs) (any, error) {
|
|
return &ResultSetProxy{
|
|
RS: &models.ResultSet{},
|
|
}, nil
|
|
}
|
|
|
|
var rsQueryDoc = repl.Doc{
|
|
Brief: "Runs a query and returns the results as a result-set",
|
|
Usage: "QUERY [ARGS] [-table NAME]",
|
|
Args: []repl.ArgDoc{
|
|
{Name: "query", Brief: "Query expression to run"},
|
|
{Name: "args", Brief: "Hash of argument values to substitute into the query"},
|
|
{Name: "-table", Brief: "Optional table name to use for the query"},
|
|
},
|
|
Detailed: `
|
|
If no table is specified, then the value of @table will be used. If this is unavailable,
|
|
the command will return an error.
|
|
`,
|
|
}
|
|
|
|
func (rs *rsModule) rsQuery(ctx context.Context, args ucl.CallArgs) (any, error) {
|
|
var expr string
|
|
if err := args.Bind(&expr); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
q, err := queryexpr.Parse(expr)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if args.NArgs() > 0 {
|
|
var queryArgs ucl.Hashable
|
|
if err := args.Bind(&queryArgs); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
queryNames := map[string]string{}
|
|
queryValues := map[string]types.AttributeValue{}
|
|
queryArgs.Each(func(k string, v ucl.Object) error {
|
|
if v == nil {
|
|
return nil
|
|
}
|
|
|
|
queryNames[k] = v.String()
|
|
|
|
switch v.(type) {
|
|
case ucl.StringObject:
|
|
queryValues[k] = &types.AttributeValueMemberS{Value: v.String()}
|
|
case ucl.IntObject:
|
|
queryValues[k] = &types.AttributeValueMemberN{Value: v.String()}
|
|
// TODO: other types
|
|
}
|
|
return nil
|
|
})
|
|
|
|
q = q.WithNameParams(queryNames).WithValueParams(queryValues)
|
|
}
|
|
|
|
var tableInfo *models.TableInfo
|
|
if args.HasSwitch("table") {
|
|
var tblName string
|
|
if err := args.BindSwitch("table", &tblName); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
tableInfo, err = rs.tableService.Describe(ctx, tblName)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
} else if currRs := rs.state.ResultSet(); currRs != nil && currRs.TableInfo != nil {
|
|
tableInfo = currRs.TableInfo
|
|
} else {
|
|
return nil, errors.New("no table specified")
|
|
}
|
|
|
|
newResultSet, err := rs.tableService.ScanOrQuery(context.Background(), tableInfo, q, nil)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return &ResultSetProxy{
|
|
RS: newResultSet,
|
|
}, nil
|
|
}
|
|
|
|
func moduleRS(tableService *tables.Service, state *controllers.State) ucl.Module {
|
|
m := &rsModule{
|
|
tableService: tableService,
|
|
state: state,
|
|
}
|
|
|
|
return ucl.Module{
|
|
Name: "rs",
|
|
Builtins: map[string]ucl.BuiltinHandler{
|
|
"new": m.rsNew,
|
|
"query": m.rsQuery,
|
|
},
|
|
}
|
|
}
|