src/SQLite3/SQLite3.js
/**
* The script is part of toolbox-wsh.
*
* AUTHOR:
* natade (http://twitter.com/natadea)
*
* LICENSE:
* The MIT license https://opensource.org/licenses/MIT
*/
/// <reference path="../../include/SenkoWSH.d.ts" />
import SQLite3Schema from "./SQLite3Schema.js";
import SQLite3IF from "./SQLite3IF.js";
/**
* SQL のタイムアウト設定
*/
const SQL_TIME_OUT = ".timeout 1000\n";
/**
* WSH で SQLite3 を使用するためのライブラリ
* @requires SenkoWSH
*/
export default class SQLite3 {
/**
* 利用するデータベースをセット
* @param {SFile} db_file DBファイル
* @returns {Object<string, SQLite3IF>} テーブル操作用データ
*/
static use(db_file) {
/**
* @type {Object<string, SQLite3IF>}
*/
const output = {};
// テーブル名のリストを作成
const table_name = SQLite3.execSQL(db_file, ".tables", "-readonly");
if(!table_name) {
console.log("Error : tables " + db_file);
return null;
}
const table_name_list = table_name.trim().split(/\s+/);
// テーブル内の列データを作成する
/**
* 列名
* @type {string[]}
*/
const table_info_sql = [];
for(let i = 0; i < table_name_list.length; i++) {
const key = table_name_list[i];
table_info_sql.push("pragma table_info(" + key + ");");
}
// テーブル内の列データを全て取得する
const table_info_data = SQLite3.execSQL(db_file, table_info_sql.join(""), "-readonly -json");
if(!table_info_data) {
console.log("Error : table_info " + db_file);
return null;
}
// []で括られた1テーブルごとのJSON情報から、1テーブルずつ抜き出して、データを格納する
/**
* 列情報
* @type {SQLite3Schema[]}
*/
const type_obj_list = [];
/**
* @param {string} table_info_text
* @returns {string}
* @private
*/
const create_table_info = function(table_info_text) {
type_obj_list.push(SQLite3Schema.create(table_info_text));
return "";
}
table_info_data.replace(/(\[[^\]]+\])/g, create_table_info);
// IFを作成していく
for(let i = 0; i < table_name_list.length; i++) {
const key = table_name_list[i];
const data = new SQLite3IF(db_file, key, type_obj_list[i]);
output[key] = data;
}
return output;
}
/**
* データベースをバキュームする
* @param {SFile} db_file DBファイル
* @returns {boolean}
*/
static vaccum(db_file) {
return SQLite3.execSQL(db_file, "vacuum;") !== null;
}
/**
* SQL文を実行する
* @param {SFile} db_file DBファイル
* @param {string} sql SQL文
* @param {string} [option] 実行時のオプション
* @returns {string | null} SQL実行結果
*/
static execSQL(db_file, sql, option) {
if(!SQLite3.sqlite3) {
console.log("Error : execSQL " + db_file + "," + sql);
return null;
}
const option_ = option !== undefined ? option : "";
const sql_file = SFile.createTempFile();
const sqt_text = SQL_TIME_OUT + sql;
sql_file.writeString(sqt_text, "utf-8", "\r\n", false);
const script = "\"" + SQLite3.sqlite3.getAbsolutePath() + "\" \"" + db_file.getAbsolutePath() + "\" " + option_ + " < \"" + sql_file.getAbsolutePath() + "\"";
const output = System.execBatchScript(script, "utf-8");
sql_file.remove();
if(output.exit_code) {
console.log(output.error);
return null;
}
return output.out;
}
/**
* ツールをインストールする
* - `./lib/sqlite3.exe` を利用する
* - ファイルが存在しない場合は自動でダウンロードする
* - 本ライブラリを使用する場合は、`setSQLite3` でツールを設定するか、`install` でダウンロードする必要がある
*
* @returns {boolean}
*/
static install() {
if(SQLite3.sqlite3) {
return true;
}
const exe_path = "./lib/sqlite3.exe";
const exe_file = new SFile(exe_path);
if(exe_file.isFile()) {
// ファイルがある場合はそれを設定する
return SQLite3.setSQLite3(exe_file);
}
else {
// ファイルがない場合は、ダウンロードしてくれる
new SFile("./lib").mkdirs();
const download_url = "https://www.sqlite.org/download.html";
const download_text = new SFile(download_url).readString();
if(download_text) {
const match_data = download_text.match(/'[^']+\/sqlite-tools-win32[^']+'/);
if(match_data) {
const match_text = match_data[0].toString();
const zip_url = "https://www.sqlite.org/" + match_text.substr(1, match_text.length - 2);
const zip_binary = new SFile(zip_url).readBinary();
if(zip_binary.length !== 0) {
const temp_file_1 = SFile.createTempFile();
temp_file_1.mkdirs();
const zip_file = new SFile(temp_file_1 + "\\" + new SFile(zip_url).getName());
zip_file.writeBinary(zip_binary);
const temp_file_2 = SFile.createTempFile();
SFile.extract(zip_file, temp_file_2);
/**
* @type {SFile}
*/
const sqlite3_file = SFile.findFile(temp_file_2, /\\sqlite3.exe$/i);
if(sqlite3_file) {
sqlite3_file.move("./lib");
}
temp_file_1.remove();
temp_file_2.remove();
return SQLite3.setSQLite3(sqlite3_file);
}
}
}
}
return false;
}
/**
* ツールを設定する
* - `*.db` を操作するための `sqlite-tools-win32` に含まれる `sqlite3.exe` を設定する
* @param {SFile|string} sqlite_tool_path
* @returns {boolean}
*/
static setSQLite3(sqlite_tool_path) {
const exe_file = new SFile(sqlite_tool_path);
if(!exe_file.isFile() || !/sqlite3.exe$/i.test(exe_file.getAbsolutePath()) ) {
return false;
}
SQLite3.sqlite3 = exe_file;
return true;
}
}
/**
* `*.db` を操作するための `sqlite-tools-win32` に含まれる `sqlite3.exe`
* @type {SFile}
*/
SQLite3.sqlite3 = null;