217 lines
5.8 KiB
Go
217 lines
5.8 KiB
Go
package cmdpacks
|
|
|
|
import (
|
|
"fmt"
|
|
"github.com/aws/aws-sdk-go-v2/service/dynamodb/types"
|
|
"github.com/lmika/dynamo-browse/internal/dynamo-browse/models"
|
|
"maps"
|
|
"strconv"
|
|
"ucl.lmika.dev/ucl"
|
|
)
|
|
|
|
type proxyInfo[T comparable] struct {
|
|
fields map[string]func(t T) ucl.Object
|
|
lenFunc func(t T) int
|
|
strFunc func(t T) string
|
|
}
|
|
|
|
type SimpleProxy[T comparable] struct {
|
|
value T
|
|
proxyInfo *proxyInfo[T]
|
|
}
|
|
|
|
func (tp SimpleProxy[T]) ProxyValue() T {
|
|
return tp.value
|
|
}
|
|
|
|
func (tp SimpleProxy[T]) String() string {
|
|
if tp.proxyInfo.strFunc != nil {
|
|
return tp.proxyInfo.strFunc(tp.value)
|
|
}
|
|
return fmt.Sprint(tp.value)
|
|
}
|
|
|
|
func (tp SimpleProxy[T]) Truthy() bool {
|
|
var zeroT T
|
|
return tp.value != zeroT
|
|
}
|
|
|
|
func (tp SimpleProxy[T]) Len() int {
|
|
if tp.proxyInfo.lenFunc != nil {
|
|
return tp.proxyInfo.lenFunc(tp.value)
|
|
}
|
|
return len(tp.proxyInfo.fields)
|
|
}
|
|
|
|
func (tp SimpleProxy[T]) Value(k string) ucl.Object {
|
|
f, ok := tp.proxyInfo.fields[k]
|
|
if !ok {
|
|
return nil
|
|
}
|
|
return f(tp.value)
|
|
}
|
|
|
|
func (tp SimpleProxy[T]) Each(fn func(k string, v ucl.Object) error) error {
|
|
for key := range maps.Keys(tp.proxyInfo.fields) {
|
|
if err := fn(key, tp.Value(key)); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
type simpleProxyList[T comparable] struct {
|
|
values []T
|
|
converter func(T) ucl.Object
|
|
}
|
|
|
|
func newSimpleProxyList[T comparable](values []T, converter func(T) ucl.Object) simpleProxyList[T] {
|
|
return simpleProxyList[T]{values: values, converter: converter}
|
|
}
|
|
|
|
func (tp simpleProxyList[T]) String() string {
|
|
return fmt.Sprint(tp.values)
|
|
}
|
|
|
|
func (tp simpleProxyList[T]) Truthy() bool {
|
|
return len(tp.values) > 0
|
|
}
|
|
|
|
func (tp simpleProxyList[T]) Len() int {
|
|
return len(tp.values)
|
|
}
|
|
|
|
func (tp simpleProxyList[T]) Index(k int) ucl.Object {
|
|
return tp.converter(tp.values[k])
|
|
}
|
|
|
|
func newResultSetProxy(rs *models.ResultSet) ucl.Object {
|
|
return SimpleProxy[*models.ResultSet]{value: rs, proxyInfo: resultSetProxyFields}
|
|
}
|
|
|
|
var resultSetProxyFields = &proxyInfo[*models.ResultSet]{
|
|
lenFunc: func(t *models.ResultSet) int { return len(t.Items()) },
|
|
strFunc: func(t *models.ResultSet) string {
|
|
return fmt.Sprintf("ResultSet(%v:%d)", t.TableInfo.Name, len(t.Items()))
|
|
},
|
|
fields: map[string]func(t *models.ResultSet) ucl.Object{
|
|
"Table": func(t *models.ResultSet) ucl.Object { return newTableProxy(t.TableInfo) },
|
|
"Items": func(t *models.ResultSet) ucl.Object { return resultSetItemsProxy{t} },
|
|
"HasNextPage": func(t *models.ResultSet) ucl.Object { return ucl.BoolObject(t.HasNextPage()) },
|
|
},
|
|
}
|
|
|
|
func newTableProxy(table *models.TableInfo) ucl.Object {
|
|
return SimpleProxy[*models.TableInfo]{value: table, proxyInfo: tableProxyFields}
|
|
}
|
|
|
|
var tableProxyFields = &proxyInfo[*models.TableInfo]{
|
|
strFunc: func(t *models.TableInfo) string {
|
|
return fmt.Sprintf("Table(%v)", t.Name)
|
|
},
|
|
fields: map[string]func(t *models.TableInfo) ucl.Object{
|
|
"Name": func(t *models.TableInfo) ucl.Object { return ucl.StringObject(t.Name) },
|
|
"Keys": func(t *models.TableInfo) ucl.Object { return newKeyAttributeProxy(t.Keys) },
|
|
"DefinedAttributes": func(t *models.TableInfo) ucl.Object { return ucl.StringListObject(t.DefinedAttributes) },
|
|
"GSIs": func(t *models.TableInfo) ucl.Object { return newSimpleProxyList(t.GSIs, newGSIProxy) },
|
|
},
|
|
}
|
|
|
|
func newKeyAttributeProxy(keyAttrs models.KeyAttribute) ucl.Object {
|
|
return SimpleProxy[models.KeyAttribute]{value: keyAttrs, proxyInfo: keyAttributeProxyFields}
|
|
}
|
|
|
|
var keyAttributeProxyFields = &proxyInfo[models.KeyAttribute]{
|
|
strFunc: func(t models.KeyAttribute) string {
|
|
return fmt.Sprintf("KeyAttribute(%v,%v)", t.PartitionKey, t.SortKey)
|
|
},
|
|
fields: map[string]func(t models.KeyAttribute) ucl.Object{
|
|
"PartitionKey": func(t models.KeyAttribute) ucl.Object { return ucl.StringObject(t.PartitionKey) },
|
|
"SortKey": func(t models.KeyAttribute) ucl.Object { return ucl.StringObject(t.SortKey) },
|
|
},
|
|
}
|
|
|
|
func newGSIProxy(gsi models.TableGSI) ucl.Object {
|
|
return SimpleProxy[models.TableGSI]{value: gsi, proxyInfo: gsiProxyFields}
|
|
}
|
|
|
|
var gsiProxyFields = &proxyInfo[models.TableGSI]{
|
|
strFunc: func(t models.TableGSI) string {
|
|
return fmt.Sprintf("TableGSI(%v,(%v,%v))", t.Name, t.Keys.PartitionKey, t.Keys.SortKey)
|
|
},
|
|
fields: map[string]func(t models.TableGSI) ucl.Object{
|
|
"Name": func(t models.TableGSI) ucl.Object { return ucl.StringObject(t.Name) },
|
|
"Keys": func(t models.TableGSI) ucl.Object { return newKeyAttributeProxy(t.Keys) },
|
|
},
|
|
}
|
|
|
|
type resultSetItemsProxy struct {
|
|
resultSet *models.ResultSet
|
|
}
|
|
|
|
func (ip resultSetItemsProxy) String() string {
|
|
return "RSItem()"
|
|
}
|
|
|
|
func (ip resultSetItemsProxy) Truthy() bool {
|
|
return len(ip.resultSet.Items()) > 0
|
|
}
|
|
|
|
func (tp resultSetItemsProxy) Len() int {
|
|
return len(tp.resultSet.Items())
|
|
}
|
|
|
|
func (tp resultSetItemsProxy) Index(k int) ucl.Object {
|
|
return itemProxy{resultSet: tp.resultSet, idx: k, item: tp.resultSet.Items()[k]}
|
|
}
|
|
|
|
type itemProxy struct {
|
|
resultSet *models.ResultSet
|
|
idx int
|
|
item models.Item
|
|
}
|
|
|
|
func (ip itemProxy) String() string {
|
|
return fmt.Sprintf("RSItems(%v)", len(ip.item))
|
|
}
|
|
|
|
func (ip itemProxy) Truthy() bool {
|
|
return len(ip.item) > 0
|
|
}
|
|
|
|
func (tp itemProxy) Len() int {
|
|
return len(tp.item)
|
|
}
|
|
|
|
func (tp itemProxy) Value(k string) ucl.Object {
|
|
f, ok := tp.item[k]
|
|
if !ok {
|
|
return nil
|
|
}
|
|
return convertAttributeValueToUCLObject(f)
|
|
}
|
|
|
|
func (tp itemProxy) Each(fn func(k string, v ucl.Object) error) error {
|
|
for key := range maps.Keys(tp.item) {
|
|
if err := fn(key, tp.Value(key)); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func convertAttributeValueToUCLObject(attrValue types.AttributeValue) ucl.Object {
|
|
switch t := attrValue.(type) {
|
|
case *types.AttributeValueMemberS:
|
|
return ucl.StringObject(t.Value)
|
|
case *types.AttributeValueMemberN:
|
|
i, err := strconv.ParseInt(t.Value, 10, 64)
|
|
if err != nil {
|
|
return nil
|
|
}
|
|
return ucl.IntObject(i)
|
|
}
|
|
// TODO: the rest
|
|
return nil
|
|
}
|