Search Apps Documentation Source Content File Folder Download Copy Actions Download State String Boolean Number Struct Map Slice Pointer Function Closure Reference Nil Package Type Interface Unknown

datasource source pure

Package datasource defines generic interfaces for datasources.

Readme View source

Datasource Package

Package defines generic interfaces for datasources. A datasource is a set of records that can be read one at a time or iterated, and that can optionally be taggable so they can be filtered by category.

Datasources are useful when the data exchanged between different realms has to stay generic, avoiding direct dependencies between them. A realm that consumes records only needs to know the Datasource interface, not the realm that provides them.

The package doesn't ship a datasource implementation. It provides the contracts, a Query type configured with the WithOffset, WithCount, ByTag and WithFilter options, and the NewIterator and QueryRecords helpers. How each query option is honoured is up to the datasource. QueryRecords enforces the record count itself, so datasources only have to apply the tag, filters and offset.

Datasources that keep their records in memory can use NewRecordIterator to return the iterator that queries expect, and NewFieldsFromMap to expose a map as read-only record fields, instead of writing their own.

Warning

For security, any public function that accepts a Datasource as a parameter from external callers MUST verify that the received datasource is an expected canonical one.

Repository can be found at jeronimoalbi/gnome, as part of jeronimoalbi's Gno smart contracts monorepo.

Usage

  1package main
  2
  3import (
  4	"errors"
  5	"strings"
  6
  7	"gno.land/p/g17khqpukees4237dtn3astzapmp462vjhsz6st4/datasource"
  8)
  9
 10func main() {
 11	var ds datasource.Datasource = posts{
 12		{"1", "Hello Gno", []string{"gno"}},
 13		{"2", "Realms 101", []string{"gno", "realms"}},
 14		{"3", "Cooking pasta", []string{"food"}},
 15		{"4", "Testing in Gno", []string{"gno", "testing"}},
 16	}
 17
 18	// Get the first two records tagged with "gno"
 19	records, err := datasource.QueryRecords(
 20		ds,
 21		datasource.ByTag("gno"),
 22		datasource.WithCount(2),
 23	)
 24	if err != nil {
 25		panic(err)
 26	}
 27
 28	for _, r := range records {
 29		println(r.ID(), r.String())
 30	}
 31
 32	// Get the next page of records tagged with "gno"
 33	records, err = datasource.QueryRecords(
 34		ds,
 35		datasource.ByTag("gno"),
 36		datasource.WithOffset(2),
 37		datasource.WithCount(2),
 38	)
 39	if err != nil {
 40		panic(err)
 41	}
 42
 43	for _, r := range records {
 44		println(r.ID(), r.String())
 45	}
 46
 47	// Get a single record, and use its optional interfaces
 48	r, err := ds.Record("2")
 49	if err != nil {
 50		panic(err)
 51	}
 52
 53	if t, ok := r.(datasource.TaggableRecord); ok {
 54		println("Tags:", strings.Join(t.Tags(), ", "))
 55	}
 56
 57	fields, err := r.Fields()
 58	if err != nil {
 59		panic(err)
 60	}
 61
 62	title, _ := fields.Get("title")
 63	println("Title:", title.(string))
 64}
 65
 66// Datasource: A list of posts
 67type posts []post
 68
 69func (ps posts) Size() int { return len(ps) }
 70
 71func (ps posts) Record(id string) (datasource.Record, error) {
 72	for _, p := range ps {
 73		if p.id == id {
 74			return p, nil
 75		}
 76	}
 77	return nil, errors.New("record not found")
 78}
 79
 80func (ps posts) Records(q datasource.Query) datasource.Iterator {
 81	var records []datasource.Record
 82	for _, p := range ps {
 83		if q.Tag == "" || p.hasTag(q.Tag) {
 84			records = append(records, p)
 85		}
 86	}
 87
 88	if q.Offset >= len(records) {
 89		return datasource.NewRecordIterator(nil)
 90	}
 91	return datasource.NewRecordIterator(records[q.Offset:])
 92}
 93
 94// TaggableRecord: A post
 95type post struct {
 96	id    string
 97	title string
 98	tags  []string
 99}
100
101func (p post) ID() string     { return p.id }
102func (p post) String() string { return p.title }
103func (p post) Tags() []string { return p.tags }
104
105func (p post) Fields() (datasource.Fields, error) {
106	return datasource.NewFieldsFromMap(map[string]any{
107		"title": p.title,
108	}), nil
109}
110
111func (p post) hasTag(tag string) bool {
112	for _, t := range p.tags {
113		if t == tag {
114			return true
115		}
116	}
117	return false
118}
119
120// Output:
121// 1 Hello Gno
122// 2 Realms 101
123// 4 Testing in Gno
124// Tags: gno, realms
125// Title: Realms 101

