db_factory.go 2.2 KB

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