2018-01-16 06:09:17 +00:00
|
|
|
const frappe = require('frappejs');
|
2018-01-12 12:25:07 +00:00
|
|
|
const sqlite3 = require('sqlite3').verbose();
|
2018-02-08 06:46:38 +00:00
|
|
|
const Database = require('./database');
|
2018-02-07 13:23:52 +00:00
|
|
|
const debug = false;
|
2018-01-12 12:25:07 +00:00
|
|
|
|
2018-02-08 06:46:38 +00:00
|
|
|
module.exports = class sqliteDatabase extends Database {
|
|
|
|
constructor({ dbPath }) {
|
|
|
|
super();
|
|
|
|
this.dbPath = dbPath;
|
2018-01-31 13:04:46 +00:00
|
|
|
}
|
|
|
|
|
2018-02-08 06:46:38 +00:00
|
|
|
connect(dbPath) {
|
|
|
|
if (dbPath) {
|
|
|
|
this.dbPath = dbPath;
|
2018-01-31 13:04:46 +00:00
|
|
|
}
|
|
|
|
return new Promise(resolve => {
|
2018-02-08 06:46:38 +00:00
|
|
|
this.conn = new sqlite3.Database(this.dbPath, () => {
|
2018-01-31 13:04:46 +00:00
|
|
|
if (debug) {
|
|
|
|
this.conn.on('trace', (trace) => console.log(trace));
|
|
|
|
}
|
|
|
|
resolve();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2018-02-08 06:46:38 +00:00
|
|
|
async tableExists(table) {
|
|
|
|
const name = await this.sql(`SELECT name FROM sqlite_master WHERE type='table' AND name='${table}'`);
|
|
|
|
return (name && name.length) ? true : false;
|
2018-01-31 13:04:46 +00:00
|
|
|
}
|
|
|
|
|
2018-02-08 06:46:38 +00:00
|
|
|
async runCreateTableQuery(doctype, columns, values) {
|
2018-01-31 13:04:46 +00:00
|
|
|
const query = `CREATE TABLE IF NOT EXISTS ${frappe.slug(doctype)} (
|
2018-01-12 12:25:07 +00:00
|
|
|
${columns.join(", ")})`;
|
|
|
|
|
2018-01-31 13:04:46 +00:00
|
|
|
return await this.run(query, values);
|
|
|
|
}
|
|
|
|
|
2018-02-08 06:46:38 +00:00
|
|
|
getColumnDefinition(df) {
|
2018-02-01 09:24:28 +00:00
|
|
|
return `${df.fieldname} ${this.type_map[df.fieldtype]} ${df.reqd && !df.default ? "not null" : ""} ${df.default ? `default ${df.default}` : ""}`
|
2018-01-31 13:04:46 +00:00
|
|
|
}
|
|
|
|
|
2018-02-08 06:46:38 +00:00
|
|
|
async getTableColumns(doctype) {
|
|
|
|
return (await this.sql(`PRAGMA table_info(${doctype})`)).map(d => d.name);
|
2018-01-31 13:04:46 +00:00
|
|
|
}
|
|
|
|
|
2018-02-08 06:46:38 +00:00
|
|
|
async runAlterTableQuery(doctype, field, values) {
|
|
|
|
await this.run(`ALTER TABLE ${frappe.slug(doctype)} ADD COLUMN ${this.getColumnDefinition(field)}`, values);
|
2018-01-31 13:04:46 +00:00
|
|
|
}
|
|
|
|
|
2018-02-08 06:46:38 +00:00
|
|
|
getOne(doctype, name, fields = '*') {
|
|
|
|
fields = this.prepareFields(fields);
|
2018-01-31 13:04:46 +00:00
|
|
|
return new Promise((resolve, reject) => {
|
|
|
|
this.conn.get(`select ${fields} from ${frappe.slug(doctype)}
|
2018-01-12 12:25:07 +00:00
|
|
|
where name = ?`, name,
|
2018-01-31 13:04:46 +00:00
|
|
|
(err, row) => {
|
|
|
|
resolve(row || {});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2018-02-08 06:46:38 +00:00
|
|
|
async insertOne(doctype, doc) {
|
|
|
|
let fields = this.getKeys(doctype);
|
2018-01-31 13:04:46 +00:00
|
|
|
let placeholders = fields.map(d => '?').join(', ');
|
|
|
|
|
2018-02-01 11:07:36 +00:00
|
|
|
if (!doc.name) {
|
2018-02-08 06:46:38 +00:00
|
|
|
doc.name = frappe.getRandomName();
|
2018-02-01 11:07:36 +00:00
|
|
|
}
|
|
|
|
|
2018-01-31 13:04:46 +00:00
|
|
|
return await this.run(`insert into ${frappe.slug(doctype)}
|
2018-02-01 11:07:36 +00:00
|
|
|
(${fields.map(field => field.fieldname).join(", ")})
|
2018-02-08 06:46:38 +00:00
|
|
|
values (${placeholders})`, this.getFormattedValues(fields, doc));
|
2018-01-31 13:04:46 +00:00
|
|
|
}
|
2018-01-12 12:25:07 +00:00
|
|
|
|
2018-02-08 06:46:38 +00:00
|
|
|
async updateOne(doctype, doc) {
|
|
|
|
let fields = this.getKeys(doctype);
|
2018-01-31 13:04:46 +00:00
|
|
|
let assigns = fields.map(field => `${field.fieldname} = ?`);
|
2018-02-08 06:46:38 +00:00
|
|
|
let values = this.getFormattedValues(fields, doc);
|
2018-01-31 12:56:21 +00:00
|
|
|
|
2018-01-31 13:04:46 +00:00
|
|
|
// additional name for where clause
|
|
|
|
values.push(doc.name);
|
2018-01-31 12:56:21 +00:00
|
|
|
|
2018-01-31 13:04:46 +00:00
|
|
|
return await this.run(`update ${frappe.slug(doctype)}
|
2018-01-12 12:25:07 +00:00
|
|
|
set ${assigns.join(", ")} where name=?`, values);
|
2018-01-31 13:04:46 +00:00
|
|
|
}
|
|
|
|
|
2018-02-08 06:46:38 +00:00
|
|
|
async runDeleteOtherChildren(field, added) {
|
|
|
|
// delete other children
|
|
|
|
// `delete from doctype where parent = ? and name not in (?, ?, ?)}`
|
|
|
|
await this.run(`delete from ${frappe.slug(field.childtype)}
|
|
|
|
where
|
|
|
|
parent = ? and
|
|
|
|
name not in (${added.slice(1).map(d => '?').join(', ')})`, added);
|
2018-01-31 13:04:46 +00:00
|
|
|
}
|
|
|
|
|
2018-02-08 06:46:38 +00:00
|
|
|
async deleteOne(doctype, name) {
|
|
|
|
return await this.run(`delete from ${frappe.slug(doctype)} where name=?`, name);
|
2018-02-01 11:07:36 +00:00
|
|
|
}
|
|
|
|
|
2018-02-08 06:46:38 +00:00
|
|
|
async deleteChildren(parenttype, parent) {
|
|
|
|
await this.run(`delete from ${parent} where parent=?`, parent);
|
2018-02-01 11:07:36 +00:00
|
|
|
}
|
|
|
|
|
2018-02-08 06:46:38 +00:00
|
|
|
getAll({ doctype, fields, filters, start, limit, order_by = 'modified', order = 'desc' } = {}) {
|
2018-01-31 13:04:46 +00:00
|
|
|
if (!fields) {
|
2018-02-08 06:46:38 +00:00
|
|
|
fields = frappe.getMeta(doctype).getKeywordFields();
|
2018-01-31 13:04:46 +00:00
|
|
|
}
|
|
|
|
return new Promise((resolve, reject) => {
|
2018-02-08 06:46:38 +00:00
|
|
|
let conditions = this.getFilterConditions(filters);
|
2018-01-31 13:04:46 +00:00
|
|
|
|
|
|
|
this.conn.all(`select ${fields.join(", ")}
|
2018-01-12 12:25:07 +00:00
|
|
|
from ${frappe.slug(doctype)}
|
|
|
|
${conditions.conditions ? "where" : ""} ${conditions.conditions}
|
|
|
|
${order_by ? ("order by " + order_by) : ""} ${order_by ? (order || "asc") : ""}
|
|
|
|
${limit ? ("limit " + limit) : ""} ${start ? ("offset " + start) : ""}`, conditions.values,
|
2018-01-31 13:04:46 +00:00
|
|
|
(err, rows) => {
|
|
|
|
if (err) {
|
|
|
|
reject(err);
|
|
|
|
} else {
|
|
|
|
resolve(rows);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
run(query, params) {
|
|
|
|
return new Promise((resolve, reject) => {
|
|
|
|
this.conn.run(query, params, (err) => {
|
|
|
|
if (err) {
|
2018-02-01 11:07:36 +00:00
|
|
|
if (debug) {
|
2018-02-07 16:44:59 +00:00
|
|
|
console.log(err);
|
2018-02-01 11:07:36 +00:00
|
|
|
}
|
2018-01-31 13:04:46 +00:00
|
|
|
reject(err);
|
|
|
|
} else {
|
|
|
|
resolve();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
sql(query, params) {
|
|
|
|
return new Promise((resolve) => {
|
|
|
|
this.conn.all(query, params, (err, rows) => {
|
|
|
|
resolve(rows);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
async commit() {
|
|
|
|
try {
|
|
|
|
await this.run('commit');
|
|
|
|
} catch (e) {
|
|
|
|
if (e.errno !== 1) {
|
|
|
|
throw e;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-02-08 06:46:38 +00:00
|
|
|
initTypeMap() {
|
2018-01-31 13:04:46 +00:00
|
|
|
this.type_map = {
|
|
|
|
'Currency': 'real'
|
|
|
|
, 'Int': 'integer'
|
|
|
|
, 'Float': 'real'
|
|
|
|
, 'Percent': 'real'
|
|
|
|
, 'Check': 'integer'
|
|
|
|
, 'Small Text': 'text'
|
|
|
|
, 'Long Text': 'text'
|
|
|
|
, 'Code': 'text'
|
|
|
|
, 'Text Editor': 'text'
|
|
|
|
, 'Date': 'text'
|
|
|
|
, 'Datetime': 'text'
|
|
|
|
, 'Time': 'text'
|
|
|
|
, 'Text': 'text'
|
|
|
|
, 'Data': 'text'
|
|
|
|
, 'Link': 'text'
|
|
|
|
, 'Dynamic Link': 'text'
|
|
|
|
, 'Password': 'text'
|
|
|
|
, 'Select': 'text'
|
|
|
|
, 'Read Only': 'text'
|
|
|
|
, 'Attach': 'text'
|
|
|
|
, 'Attach Image': 'text'
|
|
|
|
, 'Signature': 'text'
|
|
|
|
, 'Color': 'text'
|
|
|
|
, 'Barcode': 'text'
|
|
|
|
, 'Geolocation': 'text'
|
|
|
|
}
|
|
|
|
}
|
2018-01-12 12:25:07 +00:00
|
|
|
}
|