godb.js 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687
  1. /*! *****************************************************************************
  2. Copyright (c) Microsoft Corporation.
  3. Permission to use, copy, modify, and/or distribute this software for any
  4. purpose with or without fee is hereby granted.
  5. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
  6. REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
  7. AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
  8. INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  9. LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
  10. OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  11. PERFORMANCE OF THIS SOFTWARE.
  12. ***************************************************************************** */
  13. var __assign = function() {
  14. __assign = Object.assign || function __assign(t) {
  15. for (var s, i = 1, n = arguments.length; i < n; i++) {
  16. s = arguments[i];
  17. for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p];
  18. }
  19. return t;
  20. };
  21. return __assign.apply(this, arguments);
  22. };
  23. function __awaiter(thisArg, _arguments, P, generator) {
  24. function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
  25. return new (P || (P = Promise))(function (resolve, reject) {
  26. function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
  27. function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
  28. function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
  29. step((generator = generator.apply(thisArg, _arguments || [])).next());
  30. });
  31. }
  32. function __generator(thisArg, body) {
  33. var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
  34. return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
  35. function verb(n) { return function (v) { return step([n, v]); }; }
  36. function step(op) {
  37. if (f) throw new TypeError("Generator is already executing.");
  38. while (_) try {
  39. if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
  40. if (y = 0, t) op = [op[0] & 2, t.value];
  41. switch (op[0]) {
  42. case 0: case 1: t = op; break;
  43. case 4: _.label++; return { value: op[1], done: false };
  44. case 5: _.label++; y = op[1]; op = [0]; continue;
  45. case 7: op = _.ops.pop(); _.trys.pop(); continue;
  46. default:
  47. if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
  48. if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
  49. if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
  50. if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
  51. if (t[2]) _.ops.pop();
  52. _.trys.pop(); continue;
  53. }
  54. op = body.call(thisArg, _);
  55. } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
  56. if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
  57. }
  58. }
  59. // TODO: GLOBAL ERROR HANDLER
  60. // TODO: optimizing for duplicated codes, make a global promise to handle error
  61. // TODO: make sure that schema is sync with objectStore
  62. var GoDBTable = /** @class */ (function () {
  63. function GoDBTable(godb, name, schema) {
  64. this.godb = godb;
  65. this.name = name;
  66. this.schema = schema || null;
  67. }
  68. // crud(operation: GoDBTableCRUD): Promise<void | GoDBData | GoDBData[]> {
  69. // return new Promise((resolve, reject) => {
  70. // this.godb.getDB((idb) => {
  71. // try {
  72. // } catch (err) {
  73. // reject(err);
  74. // }
  75. // });
  76. // });
  77. // }
  78. // TODO: check if criteria's key fits schema
  79. GoDBTable.prototype.get = function (criteria) {
  80. var _this = this;
  81. return new Promise(function (resolve, reject) {
  82. _this.godb.getDB(function (idb) {
  83. try {
  84. var store = idb
  85. .transaction(_this.name, 'readonly')
  86. .objectStore(_this.name);
  87. // if the key is not unique, return one object with least id
  88. // TODO: warning user if the key is not unique
  89. var onSuccess = function (e) {
  90. var result = e.target.result;
  91. resolve(result);
  92. };
  93. var onError = function (e) {
  94. var error = e.target.error;
  95. reject(error);
  96. };
  97. if (typeof criteria === 'object') {
  98. var key = Object.keys(criteria)[0];
  99. var value = criteria[key];
  100. var request = key === 'id'
  101. ? store.get(value)
  102. : store.index(key).get(value);
  103. request.onsuccess = onSuccess;
  104. request.onerror = onError;
  105. }
  106. else if (typeof criteria === 'number') {
  107. var request = store.get(criteria);
  108. request.onsuccess = onSuccess;
  109. request.onerror = onError;
  110. }
  111. else {
  112. reject(new Error('Table.get() failed: invalid criteria'));
  113. }
  114. }
  115. catch (err) {
  116. reject(err);
  117. }
  118. });
  119. });
  120. };
  121. GoDBTable.prototype.getAll = function (limit) {
  122. var _this = this;
  123. return new Promise(function (resolve, reject) {
  124. _this.godb.getDB(function (idb) {
  125. try {
  126. var store = idb
  127. .transaction(_this.name, 'readonly')
  128. .objectStore(_this.name);
  129. var request = limit
  130. ? store.getAll(null, limit)
  131. : store.getAll();
  132. request.onsuccess = function (e) {
  133. var result = e.target.result;
  134. resolve(result);
  135. };
  136. request.onerror = function (e) {
  137. var error = e.target.error;
  138. reject(error);
  139. };
  140. }
  141. catch (err) {
  142. reject(err);
  143. }
  144. });
  145. });
  146. };
  147. // TODO: check data's schema
  148. // resolve: id of added item
  149. GoDBTable.prototype.add = function (data) {
  150. var _this = this;
  151. return new Promise(function (resolve, reject) {
  152. _this.godb.getDB(function (idb) {
  153. try {
  154. var store = idb
  155. .transaction(_this.name, 'readwrite')
  156. .objectStore(_this.name);
  157. var request = store.add(data);
  158. // TODO: according to MDN, `onsuccess` does not exactly mean a successful adding
  159. request.onsuccess = function (e) {
  160. var result = e.target.result;
  161. resolve(__assign(__assign({}, data), { id: result }));
  162. };
  163. request.onerror = function (e) {
  164. var error = e.target.error;
  165. reject(error);
  166. };
  167. }
  168. catch (err) {
  169. reject(err);
  170. }
  171. });
  172. });
  173. };
  174. // TODO FIX: the order might be unexpected when
  175. // `addMany` and `add` were executing at the same time
  176. GoDBTable.prototype.addMany = function (data) {
  177. var _this = this;
  178. return new Promise(function (resolve, reject) { return __awaiter(_this, void 0, void 0, function () {
  179. var arr, _i, data_1, item, _a, _b;
  180. return __generator(this, function (_c) {
  181. switch (_c.label) {
  182. case 0:
  183. if (!Array.isArray(data)) return [3 /*break*/, 5];
  184. arr = [];
  185. _i = 0, data_1 = data;
  186. _c.label = 1;
  187. case 1:
  188. if (!(_i < data_1.length)) return [3 /*break*/, 4];
  189. item = data_1[_i];
  190. _b = (_a = arr).push;
  191. return [4 /*yield*/, this.add(item)];
  192. case 2:
  193. _b.apply(_a, [_c.sent()]);
  194. _c.label = 3;
  195. case 3:
  196. _i++;
  197. return [3 /*break*/, 1];
  198. case 4:
  199. resolve(arr);
  200. return [3 /*break*/, 6];
  201. case 5:
  202. reject(new Error('Table.addMany() failed: input data should be an array'));
  203. _c.label = 6;
  204. case 6: return [2 /*return*/];
  205. }
  206. });
  207. }); });
  208. };
  209. // TODO: check data's schema
  210. // if data is not in table, `put` will add the data, otherwise update
  211. // TODO: check schema's unique key, which decides whether update or add data
  212. // resolve: id of updated item
  213. GoDBTable.prototype.put = function (data) {
  214. var _this = this;
  215. return new Promise(function (resolve, reject) {
  216. _this.godb.getDB(function (idb) {
  217. if (!(data && typeof data === 'object'))
  218. return reject(new Error('Table.put() failed: data should be an object'));
  219. if (!data.id)
  220. return reject(new Error('Table.put() failed: id is required in data'));
  221. try {
  222. var store = idb
  223. .transaction(_this.name, 'readwrite')
  224. .objectStore(_this.name);
  225. // equals to `add(data)` if `data` is not in table
  226. var request = store.put(data);
  227. // TODO: according to MDN, `onsuccess` does not exactly mean a successful adding
  228. request.onsuccess = function (e) {
  229. var result = e.target.result;
  230. resolve(__assign(__assign({}, data), { id: result }));
  231. };
  232. request.onerror = function (e) {
  233. var error = e.target.error;
  234. reject(error);
  235. };
  236. }
  237. catch (err) {
  238. reject(err);
  239. }
  240. });
  241. });
  242. };
  243. // update only, be ware of the difference to `put`
  244. GoDBTable.prototype.update = function () {
  245. };
  246. GoDBTable.prototype["delete"] = function (criteria) {
  247. var _this = this;
  248. return new Promise(function (resolve, reject) {
  249. _this.godb.getDB(function (idb) {
  250. try {
  251. _this.get(criteria).then(function (doc) {
  252. var store = idb
  253. .transaction(_this.name, 'readwrite')
  254. .objectStore(_this.name);
  255. var request = store["delete"](doc.id);
  256. request.onsuccess = function () {
  257. resolve();
  258. };
  259. request.onerror = function (e) {
  260. var error = e.target.error;
  261. reject(error);
  262. };
  263. });
  264. }
  265. catch (err) {
  266. reject(err);
  267. }
  268. });
  269. });
  270. };
  271. // find by a function
  272. GoDBTable.prototype.find = function (fn) {
  273. var _this = this;
  274. return new Promise(function (resolve, reject) {
  275. _this.godb.getDB(function (idb) {
  276. try {
  277. var store = idb
  278. .transaction(_this.name, 'readonly')
  279. .objectStore(_this.name);
  280. store.openCursor().onsuccess = function (e) {
  281. var cursor = e.target.result;
  282. if (cursor) {
  283. if (fn(cursor.value))
  284. return resolve(cursor.value);
  285. cursor["continue"]();
  286. }
  287. else {
  288. resolve(null);
  289. }
  290. };
  291. }
  292. catch (err) {
  293. reject(err);
  294. }
  295. });
  296. });
  297. };
  298. // return all results by a find function
  299. GoDBTable.prototype.findAll = function (fn) {
  300. var _this = this;
  301. return new Promise(function (resolve, reject) {
  302. _this.godb.getDB(function (idb) {
  303. try {
  304. var store = idb
  305. .transaction(_this.name, 'readonly')
  306. .objectStore(_this.name);
  307. var data_2 = [];
  308. store.openCursor().onsuccess = function (e) {
  309. var cursor = e.target.result;
  310. if (cursor) {
  311. if (fn(cursor.value))
  312. data_2.push(cursor.value);
  313. cursor["continue"]();
  314. }
  315. else {
  316. resolve(data_2);
  317. }
  318. };
  319. }
  320. catch (err) {
  321. reject(err);
  322. }
  323. });
  324. });
  325. };
  326. // TODO: people.where('age').below(22).toArray()
  327. GoDBTable.prototype.where = function () {
  328. };
  329. // showing 1000 items maximum in Chrome and Firefox
  330. GoDBTable.prototype.consoleTable = function (limit) {
  331. var _this = this;
  332. if (limit === void 0) { limit = 1000; }
  333. return new Promise(function (resolve, reject) {
  334. _this.godb.getDB(function (idb) {
  335. try {
  336. if (limit > 1000) {
  337. console.warn("Table.consoleTable() expects a limit no more than 1000");
  338. limit = 1000;
  339. }
  340. var count_1 = 0;
  341. var data_3 = {};
  342. var store = idb
  343. .transaction(_this.name, 'readonly')
  344. .objectStore(_this.name);
  345. store.openCursor().onsuccess = function (e) {
  346. var cursor = e.target.result;
  347. if (cursor && count_1 < limit) {
  348. count_1 += 1;
  349. data_3[cursor.key] = __assign({}, cursor.value);
  350. delete data_3[cursor.key].id;
  351. cursor["continue"]();
  352. }
  353. else {
  354. console.log("Data in Table['" + _this.name + "'] of Database['" + _this.godb.name + "'], limit " + limit + ":");
  355. console.table(data_3);
  356. resolve();
  357. }
  358. };
  359. }
  360. catch (err) {
  361. reject(err);
  362. }
  363. });
  364. });
  365. };
  366. return GoDBTable;
  367. }());
  368. var global = window;
  369. var indexedDB = global.indexedDB ||
  370. global.webkitIndexedDB ||
  371. global.mozIndexedDB ||
  372. global.msIndexedDB;
  373. var GoDB = /** @class */ (function () {
  374. function GoDB(name, schema, config) {
  375. // init params
  376. this.version = 0;
  377. this.tables = {};
  378. this._callbackQueue = [];
  379. // save database's name
  380. this.name = name;
  381. // settings
  382. if (config) {
  383. var version = config.version;
  384. if (version)
  385. this.version = version;
  386. }
  387. // init tables, `this.idb` is null when init
  388. this.updateSchema(schema);
  389. // open connection to the IndexedDB
  390. this.getDB();
  391. }
  392. GoDB.prototype.table = function (table, tableSchema) {
  393. if (!this.tables[table]) {
  394. this.tables[table] = new GoDBTable(this, table, tableSchema);
  395. this.updateSchema();
  396. }
  397. else if (tableSchema) {
  398. this.tables[table] = new GoDBTable(this, table, tableSchema);
  399. if (this._shouldUpgrade())
  400. this.updateSchema();
  401. }
  402. return this.tables[table];
  403. };
  404. GoDB.prototype.updateSchema = function (schema) {
  405. if (schema) {
  406. this.tables = {};
  407. for (var table in schema)
  408. this.tables[table] = new GoDBTable(this, table, schema[table]);
  409. }
  410. if (this.idb) {
  411. // create new objectStores when database is already opened
  412. console.log("Updating Schema of Database['" + this.name + "']");
  413. this.idb.close();
  414. // activate callbackQueue in getDB()
  415. // and avoid repeating calling _openDB() before db's opening
  416. this.idb = null;
  417. // triger `onupgradeneeded` event in _openDB() to update objectStores
  418. this._openDB(++this.version, true);
  419. }
  420. };
  421. GoDB.prototype.close = function () {
  422. if (this.idb) {
  423. this.idb.close();
  424. this.idb = null;
  425. this._connection = null;
  426. this._closed = true;
  427. console.log("A connection to Database['" + this.name + "'] is closed");
  428. }
  429. else {
  430. console.warn("Unable to close Database['" + this.name + "']: it is not opened yet");
  431. }
  432. };
  433. // drop a database
  434. GoDB.prototype.drop = function () {
  435. var _this = this;
  436. return new Promise(function (resolve, reject) {
  437. var database = _this.name;
  438. _this.close();
  439. // no need to handle Exception according to MDN
  440. var deleteRequest = indexedDB.deleteDatabase(database);
  441. deleteRequest.onsuccess = function (ev) {
  442. _this.version = 0;
  443. console.log("Database['" + database + "'] is successfully dropped");
  444. if (_this.onClosed) {
  445. if (typeof _this.onClosed === 'function')
  446. _this.onClosed();
  447. else
  448. console.warn("'onClosed' should be a function, not " + typeof _this.onClosed);
  449. _this.onClosed = null;
  450. }
  451. resolve(ev);
  452. };
  453. deleteRequest.onerror = function (ev) {
  454. var error = ev.target.error;
  455. var name = error.name, message = error.message;
  456. console.warn("Unable to drop Database['" + database + "'] \n- " + name + ": " + message);
  457. reject(name + ": " + message);
  458. };
  459. });
  460. };
  461. GoDB.prototype.getDBState = function () {
  462. if (this._closed)
  463. return 'closed';
  464. if (this.idb)
  465. return 'opened';
  466. if (this._connection)
  467. return 'connecting';
  468. return 'init';
  469. };
  470. /**
  471. * It is necessary to get `IDBDatabase` instance (`this.idb`) before
  472. * table operations like table.add(), table.get(), etc.
  473. * that's why a `getDB` function was needed in this class
  474. *
  475. * There are 4 possible states when calling `getDB`:
  476. *
  477. * State `closed`: database is closed or dropped by user
  478. * Operation: warning user in console, not calling callback
  479. * Where: After invoking `this.close()` or `this.drop()`
  480. *
  481. * State `init`: no connection yet (`this.connection` is undefined)
  482. * Operation: open connection to the IndexedDB database
  483. * Where: Constructor's `this.getDB()`, only executed once
  484. *
  485. * State `connecting`: connection opened, but db is not opened yet (`this.idb` is undefined)
  486. * Operation: push the table operations to a queue, executing them when db is opened
  487. * Where: Table operations that are in the same macrotask as `new GoDB()`
  488. *
  489. * State `opened`: The database is opened
  490. * Operation: Invoking the callback synchronously with `this.idb`
  491. * Where: Table operations when the db is opened,
  492. * mention that the db's opening only takes a few milliseconds,
  493. * and normally most of user's table operations will happen after db's opening
  494. *
  495. * State sequence:
  496. * init -> connecting -> opened -> closed
  497. *
  498. * Attention: callback is async-called in state `init` and `connecting`,
  499. * but being sync-called in state `opened`
  500. */
  501. GoDB.prototype.getDB = function (callback) {
  502. // State `opened`: db is opened, calling callback synchronously with IDBDatabase instance
  503. if (this.idb) {
  504. if (callback && typeof callback === 'function')
  505. callback(this.idb);
  506. return;
  507. }
  508. // State `closed`: db is closed
  509. if (this._closed) {
  510. console.warn("Database['" + this.name + "'] is closed, operations will not be executed");
  511. return;
  512. }
  513. // State `connecting`: connection is opened, but db is not opened yet
  514. if (this._connection) {
  515. if (callback && typeof callback === 'function')
  516. this._callbackQueue.push(callback);
  517. return;
  518. }
  519. // State `init`: opening connection to IndexedDB
  520. // In case user has set a version in GoDBConfig
  521. if (this.version)
  522. this._openDB(this.version);
  523. else
  524. this._openDB();
  525. };
  526. GoDB.prototype._openDB = function (version, stopUpgrade) {
  527. var _this = this;
  528. var database = this.name;
  529. var tables = this.tables;
  530. this._connection = version
  531. ? indexedDB.open(database, version)
  532. : indexedDB.open(database);
  533. this._connection.onsuccess = function (ev) {
  534. var result = _this._connection.result
  535. || ev.target.result;
  536. _this.version = result.version;
  537. // triggered when 'onupgradeneeded' was not called
  538. // meaning that the database was already existed in browser
  539. if (!_this.idb) {
  540. _this.idb = result;
  541. console.log("Database['" + database + "'] with version (" + result.version + ") is exisiting");
  542. }
  543. // @ts-ignore
  544. for (var _i = 0, _a = _this.idb.objectStoreNames; _i < _a.length; _i++) {
  545. var name_1 = _a[_i];
  546. if (!_this.tables[name_1])
  547. _this.tables[name_1] = new GoDBTable(_this, name_1);
  548. }
  549. // `stopUpgrade` is used to avoid infinite recursion
  550. if (_this._shouldUpgrade() && !stopUpgrade) {
  551. // make sure the objectStores structure are matching with the Schema
  552. _this.updateSchema();
  553. }
  554. else {
  555. console.log("A connection to Database['" + database + "'] is opening");
  556. // executing Table operations invoked by user at State `connecting`
  557. if (_this._callbackQueue.length) {
  558. _this._callbackQueue.forEach(function (fn) { return fn(_this.idb); });
  559. _this._callbackQueue = [];
  560. }
  561. // call onOpened if it is defined by user
  562. if (_this.onOpened) {
  563. if (typeof _this.onOpened === 'function')
  564. _this.onOpened(_this.idb);
  565. else
  566. console.warn("'onOpened' should be a function, not " + typeof _this.onOpened);
  567. _this.onOpened = null;
  568. }
  569. }
  570. };
  571. // called when db version is changing
  572. // it is called before `onsuccess`
  573. this._connection.onupgradeneeded = function (ev) {
  574. var oldVersion = ev.oldVersion, newVersion = ev.newVersion, target = ev.target;
  575. var transaction = target.transaction;
  576. // get IndexedDB database instance
  577. _this.idb = target.result;
  578. _this.version = newVersion;
  579. if (oldVersion === 0)
  580. console.log("Creating Database['" + database + "'] with version (" + newVersion + ")");
  581. // make sure the IDB objectStores structure are matching with GoDB Tables' Schema
  582. for (var table in tables)
  583. _this._updateObjectStore(table, tables[table].schema, transaction);
  584. if (oldVersion !== 0)
  585. console.log("Database['" + database + "'] version changed from (" + oldVersion + ") to (" + newVersion + ")");
  586. };
  587. this._connection.onerror = function (ev) {
  588. var error = ev.target.error;
  589. var name = error.name, message = error.message;
  590. throw Error("Failed to open Database['" + database + "']"
  591. + ("\n- " + name + ": " + message));
  592. };
  593. this._connection.onblocked = function (ev) {
  594. var _a = ev, newVersion = _a.newVersion, oldVersion = _a.oldVersion;
  595. console.warn("Database['" + database + "'] is opening somewhere with version (" + oldVersion + "),", "thus new opening request to version (" + newVersion + ") was blocked.");
  596. };
  597. };
  598. // check if it is needed to update the objectStores in a existing database
  599. // return true when objectStores structure are not matching with the schema
  600. // - objectStore (table) is not existing
  601. // - table schema has one or more index that objectStore do not have
  602. // - index properties are different from which defined in schema
  603. GoDB.prototype._shouldUpgrade = function () {
  604. var idb = this.idb;
  605. if (!idb)
  606. return false;
  607. var tables = this.tables;
  608. for (var table in tables) {
  609. // check if objectStores is existing
  610. if (idb.objectStoreNames.contains(table)) {
  611. var transaction = idb.transaction(table, 'readonly');
  612. var _a = transaction.objectStore(table), indexNames = _a.indexNames, keyPath = _a.keyPath, autoIncrement = _a.autoIncrement;
  613. // if the keyPath is not 'id', or it is not autoIncrement
  614. if (keyPath !== 'id' || !autoIncrement) {
  615. this.close();
  616. throw Error("The current existing objectStore '" + table + "' in IndexedDB '" + this.name + "'"
  617. + (" has a " + (autoIncrement ? '' : 'non-') + "autoIncrement keyPath `" + keyPath + "`,")
  618. + " while GoDB requires an autoIncrement keyPath `id`,"
  619. + (" thus GoDB can not open Database['" + this.name + "']"));
  620. }
  621. for (var index in tables[table].schema) {
  622. // check if the objectStore has the index
  623. if (indexNames.contains(index)) ;
  624. else {
  625. // closing the transaction to avoid db's `blocked` event when upgrading
  626. transaction.abort();
  627. return true;
  628. }
  629. }
  630. transaction.abort();
  631. }
  632. else {
  633. return true;
  634. }
  635. }
  636. return false;
  637. };
  638. // applying the schema to corresponding IndexedDB objectStores to setup indexes
  639. // require IDBTransaction `versionchange`
  640. // it can only be called in `onupgradeneeded`
  641. GoDB.prototype._updateObjectStore = function (table, schema, transaction) {
  642. var idb = this.idb;
  643. if (!idb)
  644. return;
  645. var putIndex = function (index, store, update) {
  646. if (index === 'id')
  647. return;
  648. if (update)
  649. store.deleteIndex(index);
  650. store.createIndex(index, index, {
  651. unique: !!schema[index]['unique'],
  652. multiEntry: !!schema[index]['multiEntry']
  653. });
  654. console.log((update ? 'Updating' : 'Creating') + " Index['" + index + "']", "in Table['" + table + "'], Database['" + idb.name + "']");
  655. };
  656. if (idb.objectStoreNames.contains(table)) {
  657. // objectStore is existing, update its indexes
  658. var store = transaction.objectStore(table);
  659. var indexNames = store.indexNames;
  660. // if the objectStore contains an index, update the index
  661. // if not, create a new index in the objectStore
  662. for (var index in this.tables[table].schema)
  663. putIndex(index, store, indexNames.contains(index));
  664. }
  665. else {
  666. // create objectStore if not exist
  667. var store = idb.createObjectStore(table, {
  668. keyPath: 'id',
  669. autoIncrement: true
  670. });
  671. console.log("Creating Table['" + table + "'] in Database['" + idb.name + "']");
  672. for (var index in schema)
  673. putIndex(index, store);
  674. }
  675. };
  676. return GoDB;
  677. }());
  678. export default GoDB;