Я пишу сложную (или нет) архитектуру для JS приложения. Может быть, PWA. Я хотел использовать IndexedDb в качестве хранилища в этом приложении, но не могу понять, как вписать его в систему разработки, ориентированную на сервис / магазин.
У меня есть какой-то сервис, простой интерфейс, который позволяет легко использовать операции CRUD из контроллера или компонентов. Эта служба имеет следующий код:
class Service {
constructor(stores, table) {
this.stores = stores;
this.table = table;
this.default = this.stores.getDefault();
}
list() {
return this.default.list(this.table);
}
add(value) {
const val = value;
val.id = crypto.uuid();
this.stores.list(this.table).forEach((store) => {
store.add(this.table, val);
});
}
update(value) {
this.stores.list(this.table).forEach((store) => {
store.update(value);
});
return true;
}
save(value) {
this.stores.list(this.table).forEach((store) => {
if (value.id) {
store.update(this.table, value);
} else {
store.add(this.table, value);
}
});
return true;
}
remove(value) {
this.stores.list(this.table).forEach((store) => {
store.remove(this.table, value);
});
return true;
}
obtain(value) {
return this.default.obtain(this.table, value);
}
getIndex(value) {
return this.default.getIndex(this.table, value);
}
}
export default Service;
Эта служба получает коллекцию магазинов. «Магазины» - это объекты, которые позволяют сохранять данные в разных базах данных.
У меня есть класс, управляющий магазинами:
export default class Stores {
constructor() {
this.stores = [];
this.default = '';
}
add(store) {
this.stores.push(store);
}
list() {
return this.stores;
}
getDefault() {
const d = this.stores.findIndex((x) => x.name === this.default);
return this.stores[d];
}
}
И, наконец, у меня есть коллекция хранилищ, которые разрешают операции с данными CRUD, например Store for localStorage:
import Store from './store';
const provider = 'localStorage';
export default class LocalStorageStore extends Store {
constructor() {
super();
this.name = provider;
this.data = [];
}
list(table) {
this.data[table] = localStorage.getItem(table);
return this.data[table] || [];
}
add(table, value) {
if (!this.data[table]) {
this.data[table] = [];
}
this.data[table].push(value);
localStorage.setItem(table, this.data[table]);
}
update(table, value) {
const index = this.getIndex(table, value);
this.data[table][index] = value;
localStorage.setItem(table, this.data[table]);
}
remove(table, value) {
const index = this.getIndex(table, value);
this.data[table].splice(index, 1);
localStorage.setItem(table, this.data[table]);
return true;
}
obtain(table, value) {
return this.data[table].find((v) => v.id === value.id);
}
getIndex(table, value) {
return this.data[table].findIndex((v) => v.id === value.id);
}
}
Базовое хранилище:
export default class Store {
get provider() {
return this.name;
}
}
с учетом этого легко представить, что у меня есть хранилища, которые отправляют данные на сервер и т. Д. c ...
Теперь, в момент инициализации приложения я инициализирую магазины и сервисы:
this.stores = new Stores();
const ls = new LocalStorageStore();
this.stores.add(ls);
this.stores.default = ls.provider;
// and some others
Теперь, когда вызывается маршрут, я инициализирую сервис:
class SupplierService extends Service {
constructor(stores) {
super(stores, 'supplier');
}
}
export default SupplierService;
и вызываю контроллер:
const ps = new SupplierService(me.stores);
const p = new SuppliersController(me.auth, ps);
Контроллер:
class SuppliersController {
constructor(auth, service) {
this.auth = auth;
this.service = service;
}
render() {
const data = this.service.list();
if (data.length > 0) {
//loop here to draw a <table> with <tr>
}
}
В этой архитектуре я не вижу, как создавать объекты Store и инициализировать базу данных в IndexedDB. Когда я вызываю службу, я передаю имя таблицы и ожидаю, что база данных и магазин открыты.
export default class IndexedDbStore extends Store {
constructor() {
super();
this.name = provider;
this.db = null;
const trick = (async () => this.init());
trick();
}
async init() {
this.db = await window.indexedDB.open('database', 1);
this.db.onsuccess = this.iOnSuccess;
this.db.onupgradeneeded = this.iOnUpgrade;
this.db.onerror = this.iOnError;
}
// eslint-disable-next-line class-methods-use-this
iOnSuccess(event) {
console.log('success', event);
}
// eslint-disable-next-line class-methods-use-this
iOnUpgrade(event) {
console.log('upgrade', event);
}
// eslint-disable-next-line class-methods-use-this
iOnError(event) {
console.log('upgrade', event);
}
async getTable(table) {
let tx;
try {
tx = await this.db.result.objectStore(table);
} catch (e) {
await this.db.result.createObjectStore(table, {
keyPath: 'id',
autoIncrement: true,
});
}
return tx;
}
async list(table) {
const tx = await this.getTable(table);
const data = await tx.getAll();
await tx.done();
return data;
}
}
С этим предыдущим кодом и всей архитектурой, когда я вызываю
this.service.list();
список ( таблица), но я не знаю, почему не выполняется onupgradeneeded, this.db имеет объект IDBRequestDatabase, но я просто получаю сообщение об ошибке:
indexedDbStorage.js:45 Uncaught (in promise) DOMException: Failed to execute 'createObjectStore' on 'IDBDatabase': The database is not running a version change transaction.
objectCreateStore можно выполнить только в onupgradeneeded. Но я не могу поставить его там, потому что если я позвоню с другого контроллера с другими сервисами, onupgradeneeded не будет выполнен.
Engli sh не мой естественный язык, и я не знаю, если Я передаю суть моей проблемы.
Спасибо!