1 //go:build js && wasm
2 // +build js,wasm
3 4 package idb
5 6 import (
7 "syscall/js"
8 9 "github.com/hack-pad/safejs"
10 )
11 12 // ObjectStoreOptions contains all available options for creating an ObjectStore
13 type ObjectStoreOptions struct {
14 KeyPath js.Value
15 AutoIncrement bool
16 }
17 18 // ObjectStore represents an object store in a database. Records within an object store are sorted according to their keys. This sorting enables fast insertion, look-up, and ordered retrieval.
19 type ObjectStore struct {
20 base *baseObjectStore // don't embed to avoid generated docs with the wrong receiver type (ObjectStore vs *ObjectStore)
21 }
22 23 func wrapObjectStore(txn *Transaction, jsObjectStore safejs.Value) *ObjectStore {
24 return &ObjectStore{wrapBaseObjectStore(txn, jsObjectStore)}
25 }
26 27 // IndexNames returns a list of the names of indexes on objects in this object store.
28 func (o *ObjectStore) IndexNames() ([]string, error) {
29 indexNames, err := o.base.jsObjectStore.Get("indexNames")
30 if err != nil {
31 return nil, err
32 }
33 return stringsFromArray(indexNames)
34 }
35 36 // KeyPath returns the key path of this object store. If this returns js.Null(), the application must provide a key for each modification operation.
37 func (o *ObjectStore) KeyPath() (safejs.Value, error) {
38 return o.base.jsObjectStore.Get("keyPath")
39 }
40 41 // Name returns the name of this object store.
42 func (o *ObjectStore) Name() (string, error) {
43 name, err := o.base.jsObjectStore.Get("name")
44 if err != nil {
45 return "", err
46 }
47 return name.String()
48 }
49 50 // Transaction returns the Transaction object to which this object store belongs.
51 func (o *ObjectStore) Transaction() (*Transaction, error) {
52 if o.base.txn == (*Transaction)(nil) {
53 return nil, errNotInTransaction
54 }
55 return o.base.txn, nil
56 }
57 58 // AutoIncrement returns the value of the auto increment flag for this object store.
59 func (o *ObjectStore) AutoIncrement() (bool, error) {
60 autoIncrement, err := o.base.jsObjectStore.Get("autoIncrement")
61 if err != nil {
62 return false, err
63 }
64 return autoIncrement.Bool()
65 }
66 67 // Add returns an AckRequest, and, in a separate thread, creates a structured clone of the value, and stores the cloned value in the object store. This is for adding new records to an object store.
68 func (o *ObjectStore) Add(value safejs.Value) (*AckRequest, error) {
69 reqValue, err := o.base.jsObjectStore.Call("add", value)
70 if err != nil {
71 return nil, tryAsDOMException(err)
72 }
73 req := wrapRequest(o.base.txn, reqValue)
74 return newAckRequest(req), nil
75 }
76 77 // AddKey is the same as Add, but includes the key to use to identify the record.
78 func (o *ObjectStore) AddKey(key, value safejs.Value) (*AckRequest, error) {
79 reqValue, err := o.base.jsObjectStore.Call("add", value, key)
80 if err != nil {
81 return nil, tryAsDOMException(err)
82 }
83 req := wrapRequest(o.base.txn, reqValue)
84 return newAckRequest(req), nil
85 }
86 87 // Clear returns an AckRequest, then clears this object store in a separate thread. This is for deleting all current records out of an object store.
88 func (o *ObjectStore) Clear() (*AckRequest, error) {
89 reqValue, err := o.base.jsObjectStore.Call("clear")
90 if err != nil {
91 return nil, tryAsDOMException(err)
92 }
93 req := wrapRequest(o.base.txn, reqValue)
94 return newAckRequest(req), nil
95 }
96 97 // Count returns a UintRequest, and, in a separate thread, returns the total number of records in the store.
98 func (o *ObjectStore) Count() (*UintRequest, error) {
99 return o.base.Count()
100 }
101 102 // CountKey returns a UintRequest, and, in a separate thread, returns the total number of records that match the provided key.
103 func (o *ObjectStore) CountKey(key safejs.Value) (*UintRequest, error) {
104 return o.base.CountKey(key)
105 }
106 107 // CountRange returns a UintRequest, and, in a separate thread, returns the total number of records that match the provided KeyRange.
108 func (o *ObjectStore) CountRange(keyRange *KeyRange) (*UintRequest, error) {
109 return o.base.CountRange(keyRange)
110 }
111 112 // CreateIndex creates a new index during a version upgrade, returning a new Index object in the connected database.
113 func (o *ObjectStore) CreateIndex(name string, keyPath safejs.Value, options IndexOptions) (*Index, error) {
114 jsIndex, err := o.base.jsObjectStore.Call("createIndex", name, keyPath, map[string]interface{}{
115 "unique": options.Unique,
116 "multiEntry": options.MultiEntry,
117 })
118 if err != nil {
119 return nil, tryAsDOMException(err)
120 }
121 return wrapIndex(o.base.txn, jsIndex), nil
122 }
123 124 // Delete returns an AckRequest, and, in a separate thread, deletes the store object selected by the specified key. This is for deleting individual records out of an object store.
125 func (o *ObjectStore) Delete(key safejs.Value) (*AckRequest, error) {
126 reqValue, err := o.base.jsObjectStore.Call("delete", key)
127 if err != nil {
128 return nil, tryAsDOMException(err)
129 }
130 req := wrapRequest(o.base.txn, reqValue)
131 return newAckRequest(req), nil
132 }
133 134 // DeleteIndex destroys the specified index in the connected database, used during a version upgrade.
135 func (o *ObjectStore) DeleteIndex(name string) error {
136 _, err := o.base.jsObjectStore.Call("deleteIndex", name)
137 return tryAsDOMException(err)
138 }
139 140 // GetAllKeys returns an ArrayRequest that retrieves record keys for all objects in the object store.
141 func (o *ObjectStore) GetAllKeys() (*ArrayRequest, error) {
142 return o.base.GetAllKeys()
143 }
144 145 // GetAllKeysRange returns an ArrayRequest that retrieves record keys for all objects in the object store matching the specified query. If maxCount is 0, retrieves all objects matching the query.
146 func (o *ObjectStore) GetAllKeysRange(query *KeyRange, maxCount uint) (*ArrayRequest, error) {
147 return o.base.GetAllKeysRange(query, maxCount)
148 }
149 150 // Get returns a Request, and, in a separate thread, returns the objects selected by the specified key. This is for retrieving specific records from an object store.
151 func (o *ObjectStore) Get(key safejs.Value) (*Request, error) {
152 return o.base.Get(key)
153 }
154 155 // GetKey returns a Request, and, in a separate thread retrieves and returns the record key for the object matching the specified parameter.
156 func (o *ObjectStore) GetKey(value safejs.Value) (*Request, error) {
157 return o.base.GetKey(value)
158 }
159 160 // Index opens an index from this object store after which it can, for example, be used to return a sequence of records sorted by that index using a cursor.
161 func (o *ObjectStore) Index(name string) (*Index, error) {
162 jsIndex, err := o.base.jsObjectStore.Call("index", name)
163 if err != nil {
164 return nil, tryAsDOMException(err)
165 }
166 return wrapIndex(o.base.txn, jsIndex), nil
167 }
168 169 // Put returns a Request, and, in a separate thread, creates a structured clone of the value, and stores the cloned value in the object store. This is for updating existing records in an object store when the transaction's mode is readwrite.
170 func (o *ObjectStore) Put(value safejs.Value) (*Request, error) {
171 reqValue, err := o.base.jsObjectStore.Call("put", value)
172 if err != nil {
173 return nil, tryAsDOMException(err)
174 }
175 return wrapRequest(o.base.txn, reqValue), nil
176 }
177 178 // PutKey is the same as Put, but includes the key to use to identify the record.
179 func (o *ObjectStore) PutKey(key, value safejs.Value) (*Request, error) {
180 reqValue, err := o.base.jsObjectStore.Call("put", value, key)
181 if err != nil {
182 return nil, tryAsDOMException(err)
183 }
184 return wrapRequest(o.base.txn, reqValue), nil
185 }
186 187 // OpenCursor returns a CursorWithValueRequest, and, in a separate thread, returns a new CursorWithValue. Used for iterating through an object store by primary key with a cursor.
188 func (o *ObjectStore) OpenCursor(direction CursorDirection) (*CursorWithValueRequest, error) {
189 return o.base.OpenCursor(direction)
190 }
191 192 // OpenCursorKey is the same as OpenCursor, but opens a cursor over the given key instead.
193 func (o *ObjectStore) OpenCursorKey(key safejs.Value, direction CursorDirection) (*CursorWithValueRequest, error) {
194 return o.base.OpenCursorKey(key, direction)
195 }
196 197 // OpenCursorRange is the same as OpenCursor, but opens a cursor over the given range instead.
198 func (o *ObjectStore) OpenCursorRange(keyRange *KeyRange, direction CursorDirection) (*CursorWithValueRequest, error) {
199 return o.base.OpenCursorRange(keyRange, direction)
200 }
201 202 // OpenKeyCursor returns a CursorRequest, and, in a separate thread, returns a new Cursor. Used for iterating through all keys in an object store.
203 func (o *ObjectStore) OpenKeyCursor(direction CursorDirection) (*CursorRequest, error) {
204 return o.base.OpenKeyCursor(direction)
205 }
206 207 // OpenKeyCursorKey is the same as OpenKeyCursor, but opens a cursor over the given key instead.
208 func (o *ObjectStore) OpenKeyCursorKey(key safejs.Value, direction CursorDirection) (*CursorRequest, error) {
209 return o.base.OpenKeyCursorKey(key, direction)
210 }
211 212 // OpenKeyCursorRange is the same as OpenKeyCursor, but opens a cursor over the given key range instead.
213 func (o *ObjectStore) OpenKeyCursorRange(keyRange *KeyRange, direction CursorDirection) (*CursorRequest, error) {
214 return o.base.OpenKeyCursorRange(keyRange, direction)
215 }
216