Проблемы с indexeddb и архитектурой не позволяют создать objectStore - PullRequest
0 голосов
/ 06 апреля 2020

Я пишу сложную (или нет) архитектуру для 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 не мой естественный язык, и я не знаю, если Я передаю суть моей проблемы.

Спасибо!

...