Replies: 6 comments 21 replies
-
This has come up with 2-3 in the past couple weeks. I would love to see this land in the sdk. Are there more docs I can read on it, I would like to start using the package sooner rather than later. |
Beta Was this translation helpful? Give feedback.
-
I concur with the problem outlined by this discussion. There's a lack of information on how keys should be structured, not only for the purpose of creating second idxs, but also in terms of format and ordering of its components. This ordering affects how range iteration is performed and is usually very error-prone or underperforming due to the lack of docs. I agree with @marbar3778 that this should definitely be included on the SDK and that we should create a comprehensive doc for keys and prefixing as the acceptance criteria so that other apps can also follow the standards we set for the SDK. |
Beta Was this translation helpful? Give feedback.
-
Proposed Upgrades to ORMI’d like to propose a future direction that is a hybrid of the current ORM and AIB’s State Object proposal. /cc @fdymylja @jgimeno @robert-zaremba @blushi Store Objects/Tables in proto files
message Balance {
option (cosmos_proto.table) = {
primary_key: "address, denom"
index: "denom, address"
};
bytes address = 1;
string denom = 2;
string amount = 3;
} Auto-generated store object clients
type BalanceClient interface {
Get(ctx context.Context, address []byte, denom string, opts ...client.GetOption) (*Balance, error)
List(ctx context.Context, opts ...client.ListOption) (BalanceIterator, error)
ListByAddress(ctx context.Context, address []byte, opts ...client.ListOption) (BalanceIterator, error)
ListByDenom(ctx context.Context, denom string, opts ...client.ListOption) (BalanceIterator, error)
Create(ctx context.Context, balance *Balance, opts ...client.CreateOption) error
Delete(ctx context.Context, balance *Balance, opts ...client.DeleteOption) error
Update(ctx context.Context, balance *Balance, opts ...client.UpdateOption) error
} This Also, primary key storage should be handled efficiently via code generation, meaning:
I have included a context in the Proof FormatWith the separation of
I believe this will allow for a much better client UX for proofs because the:
Other possibilities
|
Beta Was this translation helpful? Give feedback.
-
The API I was experimenting with for ORM Objects was a fastpath implementation of protoreflect. Given the protobuf ORM Object definition: syntax="proto3";
package cosmos.base.orm.v1alpha1;
option go_package = "github.com/cosmos/cosmos-sdk/orm/types";
// SchemaDefinition defines an ORM object schema definition
message SchemaDefinition {
// singleton marks if the object is a singleton
// by singleton we mean an object of which only
// one instance can exist in the object namespace.
// if singleton is set to true, primary_keys and
// secondary_keys must be empty and autoincrement must
// be set to false.
bool singleton = 1;
// auto_id marks associates the object with an unique
// ID which is auto generated and increased each time
// a new object is created in the namespace.
// If auto_id is set to true, singleton must be false
// and primary_keys must be empty, there can be secondary keys.
bool auto_id = 2;
// primary_keys marks the fields that are used to
// to save the concrete object.
repeated string primary_keys = 3;
// secondary_keys marks the field of the object
// that are used to make the object queryable
// by its fields.
repeated string secondary_keys = 4;
} The following would be the // Object represents an object that can be used with ORM
type Object interface {
codec.ProtoMarshaler
// NewObject instantiates a new empty instance of Object
NewObject() Object
// UnsetField unsets Object's field given its protoreflect.FieldDescriptor.
// It panics if the field is not part of the Object
UnsetField(field protoreflect.FieldDescriptor)
// SetField sets the Object's field given its protoreflect.FieldDescriptor.
// It panics if the field is not part of the Object or if the
// protoreflect.Value used is of a kind that does not match the field.
SetField(field protoreflect.FileDescriptor, value protoreflect.Value)
// GetField gets the Object's field given its protoreflect.FieldDescriptor
// It panics if the field is not part of the Object.
GetField(field protoreflect.FieldDescriptor) protoreflect.Value
} This API is flexible enough to allow us to build the primary keys and secondary keys of object. The idea is that then given a type Schema interface {
// Name returns the name identifier, represented as the protobuf fullname of the object
Name() string
// TypePrefix identifies the [2]byte prefix for the object namespace
TypePrefix() TypePrefix
// EncodePrimaryKey returns the primary key of the provided orm.Object
EncodePrimaryKey(object orm.Object) []byte
// EncodeObject encodes the orm.Object after resetting its primary key fields
// NOTE: the fields are set back after encoding, but this means that orm.Object
// cannot be used concurrently when is being encoded by Schema
EncodeObject(object orm.Object) []byte
// DecodeObject decodes the orm.Object given its primary key and value
DecodeObject(primaryKey []byte, value[]byte, object orm.Object)
// EncodeSecondaryKeyByName encodes the field of the provided object
// after retrieving its value given the protoreflect.Name of the field
EncodeSecondaryKeyByName(fieldName protoreflect.Name, object orm.Object) []byte
// EncodeSecondaryKey encodes the field of the provided object
// after retrieving its value given the protoreflect.FieldDescriptor of the field
EncodeSecondaryKey(fd protoreflect.FieldDescriptor, object orm.Object) []byte
} For example, if balance was a StateObject, the following would be the generated interface implementation of StateObject: type Balance struct {
Owner []byte
Amount string (sdk.Coin)
}
func (x Balance) GetField(fd protoreflect.FieldDescriptor) protoreflect.Value {
switch fd.Name() {
case "owner":
return protoreflect.ValueOfBytes(x.Owner)
case "amount":
return protoreflect.ValueOfString(x.Owner)
default:
panic("object blabla does not have field bla bla")
}
}
func (x *Balance) SetField(fd protoreflect.FieldDescriptor, value protoreflect.Value) {
switch fd.Name() {
case "owner":
x.Owner = value.Bytes()
...
}
}
func (x *Balance) UnsetField(fd protoreflect.FieldDescriptor) { ... } |
Beta Was this translation helpful? Give feedback.
-
Somewhat related to #9337, we can use the design in #9156 (comment)) to define generic URIs for any on-chain entity. Maybe something like:
Ex: The question of how to uniquely name a chain in an IBC context is still an unsolved problem, but this sort of URI format could still be useful for off-chain linked data (i.e. RDF, JSON-LD) use cases where there is social consensus on chain names. Also in a linked data context, we could define a JSON-LD serialization of an entity as its proto JSON serialization with a linked data context that maps every field name to a URI like /cc @blushi @clevinson |
Beta Was this translation helpful? Give feedback.
-
Auxiliary Module StoreLinking a proposal of using a separate store for managing helper records (helper record is a record which doesn't need a state proof, but it's needed to efficiently process a transaction). |
Beta Was this translation helpful? Give feedback.
-
This is linked to meta-issue #7096.
Summary
This issue proposes a new table-store package which allows for automatic secondary index creation. The code for this already exists here: https://github.com/regen-network/cosmos-modules/tree/master/incubator/orm but it is not part of the SDK.
Problem Definition
Oftentimes modules want to create secondary indexes for data being stored. A good example is
x/staking
(seex/staking/types/keys.go
). As can be seen in thex/staking
example, it is fairly complex to do this manually.Proposal
The table-store package would provide a framework for creating effectively database tables with primary and secondary keys.
The current implementation of this is called
orm
(for object-relational mapping), but a more correct name is likely table-store. Instead of a key-value store, we actually have a relational database table store.Currently this implementation has support for:
uint64
primary keysuint64
secondary indexes[]byte
secondary indexesMore functionality could be added as needed.
This is related to the proposed store decoders in #9158. The table store decoder would automatically implement the interface described there so that modules using the table store would be automatically indexable in databases like PostgreSQL.
/cc @blushi @i-norden @robert-zaremba
Beta Was this translation helpful? Give feedback.
All reactions