or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

cursor-navigation.mddatabase-operations.mdenhanced-database.mdindex-operations.mdindex.mdobject-store-operations.mdpromise-wrapping.mdtransaction-management.md
tile.json

object-store-operations.mddocs/

0

# Object Store Operations

1

2

Enhanced object store interface with promise-based operations and async iteration support.

3

4

## Capabilities

5

6

### Store Properties

7

8

Access object store metadata and transaction information.

9

10

```typescript { .api }

11

/**

12

* The names of indexes in the store

13

*/

14

readonly indexNames: TypedDOMStringList<IndexNames<DBTypes, StoreName>>;

15

16

/**

17

* The associated transaction

18

*/

19

readonly transaction: IDBPTransaction<DBTypes, TxStores, Mode>;

20

```

21

22

**Usage Examples:**

23

24

```typescript

25

const tx = db.transaction("users", "readwrite");

26

const userStore = tx.store;

27

28

// Check available indexes

29

console.log("Available indexes:", [...userStore.indexNames]);

30

31

// Access parent transaction

32

console.log("Transaction mode:", userStore.transaction.mode);

33

34

// Check if specific index exists

35

if (userStore.indexNames.contains("email")) {

36

const emailIndex = userStore.index("email");

37

const userByEmail = await emailIndex.get("alice@example.com");

38

}

39

```

40

41

### Data Modification Operations

42

43

Add, update, and delete records in the object store.

44

45

#### Add Operation

46

47

```typescript { .api }

48

/**

49

* Add a value to the store

50

* Rejects if an item of a given key already exists in the store

51

* Only available in readwrite and versionchange transactions

52

* @param value - Value to add to the store

53

* @param key - Optional key (if not using keyPath)

54

* @returns Promise resolving to the key of the added item

55

*/

56

add: Mode extends 'readonly'

57

? undefined

58

: (

59

value: StoreValue<DBTypes, StoreName>,

60

key?: StoreKey<DBTypes, StoreName> | IDBKeyRange

61

) => Promise<StoreKey<DBTypes, StoreName>>;

62

```

63

64

#### Put Operation

65

66

```typescript { .api }

67

/**

68

* Put an item in the store

69

* Replaces any item with the same key

70

* Only available in readwrite and versionchange transactions

71

* @param value - Value to put in the store

72

* @param key - Optional key (if not using keyPath)

73

* @returns Promise resolving to the key of the stored item

74

*/

75

put: Mode extends 'readonly'

76

? undefined

77

: (

78

value: StoreValue<DBTypes, StoreName>,

79

key?: StoreKey<DBTypes, StoreName> | IDBKeyRange

80

) => Promise<StoreKey<DBTypes, StoreName>>;

81

```

82

83

#### Delete Operation

84

85

```typescript { .api }

86

/**

87

* Deletes records in store matching the given query

88

* Only available in readwrite and versionchange transactions

89

* @param key - Key or key range to delete

90

* @returns Promise that resolves when deletion is complete

91

*/

92

delete: Mode extends 'readonly'

93

? undefined

94

: (key: StoreKey<DBTypes, StoreName> | IDBKeyRange) => Promise<void>;

95

```

96

97

#### Clear Operation

98

99

```typescript { .api }

100

/**

101

* Deletes all records in store

102

* Only available in readwrite and versionchange transactions

103

* @returns Promise that resolves when clearing is complete

104

*/

105

clear: Mode extends 'readonly' ? undefined : () => Promise<void>;

106

```

107

108

**Data Modification Examples:**

109

110

