PathrockNetwork Gno Explorer
HomeBlocksTransactionsTokensRealmsPackagesValidatorsAnalytics

PathrockNetwork Gno Explorer — an independent explorer for Gno.land Mainnet (gnoland-1), operated by PathrockNetwork. Not an official Gno.land service.

gnowebarchive RPC

gno.land/p/g17khqpukees4237dtn3astzapmp462vjhsz6st4/datastore

Package
Open in gnoweb ↗

Overview

Kind
Pure package
Name
datastore
Namespace
g17khqpukees4237dtn3astzapmp462vjhsz6st4
Files
11 (README)(gnomod.toml)
Exported functions
n/a — not supported for pure packages by the node (vm/qfuncs)
Module
gno.land/p/g17khqpukees4237dtn3astzapmp462vjhsz6st4/datastore
gno
0.9

Files (11)

  • README.mdmarkdown
  • gnomod.tomltoml
  • datastore.gnogno
  • index.gnogno
  • query_options.gnogno
  • query.gnogno
  • record.gnogno
  • schema_options.gnogno
  • schema.gnogno
  • storage_options.gnogno
  • storage.gnogno
  • storage.gnogno
    1package datastore23import (4	"errors"5	"strings"67	"gno.land/p/moul/collection/v0"8

    Functions

    not supported for pure packages by the node (vm/qfuncs)

    Signatures reconstructed verbatim from vm/qfuncs — interface params keep their inline definitions.

    "gno.land/p/nt/bptree/v0"
    9 "gno.land/p/nt/seqid/v0"
    10)
    11
    12// NewStorage creates a new records storage.
    13func NewStorage(name string, options ...StorageOption) Storage {
    14 s := Storage{
    15 name: name,
    16 collection: collection.New(),
    17 schema: NewSchema(strings.Title(name)),
    18 }
    19
    20 for _, apply := range options {
    21 apply(&s)
    22 }
    23 return s
    24}
    25
    26// Storage stores a collection of records.
    27//
    28// By default it searches records by record ID but it allows
    29// using custom user defined indexes for other record fields.
    30//
    31// When a storage is created it defines a default schema that
    32// keeps track of record fields. Storage can be optionally
    33// created with a user defined schema in cases where the number
    34// of fields has to be pre-defined or when new records must have
    35// one or more fields initialized to default values.
    36type Storage struct {
    37 name string
    38 collection *collection.Collection
    39 schema *Schema
    40}
    41
    42// Name returns storage's name.
    43func (s Storage) Name() string {
    44 return s.name
    45}
    46
    47// Collection returns the undelying collection used by the
    48// storage to store all records.
    49func (s Storage) Collection() *collection.Collection {
    50 return s.collection
    51}
    52
    53// Schema returns the schema being used to track record fields.
    54func (s Storage) Schema() *Schema {
    55 return s.schema
    56}
    57
    58// Size returns the number of records that the storage have.
    59func (s Storage) Size() int {
    60 return s.collection.GetIndex(collection.IDIndex).Size()
    61}
    62
    63// NewRecord creates a new storage record.
    64//
    65// If a custom schema with default field values is assigned to
    66// storage it's used to assign initial default values when new
    67// records are created.
    68//
    69// Creating a new record doesn't assign an ID to it, a new ID
    70// is generated and assigned to the record when it's saved for
    71// the first time.
    72func (s Storage) NewRecord() Record {
    73 r := &record{
    74 schema: s.schema,
    75 collection: s.collection,
    76 values: bptree.NewBPTree32(),
    77 }
    78
    79 // Assign default record values if the schema defines them
    80 for i, name := range s.schema.Fields() {
    81 if v, found := s.schema.GetDefaultByIndex(i); found {
    82 r.Set(name, v)
    83 }
    84 }
    85 return r
    86}
    87
    88// Query returns a recordset that matches the query parameters.
    89// By default query selects records using the ID index.
    90//
    91// Example usage:
    92//
    93// // Get 50 records starting from the one at position 100
    94// rs, _ := storage.Query(
    95// WithOffset(100),
    96// WithSize(50),
    97// )
    98//
    99// // Iterate records to create a new slice
    100// var records []Record
    101// rs.Iterate(func (r Record) bool {
    102// records = append(records, r)
    103// return false
    104// })
    105func (s Storage) Query(options ...QueryOption) (Recordset, error) {
    106 // Initialize the recordset for the query
    107 rs := recordset{
    108 query: defaultQuery,
    109 records: s.collection.GetIndex(collection.IDIndex),
    110 }
    111
    112 for _, apply := range options {
    113 if err := apply(&rs.query); err != nil {
    114 return nil, err
    115 }
    116 }
    117
    118 indexName := rs.query.IndexName()
    119 if indexName != collection.IDIndex {
    120 // When using a custom index get the keys to get records from the ID index
    121 keys, err := s.getIndexRecordsKeys(indexName, rs.query.IndexKey())
    122 if err != nil {
    123 return nil, err
    124 }
    125
    126 // Adjust the number of keys to match available query options
    127 if offset := rs.query.Offset(); offset > 0 {
    128 if offset > len(keys) {
    129 keys = nil
    130 } else {
    131 keys = keys[offset:]
    132 }
    133 }
    134
    135 if size := rs.query.Size(); size > 0 && size < len(keys) {
    136 keys = keys[:size]
    137 }
    138
    139 rs.keys = keys
    140 rs.size = len(keys)
    141 } else {
    142 // When using the default ID index init size with the total number of records
    143 rs.size = rs.records.Size()
    144
    145 // Adjust recordset size to match available query options
    146 if offset := rs.query.Offset(); offset > 0 {
    147 if offset > rs.size {
    148 rs.size = 0
    149 } else {
    150 rs.size -= offset
    151 }
    152 }
    153
    154 if size := rs.query.Size(); size > 0 && size < rs.size {
    155 rs.size = size
    156 }
    157 }
    158
    159 return rs, nil
    160}
    161
    162// MustQuery returns a recordset that matches the query parameters or panics on error.
    163// By default query selects records using the ID index.
    164//
    165// Example usage:
    166//
    167// // Get 50 records starting from the one at position 100
    168// var records []Record
    169// storage.MustQuery(
    170// WithOffset(100),
    171// WithSize(50),
    172// ).Iterate(func (r Record) bool {
    173// records = append(records, r)
    174// return false
    175// })
    176func (s Storage) MustQuery(options ...QueryOption) Recordset {
    177 rs, err := s.Query(options...)
    178 if err != nil {
    179 panic(err)
    180 }
    181 return rs
    182}
    183
    184// Get returns the first record found for a key within a storage index.
    185//
    186// This is a convenience method to get a single record. A multi index will
    187// always return the first record value for the specified key in this case.
    188// To get multiple records create a query using a custom index and key value
    189// or use the underlying storage collection.
    190func (s Storage) Get(indexName, indexKey string) (_ Record, found bool) {
    191 iter := s.collection.Get(indexName, indexKey)
    192 if iter.Next() {
    193 return iter.Value().Obj.(Record), true
    194 }
    195 return nil, false
    196}
    197
    198// GetByID returns a record whose ID matches the specified ID.
    199func (s Storage) GetByID(id uint64) (_ Record, found bool) {
    200 iter := s.collection.Get(collection.IDIndex, seqid.ID(id).String())
    201 if iter.Next() {
    202 return iter.Value().Obj.(Record), true
    203 }
    204 return nil, false
    205}
    206
    207// Delete deletes a record from the storage.
    208func (s Storage) Delete(id uint64) bool {
    209 return s.collection.Delete(id)
    210}
    211
    212func (s Storage) getIndexRecordsKeys(indexName, indexKey string) ([]string, error) {
    213 idx := s.collection.GetIndex(indexName)
    214 if idx == nil {
    215 return nil, errors.New("storage index for query not found: " + indexName)
    216 }
    217
    218 keys := castIfaceToRecordKeys(idx.Get(indexKey))
    219 if keys == nil {
    220 return nil, errors.New("unexpected storage index key format")
    221 }
    222 return keys, nil
    223}
    224
    225func castIfaceToRecordKeys(v interface{}) []string {
    226 switch k := v.(type) {
    227 case []string:
    228 return k
    229 case string:
    230 return []string{k}
    231 }
    232 return nil
    233}
    234