Skip to content

Commit

Permalink
Merge pull request #32 from hyperledger-labs/refactor/update-recursive
Browse files Browse the repository at this point in the history
Refactor putRecursive to avoid getRecursive and updating unchanged assets
  • Loading branch information
andremacedopv authored Dec 12, 2023
2 parents 6546b51 + b7ef139 commit 01e3bd7
Show file tree
Hide file tree
Showing 3 changed files with 313 additions and 147 deletions.
93 changes: 52 additions & 41 deletions assets/put.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package assets
import (
"encoding/json"
"fmt"
"reflect"
"strings"

"github.com/hyperledger-labs/cc-tools/errors"
Expand Down Expand Up @@ -92,60 +93,62 @@ func (a *Asset) PutNew(stub *sw.StubWrapper) (map[string]interface{}, errors.ICC
return res, nil
}

func putRecursive(stub *sw.StubWrapper, object map[string]interface{}, root bool) (map[string]interface{}, errors.ICCError) {
func putRecursive(stub *sw.StubWrapper, object map[string]interface{}) (map[string]interface{}, errors.ICCError) {
var err error

objAsKey, err := NewKey(object)
if err != nil {
return nil, errors.WrapError(err, "unable to create asset object")
}

if !root {
exists, err := objAsKey.ExistsInLedger(stub)
exists, err := objAsKey.ExistsInLedger(stub)
if err != nil {
return nil, errors.WrapError(err, "failed checking if asset exists")
}

propsToUpdate := map[string]bool{}
if exists {
asset, err := objAsKey.GetMap(stub)
if err != nil {
return nil, errors.WrapError(err, "failed checking if asset exists")
return nil, errors.WrapError(err, "failed fetching asset that already exists")
}
if exists {
asset, err := objAsKey.GetRecursive(stub)
if err != nil {
return nil, errors.WrapError(err, "failed fetching sub-asset that already exists")
}
if asset == nil {
return nil, errors.NewCCError("existing sub-asset could not be fetched", 404)
}

// If asset key is not in object, add asset value to object (so that properties are not erased)
for k := range asset {
if _, ok := object[k]; !ok {
object[k] = asset[k]
}
// If asset key is not in object, add asset value to object (so that properties are not erased)
for k := range asset {
if _, ok := object[k]; !ok {
object[k] = asset[k]
}

// TODO: check property by property if asset must be updated
}
}

objAsAsset, err := NewAsset(object)
if err != nil {
return nil, errors.WrapError(err, "unable to create asset object")
// Check props to update
for k, v := range object {
if !reflect.DeepEqual(v, asset[k]) {
propsToUpdate[k] = true
}
}
}

subAssetsMap := map[string]interface{}{}
subAssets := objAsAsset.Type().SubAssets()
subAssets := objAsKey.Type().SubAssets()
for _, subAsset := range subAssets {
subAssetInterface, ok := object[subAsset.Tag]
if !ok {
// if subAsset is not included, continue onwards to the next possible subAsset
continue
}

if propsToUpdate[subAsset.Tag] {
delete(propsToUpdate, subAsset.Tag)
}

// Extract asset type
isArray := false
dType := subAsset.DataType
if strings.HasPrefix(dType, "[]") {
isArray = true
dType = strings.TrimPrefix(dType, "[]")
}

dType = strings.TrimPrefix(dType, "->")
subAssetInterface, ok := object[subAsset.Tag]
if !ok {
// if subAsset is not included, continue onwards to the next possible subAsset
continue
}

var objArray []interface{}
if !isArray {
Expand Down Expand Up @@ -178,36 +181,44 @@ func putRecursive(stub *sw.StubWrapper, object map[string]interface{}, root bool
return nil, errors.NewCCError(fmt.Sprintf("asset reference property '%s' must have an '@assetType' property", subAsset.Tag), 400)
}
}
putSubAsset, err := putRecursive(stub, obj, false)
putSubAsset, err := putRecursive(stub, obj)
if err != nil {
return nil, errors.WrapError(err, fmt.Sprintf("failed to put sub-asset %s recursively", subAsset.Tag))
}
objArray[idx] = putSubAsset
}

if isArray {
subAssetsMap[subAsset.Tag] = objArray
object[subAsset.Tag] = objArray
} else {
subAssetsMap[subAsset.Tag] = objArray[0]
object[subAsset.Tag] = objArray[0]
}
subAssetsMap[subAsset.Tag] = object[subAsset.Tag]
}

putAsset, err := objAsAsset.Put(stub)
if err != nil {
return nil, errors.WrapError(err, fmt.Sprintf("failed to put asset of type %s", objAsAsset.TypeTag()))
}
if shouldUpdate := len(propsToUpdate) > 0; shouldUpdate || !exists {
objAsAsset, err := NewAsset(object)
if err != nil {
return nil, errors.WrapError(err, "unable to create asset object")
}

for tag, subAsset := range subAssetsMap {
putAsset[tag] = subAsset
object, err = objAsAsset.Put(stub)
if err != nil {
return nil, errors.WrapError(err, fmt.Sprintf("failed to put asset of type %s", objAsAsset.TypeTag()))
}

for tag, subAsset := range subAssetsMap {
object[tag] = subAsset
}
}

return putAsset, nil
return object, nil
}

// PutRecursive inserts asset and all its subassets in blockchain.
// This method is experimental and might not work as intended. Use with caution.
func PutRecursive(stub *sw.StubWrapper, object map[string]interface{}) (map[string]interface{}, errors.ICCError) {
return putRecursive(stub, object, true)
return putRecursive(stub, object)
}

// PutNewRecursive inserts asset and all its subassets in blockchain
Expand Down
8 changes: 3 additions & 5 deletions assets/update.go
Original file line number Diff line number Diff line change
Expand Up @@ -159,11 +159,9 @@ func (k *Key) Update(stub *sw.StubWrapper, update map[string]interface{}) (map[s
writePermission = true
break
}
} else { // if writer is not regexp
if w == txCreator {
writePermission = true
break
}
} else if w == txCreator { // if writer is not regexp
writePermission = true
break
}
}
if !writePermission {
Expand Down
Loading

0 comments on commit 01e3bd7

Please sign in to comment.