Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: adding support for arbitrary field #2717

Merged
merged 10 commits into from
Sep 11, 2024
67 changes: 45 additions & 22 deletions examples/gno.land/r/demo/profile/profile.gno
Original file line number Diff line number Diff line change
@@ -1,18 +1,19 @@
package profile

import (
"errors"
"std"

"gno.land/p/demo/avl"
"gno.land/p/demo/mux"
"gno.land/p/demo/ufmt"
)

var (
fields = avl.NewTree()
router = mux.NewRouter()
)

// Standard fields
const (
DisplayName = "DisplayName"
Homepage = "Homepage"
Expand All @@ -25,13 +26,28 @@ const (
InvalidField = "InvalidField"
)

// Events
const (
ProfileFieldCreated = "ProfileFieldCreated"
ProfileFieldUpdated = "ProfileFieldUpdated"
)

// Field types used when emitting event
const FieldType = "FieldType"

const (
BoolField = "BoolField"
StringField = "StringField"
IntField = "IntField"
)

func init() {
router.HandleFunc("", homeHandler)
router.HandleFunc("u/{addr}", profileHandler)
router.HandleFunc("f/{addr}/{field}", fieldHandler)
}

// list of supported string fields
// List of supported string fields
var stringFields = map[string]bool{
DisplayName: true,
Homepage: true,
Expand All @@ -41,54 +57,61 @@ var stringFields = map[string]bool{
GravatarEmail: true,
}

// list of support int fields
// List of support int fields
var intFields = map[string]bool{
Age: true,
}

// list of support bool fields
// List of support bool fields
var boolFields = map[string]bool{
AvailableForHiring: true,
}

// Setters

func SetStringField(field, value string) error {
func SetStringField(field, value string) bool {
addr := std.PrevRealm().Addr()
if _, ok := stringFields[field]; !ok {
return errors.New("invalid string field")
key := addr.String() + ":" + field
zivkovicmilos marked this conversation as resolved.
Show resolved Hide resolved
updated := fields.Set(key, value)

event := ProfileFieldCreated
if updated {
event = ProfileFieldUpdated
}

key := addr.String() + ":" + field
fields.Set(key, value)
std.Emit(event, FieldType, StringField, field, value)

return nil
return updated
}

func SetIntField(field string, value int) error {
func SetIntField(field string, value int) bool {
addr := std.PrevRealm().Addr()
key := addr.String() + ":" + field
updated := fields.Set(key, value)

if _, ok := intFields[field]; !ok {
return errors.New("invalid int field")
event := ProfileFieldCreated
if updated {
event = ProfileFieldUpdated
}

key := addr.String() + ":" + field
fields.Set(key, value)
std.Emit(event, FieldType, IntField, field, string(value))

return nil
return updated
}

func SetBoolField(field string, value bool) error {
func SetBoolField(field string, value bool) bool {
addr := std.PrevRealm().Addr()
key := addr.String() + ":" + field
updated := fields.Set(key, value)

if _, ok := boolFields[field]; !ok {
return errors.New("invalid bool field")
event := ProfileFieldCreated
if updated {
event = ProfileFieldUpdated
}

key := addr.String() + ":" + field
fields.Set(key, value)
std.Emit(event, FieldType, BoolField, field, ufmt.Sprintf("%t", value))

return nil
return updated
}

// Getters
Expand Down
94 changes: 59 additions & 35 deletions examples/gno.land/r/demo/profile/profile_test.gno
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,15 @@ func TestStringFields(t *testing.T) {
name := GetStringField(alice, DisplayName, "anon")
uassert.Equal(t, "anon", name)

// Set
err := SetStringField(DisplayName, "Alice foo")
uassert.NoError(t, err)
err = SetStringField(Homepage, "https://example.com")
uassert.NoError(t, err)
// Set new key
updated := SetStringField(DisplayName, "Alice foo")
uassert.Equal(t, updated, false)
updated = SetStringField(Homepage, "https://example.com")
uassert.Equal(t, updated, false)

// Update the key
updated = SetStringField(DisplayName, "Alice foo")
uassert.Equal(t, updated, true)

// Get after setting
name = GetStringField(alice, DisplayName, "anon")
Expand All @@ -50,9 +54,13 @@ func TestIntFields(t *testing.T) {
age := GetIntField(bob, Age, 25)
uassert.Equal(t, 25, age)

// Set
err := SetIntField(Age, 30)
uassert.NoError(t, err)
// Set new key
updated := SetIntField(Age, 30)
uassert.Equal(t, updated, false)

// Update the key
updated = SetIntField(Age, 30)
uassert.Equal(t, updated, true)

// Get after setting
age = GetIntField(bob, Age, 25)
Expand All @@ -67,45 +75,28 @@ func TestBoolFields(t *testing.T) {
uassert.Equal(t, false, hiring)

// Set
err := SetBoolField(AvailableForHiring, true)
uassert.NoError(t, err)
updated := SetBoolField(AvailableForHiring, true)
uassert.Equal(t, updated, false)

// Update the key
updated = SetBoolField(AvailableForHiring, true)
uassert.Equal(t, updated, true)

// Get after setting
hiring = GetBoolField(charlie, AvailableForHiring, false)
uassert.Equal(t, true, hiring)
}

func TestInvalidStringField(t *testing.T) {
std.TestSetRealm(std.NewUserRealm(dave))

err := SetStringField(InvalidField, "test")
uassert.Error(t, err)
}

func TestInvalidIntField(t *testing.T) {
std.TestSetRealm(std.NewUserRealm(eve))

err := SetIntField(InvalidField, 123)
uassert.Error(t, err)
}

func TestInvalidBoolField(t *testing.T) {
std.TestSetRealm(std.NewUserRealm(frank))

err := SetBoolField(InvalidField, true)
uassert.Error(t, err)
}

func TestMultipleProfiles(t *testing.T) {
// Set profile for user1
std.TestSetRealm(std.NewUserRealm(user1))
err := SetStringField(DisplayName, "User One")
uassert.NoError(t, err)
updated := SetStringField(DisplayName, "User One")
uassert.Equal(t, updated, false)

// Set profile for user2
std.TestSetRealm(std.NewUserRealm(user2))
err = SetStringField(DisplayName, "User Two")
uassert.NoError(t, err)
updated = SetStringField(DisplayName, "User Two")
uassert.Equal(t, updated, false)

// Get profiles
std.TestSetRealm(std.NewUserRealm(user1)) // Switch back to user1
Expand All @@ -116,3 +107,36 @@ func TestMultipleProfiles(t *testing.T) {
uassert.Equal(t, "User One", name1)
uassert.Equal(t, "User Two", name2)
}

func TestArbitraryStringField(t *testing.T) {
std.TestSetRealm(std.NewUserRealm(user1))

// Set arbitrary string field
updated := SetStringField("MyEmail", "my@email.com")
uassert.Equal(t, updated, false)

val := GetStringField(user1, "MyEmail", "")
uassert.Equal(t, val, "my@email.com")
}

func TestArbitraryIntField(t *testing.T) {
std.TestSetRealm(std.NewUserRealm(user1))

// Set arbitrary int field
updated := SetIntField("MyIncome", 100_000)
uassert.Equal(t, updated, false)

val := GetIntField(user1, "MyIncome", 0)
uassert.Equal(t, val, 100_000)
}

func TestArbitraryBoolField(t *testing.T) {
std.TestSetRealm(std.NewUserRealm(user1))

// Set arbitrary int field
updated := SetBoolField("IsWinner", true)
uassert.Equal(t, updated, false)

val := GetBoolField(user1, "IsWinner", false)
uassert.Equal(t, val, true)
}
Loading