```typescript

111

// Write operations (readwrite transaction required)

112

const tx = db.transaction("users", "readwrite");

113

const userStore = tx.store;

114

115

// Add new records (fails if key exists)

116

const userId1 = await userStore.add({ name: "Alice", email: "alice@example.com" });

117

const userId2 = await userStore.add({ name: "Bob", email: "bob@example.com" });

118

119

// Put records (replaces if key exists)

120

await userStore.put({ id: userId1, name: "Alice Smith", email: "alice@example.com" });

121

122

// Delete specific record

123

await userStore.delete(userId2);

124

125

// Delete multiple records with key range

126

await userStore.delete(IDBKeyRange.bound(100, 200));

127

128

// Clear all records

129

await userStore.clear();

130

131

await tx.done;

132

133

// Read operations (readonly transaction is sufficient)

134

const readTx = db.transaction("users", "readonly");

135

const readStore = readTx.store;

136

137

// These operations are not available in readonly mode:

138

// readStore.add - undefined

139

// readStore.put - undefined

140

// readStore.delete - undefined

141

// readStore.clear - undefined

142

```

143

144

### Data Retrieval Operations

145

146

Query and retrieve records from the object store.

147

148

#### Get Operations

149

150

```typescript { .api }

151

/**

152

* Retrieves the value of the first record matching the query

153

* Resolves with undefined if no match is found

154

* @param query - Key or key range to match

155

* @returns Promise resolving to the value or undefined

156

*/

157

get(

158

query: StoreKey<DBTypes, StoreName> | IDBKeyRange

159

): Promise<StoreValue<DBTypes, StoreName> | undefined>;

160

161

/**

162

* Retrieves all values that match the query

163

* @param query - Key or key range to match (optional)

164

* @param count - Maximum number of values to return (optional)

165

* @returns Promise resolving to array of matching values

166

*/

167

getAll(

168

query?: StoreKey<DBTypes, StoreName> | IDBKeyRange | null,

169

count?: number

170

): Promise<StoreValue<DBTypes, StoreName>[]>;

171

```

172

173

#### Key Operations

174

175

```typescript { .api }

176

/**

177

* Retrieves the key of the first record that matches the query

178

* Resolves with undefined if no match is found

179

* @param query - Key or key range to match

180

* @returns Promise resolving to the key or undefined

181

*/

182

getKey(

183

query: StoreKey<DBTypes, StoreName> | IDBKeyRange

184

): Promise<StoreKey<DBTypes, StoreName> | undefined>;

185

186

/**

187

* Retrieves the keys of records matching the query

188

* @param query - Key or key range to match (optional)

189

* @param count - Maximum number of keys to return (optional)

190

* @returns Promise resolving to array of matching keys

191

*/

192

getAllKeys(

193

query?: StoreKey<DBTypes, StoreName> | IDBKeyRange | null,

194

count?: number

195

): Promise<StoreKey<DBTypes, StoreName>[]>;

196

```

197

198

#### Count Operation

199

200

```typescript { .api }

201

/**

202

* Retrieves the number of records matching the given query

203

* @param key - Key or key range to count (optional)

204

* @returns Promise resolving to the count

205

*/

206

count(

207

key?: StoreKey<DBTypes, StoreName> | IDBKeyRange | null

208

): Promise<number>;

209

```

210

211

**Data Retrieval Examples:**

212

213

```typescript

214

const tx = db.transaction("users", "readonly");

215

const userStore = tx.store;

216

217

// Get single record by key

218

const user = await userStore.get("user123");

219

if (user) {

220

console.log("Found user:", user.name);

221

}

222

223

// Get multiple records

224

const allUsers = await userStore.getAll();

225

const recentUsers = await userStore.getAll(IDBKeyRange.lowerBound(1000));

226

const firstTenUsers = await userStore.getAll(null, 10);

227

228

// Get keys only (more efficient when you don't need values)

229

const allUserKeys = await userStore.getAllKeys();

230

const recentUserKeys = await userStore.getAllKeys(IDBKeyRange.lowerBound(1000), 50);

231

232

// Get specific key

233

const foundKey = await userStore.getKey(IDBKeyRange.bound("user100", "user200"));

234

235

// Count records

236

const totalUsers = await userStore.count();

237

const activeUsers = await userStore.count(IDBKeyRange.only("active"));

238

239

await tx.done;

240

```

