databaseAction(modelPath, modelArtifacts) {
        return new Promise((resolve, reject)=>{
            const openRequest = this.indexedDB.open(DATABASE_NAME, DATABASE_VERSION);
            openRequest.onupgradeneeded = ()=>setUpDatabase(openRequest);
            openRequest.onsuccess = ()=>{
                const db = openRequest.result;
                if (modelArtifacts == null) {
                    // Read model out from object store.
                    const modelTx = db.transaction(MODEL_STORE_NAME, "readonly");
                    const modelStore = modelTx.objectStore(MODEL_STORE_NAME);
                    const getRequest = modelStore.get(this.modelPath);
                    getRequest.onsuccess = ()=>{
                        if (getRequest.result == null) {
                            db.close();
                            return reject(new Error(`Cannot find model with path '${this.modelPath}' ` + `in IndexedDB.`));
                        } else resolve(getRequest.result.modelArtifacts);
                    };
                    getRequest.onerror = (error)=>{
                        db.close();
                        return reject(getRequest.error);
                    };
                    modelTx.oncomplete = ()=>db.close();
                } else {
                    // Put model into object store.
                    // Concatenate all the model weights into a single ArrayBuffer. Large
                    // models (~1GB) have problems saving if they are not concatenated.
                    // TODO(mattSoulanille): Save large models to multiple indexeddb
                    // records.
                    modelArtifacts.weightData = (0, _compositeArrayBuffer.CompositeArrayBuffer).join(modelArtifacts.weightData);
                    const modelArtifactsInfo = (0, _ioUtils.getModelArtifactsInfoForJSON)(modelArtifacts);
                    // First, put ModelArtifactsInfo into info store.
                    const infoTx = db.transaction(INFO_STORE_NAME, "readwrite");
                    let infoStore = infoTx.objectStore(INFO_STORE_NAME);
                    let putInfoRequest;
                    try {
                        putInfoRequest = infoStore.put({
                            modelPath: this.modelPath,
                            modelArtifactsInfo
                        });
                    } catch (error) {
                        return reject(error);
                    }
                    let modelTx;
                    putInfoRequest.onsuccess = ()=>{
                        // Second, put model data into model store.
                        modelTx = db.transaction(MODEL_STORE_NAME, "readwrite");
                        const modelStore = modelTx.objectStore(MODEL_STORE_NAME);
                        let putModelRequest;
                        try {
                            putModelRequest = modelStore.put({
                                modelPath: this.modelPath,
                                modelArtifacts,
                                modelArtifactsInfo
                            });
                        } catch (error) {
                            // Sometimes, the serialized value is too large to store.
                            return reject(error);
                        }
                        putModelRequest.onsuccess = ()=>resolve({
                                modelArtifactsInfo
                            });
                        putModelRequest.onerror = (error)=>{
                            // If the put-model request fails, roll back the info entry as
                            // well.
                            infoStore = infoTx.objectStore(INFO_STORE_NAME);
                            const deleteInfoRequest = infoStore.delete(this.modelPath);
                            deleteInfoRequest.onsuccess = ()=>{
                                db.close();
                                return reject(putModelRequest.error);
                            };
                            deleteInfoRequest.onerror = (error)=>{
                                db.close();
                                return reject(putModelRequest.error);
                            };
                        };
                    };
                    putInfoRequest.onerror = (error)=>{
                        db.close();
                        return reject(putInfoRequest.error);
                    };
                    infoTx.oncomplete = ()=>{
                        if (modelTx == null) db.close();
                        else modelTx.oncomplete = ()=>db.close();
                    };
                }
            };
            openRequest.onerror = (error)=>reject(openRequest.error);
        });
    }
Perform database action to put model artifacts into or read model artifacts
from IndexedDB object store.

Whether the action is put or get depends on whether `modelArtifacts` is
specified. If it is specified, the action will be put; otherwise the action
will be get.

@param modelPath A unique string path for the model.
@param modelArtifacts If specified, it will be the model artifacts to be
  stored in IndexedDB.
@returns A `Promise` of `SaveResult`, if the action is put, or a `Promise`
  of `ModelArtifacts`, if the action is get.