idb-ts 3.3.0 → 3.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/index.js CHANGED
@@ -9,61 +9,299 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
9
9
  });
10
10
  };
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
- exports.DataClass = exports.KeyPath = exports.Database = void 0;
12
+ exports.KeyGenerators = exports.Index = exports.DataClass = exports.CompositeKeyPath = exports.KeyPath = exports.Database = void 0;
13
13
  require("reflect-metadata");
14
- function KeyPath() {
14
+ class QueryBuilder {
15
+ constructor(db, storeName) {
16
+ this.conditions = [];
17
+ this.orderDirection = 'asc';
18
+ this.db = db;
19
+ this.storeName = storeName;
20
+ }
21
+ where(field) {
22
+ this.currentField = field;
23
+ return this;
24
+ }
25
+ and(field) {
26
+ this.currentField = field;
27
+ return this;
28
+ }
29
+ equals(value) {
30
+ if (!this.currentField)
31
+ throw new Error('No field specified for equals');
32
+ this.conditions.push({ field: this.currentField, op: 'equals', value });
33
+ this.currentField = undefined;
34
+ return this;
35
+ }
36
+ gt(value) {
37
+ if (!this.currentField)
38
+ throw new Error('No field specified for gt');
39
+ this.conditions.push({ field: this.currentField, op: 'gt', value });
40
+ this.currentField = undefined;
41
+ return this;
42
+ }
43
+ gte(value) {
44
+ if (!this.currentField)
45
+ throw new Error('No field specified for gte');
46
+ this.conditions.push({ field: this.currentField, op: 'gte', value });
47
+ this.currentField = undefined;
48
+ return this;
49
+ }
50
+ lt(value) {
51
+ if (!this.currentField)
52
+ throw new Error('No field specified for lt');
53
+ this.conditions.push({ field: this.currentField, op: 'lt', value });
54
+ this.currentField = undefined;
55
+ return this;
56
+ }
57
+ lte(value) {
58
+ if (!this.currentField)
59
+ throw new Error('No field specified for lte');
60
+ this.conditions.push({ field: this.currentField, op: 'lte', value });
61
+ this.currentField = undefined;
62
+ return this;
63
+ }
64
+ orderBy(field, direction = 'asc') {
65
+ this.orderField = field;
66
+ this.orderDirection = direction;
67
+ return this;
68
+ }
69
+ limit(n) {
70
+ this.limitCount = n;
71
+ return this;
72
+ }
73
+ offset(n) {
74
+ this.offsetCount = n;
75
+ return this;
76
+ }
77
+ useIndex(indexName) {
78
+ this.indexName = indexName;
79
+ return this;
80
+ }
81
+ range(start, end) {
82
+ this.rangeStart = start;
83
+ this.rangeEnd = end;
84
+ return this;
85
+ }
86
+ execute() {
87
+ return __awaiter(this, void 0, void 0, function* () {
88
+ return new Promise((resolve, reject) => {
89
+ const tx = this.db.transaction(this.storeName, 'readonly');
90
+ let store = tx.objectStore(this.storeName);
91
+ let request;
92
+ let results = [];
93
+ if (this.indexName) {
94
+ if (!store.indexNames.contains(this.indexName)) {
95
+ reject(new Error(`Index '${this.indexName}' does not exist on ${this.storeName}`));
96
+ return;
97
+ }
98
+ const index = store.index(this.indexName);
99
+ let keyRange;
100
+ if (this.rangeStart !== undefined && this.rangeEnd !== undefined) {
101
+ keyRange = IDBKeyRange.bound(this.rangeStart, this.rangeEnd);
102
+ }
103
+ else if (this.rangeStart !== undefined) {
104
+ keyRange = IDBKeyRange.lowerBound(this.rangeStart);
105
+ }
106
+ else if (this.rangeEnd !== undefined) {
107
+ keyRange = IDBKeyRange.upperBound(this.rangeEnd);
108
+ }
109
+ request = index.openCursor(keyRange);
110
+ }
111
+ else {
112
+ request = store.openCursor();
113
+ }
114
+ request.onsuccess = () => {
115
+ const cursor = request.result;
116
+ if (cursor) {
117
+ let match = true;
118
+ const value = cursor.value;
119
+ for (const cond of this.conditions) {
120
+ const val = value[cond.field];
121
+ switch (cond.op) {
122
+ case 'equals':
123
+ match = match && val === cond.value;
124
+ break;
125
+ case 'gt':
126
+ match = match && val > cond.value;
127
+ break;
128
+ case 'gte':
129
+ match = match && val >= cond.value;
130
+ break;
131
+ case 'lt':
132
+ match = match && val < cond.value;
133
+ break;
134
+ case 'lte':
135
+ match = match && val <= cond.value;
136
+ break;
137
+ }
138
+ }
139
+ if (match)
140
+ results.push(value);
141
+ cursor.continue();
142
+ }
143
+ else {
144
+ if (this.orderField) {
145
+ results.sort((a, b) => {
146
+ const va = a[this.orderField];
147
+ const vb = b[this.orderField];
148
+ if (va < vb)
149
+ return this.orderDirection === 'asc' ? -1 : 1;
150
+ if (va > vb)
151
+ return this.orderDirection === 'asc' ? 1 : -1;
152
+ return 0;
153
+ });
154
+ }
155
+ if (this.offsetCount !== undefined)
156
+ results = results.slice(this.offsetCount);
157
+ if (this.limitCount !== undefined)
158
+ results = results.slice(0, this.limitCount);
159
+ resolve(results);
160
+ }
161
+ };
162
+ request.onerror = () => reject(request.error);
163
+ });
164
+ });
165
+ }
166
+ }
167
+ class KeyGenerators {
168
+ static uuid() {
169
+ return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
170
+ const r = Math.random() * 16 | 0;
171
+ const v = c === 'x' ? r : (r & 0x3 | 0x8);
172
+ return v.toString(16);
173
+ });
174
+ }
175
+ static timestamp() {
176
+ return Date.now();
177
+ }
178
+ static random() {
179
+ return Math.random().toString(36).substring(2, 15);
180
+ }
181
+ }
182
+ exports.KeyGenerators = KeyGenerators;
183
+ function KeyPath(options) {
15
184
  return (target, propertyKey) => {
16
185
  const constructor = target.constructor;
17
- Reflect.defineMetadata("keypath", [propertyKey], constructor);
186
+ const existingKeypaths = Reflect.getMetadata("individual_keypaths", constructor) || [];
187
+ existingKeypaths.push(propertyKey);
188
+ Reflect.defineMetadata("individual_keypaths", existingKeypaths, constructor);
189
+ const metadata = {
190
+ fields: propertyKey,
191
+ options: options
192
+ };
193
+ Reflect.defineMetadata("keypath", metadata, constructor);
18
194
  };
19
195
  }