241

242

### Index Management

243

244

Create and access indexes during database upgrades.

245

246

```typescript { .api }

247

/**

248

* Creates a new index in store

249

* Throws "InvalidStateError" if not called within an upgrade transaction

250

* Only available in versionchange transactions

251

* @param name - Name of the index

252

* @param keyPath - Property path or array of paths for the index

253

* @param options - Index configuration options

254

* @returns Enhanced index interface

255

*/

256

createIndex: Mode extends 'versionchange'

257

? <IndexName extends IndexNames<DBTypes, StoreName>>(

258

name: IndexName,

259

keyPath: string | string[],

260

options?: IDBIndexParameters

261

) => IDBPIndex<DBTypes, TxStores, StoreName, IndexName, Mode>

262

: undefined;

263

264

/**

265

* Get an index by name

266

* @param name - Name of the index

267

* @returns Enhanced index interface

268

*/

269

index<IndexName extends IndexNames<DBTypes, StoreName>>(

270

name: IndexName

271

): IDBPIndex<DBTypes, TxStores, StoreName, IndexName, Mode>;

272

```

273

274

**Index Management Examples:**

275

276

```typescript

277

// Creating indexes during database upgrade

278

const db = await openDB("my-database", 2, {

279

upgrade(db, oldVersion) {

280

if (oldVersion < 1) {

281

const userStore = db.createObjectStore("users", {

282

keyPath: "id",

283

autoIncrement: true

284

});

285

286

// Create various types of indexes

287

userStore.createIndex("email", "email", { unique: true });

288

userStore.createIndex("name", "name");

289

userStore.createIndex("age", "age");

290

userStore.createIndex("fullName", ["firstName", "lastName"]);

291

userStore.createIndex("tags", "tags", { multiEntry: true });

292

}

293

}

294

});

295

296

// Using indexes for queries

297

const tx = db.transaction("users", "readonly");

298

const userStore = tx.store;

299

300

// Access specific indexes

301

const emailIndex = userStore.index("email");

302

const nameIndex = userStore.index("name");

303

const ageIndex = userStore.index("age");

304

305

// Query using indexes

306

const userByEmail = await emailIndex.get("alice@example.com");

307

const usersByName = await nameIndex.getAll("Alice");

308

const youngUsers = await ageIndex.getAll(IDBKeyRange.upperBound(25));

309

```

310

311

### Cursor Operations

312

313

Open cursors for efficient iteration over large datasets.

314

315

```typescript { .api }

316

/**

317

* Opens a cursor over the records matching the query

318

* Resolves with null if no matches are found

319

* @param query - Key or key range to match (optional)

320

* @param direction - Cursor direction (next, nextunique, prev, prevunique)

321

* @returns Promise resolving to cursor or null

322

*/

323

openCursor(

324

query?: StoreKey<DBTypes, StoreName> | IDBKeyRange | null,

325

direction?: IDBCursorDirection

326

): Promise<IDBPCursorWithValue<DBTypes, TxStores, StoreName, unknown, Mode> | null>;

327

328

/**

329

* Opens a cursor over the keys matching the query

330

* Resolves with null if no matches are found

331

* @param query - Key or key range to match (optional)

332

* @param direction - Cursor direction (next, nextunique, prev, prevunique)

333

* @returns Promise resolving to cursor or null

334

*/

335

openKeyCursor(

336

query?: StoreKey<DBTypes, StoreName> | IDBKeyRange | null,

337

direction?: IDBCursorDirection

338

): Promise<IDBPCursor<DBTypes, TxStores, StoreName, unknown, Mode> | null>;

339

```

340

341

**Cursor Usage Examples:**

342

343

