go-vise

Constrained Size Output Virtual Machine
Info | Log | Files | Refs | README | LICENSE

db.go (4450B)


      1 package resource
      2 
      3 import (
      4 	"context"
      5 	"errors"
      6 
      7 	"git.defalsify.org/vise.git/db"
      8 )
      9 
     10 const (
     11 	resource_max_datatype = db.DATATYPE_STATICLOAD
     12 )
     13 
     14 // DbResource is a MenuResource that uses the given db.Db implementation as data retriever.
     15 //
     16 // It implements the Resource interface.
     17 //
     18 // The DbResource can resolve any db.DATATYPE_* if instructed to do so.
     19 type DbResource struct {
     20 	*MenuResource
     21 	typs uint8
     22 	db db.Db
     23 }
     24 
     25 // NewDbResource instantiates a new DbResource
     26 //
     27 // By default it will handle db.DATATYPE_TEPMLATE, db.DATATYPE_MENU and db.DATATYPE_BIN.
     28 func NewDbResource(store db.Db) *DbResource {
     29 	if !store.Safe() {
     30 		logg.Warnf("Db is not safe for use with resource. Make sure it is properly locked before issuing the first retrieval, or it will panic!")
     31 	}
     32 	rs := &DbResource{
     33 		MenuResource: NewMenuResource(),
     34 		db: store,
     35 		typs: db.DATATYPE_TEMPLATE | db.DATATYPE_MENU | db.DATATYPE_BIN,
     36 	}
     37 	rs.WithMenuGetter(rs.DbGetMenu)
     38 	rs.WithCodeGetter(rs.DbGetCode)
     39 	rs.WithTemplateGetter(rs.DbGetTemplate)
     40 	rs.WithEntryFuncGetter(rs.DbFuncFor)
     41 	return rs
     42 }
     43 
     44 // Without is a chainable function that disables handling of the given data type.
     45 func(g *DbResource) Without(typ uint8) *DbResource {
     46 	g.typs &= ^typ
     47 	return g
     48 }
     49 
     50 // Without is a chainable function that enables handling of the given data type.
     51 func(g *DbResource) With(typ uint8) *DbResource {
     52 	g.typs |= typ
     53 	return g
     54 }
     55 
     56 // WithOnly is a chainable convenience function that disables handling of all except the given data type.
     57 func(g *DbResource) WithOnly(typ uint8) *DbResource {
     58 	g.typs = typ
     59 	return g
     60 }
     61 
     62 func(g *DbResource) mustSafe() {
     63 	if !g.db.Safe() {
     64 		panic("db unsafe for resource (db.Db.Safe() == false)")
     65 	}
     66 }
     67 
     68 // retrieve from underlying db.
     69 func(g *DbResource) fn(ctx context.Context, sym string) ([]byte, error) {
     70 	g.mustSafe()
     71 	return g.db.Get(ctx, []byte(sym))
     72 }
     73 
     74 // retrieve from underlying db using a string key.
     75 func(g *DbResource) sfn(ctx context.Context, sym string) (string, error) {
     76 	b, err := g.fn(ctx, sym)
     77 	if err != nil {
     78 		return "", err
     79 	}
     80 	return string(b), nil
     81 }
     82 
     83 // Will fail if support for db.DATATYPE_TEMPLATE has been disabled.
     84 //
     85 // By default bound to GetTemplate. Can be replaced with WithTemplateGetter.
     86 func(g *DbResource) DbGetTemplate(ctx context.Context, sym string) (string, error) {
     87 	if g.typs & db.DATATYPE_TEMPLATE == 0 {
     88 		return "", errors.New("not a template getter")
     89 	}
     90 	g.db.SetPrefix(db.DATATYPE_TEMPLATE)
     91 	return g.sfn(ctx, sym)
     92 }
     93 
     94 // Will fail if support for db.DATATYPE_MENU has been disabled.
     95 //
     96 // By default bound to GetMenu. Can be replaced with WithMenuGetter.
     97 func(g *DbResource) DbGetMenu(ctx context.Context, sym string) (string, error) {
     98 	if g.typs & db.DATATYPE_MENU == 0{
     99 		return "", errors.New("not a menu getter")
    100 	}
    101 	g.db.SetPrefix(db.DATATYPE_MENU)
    102 	qSym := sym + "_menu"
    103 	v, err := g.sfn(ctx, qSym)
    104 	if err != nil {
    105 		if db.IsNotFound(err) {
    106 			logg.TraceCtxf(ctx, "menu unresolved", "sym", sym)
    107 			v = sym
    108 		}
    109 	}
    110 	return v, nil
    111 }
    112 
    113 // Will fail if support for db.DATATYPE_BIN has been disabled.
    114 //
    115 // By default bound to GetCode. Can be replaced with WithCodeGetter.
    116 func(g *DbResource) DbGetCode(ctx context.Context, sym string) ([]byte, error) {
    117 	logg.TraceCtxf(ctx, "getcode", "sym", sym)
    118 	if g.typs & db.DATATYPE_BIN == 0 {
    119 		return nil, errors.New("not a code getter")
    120 	}
    121 	g.db.SetPrefix(db.DATATYPE_BIN)
    122 	return g.fn(ctx, sym)
    123 }
    124 
    125 // The method will first attempt to resolve using the function registered
    126 // with the MenuResource parent class.
    127 // 
    128 // If no match is found, and if support for db.DATATYPE_STATICLOAD has been enabled,
    129 // an additional lookup will be performed using the underlying db.
    130 //
    131 // By default bound to FuncFor. Can be replaced with WithEntryFuncGetter.
    132 func(g *DbResource) DbFuncFor(ctx context.Context, sym string) (EntryFunc, error) {
    133 	fn, err := g.MenuResource.FallbackFunc(ctx, sym)
    134 	if err == nil {
    135 		return fn, nil
    136 	}
    137 	if g.typs & db.DATATYPE_STATICLOAD == 0 {
    138 		return nil, errors.New("not a staticload getter")
    139 	}
    140 	g.db.SetPrefix(db.DATATYPE_STATICLOAD)
    141 	b, err := g.fn(ctx, sym)
    142 	if err != nil {
    143 		if !db.IsNotFound(err) {
    144 			return nil, err
    145 		}
    146 		b, err = g.fn(ctx, sym + ".txt")
    147 		if err != nil {
    148 			return nil, err
    149 		}
    150 	}
    151 	return func(ctx context.Context, nodeSym string, input []byte) (Result, error) {
    152 		return Result{
    153 			Content: string(b),
    154 		}, nil
    155 	}, nil
    156 }
    157 
    158 // Close implements the Resource interface.
    159 func(g *DbResource) Close() error {
    160 	return g.db.Close()
    161 }