SQLite3ファイルをダウンロード&アップロードできるようにした。

ブツ

eyecatch.png

前回まで

コード

sql.js

sql.jsはSQLite3のファイルデータを読書するライブラリ。これを使ってつぶやきの内容をDBファイルに保存する。それを読み込んでHTML表示する。

cdnなどからライブラリファイルを取得する。

  • sql-wasm.wasm
  • sql-wasm.min.js

それを適当に配置し、index.htmlで参照する。

<script src="lib/sql.js/1.7.0/sql-wasm.min.js"></script>

おおよその使い方は以下。

const SQL = await initSqlJs({locateFile: file => `lib/sql.js/1.7.0/${file}`})
const DB = this.SQL.Database(dbAsUint8Array) // 引数にDBファイルのデータをUint8Array型で渡すとロード。なければ新規。
DB.exec(`create table if not exists comments (
  id integer primary key not null,
  content text not null,
  created integer not null
);`)
DB.exec(`insert into comments (content, created) values ('test',${Math.floor(new Date().getTime()/1000)});`)
const cms = DB.exec(`select * from comments;`)
for (const row of cms[0].values) {
    console.debug(row[0], row[1], row[2])
}
DB.export() // SQLite3データをUnit8Array型で取得する。これをファイル化してダウンロードする

ダウンロード

ブラウザでファイルをダウンロードする方法は以下。

const content = await this.#makeDb()
const url = (window.URL || window.webkitURL).createObjectURL(new Blob([content], {type: 'application/octet-stream'}));
const download = document.createElement('a');
download.href = url;
download.download = `mylog.db`;
download.click();
(window.URL || window.webkitURL).revokeObjectURL(url);

ダウンロードするファイルはSQLite3のDBファイル。それを作成するのは以下。DBファイルデータを作成し、テーブルとレコードをSQL文によって作成する。

大本のデータは前回のようにdexie.jsを介してIndexedDBに保存してある。そこからデータを取得し、SQL文を作って発行し、SQLite3ファイルを作成している。

async #makeDb() {
    if (!this.SQL) { this.SQL = await initSqlJs({locateFile: file => `lib/sql.js/1.7.0/${file}`}) }
    const db = new this.SQL.Database();
    db.exec(`BEGIN;`)
    await this.#makeTableComments(db)
    db.exec(`COMMIT;`)
    return db.export()
}
async #makeTableComments(db) {
    db.exec(this.#createSqlComments())
    const cms = await this.db.dexie.comments.toArray()
    for (const c of cms) {
        db.exec(`insert into comments (content, created) values ('${c.content}',${c.created});`)
    }
}
    #createSqlComments() { return `
create table if not exists comments (
  id integer primary key not null,
  content text not null,
  created integer not null
);`
    }

アップロード

SQLite3ファイルを所定の領域dropZone要素にドラッグ&ドロップすると、ファイルを読み込む。

ドラッグ&ドロップのイベント処理

dropZone.addEventListener('drop', async(e)=>{
    var files = e.dataTransfer.files;
    if (files.length > 1) { return Toaster.toast('アップロードできるファイルは1つだけです。', true); }
    fileInput.files = files;
    const fr = new FileReader();
    fr.readAsArrayBuffer(files[0])
    fr.addEventListener('load', async(event) => {
        await this.#load(files[0].name, new Uint8Array(fr.result)) 
    })
}, false);

ファイルを読み込む方法は他にも<input type="file">やFileSystemAccess APIによるものもあるが割愛する。詳しくはソースコード参照。

SQLite3DBファイルの読込は先述のとおり以下コードになる。そこに渡すデータをUint8Array型に変換している所がキモ。

const SQL = await initSqlJs({locateFile: file => `lib/sql.js/1.7.0/${file}`})
const DB = this.SQL.Database(dbAsUint8Array) // 引数にDBファイルのデータをUint8Array型で渡すとロード。なければ新規。

SQLite3ファイルの読込

async #load(name, content) { // ローカルのsqlite3ファイルからIndexedDBへマージする
    const db = await this.sqlFile.read(name)
    let res = await this.#valid(db)
    if (!res) { Loading.hide(); return; }
    // SQLite3DBレコードをIndexedDBに挿入する
    this.db.dexie.comments.clear()
    res = db.exec(`select * from comments;`)
    for (const row of res[0].values) {
        await this.db.dexie.comments.put({
            id: row[0],
            content: row[1],
            created: row[2],
        })
    }
}

SQLite3DBファイルをロードしたら全レコードをselect文で取得し、その結果をdexie.jsを介してIndexedDBに挿入する。