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 }