```typescript

344

const tx = db.transaction("users", "readonly");

345

const userStore = tx.store;

346

347

// Iterate with cursor manually

348

let cursor = await userStore.openCursor();

349

while (cursor) {

350

console.log("User:", cursor.key, cursor.value);

351

cursor = await cursor.continue();

352

}

353

354

// Iterate over keys only

355

let keyCursor = await userStore.openKeyCursor();

356

while (keyCursor) {

357

console.log("User key:", keyCursor.key);

358

keyCursor = await keyCursor.continue();

359

}

360

361

// Cursor with query and direction

362

let filteredCursor = await userStore.openCursor(

363

IDBKeyRange.bound("user100", "user200"),

364

"prev" // Reverse order

365

);

366

while (filteredCursor) {

367

console.log("Filtered user:", filteredCursor.value);

368

filteredCursor = await filteredCursor.continue();

369

}

370

```

371

372

### Async Iteration

373

374

Use modern async iteration syntax for convenient data traversal.

375

376

```typescript { .api }

377

/**

378

* Iterate over the store using async iteration

379

* @returns Async iterable iterator over cursor values

380

*/

381

[Symbol.asyncIterator](): AsyncIterableIterator<

382

IDBPCursorWithValueIteratorValue<DBTypes, TxStores, StoreName, unknown, Mode>

383

>;

384

385

/**

386

* Iterate over the records matching the query

387

* @param query - Key or key range to match (optional)

388

* @param direction - Cursor direction (optional)

389

* @returns Async iterable iterator over cursor values

390

*/

391

iterate(

392

query?: StoreKey<DBTypes, StoreName> | IDBKeyRange | null,

393

direction?: IDBCursorDirection

394

): AsyncIterableIterator<

395

IDBPCursorWithValueIteratorValue<DBTypes, TxStores, StoreName, unknown, Mode>

396

>;

397

```

398

399

**Async Iteration Examples:**

400

401

```typescript

402

const tx = db.transaction("users", "readonly");

403

const userStore = tx.store;

404

405

// Iterate over all records

406

for await (const cursor of userStore) {

407

console.log("User:", cursor.key, cursor.value);

408

409

// Control iteration

410

if (cursor.value.age < 18) {

411

cursor.continue(); // Skip to next

412

}

413

}

414

415

// Iterate with query

416

for await (const cursor of userStore.iterate(IDBKeyRange.bound(100, 200))) {

417

console.log("User in range:", cursor.value);

418

419

// Early termination

420

if (cursor.value.name === "Target User") {

421

break;

422

}

423

}

424

425

// Iterate in reverse order

426

for await (const cursor of userStore.iterate(null, "prev")) {

427

console.log("User (reverse):", cursor.value);

428

}

429

430

// Collect results with async iteration

431

const activeUsers = [];

432

for await (const cursor of userStore.iterate()) {

433

if (cursor.value.status === "active") {

434

activeUsers.push(cursor.value);

435

}

436

}

437

438

await tx.done;

439

```

440

441

### Performance Optimization

442

443

Strategies for efficient object store operations.

444

445

**Batch Operations:**

446

447

```typescript

448

async function batchAddUsers(users: User[]) {

449

const tx = db.transaction("users", "readwrite");

450

const userStore = tx.store;

451

452

// Start all operations without awaiting individually

453

const promises = users.map(user => userStore.add(user));

454

455

// Wait for all operations and transaction completion

456

await Promise.all([...promises, tx.done]);

457

}

458

```

459

460

**Efficient Counting:**

461

462

```typescript

463

// Use count() instead of getAll().length for better performance

464

const userCount = await userStore.count();

465

466

// Count with filters using key ranges

467

const adultCount = await userStore.index("age").count(IDBKeyRange.lowerBound(18));

468

```

469

470

**Key-Only Queries:**

471

472

```typescript

473

// More efficient when you only need keys

474

const userKeys = await userStore.getAllKeys();

475

476

// Instead of

477

const users = await userStore.getAll();

478

const keys = users.map(user => user.id); // Less efficient

479

```