SQLite3ファイルをダウンロード&アップロードできるようにした。
ブツ
前回まで
コード
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に挿入する。