db_factory.go raw
1 //go:build js && wasm
2 // +build js,wasm
3
4 package idb
5
6 import (
7 "context"
8 "errors"
9 "sync"
10 "syscall/js"
11
12 "github.com/hack-pad/safejs"
13 )
14
15 // Factory lets applications asynchronously access the indexed databases. A typical program will call Global() to access window.indexedDB.
16 type Factory struct {
17 jsFactory safejs.Value
18 }
19
20 var (
21 global *Factory
22 globalErr error
23 globalOnce sync.Once
24 )
25
26 // Global returns the global IndexedDB instance.
27 // Can be called multiple times, will always return the same result (or error if one occurs).
28 func Global() *Factory {
29 globalOnce.Do(func() {
30 var jsFactory safejs.Value
31 jsFactory, globalErr = safejs.Global().Get("indexedDB")
32 if globalErr != nil {
33 return
34 }
35 var truthy bool
36 truthy, globalErr = jsFactory.Truthy()
37 if globalErr != nil {
38 return
39 }
40 if truthy {
41 global, globalErr = WrapFactory(safejs.Unsafe(jsFactory))
42 } else {
43 globalErr = errors.New("Global JS variable 'indexedDB' is not defined")
44 }
45 })
46 if globalErr != nil {
47 panic(globalErr)
48 }
49 return global
50 }
51
52 // WrapFactory wraps the given IDBFactory object
53 func WrapFactory(jsFactory js.Value) (*Factory, error) {
54 return &Factory{
55 jsFactory: safejs.Safe(jsFactory),
56 }, nil
57 }
58
59 // Open requests to open a connection to a database.
60 func (f *Factory) Open(upgradeCtx context.Context, name string, version uint, upgrader Upgrader) (*OpenDBRequest, error) {
61 args := []interface{}{name}
62 if version > 0 {
63 args = append(args, version)
64 }
65 reqValue, err := f.jsFactory.Call("open", args...)
66 if err != nil {
67 return nil, tryAsDOMException(err)
68 }
69 req := wrapRequest(nil, reqValue)
70 return newOpenDBRequest(upgradeCtx, req, upgrader)
71 }
72
73 // DeleteDatabase requests the deletion of a database.
74 func (f *Factory) DeleteDatabase(name string) (*AckRequest, error) {
75 reqValue, err := f.jsFactory.Call("deleteDatabase", name)
76 if err != nil {
77 return nil, tryAsDOMException(err)
78 }
79 req := wrapRequest(nil, reqValue)
80 return newAckRequest(req), nil
81 }
82
83 // CompareKeys compares two keys and returns a result indicating which one is greater in value.
84 func (f *Factory) CompareKeys(a, b js.Value) (int, error) {
85 compare, err := f.jsFactory.Call("cmp", a, b)
86 if err != nil {
87 return 0, tryAsDOMException(err)
88 }
89 return compare.Int()
90 }
91