上一篇文章提及到vscode里面涉及到两个数据库的使用,IndexDB和SQLite,关于IndexDB数据库的使用,感兴趣的同学可以查看我的上一篇文章,本文主要讲解SQLite数据库。
SQLite,著名的本地关系型数据库,官网: https://www.sqlite.org/index.html
vscode在此基础上进行了封装@vscode/sqlite3
npm: https://www.npmjs.com/package/@vscode/sqlite3
github: https://github.com/microsoft/vscode-node-sqlite3
文档:https://github.com/TryGhost/node-sqlite3/wiki/API#getsql–param—callback
npm install sqlite3
# or
yarn add sqlite3
使用,官方给了一个简单的例子:
const sqlite3 = require('sqlite3').verbose();
const db = new sqlite3.Database(':memory:');
db.serialize(() => {
db.run("CREATE TABLE lorem (info TEXT)");
const stmt = db.prepare("INSERT INTO lorem VALUES (?)");
for (let i = 0; i < 10; i++) {
stmt.run("Ipsum " + i);
}
stmt.finalize();
db.each("SELECT rowid AS id, info FROM lorem", (err, row) => {
console.log(row.id + ": " + row.info);
});
});
db.close();
执行结果
封装一个简单是增删改查的例子
export interface IDatabaseNew {
// getSome(): void;
// getProjectInformationDB(): Promise<any>;
deleteData(queryKey: string, queryValue: any): Promise<any>;
insertData(data: object): Promise<boolean>;
queryData(queryKey: string, queryValue: string): Promise<any>;
updataData(queryMap: {
[propName: string]: any }, conditions: {
[propName: string]: any }): Promise<boolean>;
}
export class DatabaseNew implements IDatabaseNew {
private readonly DB = this.connect(this.path, this.tableName);
private readonly session = this.getSession();
constructor(
private readonly path: string,
private readonly tableName: string,
private readonly userAuthenticationService: IUserAuthenticationService,
) {
}
async getSession() {
return await this.userAuthenticationService.getSession();
}
async updataData(queryMap: {
[propName: string]: any }, conditions: {
[propName: string]: any }): Promise<boolean> {
// db.serialize
let DB = await this.DB;
// let session = await this.session;
return new Promise<boolean>((resolve, reject) => {
if (queryMap && Object.keys(queryMap).length > 0) {
DB.all(`PRAGMA table_info(${
this.tableName})`, async (err: any, rows: any) => {
if (err) {
reject(false);
}
const keyNameList = rows.map((it: {
name: any }) => it.name);
const keyList: string[] = [];
const valueList: any[] = [];
for (let key of Object.keys(queryMap)) {
let value = queryMap[key];
keyList.push(key);
if (keyNameList.indexOf(key) === -1) {
DB = await new Promise<Database>((res, rej) => {
const newdb = DB.run(`ALTER TABLE ${
this.tableName} ADD COLUMN ${
key} NONE`, (err: any) => {
if (err) {
rej(err);
}
res(newdb);
});
});
}
if (value instanceof Object) {
valueList.push(JSON.stringify(value));
} else {
valueList.push(value);
}
}
// eslint-disable-next-line code-no-unexternalized-strings
DB.run(`UPDATE ${
this.tableName} SET ${
keyList.map(item => item + '=?').join(',')} WHERE ${
Object.keys(conditions).map(item => item + '=?').join(',')} ;`, [...valueList, ...Object.values(conditions)], (err: any, row: any) => {
if (err) {
reject(false);
}
resolve(true);
});
});
} else {
reject(false);
}
});
}
async deleteData(queryKey: string, queryValue: any): Promise<any> {
let DB = await this.DB;
// let session = await this.session;
return new Promise<any>((resolve, reject) => {
DB.get(`DELETE FROM ${
this.tableName} WHERE ${
queryKey} = '${
queryValue}' ;`, (err: any, row: any) => {
if (err) {
reject(err);
}
resolve(true);
});
});
}
async selecAllData(): Promise<any> {
let DB = await this.DB;
return new Promise<any>((resolve, reject) => {
DB.all(`SELECT * FROM ${
this.tableName} ;`, (err: any, row: any) => {
if (err) {
resolve(undefined);
}
if (row && row.length) {
row.forEach((item: any) => {
for (let key of Object.keys(item)) {
let value = item[key];
if (isJSON(value)) {
item[key] = JSON.parse(value);
}
}
});
}
resolve(row);
});
});
}
async queryData(queryKey: string, queryValue: any): Promise<any> {
let DB = await this.DB;
return new Promise<any>((resolve, reject) => {
DB.get(`SELECT * FROM ${
this.tableName} WHERE ${
queryKey} = '${
queryValue}' ;`, (err: any, row: any) => {
if (err) {
resolve(undefined);
}
if (row && Object.keys(row).length > 0) {
for (let key of Object.keys(row)) {
let value = row[key];
if (isJSON(value)) {
row[key] = JSON.parse(value);
}
}
}
resolve(row);
});
});
}
async insertData(data: {
[propName: string]: any }): Promise<boolean> {
let DB = await this.DB;
return new Promise<boolean>((resolve, reject) => {
DB.serialize(() => {
DB.all(`PRAGMA table_info(${
this.tableName})`, async (err: any, rows: any) => {
if (err) {
reject(false);
}
const keyNameList = rows.map((it: {
name: any }) => it.name);
if (data && Object.keys(data).length > 0) {
const keyList: string[] = [];
const valueList: any[] = [];
for (let key of Object.keys(data)) {
let value = data[key];
keyList.push(key);
if (keyNameList.indexOf(key) === -1) {
DB = await new Promise<Database>((resolve, reject) => {
const newdb = DB.run(`ALTER TABLE ${
this.tableName} ADD COLUMN ${
key} NONE`, (err: any) => {
if (err) {
reject(err);
}
resolve(newdb);
});
});
}
if (value instanceof Object) {
valueList.push(JSON.stringify(value));
} else {
valueList.push(value);
}
}
const stmt = DB.prepare(`INSERT INTO ${
this.tableName} (${
keyList.join(',')}) VALUES(${
new Array(keyList.length).fill('?').join(',')})`);
stmt.run(valueList);
stmt.finalize();
resolve(true);
}
reject(false);
});
});
});
}
connect(path: string, tableName: string): Promise<Database> {
return new Promise((resolve, reject) => {
try {
import('@vscode/sqlite3').then(sqlite3 => {
const db: Database = new (sqlite3.Database)(path, error => {
if (error) {
return db ? db.close(() => reject(error)) : reject(error);
}
if (tableName) {
db.exec(`CREATE TABLE IF NOT EXISTS ${
tableName} (
id INTEGER PRIMARY KEY
)`, (err: any) => {
if (err) {
db.close();
return reject(err);
}
});
}
});
resolve(db);
});
} catch (error) {
if (error && error.code === 'SQLITE_BUSY') {
return this.connect(path, tableName);
}
return reject(error);
}
});
}
async close(): Promise<void | null> {
const DB = await this.DB;
return new Promise((resolve, reject) => {
DB.close((Error) => {
if (Error) {
reject(Error);
}
resolve();
});
});
}
}
实现一个服务
export interface IDatabaseService {
readonly _serviceBrand: undefined;
// getSome(): void;
getProjectInformationDB(): DatabaseNew;
getDatabaseDB(path?: string, tableName?: string): Promise<any>;
}
export class DatabaseService extends Disposable implements IDatabaseService {
declare readonly _serviceBrand: undefined;
constructor(
// @IContextKeyService private contextKeyService: IContextKeyService,
// @IEditorService private editorService: IEditorService,
@IUserAuthenticationService private readonly userAuthenticationService: IUserAuthenticationService,
@IBrowserWorkbenchEnvironmentService private readonly environmentService: IBrowserWorkbenchEnvironmentService,
) {
super();
}
getProjectInformationDB(): DatabaseNew {
let path = resources.joinPath(this.environmentService.globalStorageHome, 'info.db').fsPath;
return new DatabaseNew(path, 'projectInfo', this.userAuthenticationService);
}
getDatabaseDB(path?: string, tableName?: string) {
return new Promise((resolve, reject) => {
import('@vscode/sqlite3').then(sqlite3 => {
const db: Database = new (sqlite3.Database)('text.db', error => {
if (error) {
return db ? db.close(() => reject(error)) : reject(error);
}
if (tableName) {
db.exec(`CREATE TABLE IF NOT EXISTS ${
tableName} (
id INTEGER PRIMARY KEY
)`, (err: any) => {
if (err) {
return reject(err);
}
});
}
});
resolve(db);
});
});
}
}
调用
// 插件里根据pathId查询数据
CommandsRegistry.registerCommand('vscode.getdataFromDB', async (accessor: ServicesAccessor, ...args) => {
const databaseService = accessor.get(IDatabaseService);
const path = args[0];
const dataBase = databaseService.getProjectInformationDB();
const data = await dataBase.queryData('pathId', path);
dataBase.close();
return data;
});
CommandsRegistry.registerCommand('vscode.updatedataDB', async (accessor: ServicesAccessor, ...args) => {
const databaseService = accessor.get(IDatabaseService);
const path = args[0];
const datas = args[1];
const dataBase = databaseService.getProjectInformationDB();
const data = await dataBase.queryData('pathId', path);
if (data) {
const reuslt = await dataBase.updataData(datas, {
pathId: path });
dataBase.close();
return reuslt;
} else {
dataBase.close();
}
return null;
});
CommandsRegistry.registerCommand('vscode.insertdataDB', async (accessor: ServicesAccessor, ...args) => {
const databaseService = accessor.get(IDatabaseService);
const json = args[0];
const dataBase = databaseService.getProjectInformationDB();
const data = await dataBase.insertData(json);
dataBase.close();
if (data) {
return true;
} else {
dataBase.close();
}
return null;
});
CommandsRegistry.registerCommand('vscode.deletedataDB', async (accessor: ServicesAccessor, ...args) => {
const databaseService = accessor.get(IDatabaseService);
const key = args[0];
const value = args[1];
const dataBase = databaseService.getProjectInformationDB();
const data = await dataBase.deleteData(key, value);
dataBase.close();
if (data) {
return true;
} else {
dataBase.close();
}
return null;
});