Skip to content

Commit

Permalink
extract parent
Browse files Browse the repository at this point in the history
  • Loading branch information
RangelReale committed Sep 3, 2024
1 parent 43698f9 commit 626c6f5
Show file tree
Hide file tree
Showing 5 changed files with 85 additions and 20 deletions.
13 changes: 7 additions & 6 deletions loader.go
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ func (l *loader) loadFile(file io.Reader, tags []string) error {
return nil
}

func (l *loader) loadRoot(node ast.Node, tags []string, parent parentRowInfo) error {
func (l *loader) loadRoot(node ast.Node, tags []string, parent ParentRowInfo) error {
var values []*ast.MappingValueNode
switch n := node.(type) {
case *ast.MappingNode:
Expand Down Expand Up @@ -159,7 +159,7 @@ func (l *loader) loadRoot(node ast.Node, tags []string, parent parentRowInfo) er
return nil
}

func (l *loader) loadTables(node ast.Node, tags []string, parent parentRowInfo) error {
func (l *loader) loadTables(node ast.Node, tags []string, parent ParentRowInfo) error {
switch n := node.(type) {
case *ast.MappingValueNode:
tableID, err := getStringNode(n.Key)
Expand All @@ -185,7 +185,7 @@ func (l *loader) loadTables(node ast.Node, tags []string, parent parentRowInfo)
return nil
}

func (l *loader) loadTable(tableID string, node ast.Node, tags []string, parent parentRowInfo) error {
func (l *loader) loadTable(tableID string, node ast.Node, tags []string, parent ParentRowInfo) error {
if l.data.Tables == nil {
l.data.Tables = map[string]*Table{}
}
Expand Down Expand Up @@ -331,7 +331,7 @@ func (l *loader) loadTableConfigDefaultValues(node ast.Node, table *Table, cfg *
return nil
}

func (l *loader) loadTableRows(node ast.Node, table *Table, tags []string, parent parentRowInfo) error {
func (l *loader) loadTableRows(node ast.Node, table *Table, tags []string, parent ParentRowInfo) error {
switch n := node.(type) {
case *ast.SequenceNode:
for _, row := range n.Values {
Expand All @@ -347,7 +347,7 @@ func (l *loader) loadTableRows(node ast.Node, table *Table, tags []string, paren
return nil
}

func (l *loader) loadTableRow(node ast.Node, table *Table, tags []string, parent parentRowInfo) error {
func (l *loader) loadTableRow(node ast.Node, table *Table, tags []string, parent ParentRowInfo) error {
var values []*ast.MappingValueNode
switch n := node.(type) {
case *ast.MappingNode:
Expand All @@ -363,6 +363,7 @@ func (l *loader) loadTableRow(node ast.Node, table *Table, tags []string, parent
InternalID: uuid.New(),
Fields: map[string]any{},
Metadata: map[string]any{},
Parent: parent,
}
for _, field := range values {
switch n := field.Value.(type) {
Expand Down Expand Up @@ -435,7 +436,7 @@ func (l *loader) loadTableRow(node ast.Node, table *Table, tags []string, parent
return nil
}

func (l *loader) loadFieldValue(node ast.Node, parent parentRowInfo) (any, error) {
func (l *loader) loadFieldValue(node ast.Node, parent ParentRowInfo) (any, error) {
switch n := node.(type) {
case *ast.TagNode:
switch n.Start.Value {
Expand Down
1 change: 1 addition & 0 deletions table.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ type Row struct {
Config RowConfig
Fields map[string]any
Metadata map[string]any
Parent ParentRowInfo
}

// Clone does a deep copy of the row, to ensure source is never modified.
Expand Down
50 changes: 50 additions & 0 deletions table_extract.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,10 @@ package debefix
import (
"errors"
"fmt"
"strconv"
"strings"

"github.com/google/uuid"
)

// ExtractRows extract rows matched by the callback, returning a filtered Data instance.
Expand Down Expand Up @@ -146,6 +149,32 @@ func (d *Data) ExtractFilterValue(row Row, filter ExtractFilter) (any, error) {
if err != nil {
return nil, err
}
return fv, nil
case *ExtractFilterParent:
if row.Parent == nil {
return nil, errors.New("parents not supported in current context")
}
plevel := row.Parent.ParentLevel(ft.Level)
if !plevel.ParentSupported() {
return nil, errors.New("parents not supported in current context")
}
if !plevel.HasParent() {
return nil, errors.New("value has no parent")
}
fv, err := d.WalkTableData(plevel.TableID(), func(row Row) (bool, any, error) {
if row.InternalID != uuid.Nil && row.InternalID == plevel.InternalID() {
if rowfield, ok := row.Fields[ft.FieldName]; ok {
return true, rowfield, nil
} else {
return false, nil, fmt.Errorf("could not find field %s in internalid table %s", ft.FieldName, plevel.TableID())
}
}
return false, nil, nil
})
if err != nil {
return nil, fmt.Errorf("could not find internalid %s in table %s: %w", plevel.InternalID(), plevel.TableID(), err)
}

return fv, nil
default:
return nil, fmt.Errorf("unknown extract filter %T", filter)
Expand Down Expand Up @@ -205,6 +234,20 @@ func ParseExtractFilters(filters ...string) ([]ExtractFilter, error) {
return nil, errors.Join(ValueError, fmt.Errorf("invalid filter value: %s", filter))
}
ret = append(ret, &ExtractFilterValueRef{SourceFieldName: fields[1], TableID: fields[2], TargetFieldName: fields[3], ReturnFieldName: fields[4]})
case "parent": // parent<:level>:<fieldname>
parentLevel := 1
fieldName := fields[1]
if len(fields) == 3 {
level, err := strconv.ParseInt(fields[1], 10, 32)
if err != nil {
return nil, errors.Join(ValueError, fmt.Errorf("invalid level '%s' in parent expression: %w", fields[1], err))
}
parentLevel = int(level)
fieldName = fields[2]
} else if len(fields) != 2 {
return nil, errors.Join(ValueError, fmt.Errorf("invalid filter value: %s", filter))
}
ret = append(ret, &ExtractFilterParent{Level: parentLevel, FieldName: fieldName})
default:
return nil, errors.Join(ValueError, fmt.Errorf("invalid filter value: %s", filter))
}
Expand Down Expand Up @@ -244,7 +287,14 @@ type ExtractFilterValueRef struct {
ReturnFieldName string
}

// ExtractFilterParent has the format "parent<:level>:<fieldname>"
type ExtractFilterParent struct {
Level int
FieldName string
}

func (ExtractFilterValue) isExtractFilter() {}
func (ExtractFilterMetadata) isExtractFilter() {}
func (ExtractFilterRefID) isExtractFilter() {}
func (ExtractFilterValueRef) isExtractFilter() {}
func (ExtractFilterParent) isExtractFilter() {}
19 changes: 16 additions & 3 deletions table_extract_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"fmt"
"testing"

"github.com/google/uuid"
"gotest.tools/v3/assert"
is "gotest.tools/v3/assert/cmp"
)
Expand Down Expand Up @@ -85,20 +86,30 @@ func TestDataExtractRowsNamed(t *testing.T) {
}

func TestDataExtractValues(t *testing.T) {
tag2InternalID := uuid.New()

data := &Data{
Tables: map[string]*Table{
"tags": {
ID: "tags",
Rows: Rows{
Row{Fields: map[string]any{"tag_id": 1, "name": "this_is_1"}, Config: RowConfig{RefID: "tag1"}},
Row{Fields: map[string]any{"tag_id": 2, "name": "this_is_2"}, Config: RowConfig{RefID: "tag2"}},
Row{Fields: map[string]any{"tag_id": 2, "name": "this_is_2"}, Config: RowConfig{RefID: "tag2"}, InternalID: tag2InternalID},
},
},
"posts": {
ID: "posts",
Rows: Rows{
Row{Fields: map[string]any{"post_id": 5, "tag_id": 1}, Config: RowConfig{RefID: "post5"}},
Row{Fields: map[string]any{"post_id": 3, "tag_id": 2}, Config: RowConfig{RefID: "post3"}, Metadata: map[string]any{"post_image": "p1.jpg"}},
Row{Fields: map[string]any{"post_id": 3, "tag_id": 2}, Config: RowConfig{RefID: "post3"},
Metadata: map[string]any{"post_image": "p1.jpg"},
Parent: &defaultParentRowInfo{
parent: &noParentRowInfo{},
data: &defaultParentRowInfoData{
tableID: "tags",
internalID: tag2InternalID,
},
}},
Row{Fields: map[string]any{"post_id": 2, "tag_id": 1}, Config: RowConfig{RefID: "post2"}},
},
},
Expand All @@ -112,14 +123,16 @@ func TestDataExtractValues(t *testing.T) {
"v3": "valueref:tag_id:tags:tag_id:name",
"v4": "metadata:post_image",
"v5": "metadata:post_noimage:default.jpg",
"v6": "parent:name",
})
assert.NilError(t, err)

assert.Assert(t, is.Len(values, 5))
assert.Assert(t, is.Len(values, 6))

assert.Equal(t, 3, values["v1"])
assert.Equal(t, 1, values["v2"])
assert.Equal(t, "this_is_2", values["v3"])
assert.Equal(t, "p1.jpg", values["v4"])
assert.Equal(t, "default.jpg", values["v5"])
assert.Equal(t, "this_is_2", values["v6"])
}
22 changes: 11 additions & 11 deletions value.go
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ type valueTableDepends interface {
}

// parseValue parses !expr expressions.
func parseValue(value string, parent parentRowInfo) (Value, error) {
func parseValue(value string, parent ParentRowInfo) (Value, error) {
fields := strings.Split(value, ":")
if len(fields) == 0 {
return nil, errors.Join(ValueError, fmt.Errorf("invalid tag: %s", value))
Expand Down Expand Up @@ -149,13 +149,13 @@ func parseValue(value string, parent parentRowInfo) (Value, error) {
}
}

// parentRowInfo gets parent info from a level number.
type parentRowInfo interface {
ParentLevel(level int) parentRowInfoData
// ParentRowInfo gets parent info from a level number.
type ParentRowInfo interface {
ParentLevel(level int) ParentRowInfoData
}

// parentRowInfoData indicates if a parent exists and its information.
type parentRowInfoData interface {
// ParentRowInfoData indicates if a parent exists and its information.
type ParentRowInfoData interface {
ParentSupported() bool
HasParent() bool
TableID() string
Expand All @@ -166,7 +166,7 @@ type parentRowInfoData interface {
type noParentRowInfo struct {
}

func (n noParentRowInfo) ParentLevel(level int) parentRowInfoData {
func (n noParentRowInfo) ParentLevel(level int) ParentRowInfoData {
return &noParentRowInfoData{}
}

Expand All @@ -192,11 +192,11 @@ func (n noParentRowInfoData) InternalID() uuid.UUID {

// defaultParentRowInfoData indicates a parent exists in the current context.
type defaultParentRowInfo struct {
parent parentRowInfo
data parentRowInfoData
parent ParentRowInfo
data ParentRowInfoData
}

func (n defaultParentRowInfo) ParentLevel(level int) parentRowInfoData {
func (n defaultParentRowInfo) ParentLevel(level int) ParentRowInfoData {
if level == 1 {
return n.data
}
Expand Down Expand Up @@ -232,7 +232,7 @@ func (n defaultParentRowInfoData) InternalID() uuid.UUID {
type unsupportedParentRowInfo struct {
}

func (n unsupportedParentRowInfo) ParentLevel(level int) parentRowInfoData {
func (n unsupportedParentRowInfo) ParentLevel(level int) ParentRowInfoData {
return &unsupportedParentRowInfoData{}
}

Expand Down

0 comments on commit 626c6f5

Please sign in to comment.