20
196
  exports.KeyPath = KeyPath;
21
- function DataClass() {
197
+ function CompositeKeyPath(fields, options) {
198
+ return (target) => {
199
+ const metadata = {
200
+ fields: fields,
201
+ options: options
202
+ };
203
+ Reflect.defineMetadata("keypath", metadata, target);
204
+ };
205
+ }
206
+ exports.CompositeKeyPath = CompositeKeyPath;
207
+ function Index() {
208
+ return (target, propertyKey) => {
209
+ const constructor = target.constructor;
210
+ const existing = Reflect.getMetadata("indexes", constructor) || [];
211
+ Reflect.defineMetadata("indexes", [...existing, propertyKey], constructor);
212
+ };
213
+ }
214
+ exports.Index = Index;
215
+ function DataClass(options = {}) {
22
216
  return (target) => {
23
- if (!Reflect.getMetadata("keypath", target)) {
217
+ const keyPathMetadata = Reflect.getMetadata("keypath", target);
218
+ if (!keyPathMetadata) {
24
219
  throw new Error(`No keypath field defined for the class ${target.name}.`);
25
220
  }
26
- const keyPathFields = Reflect.getMetadata("keypath", target) || [];
27
- if (keyPathFields.length > 1) {
221
+ const individualKeypaths = Reflect.getMetadata("individual_keypaths", target) || [];
222
+ if (individualKeypaths.length > 1) {
28
223
  throw new Error(`Only one keypath field can be defined for the class ${target.name}.`);
29
224
  }
225
+ const version = options.version || 1;
30
226
  Reflect.defineMetadata("dataclass", true, target);
227
+ Reflect.defineMetadata("version", version, target);
31
228
  };
32
229
  }
33
230
  exports.DataClass = DataClass;
34
231
  class Database {
35
232
  constructor(dbName, classes) {
36
233
  this.db = null;
234
+ this.entityRepositories = new Map();
37
235
  this.dbName = dbName;
38
236
  if (!classes.every(cls => Reflect.getMetadata("dataclass", cls))) {
39
237
  throw new Error("All classes should be decorated with @DataClass.");
40
238
  }
41
239
  this.classes = classes;
240
+ this.dbVersion = this.calculateDatabaseVersion();
241
+ }
242
+ calculateDatabaseVersion() {
243
+ const versions = this.classes.map(cls => Reflect.getMetadata("version", cls) || 1);
244
+ return Math.max(...versions);
42
245
  }
43
246
  static build(dbName, classes) {
44
247
  return __awaiter(this, void 0, void 0, function* () {
45
248
  const instance = new Database(dbName, classes);
46
249
  yield instance.initDB();
250
+ instance.generateEntityRepositories();
47
251
  return instance;
48
252
  });
49
253
  }
50
254
  initDB() {
51
255
  return __awaiter(this, void 0, void 0, function* () {
52
256
  return new Promise((resolve, reject) => {
53
- const request = indexedDB.open(this.dbName, 1);
54
- request.onupgradeneeded = () => {
257
+ const request = indexedDB.open(this.dbName, this.dbVersion);
258
+ request.onupgradeneeded = (event) => {
55
259
  const db = request.result;
260
+ const oldVersion = event.oldVersion;
261
+ const newVersion = event.newVersion || this.dbVersion;
262
+ console.debug(`Database upgrade from version ${oldVersion} to ${newVersion}`);
56
263
  this.classes.forEach((cls) => {
57
- const keyPathFields = Reflect.getMetadata("keypath", cls) || [];
58
- const storeName = cls.name.toLowerCase() + "s";
59
- if (!db.objectStoreNames.contains(storeName)) {
60
- db.createObjectStore(storeName, { keyPath: keyPathFields[0] });
264
+ var _a;
265
+ const keyPathMetadata = Reflect.getMetadata("keypath", cls);
266
+ const indexFields = Reflect.getMetadata("indexes", cls) || [];
267
+ const classVersion = Reflect.getMetadata("version", cls) || 1;
268
+ const storeName = cls.name.toLowerCase();
269
+ if (classVersion > oldVersion) {
270
+ if (!db.objectStoreNames.contains(storeName)) {
271
+ console.debug(`Creating object store: ${storeName} (version ${classVersion})`);
272
+ const storeOptions = {};
273
+ if (keyPathMetadata) {
274
+ storeOptions.keyPath = keyPathMetadata.fields;
275
+ if ((_a = keyPathMetadata.options) === null || _a === void 0 ? void 0 : _a.autoIncrement) {
276
+ storeOptions.autoIncrement = true;
277
+ }
278
+ }
279
+ const store = db.createObjectStore(storeName, storeOptions);
280
+ indexFields.forEach((indexField) => {
281
+ if (!store.indexNames.contains(indexField)) {
282
+ store.createIndex(indexField, indexField, { unique: false });
283
+ }
284
+ });
285
+ }
286
+ else {
287
+ console.debug(`Updating object store: ${storeName} (version ${classVersion})`);
288
+ const transaction = request.transaction;
289
+ if (transaction) {
290
+ const store = transaction.objectStore(storeName);
291
+ indexFields.forEach((indexField) => {
292
+ if (!store.indexNames.contains(indexField)) {
293
+ console.debug(`Adding index: ${indexField} to ${storeName}`);
294
+ store.createIndex(indexField, indexField, { unique: false });
295
+ }
296
+ });
297
+ }
298
+ }
61
299
  }
62
300
  });
63
301
  };
64
302
  request.onsuccess = () => {
65
303
  this.db = request.result;
66
- console.debug(`Database initialized with object stores for: ${this.classes.map(cls => cls.name).join(", ")}`);
304
+ console.debug(`Database initialized (version ${this.dbVersion}) with object stores for: ${this.classes.map(cls => `${cls.name}(v${Reflect.getMetadata("version", cls) || 1})`).join(", ")}`);
67
305
  resolve();
68
306
  };
69
307
  request.onerror = () => {
@@ -73,141 +311,253 @@ class Database {
73
311
  });
74
312
  });
75
313
  }
76
- getObjectStore(className, mode) {
77
- if (!this.db) {
78
- throw new Error("Database not initialized.");
79
- }
80
- const storeName = className.toLowerCase() + "s";
81
- const transaction = this.db.transaction(storeName, mode);
82
- return transaction.objectStore(storeName);
83
- }
84
- create(cls, item) {
85
- return __awaiter(this, void 0, void 0, function* () {
86
- return new Promise((resolve, reject) => {
87
- try {
88
- const store = this.getObjectStore(cls.name, "readwrite");
89
- const request = store.add(item);
90
- request.onsuccess = () => {
91
- console.debug(`Item added to ${cls.name}:`, item);
92
- resolve();
93
- };
94
- request.onerror = () => {
95
- console.error(`Error adding item to ${cls.name}:`, request.error);
96
- reject(request.error);
97
- };
98
- }
99
- catch (error) {
100
- reject(error);
101
- }
314
+ generateEntityRepositories() {
315
+ this.classes.forEach(cls => {
316
+ const entityName = cls.name;
317
+ const repository = this.createEntityRepository(cls);
318
+ this.entityRepositories.set(entityName, repository);
319
+ Object.defineProperty(this, entityName, {
320
+ value: repository,
321
+ writable: false,
322
+ enumerable: true,
323
+ configurable: false
102
324
  });
103
325
  });
104
326
  }
105
- read(cls, key) {
106
- return __awaiter(this, void 0, void 0, function* () {
107
- return new Promise((resolve, reject) => {
108
- try {
109
- const store = this.getObjectStore(cls.name, "readonly");
110
- const request = store.get(key);
111
- request.onsuccess = () => {
112
- console.debug(`Item read from ${cls.name}:`, request.result);
113
- resolve(request.result);
114
- };
115
- request.onerror = () => {
116
- console.error(`Error reading item from ${cls.name}:`, request.error);
117
- reject(request.error);
118
- };
119
- }
120
- catch (error) {
121
- reject(error);
327
+ createEntityRepository(cls) {
328
+ const self = this;
329
+ const generateKey = (item) => {
330
+ var _a;
331
+ const keyPathMetadata = Reflect.getMetadata("keypath", cls);
332
+ if (!((_a = keyPathMetadata === null || keyPathMetadata === void 0 ? void 0 : keyPathMetadata.options) === null || _a === void 0 ? void 0 : _a.generator))
333
+ return undefined;
334
+ const generator = keyPathMetadata.options.generator;
335
+ if (typeof generator === 'function') {
336
+ return generator(item);
337
+ }
338
+ switch (generator) {
339
+ case 'uuid':
340
+ return KeyGenerators.uuid();
341
+ case 'timestamp':
342
+ return KeyGenerators.timestamp();
343
+ case 'random':
344
+ return KeyGenerators.random();
345
+ default:
346
+ return undefined;
347
+ }
348
+ };
349
+ const extractKey = (item) => {
350
+ const keyPathMetadata = Reflect.getMetadata("keypath", cls);
351
+ if (!keyPathMetadata)
352
+ return undefined;
353
+ const fields = keyPathMetadata.fields;
354
+ if (Array.isArray(fields)) {
355
+ return fields.map(field => item[field]);
356
+ }
357
+ else {
358
+ return item[fields];
359
+ }
360
+ };
361
+ const setKey = (item, key) => {
362
+ const keyPathMetadata = Reflect.getMetadata("keypath", cls);
363
+ if (!keyPathMetadata)
364
+ return;
365
+ const fields = keyPathMetadata.fields;
366
+ if (typeof fields === 'string') {
367
+ item[fields] = key;
368
+ }
369
+ };
370
+ return {
371
+ query() {
372
+ if (!self.db)
373
+ throw new Error('Database not initialized.');
374
+ const storeName = cls.name.toLowerCase();
375
+ return new QueryBuilder(self.db, storeName);
376
+ },
377
+ create: (item) => __awaiter(this, void 0, void 0, function* () {
378
+ var _a;
379
+ const keyPathMetadata = Reflect.getMetadata("keypath", cls);
380
+ if (((_a = keyPathMetadata === null || keyPathMetadata === void 0 ? void 0 : keyPathMetadata.options) === null || _a === void 0 ? void 0 : _a.generator) && !keyPathMetadata.options.autoIncrement) {
381
+ const currentKey = extractKey(item);
382
+ if (currentKey === undefined || currentKey === null || currentKey === '') {
383
+ const generatedKey = generateKey(item);
384
+ if (generatedKey !== undefined) {
385
+ setKey(item, generatedKey);
386
+ }
387
+ }
122
388
  }
123
- });
124
- });
125
- }
126
- update(cls, item) {
127
- return __awaiter(this, void 0, void 0, function* () {
128
- return new Promise((resolve, reject) => {
129
- try {
130
- const store = this.getObjectStore(cls.name, "readwrite");
389
+ return this.performOperation(cls.name, 'readwrite', (store) => {
390
+ const request = store.add(item);
391
+ return new Promise((resolve, reject) => {
392
+ request.onsuccess = () => {
393
+ console.debug(`Item added to ${cls.name}:`, item);
394
+ resolve();
395
+ };
396
+ request.onerror = () => reject(request.error);
397
+ });
398
+ });
399
+ }),
400
+ read: (key) => __awaiter(this, void 0, void 0, function* () {
401
+ return this.performOperation(cls.name, 'readonly', (store) => {
402
+ const request = store.get(key);
403
+ return new Promise((resolve, reject) => {
404
+ request.onsuccess = () => {
405
+ console.debug(`Item read from ${cls.name}:`, request.result);
406
+ resolve(request.result);
407
+ };
408
+ request.onerror = () => reject(request.error);
409
+ });
410
+ });
411
+ }),
412
+ update: (item) => __awaiter(this, void 0, void 0, function* () {
413
+ return this.performOperation(cls.name, 'readwrite', (store) => {
131
414
  const request = store.put(item);
132
- request.onsuccess = () => {
133
- console.debug(`Item updated in ${cls.name}:`, item);
134
- resolve();
135
- };
136
- request.onerror = () => {
137
- console.error(`Error updating item in ${cls.name}:`, request.error);
138
- reject(request.error);
139
- };
140
- }
141
- catch (error) {
142
- reject(error);
143
- }
144
- });
145
- });
146
- }
147
- delete(cls, key) {
148
- return __awaiter(this, void 0, void 0, function* () {
149
- return new Promise((resolve, reject) => {
150
- try {
151
- const store = this.getObjectStore(cls.name, "readwrite");
415
+ return new Promise((resolve, reject) => {
416
+ request.onsuccess = () => {
417
+ console.debug(`Item updated in ${cls.name}:`, item);
418
+ resolve();
419
+ };
420
+ request.onerror = () => reject(request.error);
421
+ });
422
+ });
423
+ }),
424
+ delete: (key) => __awaiter(this, void 0, void 0, function* () {
425
+ return this.performOperation(cls.name, 'readwrite', (store) => {
152
426
  const request = store.delete(key);
153
- request.onsuccess = () => {
154
- console.debug(`Item deleted from ${cls.name}:`, key);
155
- resolve();
156
- };
157
- request.onerror = () => {
158
- console.error(`Error deleting item from ${cls.name}:`, request.error);
159
- reject(request.error);
160
- };
161
- }
162
- catch (error) {
163
- reject(error);
164
- }
165
- });
166
- });
427
+ return new Promise((resolve, reject) => {
428
+ request.onsuccess = () => {
429
+ console.debug(`Item deleted from ${cls.name}:`, key);
430
+ resolve();
431
+ };
432
+ request.onerror = () => reject(request.error);
433
+ });
434
+ });
435
+ }),
436
+ list: () => __awaiter(this, void 0, void 0, function* () {
437
+ return this.performOperation(cls.name, 'readonly', (store) => {
438
+ const request = store.getAll();
439
+ return new Promise((resolve, reject) => {
440
+ request.onsuccess = () => {
441
+ console.debug(`All items from ${cls.name}:`, request.result);
442
+ resolve(request.result);
443
+ };
444
+ request.onerror = () => reject(request.error);
445
+ });
446
+ });
447
+ }),
448
+ listPaginated: (page, pageSize) => __awaiter(this, void 0, void 0, function* () {
449
+ return this.performOperation(cls.name, 'readonly', (store) => {
450
+ const request = store.getAll();
451
+ return new Promise((resolve, reject) => {
452
+ request.onsuccess = () => {
453
+ const items = request.result;
454
+ const paginatedItems = items.slice((page - 1) * pageSize, page * pageSize);
455
+ console.debug(`Paginated items from ${cls.name}:`, paginatedItems);
456
+ resolve(paginatedItems);
457
+ };
458
+ request.onerror = () => reject(request.error);
459
+ });
460
+ });
461
+ }),
462
+ findByIndex: (indexName, value) => __awaiter(this, void 0, void 0, function* () {
463
+ return this.performOperation(cls.name, 'readonly', (store) => {
464
+ if (!store.indexNames.contains(indexName)) {
465
+ throw new Error(`Index '${indexName}' does not exist on ${cls.name}`);
466
+ }
467
+ const index = store.index(indexName);
468
+ const request = index.getAll(value);
469
+ return new Promise((resolve, reject) => {
470
+ request.onsuccess = () => {
471
+ console.debug(`Items found by index ${indexName} with value ${value}:`, request.result);
472
+ resolve(request.result);
473
+ };
474
+ request.onerror = () => reject(request.error);
475
+ });
476
+ });
477
+ }),
478
+ findOneByIndex: (indexName, value) => __awaiter(this, void 0, void 0, function* () {
479
+ return this.performOperation(cls.name, 'readonly', (store) => {
480
+ if (!store.indexNames.contains(indexName)) {
481
+ throw new Error(`Index '${indexName}' does not exist on ${cls.name}`);
482
+ }
483
+ const index = store.index(indexName);
484
+ const request = index.get(value);
485
+ return new Promise((resolve, reject) => {
486
+ request.onsuccess = () => {
487
+ console.debug(`Item found by index ${indexName} with value ${value}:`, request.result);
488
+ resolve(request.result);
489
+ };
490
+ request.onerror = () => reject(request.error);
491
+ });
492
+ });
493
+ }),
494
+ count: () => __awaiter(this, void 0, void 0, function* () {
495
+ return this.performOperation(cls.name, 'readonly', (store) => {
496
+ const request = store.count();
497
+ return new Promise((resolve, reject) => {
498
+ request.onsuccess = () => {
499
+ console.debug(`Count for ${cls.name}:`, request.result);
500
+ resolve(request.result);
501
+ };
502
+ request.onerror = () => reject(request.error);
503
+ });
504
+ });
505
+ }),
506
+ exists: (key) => __awaiter(this, void 0, void 0, function* () {
507
+ return this.performOperation(cls.name, 'readonly', (store) => {
508
+ const request = store.count(key);
509
+ return new Promise((resolve, reject) => {
510
+ request.onsuccess = () => {
511
+ const exists = request.result > 0;
512
+ console.debug(`Exists check for ${cls.name} with key ${key}:`, exists);
513
+ resolve(exists);
514
+ };
515
+ request.onerror = () => reject(request.error);
516
+ });
517
+ });
518
+ }),
519
+ clear: () => __awaiter(this, void 0, void 0, function* () {
520
+ return this.performOperation(cls.name, 'readwrite', (store) => {
521
+ const request = store.clear();
522
+ return new Promise((resolve, reject) => {
523
+ request.onsuccess = () => {
524
+ console.debug(`Cleared all items from ${cls.name}`);
525
+ resolve();
526
+ };
527
+ request.onerror = () => reject(request.error);
528
+ });
529
+ });
530
+ })
531
+ };
167
532
  }
168
- list(cls) {
533
+ performOperation(className, mode, operation) {
169
534
  return __awaiter(this, void 0, void 0, function* () {
170
- return new Promise((resolve, reject) => {
171
- try {
172
- const store = this.getObjectStore(cls.name, "readonly");
173
- const request = store.getAll();
174
- request.onsuccess = () => {
175
- console.debug(`All items from ${cls.name}:`, request.result);
176
- resolve(request.result);
177
- };
178
- request.onerror = () => {
179
- console.error(`Error listing items from ${cls.name}:`, request.error);
180
- reject(request.error);
181
- };
182
- }
183
- catch (error) {
184
- reject(error);
185
- }
186
- });
535
+ if (!this.db) {
536
+ throw new Error("Database not initialized.");
537
+ }
538
+ const storeName = className.toLowerCase();
539
+ const transaction = this.db.transaction(storeName, mode);
540
+ const store = transaction.objectStore(storeName);
541
+ return operation(store);
187
542
  });
188
543
  }
189
- listPaginated(cls, page, pageSize) {
190
- return __awaiter(this, void 0, void 0, function* () {
191
- return new Promise((resolve, reject) => {
192
- try {
193
- const store = this.getObjectStore(cls.name, "readonly");
194
- const request = store.getAll();
195
- request.onsuccess = () => {
196
- const items = request.result;
197
- const paginatedItems = items.slice((page - 1) * pageSize, page * pageSize);
198
- console.debug(`Paginated items from ${cls.name}:`, paginatedItems);
199
- resolve(paginatedItems);
200
- };
201
- request.onerror = () => {
202
- console.error(`Error listing items from ${cls.name}:`, request.error);
203
- reject(request.error);
204
- };
205
- }
206
- catch (error) {
207
- reject(error);
208
- }
209
- });
544
+ getAvailableEntities() {
545
+ return Array.from(this.entityRepositories.keys());
546
+ }
547
+ getDatabaseVersion() {
548
+ return this.dbVersion;
549
+ }
550
+ getEntityVersions() {
551
+ const versions = new Map();
552
+ this.classes.forEach(cls => {
553
+ const version = Reflect.getMetadata("version", cls) || 1;
554
+ versions.set(cls.name, version);
210
555
  });
556
+ return versions;
557
+ }
558
+ getEntityVersion(entityName) {
559
+ const cls = this.classes.find(c => c.name === entityName);
560
+ return cls ? (Reflect.getMetadata("version", cls) || 1) : undefined;
211
561
  }
212
562
  }
213
563
  exports.Database = Database;