encoding of query attrs

This commit is contained in:
Roy Crihfield 2023-10-19 08:47:21 -05:00 committed by Nabarun
parent 8d7e26515b
commit 69cf8f7b56
3 changed files with 80 additions and 25 deletions

View File

@ -3,12 +3,13 @@ package keeper_test
import (
"context"
"fmt"
"os"
"reflect"
"github.com/cerc-io/laconicd/x/registry/client/cli"
"github.com/cerc-io/laconicd/x/registry/helpers"
"github.com/cerc-io/laconicd/x/registry/keeper"
registrytypes "github.com/cerc-io/laconicd/x/registry/types"
"os"
"reflect"
)
func (suite *KeeperTestSuite) TestGrpcQueryParams() {

View File

@ -22,7 +22,10 @@ import (
paramtypes "github.com/cosmos/cosmos-sdk/x/params/types"
"github.com/tendermint/tendermint/libs/log"
cid "github.com/ipfs/go-cid"
"github.com/ipld/go-ipld-prime"
"github.com/ipld/go-ipld-prime/codec/dagjson"
cidlink "github.com/ipld/go-ipld-prime/linking/cid"
basicnode "github.com/ipld/go-ipld-prime/node/basic"
)
@ -147,10 +150,20 @@ func (k Keeper) ListRecords(ctx sdk.Context) []types.Record {
// RecordsFromAttributes gets a list of records whose attributes match all provided values
func (k Keeper) RecordsFromAttributes(ctx sdk.Context, attributes []*types.QueryListRecordsRequest_KeyValueInput, all bool) ([]types.Record, error) {
log := logger(ctx).With("function", "RecordsFromAttributes")
resultRecordIds := []string{}
for i, attr := range attributes {
val := GetAttributeValue(attr.Value)
val, err := EncodeAttributeValue2(attr.Value)
if err != nil {
return nil, err
}
attributeIndex := GetAttributesIndexKey(attr.Key, val)
log.Debug("attribute index",
"key", attr.Key,
"value", val,
"value_type", fmt.Sprintf("%T", val),
"index", attributeIndex)
recordIds, err := k.GetAttributeMapping(ctx, attributeIndex)
if err != nil {
return nil, err
@ -178,27 +191,38 @@ func (k Keeper) RecordsFromAttributes(ctx sdk.Context, attributes []*types.Query
return records, nil
}
func GetAttributeValue(input *types.QueryListRecordsRequest_ValueInput) interface{} {
// TODO non recursive
func EncodeAttributeValue2(input *types.QueryListRecordsRequest_ValueInput) ([]byte, error) {
np := basicnode.Prototype.Any
nb := np.NewBuilder()
switch value := input.GetValue().(type) {
case *types.QueryListRecordsRequest_ValueInput_String_:
return value.String_
nb.AssignString(value.String_)
case *types.QueryListRecordsRequest_ValueInput_Int:
return value.Int
nb.AssignInt(value.Int)
case *types.QueryListRecordsRequest_ValueInput_Float:
return value.Float
nb.AssignFloat(value.Float)
case *types.QueryListRecordsRequest_ValueInput_Boolean:
return value.Boolean
nb.AssignBool(value.Boolean)
case *types.QueryListRecordsRequest_ValueInput_Link:
return value.Link
link := cidlink.Link{Cid: cid.MustParse(value.Link)}
nb.AssignLink(link)
case *types.QueryListRecordsRequest_ValueInput_Array:
return value.Array
// TODO
case *types.QueryListRecordsRequest_ValueInput_Map:
return value.Map
case nil:
return nil
// TODO
default:
return fmt.Errorf("Value has unepxpected type %T", value)
return nil, fmt.Errorf("Value has unepxpected type %T", value)
}
n := nb.Build()
var buf bytes.Buffer
if err := dagjson.Encode(n, &buf); err != nil {
return nil, err
}
value := buf.Bytes()
return value, nil
}
func getIntersection(a []string, b []string) []string {
@ -341,22 +365,43 @@ func (k Keeper) PutRecord(ctx sdk.Context, record types.Record) {
k.updateBlockChangeSetForRecord(ctx, record.Id)
}
func (k Keeper) processAttributes(ctx sdk.Context, attrs map[string]any, id string, prefix string) error {
np := basicnode.Prototype.Any // Pick a stle for the in-memory data.
nb := np.NewBuilder() // Create a builder.
err := dagjson.Decode(nb, bytes.NewReader(content)) // Hand the builder to decoding -- decoding will fill it in!
func (k Keeper) processAttributes(ctx sdk.Context, attrs []byte, id string, prefix string) error {
np := basicnode.Prototype.Map
nb := np.NewBuilder()
err := dagjson.Decode(nb, bytes.NewReader(attrs))
if err != nil {
return "", err
return err
}
n := nb.Build() // Call 'Build' to get the resulting Node. (It's immutable!)
n := nb.Build()
if n.Kind() != ipld.Kind_Map {
return fmt.Errorf("Record attributes must be a map, not %T", n.Kind())
}
return k.processAttributeMap(ctx, n, id, prefix)
}
for key, value := range attrs {
if subRecord, ok := value.(map[string]any); ok {
err := k.processAttributes(ctx, subRecord, id, key)
func (k Keeper) processAttributeMap(ctx sdk.Context, n ipld.Node, id string, prefix string) error {
for it := n.MapIterator(); !it.Done(); {
keynode, valuenode, err := it.Next()
if err != nil {
return err
}
key, err := keynode.AsString()
if err != nil {
return err
}
// for key, value := range attrs {
if valuenode.Kind() == ipld.Kind_Map {
err := k.processAttributeMap(ctx, valuenode, id, key)
if err != nil {
return err
}
} else {
var buf bytes.Buffer
if err := dagjson.Encode(valuenode, &buf); err != nil {
return err
}
value := buf.Bytes()
indexKey := GetAttributesIndexKey(prefix+key, value)
if err := k.SetAttributeMapping(ctx, indexKey, id); err != nil {
return err

View File

@ -13,6 +13,16 @@ const (
AuthorityUnderAuction = "auction"
)
// TODO if schema records are to be more permissive than allowing a map of fields, this type will
// become specific to content records. schema records will either occupy a new message or have new
// more general purpose helper types.
type DagJsonBlob []byte
func (b DagJsonBlob) MarshalJSON() ([]byte, error) {
return b, nil
}
// ReadablePayload represents a signed record payload that can be serialized from/to YAML.
type ReadablePayload struct {
Record map[string]interface{} `json:"record"`
@ -44,7 +54,6 @@ func (payloadObj *ReadablePayload) ToPayload() Payload {
},
Signatures: payloadObj.Signatures,
}
// TODO rm error
return payload
}
@ -96,7 +105,7 @@ func (r *ReadableRecord) ToRecordObj() (Record, error) {
func (r *ReadableRecord) CanonicalJSON() []byte {
bytes, err := canonicalJson.Marshal(r.Attributes)
if err != nil {
panic("Record marshal error.")
panic("Record marshal error: " + err.Error())
}
return bytes