| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196 |
- //go:build js && wasm
- // +build js,wasm
- package idb
- import (
- "syscall/js"
- "github.com/hack-pad/go-indexeddb/idb/internal/jscache"
- "github.com/hack-pad/safejs"
- )
- var (
- jsObjectStore safejs.Value
- cursorDirectionCache jscache.Strings
- )
- func init() {
- var err error
- jsObjectStore, err = safejs.Global().Get("IDBObjectStore")
- if err != nil {
- panic(err)
- }
- }
- // CursorDirection is the direction of traversal of the cursor
- type CursorDirection int
- const (
- // CursorNext direction causes the cursor to be opened at the start of the source.
- CursorNext CursorDirection = iota
- // CursorNextUnique direction causes the cursor to be opened at the start of the source. For every key with duplicate values, only the first record is yielded.
- CursorNextUnique
- // CursorPrevious direction causes the cursor to be opened at the end of the source.
- CursorPrevious
- // CursorPreviousUnique direction causes the cursor to be opened at the end of the source. For every key with duplicate values, only the first record is yielded.
- CursorPreviousUnique
- )
- func parseCursorDirection(s string) CursorDirection {
- switch s {
- case "nextunique":
- return CursorNextUnique
- case "prev":
- return CursorPrevious
- case "prevunique":
- return CursorPreviousUnique
- default:
- return CursorNext
- }
- }
- func (d CursorDirection) String() string {
- switch d {
- case CursorNextUnique:
- return "nextunique"
- case CursorPrevious:
- return "prev"
- case CursorPreviousUnique:
- return "prevunique"
- default:
- return "next"
- }
- }
- func (d CursorDirection) jsValue() safejs.Value {
- return cursorDirectionCache.Value(d.String())
- }
- // Cursor represents a cursor for traversing or iterating over multiple records in a Database
- type Cursor struct {
- txn *Transaction
- jsCursor safejs.Value
- iterated bool // set to true when an iteration method is called, like Continue
- }
- func wrapCursor(txn *Transaction, jsCursor safejs.Value) *Cursor {
- if txn == nil {
- txn = (*Transaction)(nil)
- }
- return &Cursor{
- txn: txn,
- jsCursor: jsCursor,
- }
- }
- // Source returns the ObjectStore or Index that the cursor is iterating
- func (c *Cursor) Source() (objectStore *ObjectStore, index *Index, err error) {
- jsSource, err := c.jsCursor.Get("source")
- if err != nil {
- return
- }
- if isInstance, _ := jsSource.InstanceOf(jsObjectStore); isInstance {
- objectStore = wrapObjectStore(c.txn, jsSource)
- } else if isInstance, _ := jsSource.InstanceOf(jsIDBIndex); isInstance {
- index = wrapIndex(c.txn, jsSource)
- }
- return
- }
- // Direction returns the direction of traversal of the cursor
- func (c *Cursor) Direction() (CursorDirection, error) {
- direction, err := c.jsCursor.Get("direction")
- if err != nil {
- return 0, err
- }
- directionStr, err := direction.String()
- return parseCursorDirection(directionStr), err
- }
- // Key returns the key for the record at the cursor's position. If the cursor is outside its range, this is set to undefined.
- func (c *Cursor) Key() (js.Value, error) {
- value, err := c.jsCursor.Get("key")
- return safejs.Unsafe(value), err
- }
- // PrimaryKey returns the cursor's current effective primary key. If the cursor is currently being iterated or has iterated outside its range, this is set to undefined.
- func (c *Cursor) PrimaryKey() (js.Value, error) {
- value, err := c.jsCursor.Get("primaryKey")
- return safejs.Unsafe(value), err
- }
- // Request returns the Request that was used to obtain the cursor.
- func (c *Cursor) Request() (*Request, error) {
- reqValue, err := c.jsCursor.Get("request")
- if err != nil {
- return nil, err
- }
- return wrapRequest(c.txn, reqValue), nil
- }
- // Advance sets the number of times a cursor should move its position forward.
- func (c *Cursor) Advance(count uint) error {
- c.iterated = true
- _, err := c.jsCursor.Call("advance", count)
- return tryAsDOMException(err)
- }
- // Continue advances the cursor to the next position along its direction.
- func (c *Cursor) Continue() error {
- c.iterated = true
- _, err := c.jsCursor.Call("continue")
- return tryAsDOMException(err)
- }
- // ContinueKey advances the cursor to the next position along its direction.
- func (c *Cursor) ContinueKey(key js.Value) error {
- c.iterated = true
- _, err := c.jsCursor.Call("continue", key)
- return tryAsDOMException(err)
- }
- // ContinuePrimaryKey sets the cursor to the given index key and primary key given as arguments. Returns an error if the source is not an index.
- func (c *Cursor) ContinuePrimaryKey(key, primaryKey js.Value) error {
- c.iterated = true
- _, err := c.jsCursor.Call("continuePrimaryKey", key, primaryKey)
- return tryAsDOMException(err)
- }
- // Delete returns an AckRequest, and, in a separate thread, deletes the record at the cursor's position, without changing the cursor's position. This can be used to delete specific records.
- func (c *Cursor) Delete() (*AckRequest, error) {
- reqValue, err := c.jsCursor.Call("delete")
- if err != nil {
- return nil, tryAsDOMException(err)
- }
- req := wrapRequest(c.txn, reqValue)
- return newAckRequest(req), nil
- }
- // Update returns a Request, and, in a separate thread, updates the value at the current position of the cursor in the object store. This can be used to update specific records.
- func (c *Cursor) Update(value js.Value) (*Request, error) {
- reqValue, err := c.jsCursor.Call("update", value)
- if err != nil {
- return nil, tryAsDOMException(err)
- }
- return wrapRequest(c.txn, reqValue), nil
- }
- // CursorWithValue represents a cursor for traversing or iterating over multiple records in a database. It is the same as the Cursor, except that it includes the value property.
- type CursorWithValue struct {
- *Cursor
- }
- func newCursorWithValue(cursor *Cursor) *CursorWithValue {
- return &CursorWithValue{cursor}
- }
- func wrapCursorWithValue(txn *Transaction, jsCursor safejs.Value) *CursorWithValue {
- return newCursorWithValue(wrapCursor(txn, jsCursor))
- }
- // Value returns the value of the current cursor
- func (c *CursorWithValue) Value() (js.Value, error) {
- value, err := c.jsCursor.Get("value")
- return safejs.Unsafe(value), err
- }
|