2020-05-29 22:22:00 +02:00
|
|
|
// Copyright 2017-2018 Xuan Sang LE <xsang.le AT gmail DOT com>
|
|
|
|
|
|
|
|
// AnTOS Web desktop is is licensed under the GNU General Public
|
|
|
|
// License v3.0, see the LICENCE file for more information
|
|
|
|
|
|
|
|
// This program is free software: you can redistribute it and/or
|
|
|
|
// modify it under the terms of the GNU General Public License as
|
|
|
|
// published by the Free Software Foundation, either version 3 of
|
|
|
|
// the License, or (at your option) any later version.
|
|
|
|
|
|
|
|
// This program is distributed in the hope that it will be useful,
|
|
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
// General Public License for more details.
|
|
|
|
|
|
|
|
// You should have received a copy of the GNU General Public License
|
2020-06-16 18:02:17 +02:00
|
|
|
// along with this program. If not, see https://www.gnu.org/licenses/.
|
2020-05-29 22:22:00 +02:00
|
|
|
|
|
|
|
namespace OS {
|
|
|
|
export namespace API {
|
|
|
|
/**
|
2020-06-17 21:06:55 +02:00
|
|
|
* Simple Virtual Database (VDB) application API.
|
2020-05-29 22:22:00 +02:00
|
|
|
*
|
2020-06-17 21:06:55 +02:00
|
|
|
* This API abstracts and provides a standard way to
|
|
|
|
* connect to a server-side relational database (e.g. sqlite).
|
|
|
|
*
|
|
|
|
* Each user when connected has their own database previously
|
|
|
|
* created. All VDB operations related to that user will be
|
|
|
|
* performed on this database.
|
|
|
|
*
|
|
|
|
* The creation of user database need to be managed by the server-side API.
|
|
|
|
* The VDB API assumes that the database already exist. All operations
|
|
|
|
* is performed in tables level
|
2020-05-29 22:22:00 +02:00
|
|
|
*
|
|
|
|
* @export
|
|
|
|
* @class DB
|
|
|
|
*/
|
|
|
|
export class DB {
|
2020-06-17 21:06:55 +02:00
|
|
|
/**
|
|
|
|
* A table name on the user's database
|
|
|
|
*
|
|
|
|
* @private
|
|
|
|
* @type {string}
|
|
|
|
* @memberof DB
|
|
|
|
*/
|
|
|
|
private table: string;
|
2020-05-29 22:22:00 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
*Creates an instance of DB.
|
2020-06-17 21:06:55 +02:00
|
|
|
* @param {string} table table name
|
2020-05-29 22:22:00 +02:00
|
|
|
* @memberof DB
|
|
|
|
*/
|
2020-06-17 21:06:55 +02:00
|
|
|
constructor(table: string) {
|
2020-05-29 22:22:00 +02:00
|
|
|
this.table = table;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2020-06-17 21:06:55 +02:00
|
|
|
* Save data to the current table. The input
|
|
|
|
* data must conform to the table record format.
|
2020-05-29 22:22:00 +02:00
|
|
|
*
|
2020-06-17 21:06:55 +02:00
|
|
|
* On the server side, if the table doest not
|
|
|
|
* exist yet, it should be created automatically
|
|
|
|
* by inferring the data structure of the input
|
|
|
|
* object
|
2020-05-29 22:22:00 +02:00
|
|
|
*
|
2020-06-17 21:06:55 +02:00
|
|
|
* @param {GenericObject<any>} d data object represents a current table record
|
2020-05-29 22:22:00 +02:00
|
|
|
* @returns {Promise<API.RequestResult>}
|
|
|
|
* @memberof DB
|
|
|
|
*/
|
2020-06-17 21:06:55 +02:00
|
|
|
save(d: GenericObject<any>): Promise<API.RequestResult> {
|
2020-06-05 17:46:04 +02:00
|
|
|
return new Promise(async (resolve, reject) => {
|
2020-05-29 22:22:00 +02:00
|
|
|
try {
|
2020-06-17 21:06:55 +02:00
|
|
|
const r = await API.handle.dbquery("save", {
|
2020-05-29 22:22:00 +02:00
|
|
|
table: this.table,
|
|
|
|
data: d,
|
|
|
|
});
|
|
|
|
if (r.error) {
|
2020-06-17 21:06:55 +02:00
|
|
|
return reject(API.throwe(r.error.toString()));
|
2020-05-29 22:22:00 +02:00
|
|
|
}
|
|
|
|
return resolve(r);
|
|
|
|
} catch (e) {
|
|
|
|
return reject(__e(e));
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2020-06-17 21:06:55 +02:00
|
|
|
* delete record(s) from the current table by
|
|
|
|
* a conditional object
|
|
|
|
*
|
|
|
|
* @param {*} c conditional object, c can be:
|
|
|
|
*
|
|
|
|
* * a `number`: the operation will delete the record with `id = c`
|
|
|
|
* * a `string`: The SQL string condition that selects record to delete
|
|
|
|
* * a conditional object represents a SQL condition statement as an object,
|
|
|
|
* example: `pid = 10 AND cid = 2` is represented by:
|
2020-05-29 22:22:00 +02:00
|
|
|
*
|
2020-06-17 21:06:55 +02:00
|
|
|
* ```typescript
|
|
|
|
* {
|
|
|
|
* exp: {
|
|
|
|
* "and": {
|
|
|
|
* pid: 10,
|
|
|
|
* cid: 2
|
|
|
|
* }
|
|
|
|
* }
|
|
|
|
* ```
|
2020-05-29 22:22:00 +02:00
|
|
|
*
|
|
|
|
* @returns {Promise<API.RequestResult>}
|
|
|
|
* @memberof DB
|
|
|
|
*/
|
2020-06-17 21:06:55 +02:00
|
|
|
delete(
|
|
|
|
c: GenericObject<any> | number | string
|
|
|
|
): Promise<API.RequestResult> {
|
2020-05-29 22:22:00 +02:00
|
|
|
return new Promise(async (resolve, reject) => {
|
|
|
|
const rq: any = { table: this.table };
|
|
|
|
if (!c || c === "") {
|
2020-06-17 21:06:55 +02:00
|
|
|
reject(API.throwe("OS.DB: unknown condition"));
|
2020-05-29 22:22:00 +02:00
|
|
|
}
|
2020-06-17 21:06:55 +02:00
|
|
|
if (isNaN(c as number)) {
|
2020-05-29 22:22:00 +02:00
|
|
|
rq.cond = c;
|
|
|
|
} else {
|
|
|
|
rq.id = c;
|
|
|
|
}
|
|
|
|
try {
|
2020-06-17 21:06:55 +02:00
|
|
|
const r = await API.handle.dbquery("delete", rq);
|
2020-05-29 22:22:00 +02:00
|
|
|
if (r.error) {
|
2020-06-17 21:06:55 +02:00
|
|
|
return reject(API.throwe(r.error.toString()));
|
2020-05-29 22:22:00 +02:00
|
|
|
}
|
|
|
|
return resolve(r);
|
|
|
|
} catch (e) {
|
|
|
|
return reject(__e(e));
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2020-06-17 21:06:55 +02:00
|
|
|
* Get a record in the table by its primary key
|
2020-05-29 22:22:00 +02:00
|
|
|
*
|
2020-06-17 21:06:55 +02:00
|
|
|
* @param {number} id the primary key value
|
|
|
|
* @returns {Promise<GenericObject<any>>} Promise on returned record data
|
2020-05-29 22:22:00 +02:00
|
|
|
* @memberof DB
|
|
|
|
*/
|
|
|
|
get(id: number): Promise<GenericObject<any>> {
|
|
|
|
return new Promise(async (resolve, reject) => {
|
|
|
|
try {
|
2020-06-17 21:06:55 +02:00
|
|
|
const r = await API.handle.dbquery("get", {
|
2020-05-29 22:22:00 +02:00
|
|
|
table: this.table,
|
|
|
|
id: id,
|
|
|
|
});
|
|
|
|
if (r.error) {
|
2020-06-17 21:06:55 +02:00
|
|
|
return reject(API.throwe(r.error.toString()));
|
2020-05-29 22:22:00 +02:00
|
|
|
}
|
|
|
|
return resolve(r.result as GenericObject<any>);
|
|
|
|
} catch (e) {
|
|
|
|
return reject(__e(e));
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2020-06-17 21:06:55 +02:00
|
|
|
* Find records by a condition
|
|
|
|
*
|
|
|
|
* @param {GenericObject<any>} cond conditional object
|
2020-05-29 22:22:00 +02:00
|
|
|
*
|
2020-06-17 21:06:55 +02:00
|
|
|
* a conditional object represents a SQL condition statement as an object,
|
|
|
|
* example: `pid = 10 AND cid = 2 ORDER BY date DESC` is represented by:
|
2020-05-29 22:22:00 +02:00
|
|
|
*
|
2020-06-17 21:06:55 +02:00
|
|
|
* ```typescript
|
|
|
|
* {
|
|
|
|
* exp: {
|
|
|
|
* "and": {
|
|
|
|
* pid: 10,
|
|
|
|
* cid: 2
|
|
|
|
* }
|
|
|
|
* },
|
|
|
|
* order: {
|
|
|
|
* date: "DESC"
|
|
|
|
* }
|
|
|
|
* }
|
|
|
|
* ```
|
2020-05-29 22:22:00 +02:00
|
|
|
* @returns {Promise<GenericObject<any>[]>}
|
|
|
|
* @memberof DB
|
|
|
|
*/
|
|
|
|
find(cond: GenericObject<any>): Promise<GenericObject<any>[]> {
|
|
|
|
return new Promise(async (resolve, reject) => {
|
|
|
|
try {
|
2020-06-17 21:06:55 +02:00
|
|
|
const r = await API.handle.dbquery("select", {
|
2020-05-29 22:22:00 +02:00
|
|
|
table: this.table,
|
|
|
|
cond,
|
|
|
|
});
|
|
|
|
if (r.error) {
|
2020-06-17 21:06:55 +02:00
|
|
|
return reject(API.throwe(r.error.toString()));
|
2020-05-29 22:22:00 +02:00
|
|
|
}
|
|
|
|
return resolve(r.result as GenericObject<any>[]);
|
|
|
|
} catch (e) {
|
|
|
|
return reject(__e(e));
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|