From b0d6c948f49fca67be67fc493cf18a03f387fc44 Mon Sep 17 00:00:00 2001 From: jeronimoalbi Date: Wed, 11 Dec 2024 15:38:38 +0100 Subject: [PATCH] feat: change datasource to use a different package --- examples/gno.land/r/leon/hof/datasource.gno | 64 ++++--- .../gno.land/r/leon/hof/datasource_test.gno | 156 ++++++++++++++++++ 2 files changed, 195 insertions(+), 25 deletions(-) create mode 100644 examples/gno.land/r/leon/hof/datasource_test.gno diff --git a/examples/gno.land/r/leon/hof/datasource.gno b/examples/gno.land/r/leon/hof/datasource.gno index 7ab89db5b60..4647b08b979 100644 --- a/examples/gno.land/r/leon/hof/datasource.gno +++ b/examples/gno.land/r/leon/hof/datasource.gno @@ -3,33 +3,36 @@ package hof import ( "errors" + "gno.land/p/demo/avl" "gno.land/p/demo/seqid" "gno.land/p/demo/ufmt" - "gno.land/p/gnome/datasource" + "gno.land/p/jeronimoalbi/datasource" ) -type Datasource struct{} +func NewDatasource() Datasource { + return Datasource{exhibition} +} -func (ds Datasource) GetRecords(offset, _ int, _ string) datasource.RecordIterator { - return &iterator{index: offset} +type Datasource struct { + exhibition *Exhibition } -func (ds Datasource) GetContent(rawID string, fn func(content string)) error { - id, err := seqid.FromString(rawID) - if err != nil { - return err - } +func (ds Datasource) Size() int { return ds.exhibition.itemsSorted.Size() } - v, ok := exhibition.itemsSorted.Get(id.String()) - if !ok { - return errors.New("realm submission not found") +func (ds Datasource) Records(q datasource.Query) datasource.Iterator { + return &iterator{ + exhibition: ds.exhibition, + index: q.Offset, + maxIndex: q.Offset + q.Count, } +} - content := ufmt.Sprintf("# Submission #%d\n\n", int(id)) - content += v.(*Item).Render(false) - - fn(content) - return nil +func (ds Datasource) Record(id string) (datasource.Record, error) { + v, found := ds.exhibition.itemsSorted.Get(id) + if !found { + return nil, errors.New("realm submission not found") + } + return record{v.(*Item)}, nil } type record struct { @@ -37,27 +40,38 @@ type record struct { } func (r record) ID() string { return r.item.id.String() } -func (r record) Title() string { return r.item.pkgpath } -func (r record) Tags() []string { return nil } +func (r record) String() string { return r.item.pkgpath } + +func (r record) Fields() (datasource.Fields, error) { + fields := avl.NewTree() + fields.Set( + "details", + ufmt.Sprintf("Votes: ⏶ %d - ⏷ %d", r.item.upvote.Size(), r.item.downvote.Size()), + ) + return fields, nil +} -func (r record) Details() string { - return ufmt.Sprintf("Votes: ⏶ %d - ⏷ %d", r.item.upvote.Size(), r.item.downvote.Size()) +func (r record) Content() (string, error) { + content := ufmt.Sprintf("# Submission #%s\n\n", r.item.id.String()) + content += r.item.Render(false) + return content, nil } type iterator struct { - index int - record *record + exhibition *Exhibition + index, maxIndex int + record *record } func (it iterator) Record() datasource.Record { return it.record } func (it iterator) Err() error { return nil } func (it *iterator) Next() bool { - if it.index >= exhibition.itemsSorted.Size() { + if it.index >= it.maxIndex || it.index >= it.exhibition.itemsSorted.Size() { return false } - _, v := exhibition.itemsSorted.GetByIndex(it.index) + _, v := it.exhibition.itemsSorted.GetByIndex(it.index) it.record = &record{v.(*Item)} it.index++ return true diff --git a/examples/gno.land/r/leon/hof/datasource_test.gno b/examples/gno.land/r/leon/hof/datasource_test.gno new file mode 100644 index 00000000000..d3aec67f024 --- /dev/null +++ b/examples/gno.land/r/leon/hof/datasource_test.gno @@ -0,0 +1,156 @@ +package hof + +import ( + "testing" + + "gno.land/p/demo/avl" + "gno.land/p/demo/uassert" + "gno.land/p/demo/urequire" + "gno.land/p/jeronimoalbi/datasource" +) + +var ( + _ datasource.Datasource = (*Datasource)(nil) + _ datasource.Record = (*record)(nil) + _ datasource.Iterator = (*iterator)(nil) +) + +func TestDatasourceRecords(t *testing.T) { + cases := []struct { + name string + items []*Item + recordIDs []string + options []datasource.QueryOption + }{ + { + name: "all items", + items: []*Item{{id: 1}, {id: 2}, {id: 3}}, + recordIDs: []string{"0000001", "0000002", "0000003"}, + }, + { + name: "with offset", + items: []*Item{{id: 1}, {id: 2}, {id: 3}}, + recordIDs: []string{"0000002", "0000003"}, + options: []datasource.QueryOption{datasource.WithOffset(1)}, + }, + { + name: "with count", + items: []*Item{{id: 1}, {id: 2}, {id: 3}}, + recordIDs: []string{"0000001", "0000002"}, + options: []datasource.QueryOption{datasource.WithCount(2)}, + }, + { + name: "with offset and count", + items: []*Item{{id: 1}, {id: 2}, {id: 3}}, + recordIDs: []string{"0000002"}, + options: []datasource.QueryOption{ + datasource.WithOffset(1), + datasource.WithCount(1), + }, + }, + } + + for _, tc := range cases { + t.Run(tc.name, func(t *testing.T) { + // Initialize a local instance of exhibition + exhibition := &Exhibition{itemsSorted: avl.NewTree()} + for _, item := range tc.items { + exhibition.itemsSorted.Set(item.id.String(), item) + } + + // Get a records iterator + ds := Datasource{exhibition} + query := datasource.NewQuery(tc.options...) + iter := ds.Records(query) + + // Start asserting + urequire.Equal(t, len(tc.items), ds.Size(), "datasource size") + + var records []datasource.Record + for iter.Next() { + records = append(records, iter.Record()) + } + urequire.Equal(t, len(tc.recordIDs), len(records), "record count") + + for i, r := range records { + uassert.Equal(t, tc.recordIDs[i], r.ID()) + } + }) + } +} + +func TestDatasourceRecord(t *testing.T) { + cases := []struct { + name string + items []*Item + id string + err string + }{ + { + name: "found", + items: []*Item{{id: 1}, {id: 2}, {id: 3}}, + id: "0000001", + }, + { + name: "no found", + items: []*Item{{id: 1}, {id: 2}, {id: 3}}, + id: "42", + err: "realm submission not found", + }, + } + + for _, tc := range cases { + t.Run(tc.name, func(t *testing.T) { + // Initialize a local instance of exhibition + exhibition := &Exhibition{itemsSorted: avl.NewTree()} + for _, item := range tc.items { + exhibition.itemsSorted.Set(item.id.String(), item) + } + + // Get a single record + ds := Datasource{exhibition} + r, err := ds.Record(tc.id) + + // Start asserting + if tc.err != "" { + uassert.ErrorContains(t, err, tc.err) + return + } + + urequire.NoError(t, err, "no error") + urequire.NotEqual(t, nil, r, "record not nil") + uassert.Equal(t, tc.id, r.ID()) + }) + } +} + +func TestItemRecord(t *testing.T) { + pkgpath := "gno.land/r/demo/test" + item := Item{ + id: 1, + pkgpath: pkgpath, + blockNum: 42, + upvote: avl.NewTree(), + downvote: avl.NewTree(), + } + item.downvote.Set("g1jg8mtutu9khhfwc4nxmuhcpftf0pajdhfvsqf5", struct{}{}) + item.upvote.Set("g1w4ek2u33ta047h6lta047h6lta047h6ldvdwpn", struct{}{}) + item.upvote.Set("g1w4ek2u3jta047h6lta047h6lta047h6l9huexc", struct{}{}) + + r := record{&item} + + uassert.Equal(t, "0000001", r.ID()) + uassert.Equal(t, pkgpath, r.String()) + + fields, _ := r.Fields() + details, found := fields.Get("details") + urequire.True(t, found, "details field") + uassert.Equal(t, "Votes: ⏶ 2 - ⏷ 1", details) + + content, _ := r.Content() + wantContent := "# Submission #0000001\n\n\n```\ngno.land/r/demo/test\n```\n\nby demo\n\n" + + "[View realm](/r/demo/test)\n\nSubmitted at Block #42\n\n" + + "#### [2👍](/r/leon/hof$help&func=Upvote&pkgpath=gno.land/r/demo/test) - " + + "[1👎](/r/leon/hof$help&func=Downvote&pkgpath=gno.land/r/demo/test)\n\n" + uassert.Equal(t, wantContent, content) +}