SQLiteDB: fix database select bug

This commit is contained in:
DanyLE 2023-02-20 18:06:10 +01:00
parent 04050f124f
commit c8ddd5ec6e
15 changed files with 1436 additions and 1498 deletions

View File

@ -13,18 +13,22 @@
}
]
},
"coffee": {
"ts": {
"require": [
"coffee"
"ts"
],
"jobs": [
{
"name": "coffee-compile",
"name": "ts-import",
"data": ["sdk://core/ts/core.d.ts", "sdk://core/ts/jquery.d.ts","sdk://core/ts/antos.d.ts"]
},
{
"name": "ts-compile",
"data": {
"src": [
"main.coffee",
"dialogs.coffee",
"tags.coffee"
"main.ts",
"dialogs.ts",
"tags.ts"
],
"dest": "build/debug/main.js"
}
@ -51,9 +55,7 @@
"data": {
"src": [
"scheme.html",
"cvsection.html",
"api/sendmail.lua",
"sendmail.html",
"package.json",
"README.md",
"main.css"
@ -62,6 +64,27 @@
}
}
]
},
"locale": {
"require": ["locale"],
"jobs": [
{
"name":"locale-gen",
"data": {
"src": "",
"exclude": ["build/", "api/"],
"locale": "en_GB",
"dest": "package.json"
}
}
]
},
"debug": {
"depend": [
"init",
"ts",
"copy"
]
},
"release": {
"require": [
@ -69,7 +92,7 @@
],
"depend": [
"init",
"coffee",
"ts",
"uglify",
"copy"
],

View File

@ -1,30 +0,0 @@
<afx-app-window data-id = "blogger-cv-sec-win" apptitle="Porforlio section" width="450" height="400">
<afx-vbox padding="5">
<afx-hbox data-height = "30" >
<afx-label data-width= "70" text = "__(Title)"></afx-label>
<input type = "text" name="title" input-class = "user-input"></input>
</afx-hbox>
<afx-hbox data-height = "30" >
<afx-label text = "__(Subtitle)" data-width= "70"></afx-label>
<input type = "text" name="subtitle" input-class = "user-input"></input>
</afx-hbox>
<afx-hbox data-height = "30" >
<afx-label text = "__(Location)" data-width= "70"></afx-label>
<input type = "text" name="location" input-class = "user-input"></input>
</afx-hbox>
<afx-hbox data-height = "30" >
<afx-label text = "__(From)" data-width= "70"></afx-label>
<input type = "text" name="start" input-class = "user-input"></input>
<afx-label text = "To:" style="text-align:center;" data-width= "70"></afx-label>
<input type = "text" name="end" input-class = "user-input"></input>
</afx-hbox>
<afx-label data-height = "30" text = "Content" style = "margin-left:5px;"></afx-label>
<div data-id="editor-container">
<textarea name="content" data-id = "contentarea" ></textarea>
</div>
<div data-height = "35" style="text-align: right;">
<afx-switch data-id = "section-publish" data-width="30"></afx-switch>
<afx-button iconclass = "fa fa-save" data-id = "bt-cv-sec-save" text = "__(Save)"></afx-button>
</div>
</afx-vbox>
</afx-app-window>

File diff suppressed because one or more lines are too long

View File

@ -1,14 +1,101 @@
{
"app":"Blogger",
"name":"Blogging application",
"description":"Backend manager for blogging",
"info":{
"app": "Blogger",
"name": "Blogging application",
"description": "Backend manager for blogging",
"info": {
"author": "Xuan Sang LE",
"email": "xsang.le@gmail.com"
},
"version":"0.2.9-a",
"category":"Internet",
"iconclass":"fa fa-book",
"dependencies": ["SimpleMDE@2.18.0-r","Katex@0.11.1-r"],
"mimes":["none"]
"version": "0.2.9-a",
"category": "Internet",
"iconclass": "fa fa-book",
"dependencies": [
"SimpleMDE@2.18.0-r",
"Katex@0.11.1-r",
"SQLiteDB@0.1.0-a"
],
"mimes": [
"none"
],
"locales": {
"en_GB": {
"Pick a parent": "Pick a parent",
"Category name": "Category name",
"Ok": "Ok",
"Cancel": "Cancel",
"Title": "Title",
"Subtitle": "Subtitle",
"Location": "Location",
"From": "From",
"Save": "Save",
"Send": "Send",
"Please select a parent category": "Please select a parent category",
"Please enter category name": "Please enter category name",
"Parent can not be the category itself": "Parent can not be the category itself",
"Title or content must not be blank": "Title or content must not be blank",
"No email selected": "No email selected",
"Unable to send mail to: {0}": "Unable to send mail to: {0}",
"Error sending mail: {0}": "Error sending mail: {0}",
"Cannot fetch subscribers data: {0}": "Cannot fetch subscribers data: {0}",
"Open/create new database": "Open/create new database",
"Unable to init database file: {0}": "Unable to init database file: {0}",
"Select image file": "Select image file",
"Unable to get file": "Unable to get file",
"Add category": "Add category",
"cv-cat-add: {0}": "cv-cat-add: {0}",
"Edit category": "Edit category",
"cv-cat-edit: {0}": "cv-cat-edit: {0}",
"Delete category": "Delete category",
"Do you really want to delete: {0}?": "Do you really want to delete: {0}?",
"cv-cat-del: {0}": "cv-cat-del: {0}",
"Please select a category": "Please select a category",
"New section entry for {0}": "New section entry for {0}",
"cv-sec-add: {0}": "cv-sec-add: {0}",
"Please select a section to move": "Please select a section to move",
"Move to": "Move to",
"cv-sec-move: {0}": "cv-sec-move: {0}",
"Please select a section to edit": "Please select a section to edit",
"Modify section entry": "Modify section entry",
"cv-sec-edit: {0}": "cv-sec-edit: {0}",
"Cannot delete the section: {0}": "Cannot delete the section: {0}",
"New": "New",
"Cannot export file for embedding to text": "Cannot export file for embedding to text",
"Preview": "Preview",
"Send mail": "Send mail",
"No post selected": "No post selected",
"Emails sent": "Emails sent",
"Error sending mails: {0}": "Error sending mails: {0}",
"Cannot fetch the entry content": "Cannot fetch the entry content",
"Delete a post": "Delete a post",
"Do you really want to delete this post ?": "Do you really want to delete this post ?",
"Cannot fetch user data": "Cannot fetch user data",
"Full name must be entered": "Full name must be entered",
"User data updated": "User data updated",
"Cannot save user data": "Cannot save user data",
"Unable to load categories": "Unable to load categories",
"Found {0} sections": "Found {0} sections",
"Please insert a title in the text: beginning with heading": "Please insert a title in the text: beginning with heading",
"Please enter tags": "Please enter tags",
"Cannot save blog: {0}": "Cannot save blog: {0}",
"Cannot add new category": "Cannot add new category",
"Unable to fetch categories": "Unable to fetch categories",
"Cannot Edit category": "Cannot Edit category",
"Cannot save section: {0}": "Cannot save section: {0}",
"Cannot move section": "Cannot move section",
"Cannot delete the category: {0} [{1}]": "Cannot delete the category: {0} [{1}]",
"Cannot delete all content of: {0} [{1}]": "Cannot delete all content of: {0} [{1}]",
"No post found: {0}": "No post found: {0}",
"Created: {0}": "Created: {0}",
"Updated: {0}": "Updated: {0}",
"Full name": "Full name",
"Address": "Address",
"Phone": "Phone",
"Email": "Email",
"Url": "Url",
"Photo": "Photo",
"Short biblio": "Short biblio",
"Categories": "Categories",
"Tags": "Tags"
}
}
}

View File

@ -1,20 +0,0 @@
<afx-app-window data-id = "blogger-send-mail-win" apptitle="Send mail" width="500" height="400" resizable = "false">
<afx-hbox>
<afx-menu data-width="150" data-id="email-list"></afx-menu>
<afx-resizer data-width="3"></afx-resizer>
<div data-width="5"></div>
<afx-vbox >
<div data-height="5"></div>
<afx-label data-height="20" text = "__(Title)"></afx-label>
<input type = "text" data-height="20" name="title" data-id = "mail-title"></input>
<afx-label data-height = "20" text = "Content" ></afx-label>
<textarea name="content" data-id = "contentarea" ></textarea>
<div data-height="5"></div>
<afx-hbox data-height = "30">
<div></div>
<afx-button iconclass = "fa fa-paper-plane" data-id = "bt-sendmail" data-width="60" text = "__(Send)"></afx-button>
</afx-hbox>
</afx-vbox>
<div data-width="5"></div>
</afx-hbox>
</afx-app-window>

Binary file not shown.

View File

@ -160,7 +160,7 @@ class BloggerSendmailDiaglog extends this.OS.GUI.BasicDialog
content: (@find "contentarea").value
@_api.apigateway data, false
.then (d) =>
return @notify __("Unable to send mail to: {0}", d.result.join(", ")) if d.error
return @notify __("Unable to send mail to: {0}", d.result.join(",")) if d.error
@quit()
.catch (e) =>
console.log e

View File

@ -1,14 +1,101 @@
{
"app":"Blogger",
"name":"Blogging application",
"description":"Backend manager for blogging",
"info":{
"app": "Blogger",
"name": "Blogging application",
"description": "Backend manager for blogging",
"info": {
"author": "Xuan Sang LE",
"email": "xsang.le@gmail.com"
},
"version":"0.2.9-a",
"category":"Internet",
"iconclass":"fa fa-book",
"dependencies": ["SimpleMDE@2.18.0-r","Katex@0.11.1-r"],
"mimes":["none"]
"version": "0.2.9-a",
"category": "Internet",
"iconclass": "fa fa-book",
"dependencies": [
"SimpleMDE@2.18.0-r",
"Katex@0.11.1-r",
"SQLiteDB@0.1.0-a"
],
"mimes": [
"none"
],
"locales": {
"en_GB": {
"Pick a parent": "Pick a parent",
"Category name": "Category name",
"Ok": "Ok",
"Cancel": "Cancel",
"Title": "Title",
"Subtitle": "Subtitle",
"Location": "Location",
"From": "From",
"Save": "Save",
"Send": "Send",
"Please select a parent category": "Please select a parent category",
"Please enter category name": "Please enter category name",
"Parent can not be the category itself": "Parent can not be the category itself",
"Title or content must not be blank": "Title or content must not be blank",
"No email selected": "No email selected",
"Unable to send mail to: {0}": "Unable to send mail to: {0}",
"Error sending mail: {0}": "Error sending mail: {0}",
"Cannot fetch subscribers data: {0}": "Cannot fetch subscribers data: {0}",
"Open/create new database": "Open/create new database",
"Unable to init database file: {0}": "Unable to init database file: {0}",
"Select image file": "Select image file",
"Unable to get file": "Unable to get file",
"Add category": "Add category",
"cv-cat-add: {0}": "cv-cat-add: {0}",
"Edit category": "Edit category",
"cv-cat-edit: {0}": "cv-cat-edit: {0}",
"Delete category": "Delete category",
"Do you really want to delete: {0}?": "Do you really want to delete: {0}?",
"cv-cat-del: {0}": "cv-cat-del: {0}",
"Please select a category": "Please select a category",
"New section entry for {0}": "New section entry for {0}",
"cv-sec-add: {0}": "cv-sec-add: {0}",
"Please select a section to move": "Please select a section to move",
"Move to": "Move to",
"cv-sec-move: {0}": "cv-sec-move: {0}",
"Please select a section to edit": "Please select a section to edit",
"Modify section entry": "Modify section entry",
"cv-sec-edit: {0}": "cv-sec-edit: {0}",
"Cannot delete the section: {0}": "Cannot delete the section: {0}",
"New": "New",
"Cannot export file for embedding to text": "Cannot export file for embedding to text",
"Preview": "Preview",
"Send mail": "Send mail",
"No post selected": "No post selected",
"Emails sent": "Emails sent",
"Error sending mails: {0}": "Error sending mails: {0}",
"Cannot fetch the entry content": "Cannot fetch the entry content",
"Delete a post": "Delete a post",
"Do you really want to delete this post ?": "Do you really want to delete this post ?",
"Cannot fetch user data": "Cannot fetch user data",
"Full name must be entered": "Full name must be entered",
"User data updated": "User data updated",
"Cannot save user data": "Cannot save user data",
"Unable to load categories": "Unable to load categories",
"Found {0} sections": "Found {0} sections",
"Please insert a title in the text: beginning with heading": "Please insert a title in the text: beginning with heading",
"Please enter tags": "Please enter tags",
"Cannot save blog: {0}": "Cannot save blog: {0}",
"Cannot add new category": "Cannot add new category",
"Unable to fetch categories": "Unable to fetch categories",
"Cannot Edit category": "Cannot Edit category",
"Cannot save section: {0}": "Cannot save section: {0}",
"Cannot move section": "Cannot move section",
"Cannot delete the category: {0} [{1}]": "Cannot delete the category: {0} [{1}]",
"Cannot delete all content of: {0} [{1}]": "Cannot delete all content of: {0} [{1}]",
"No post found: {0}": "No post found: {0}",
"Created: {0}": "Created: {0}",
"Updated: {0}": "Updated: {0}",
"Full name": "Full name",
"Address": "Address",
"Phone": "Phone",
"Email": "Email",
"Url": "Url",
"Photo": "Photo",
"Short biblio": "Short biblio",
"Categories": "Categories",
"Tags": "Tags"
}
}
}

View File

@ -232,6 +232,7 @@ namespace OS {
* user: "dany'",
* $or: {
* 'user.email': "test@mail.com",
* age: [15, 20, 25],
* age$lte: 30,
* $and: {
* 'user.birth$ne': 1986,
@ -258,6 +259,9 @@ namespace OS {
* ( contacts.user = 'dany''' ) AND
* (
* ( user.email = 'test@mail.com' ) OR
* ( contacts.age = 15 ) OR
* ( contacts.age = 20 ) OR
* ( contacts.age = 25 ) OR
* ( contacts.age <= 30 ) OR
* (
* ( user.birth != 1986 ) AND

View File

@ -99,12 +99,14 @@ handle.insert = function(data)
end
local sql = string.format("INSERT INTO %s (%s) VALUES(%s)", data.table_name, table.concat(keys,","), table.concat(vals,","))
LOG_DEBUG("Execute query: [%s]", sql)
local ret, err = sqlite.exec(db, sql);
local ret, err = sqlite.exec(db, sql)
local id = sqlite.last_insert_id(db)
sqlite.dbclose(db)
if not ret then
return error("insert: Unable to insert to %s: %s", data.table_name, err)
else
return result(ret)
return result(id)
end
end

View File

@ -99,12 +99,14 @@ handle.insert = function(data)
end
local sql = string.format("INSERT INTO %s (%s) VALUES(%s)", data.table_name, table.concat(keys,","), table.concat(vals,","))
LOG_DEBUG("Execute query: [%s]", sql)
local ret, err = sqlite.exec(db, sql);
local ret, err = sqlite.exec(db, sql)
local id = sqlite.last_insert_id(db)
sqlite.dbclose(db)
if not ret then
return error("insert: Unable to insert to %s: %s", data.table_name, err)
else
return result(ret)
return result(id)
end
end

View File

@ -1,446 +1 @@
var OS;
(function (OS) {
let API;
(function (API) {
class SQLiteDBCore {
constructor(path) {
if (!SQLiteDBCore.REGISTY) {
SQLiteDBCore.REGISTY = {};
}
this.db_file = path.asFileHandle();
if (SQLiteDBCore.REGISTY[this.db_file.path]) {
this.db_file = SQLiteDBCore.REGISTY[this.db_file.path];
}
else {
SQLiteDBCore.REGISTY[this.db_file.path] = this.db_file;
}
}
pwd() {
return "pkg://SQLiteDB/".asFileHandle();
}
fileinfo() {
return this.db_file.info;
}
/**
* init and create the db file if it does not exist
*/
init() {
return new Promise(async (ok, reject) => {
try {
if (this.db_file.ready) {
return ok(true);
}
let request = {
action: 'init',
args: {
db_source: this.db_file.path,
}
};
let _result = await this.call(request);
_result = await this.db_file.onready();
if (!this.db_file || !this.db_file.ready || this.db_file.info.type !== "file") {
throw __("DB file meta-data is invalid: {0}", this.db_file.path).__();
}
ok(true);
}
catch (e) {
reject(__e(e));
}
});
}
call(request) {
return new Promise(async (ok, reject) => {
request.args.db_source = this.db_file.path;
let cmd = {
path: this.pwd().path + "/api/api.lua",
parameters: request
};
let data = await API.apigateway(cmd, false);
if (!data.error) {
ok(data.result);
}
else {
reject(API.throwe(__("SQLiteDB server call error: {0}", data.error)));
}
});
}
request(rq) {
return new Promise(async (ok, reject) => {
try {
if (!this.db_file.ready) {
let _ = await this.init();
}
let result = await this.call(rq);
ok(result);
}
catch (e) {
reject(__e(e));
}
});
}
select(filter) {
let rq = {
action: 'select',
args: {
filter
}
};
return this.request(rq);
}
delete_records(filter) {
let rq = {
action: 'delete_records',
args: {
filter
}
};
return this.request(rq);
}
drop_table(table_name) {
let rq = {
action: 'drop_table',
args: { table_name }
};
return this.request(rq);
}
list_tables() {
let rq = {
action: 'list_table',
args: {}
};
return this.request(rq);
}
create_table(table, scheme) {
let rq = {
action: 'create_table',
args: {
table_name: table,
scheme
}
};
return this.request(rq);
}
get_table_scheme(table_name) {
let rq = {
action: 'table_scheme',
args: {
table_name
}
};
return this.request(rq);
}
insert(table_name, record, pk) {
let rq = {
action: 'insert',
args: {
table_name,
record,
pk
}
};
return this.request(rq);
}
update(table_name, record, pk) {
let rq = {
action: 'update',
args: {
table_name,
record,
pk
}
};
return this.request(rq);
}
last_insert_id() {
let rq = {
action: 'last_insert_id',
args: {}
};
return this.request(rq);
}
}
let VFS;
(function (VFS) {
/**
* SQLite VFS handle for database accessing
*
* A Sqlite file handle shall be in the following formats:
* * `sqlite://remote/path/to/file.db` refers to the entire databale (`remote/path/to/file.db` is relative to the home folder)
* - read operation, will list all available tables
* - write operations will create table
* - rm operation will delete table
* - meta operation will return file info
* - other operations are not supported
* * `sqlite://remote/path/to/file.db@table_name` refers to the table `table_name` in the database
* - meta operation will return fileinfo with table scheme information
* - read operation will read all records by filter defined by the filter as parameters
* - write operations will insert a new record
* - rm operation will delete records by filter as parameters
* - other operations are not supported
* - `sqlite://remote/path/to/file.db@table_name@id` refers to a records in `table_name` with ID `id`
* - read operation will read the current record
* - write operation will update current record
* - rm operation will delete current record
* - other operations are not supported
*
* Example of filter:
* ```ts
* {
* table_name:'contacts';
* where: {
* id$gte: 10,
* user: "dany'",
* $or: {
* 'user.email': "test@mail.com",
* age$lte: 30,
* $and: {
* 'user.birth$ne': 1986,
* age$not_between: [20,30],
* name$not_like: "%LE"
* }
* }
* },
* fields: ['name as n', 'id', 'email'],
* order: ['user.name$asc', "id$desc"],
* joins: {
* cid: 'Category.id',
* did: 'Country.id',
* uid: "User.id"
* }
*}
* ```
* This will generate the followings expressions:
* - `( self.name as n,self.id,self.email )` for fields
* - condition:
* ```
* (
* ( contacts.id >= 10 ) AND
* ( contacts.user = 'dany''' ) AND
* (
* ( user.email = 'test@mail.com' ) OR
* ( contacts.age <= 30 ) OR
* (
* ( user.birth != 1986 ) AND
* ( contacts.age NOT BETWEEN 20 AND 30 ) AND
* ( contacts.name NOT LIKE '%LE' )
* )
* )
* )
* ```
* - order: `user.name ASC,contacts.id DESC`
* - joining:
* ```
* INNER JOIN Category ON contacts.cid = Category.id
* INNER JOIN Country ON contacts.did = Country.id
* INNER JOIN Country ON contacts.did = Country.id
* ```
*
* @class SqliteFileHandle
* @extends {BaseFileHandle}
*/
class SqliteFileHandle extends VFS.BaseFileHandle {
/**
* Set a file path to the current file handle
*
*
* @param {string} p
* @returns {void}
* @memberof SqliteFileHandle
*/
setPath(p) {
let arr = p.split("@");
super.setPath(arr[0]);
if (arr.length > 3) {
throw new Error(__("Invalid file path").__());
}
this.path = p;
this._table_name = arr[1];
this._id = arr[2] ? parseInt(arr[2]) : undefined;
this._handle = new SQLiteDBCore(`home://${this.genealogy.join("/")}`);
}
/**
* Read database file meta-data
*
* Return file info on the target database file, if the table_name is specified
* return also the table scheme
*
* @returns {Promise<RequestResult>}
* @memberof SqliteFileHandle
*/
meta() {
return new Promise(async (resolve, reject) => {
try {
await this._handle.init();
let d = {
result: {
file: this._handle.fileinfo(),
schema: undefined
}, error: false
};
if (this._table_name) {
const data = await this._handle.get_table_scheme(this._table_name);
if (data.length == 0) {
d.result.schema = undefined;
}
else {
d.result.schema = {
fields: [],
types: {},
pk: undefined
};
d.result.schema.fields = data.map(e => e.name);
for (let v of data) {
d.result.schema.types[v.name] = v.type;
if (v.pk) {
d.result.schema.pk = v.name;
}
}
}
}
return resolve(d);
}
catch (e) {
return reject(__e(e));
}
});
}
/**
* Query the database based on the provided info
*
* If no table is provided, return list of tables in the
* data base.
* If the current table is specified:
* - if the record id is specfied return the record
* - otherwise, return the records in the table using the specified filter
*
* @protected
* @param {any} t filter type
* @returns {Promise<any>}
* @memberof SqliteFileHandle
*/
_rd(user_data) {
return new Promise(async (resolve, reject) => {
try {
if (this._table_name && !this.info.schema) {
throw new Error(__("Table `{0}` does not exists in database: {1}", this._table_name, this.path).__());
}
if (!this._table_name) {
// return list of tables in form of data base file handles in ready mode
let list = await this._handle.list_tables();
const map = {};
for (let v of list) {
map[v.name] = `${this.path}@${v.name}`.asFileHandle();
}
this.cache = map;
resolve(map);
}
else {
// return all the data in the table set by the filter
// if this is a table, return the filtered records
// otherwise, it is a record, fetch only that record
let filter = user_data;
if (!filter || this._id) {
filter = {};
}
filter.table_name = this._table_name;
if (this._id) {
filter.where = { id: this._id };
}
let data = await this._handle.select(filter);
if (this._id) {
this.cache = data[0];
}
else {
this.cache = data;
}
resolve(this.cache);
}
}
catch (e) {
return reject(__e(e));
}
});
}
/**
* Write commit file cache to the remote database
*
* @protected
* @param {string} t is table name, used only when create table
* @returns {Promise<RequestResult>}
* @memberof SqliteFileHandle
*/
_wr(t) {
return new Promise(async (resolve, reject) => {
try {
if (!this.cache) {
throw new Error(__("No data to submit to remote database, please check the `cache` field").__());
}
await this.onready();
if (this._id && this._table_name) {
this.cache.id = this._id;
const ret = await this._handle.update(this._table_name, this.cache, this.info.schema.pk);
resolve({ result: ret, error: false });
return;
}
if (this._table_name) {
const ret = await this._handle.insert(this._table_name, this.cache, this.info.schema.pk);
resolve({ result: ret, error: false });
return;
}
// create a new table with the scheme provided in the cache
let r = await this._handle.create_table(t, this.cache);
resolve({ result: r, error: false });
}
catch (e) {
return reject(__e(e));
}
});
}
/**
* Delete data from remote database
*
* @protected
* @param {any} user_data is table name, for delete table, otherwise, filter object for deleting records
* @returns {Promise<RequestResult>}
* @memberof SqliteFileHandle
*/
_rm(user_data) {
return new Promise(async (resolve, reject) => {
try {
if (this._table_name && !this.info.schema) {
throw new Error(__("Table `{0}` does not exists in database: {1}", this._table_name, this.path).__());
}
if (!this._table_name) {
let table_name = user_data;
if (!table_name) {
throw new Error(__("No table specified for dropping").__());
}
let ret = await this._handle.drop_table(table_name);
resolve({ result: ret, error: false });
// delete the table
}
else {
let filter = user_data;
// delete the records in the table using the filter
if (!filter || this._id) {
filter = {};
}
filter.table_name = this._table_name;
if (this._id) {
filter.where = { id: this._id };
}
let ret = await this._handle.delete_records(filter);
resolve({ result: ret, error: false });
}
}
catch (e) {
return reject(__e(e));
}
});
}
}
VFS.register("^sqlite$", SqliteFileHandle);
})(VFS = API.VFS || (API.VFS = {}));
})(API = OS.API || (OS.API = {}));
})(OS || (OS = {}));
var OS;!function(e){let t;!function(e){class t{constructor(e){t.REGISTY||(t.REGISTY={}),this.db_file=e.asFileHandle(),t.REGISTY[this.db_file.path]?this.db_file=t.REGISTY[this.db_file.path]:t.REGISTY[this.db_file.path]=this.db_file}pwd(){return"pkg://SQLiteDB/".asFileHandle()}fileinfo(){return this.db_file.info}init(){return new Promise(async(e,t)=>{try{if(this.db_file.ready)return e(!0);let t={action:"init",args:{db_source:this.db_file.path}},a=await this.call(t);if(a=await this.db_file.onready(),!this.db_file||!this.db_file.ready||"file"!==this.db_file.info.type)throw __("DB file meta-data is invalid: {0}",this.db_file.path).__();e(!0)}catch(e){t(__e(e))}})}call(t){return new Promise(async(a,i)=>{t.args.db_source=this.db_file.path;let s={path:this.pwd().path+"/api/api.lua",parameters:t},r=await e.apigateway(s,!1);r.error?i(e.throwe(__("SQLiteDB server call error: {0}",r.error))):a(r.result)})}request(e){return new Promise(async(t,a)=>{try{this.db_file.ready||await this.init(),t(await this.call(e))}catch(e){a(__e(e))}})}select(e){let t={action:"select",args:{filter:e}};return this.request(t)}delete_records(e){let t={action:"delete_records",args:{filter:e}};return this.request(t)}drop_table(e){let t={action:"drop_table",args:{table_name:e}};return this.request(t)}list_tables(){return this.request({action:"list_table",args:{}})}create_table(e,t){let a={action:"create_table",args:{table_name:e,scheme:t}};return this.request(a)}get_table_scheme(e){let t={action:"table_scheme",args:{table_name:e}};return this.request(t)}insert(e,t,a){let i={action:"insert",args:{table_name:e,record:t,pk:a}};return this.request(i)}update(e,t,a){let i={action:"update",args:{table_name:e,record:t,pk:a}};return this.request(i)}last_insert_id(){return this.request({action:"last_insert_id",args:{}})}}let a;!function(e){class a extends e.BaseFileHandle{setPath(e){let a=e.split("@");if(super.setPath(a[0]),a.length>3)throw new Error(__("Invalid file path").__());this.path=e,this._table_name=a[1],this._id=a[2]?parseInt(a[2]):void 0,this._handle=new t("home://"+this.genealogy.join("/"))}meta(){return new Promise(async(e,t)=>{try{await this._handle.init();let t={result:{file:this._handle.fileinfo(),schema:void 0},error:!1};if(this._table_name){const e=await this._handle.get_table_scheme(this._table_name);if(0==e.length)t.result.schema=void 0;else{t.result.schema={fields:[],types:{},pk:void 0},t.result.schema.fields=e.map(e=>e.name);for(let a of e)t.result.schema.types[a.name]=a.type,a.pk&&(t.result.schema.pk=a.name)}}return e(t)}catch(e){return t(__e(e))}})}_rd(e){return new Promise(async(t,a)=>{try{if(this._table_name&&!this.info.schema)throw new Error(__("Table `{0}` does not exists in database: {1}",this._table_name,this.path).__());if(this._table_name){let a=e;a&&!this._id||(a={}),a.table_name=this._table_name,this._id&&(a.where={id:this._id});let i=await this._handle.select(a);this._id?this.cache=i[0]:this.cache=i,t(this.cache)}else{let e=await this._handle.list_tables();const a={};for(let t of e)a[t.name]=`${this.path}@${t.name}`.asFileHandle();this.cache=a,t(a)}}catch(e){return a(__e(e))}})}_wr(e){return new Promise(async(t,a)=>{try{if(!this.cache)throw new Error(__("No data to submit to remote database, please check the `cache` field").__());if(await this.onready(),this._id&&this._table_name)return this.cache.id=this._id,void t({result:await this._handle.update(this._table_name,this.cache,this.info.schema.pk),error:!1});if(this._table_name)return void t({result:await this._handle.insert(this._table_name,this.cache,this.info.schema.pk),error:!1});t({result:await this._handle.create_table(e,this.cache),error:!1})}catch(e){return a(__e(e))}})}_rm(e){return new Promise(async(t,a)=>{try{if(this._table_name&&!this.info.schema)throw new Error(__("Table `{0}` does not exists in database: {1}",this._table_name,this.path).__());if(this._table_name){let a=e;a&&!this._id||(a={}),a.table_name=this._table_name,this._id&&(a.where={id:this._id}),t({result:await this._handle.delete_records(a),error:!1})}else{let a=e;if(!a)throw new Error(__("No table specified for dropping").__());t({result:await this._handle.drop_table(a),error:!1})}}catch(e){return a(__e(e))}})}}e.register("^sqlite$",a)}(a=e.VFS||(e.VFS={}))}(t=e.API||(e.API={}))}(OS||(OS={}));

File diff suppressed because one or more lines are too long

Binary file not shown.

View File

@ -86,11 +86,21 @@ namespace OS {
}
private async openFile() {
try {
let file: API.VFS.BaseFileHandle;
if (this.args && this.args.length > 0) {
file = this.args[0].path.asFileHandle();
}
else
{
const d_1 = await this.openDialog("FileDialog",{
title: __("Open file"),
mimes: this.meta().mimes
});
this.filehandle=`sqlite://${d_1.file.path.asFileHandle().genealogy.join("/")}`.asFileHandle();
file = d_1.file.path.asFileHandle();
}
this.filehandle=`sqlite://${file.genealogy.join("/")}`.asFileHandle();
await this.filehandle.onready();
this.list_tables();
}
@ -239,7 +249,7 @@ namespace OS {
this.grid_table.header = headers;
this.grid_table.rows = [];
const records = await handle.read({fields:["COUNT(*)"]});
this.n_records = records[0]["(COUNT(*))"];
this.n_records = records[0]["COUNT(*)"];
this.btn_loadmore.text = `0/${this.n_records}`;
await this.load_table();
this.container.selectedIndex = 1;
@ -252,6 +262,7 @@ namespace OS {
this.grid_table.oncelldbclick = async (e) => {
this.edit_record();
}
this.openFile();
}
private async add_record()