Overview

Package datasource defines generic interfaces for datasources.

Datasources contain a set of records which can optionally be taggable. Tags can optionally be used to filter records by taxonomy.

Datasources can help in cases where the data sent during communication between different realms needs to be generic to avoid direct dependencies.

Constants 1

const DefaultQueryRecords

1const DefaultQueryRecords = 50
source

DefaultQueryRecords defines the default number of records returned by queries.

Variables 1

var ErrInvalidRecord

1var ErrInvalidRecord = errors.New("datasource records is not valid")
source

ErrInvalidRecord indicates that a datasource contains invalid records.

Functions 9

func NewFieldsFromMap

1func NewFieldsFromMap(m map[string]any) Fields
source

NewFieldsFromMap returns read-only fields for a map of field names and values.

The map is wrapped as is and not copied, so changes made to it by the caller are also visible through the returned fields.

func NewIterator

1func NewIterator(ds Datasource, options ...QueryOption) Iterator
source

NewIterator returns a new record iterator for a datasource query.

func NewRecordIterator

1func NewRecordIterator(records []Record) Iterator
source

NewRecordIterator returns an iterator for a list of records. The iterator never returns an error and it doesn't modify the slice.

func NewQuery

1func NewQuery(options ...QueryOption) Query
source

NewQuery creates a new datasource query.

func ByTag

1func ByTag(tag string) QueryOption
source

ByTag configures query to filter by tag.

func WithCount

1func WithCount(count int) QueryOption
source

WithCount configures the number of records that query returns.

func WithFilter

1func WithFilter(field string, value any) QueryOption
source

WithFilter assigns a new filter argument to a query. This option can be used multiple times if more than one filter has to be given to the query.

func WithOffset

1func WithOffset(offset int) QueryOption
source

WithOffset configures query to return records starting from an offset.

func QueryRecords

1func QueryRecords(ds Datasource, options ...QueryOption) ([]Record, error)
source

QueryRecords return a slice of records for a datasource query.

Types 8

type ContentRecord

interface
1type ContentRecord interface {
2	// Content returns the record content.
3	Content() (string, error)
4}
source

ContentRecord defines a datasource record that can return content.

type Datasource

interface
 1type Datasource interface {
 2	// Records returns a new datasource records iterator.
 3	Records(Query) Iterator
 4
 5	// Size returns the total number of records in the datasource.
 6	// When -1 is returned it means datasource doesn't support size.
 7	Size() int
 8
 9	// Record returns a single datasource record.
10	Record(id string) (Record, error)
11}
source

Datasource defines a generic datasource.

type Fields

interface
1type Fields interface {
2	// Has checks whether a field exists.
3	Has(name string) bool
4
5	// Get retrieves the value associated with the given field.
6	Get(name string) (value any, found bool)
7}
source

Fields defines an interface for read-only fields.

type Iterator

interface
 1type Iterator interface {
 2	// Next returns true when a new record is available.
 3	Next() bool
 4
 5	// Err returns any error raised when reading records.
 6	Err() error
 7
 8	// Record returns the current record.
 9	Record() Record
10}
source

Iterator defines an iterator of datasource records.

type Query

struct
 1type Query struct {
 2	// Offset of the first record to return during iteration.
 3	Offset int
 4
 5	// Count contains the number to records that query should return.
 6	Count int
 7
 8	// Tag contains a tag to use as filter for the records.
 9	Tag string
10
11	// Filters contains optional query filters by field value.
12	Filters avl.Tree
13}
source

Query contains datasource query options.

type QueryOption

func
1type QueryOption func(*Query)
source

QueryOption configures datasource queries.

type Record

interface
 1type Record interface {
 2	// ID returns the unique record's identifier.
 3	ID() string
 4
 5	// String returns a string representation of the record.
 6	String() string
 7
 8	// Fields returns record fields and values.
 9	Fields() (Fields, error)
10}
source

Record defines a datasource record.

type TaggableRecord

interface
1type TaggableRecord interface {
2	// Tags returns a list of tags for the record.
3	Tags() []string
4}
source

TaggableRecord defines a datasource record that supports tags. Tags can be used to build a taxonomy to filter records by category.

Imports 2

Source Files 6