mirror of
https://github.com/frappe/books.git
synced 2024-11-14 09:24:04 +00:00
239 lines
5.6 KiB
JavaScript
239 lines
5.6 KiB
JavaScript
const frappe = require('frappe');
|
|
const mysql = require('mysql');
|
|
const Database = require('./database');
|
|
const debug = false;
|
|
|
|
module.exports = class mysqlDatabase extends Database {
|
|
constructor({ db_name, username, password, host }) {
|
|
super();
|
|
this.db_name = db_name;
|
|
this.username = username;
|
|
this.password = password;
|
|
this.host = host;
|
|
this.init_typeMap();
|
|
}
|
|
|
|
connect(db_name) {
|
|
if (db_name) {
|
|
this.db_name = db_name;
|
|
}
|
|
return new Promise((resolve) => {
|
|
this.conn = new mysql.createConnection({
|
|
host: this.host,
|
|
user: this.username,
|
|
password: this.password,
|
|
database: this.db_name,
|
|
});
|
|
() => {
|
|
if (debug) {
|
|
this.conn.on('trace', (trace) => console.log(trace));
|
|
}
|
|
};
|
|
resolve();
|
|
});
|
|
}
|
|
|
|
async tableExists(table) {
|
|
const name = await this.sql(`SELECT table_name
|
|
FROM information_schema.tables
|
|
WHERE table_schema = '${this.db_name}'
|
|
AND table_name = '${table}'`);
|
|
return name && name.length ? true : false;
|
|
}
|
|
|
|
async runCreateTableQuery(doctype, columns, values) {
|
|
const query = `CREATE TABLE IF NOT EXISTS ${doctype} (
|
|
${columns.join(', ')})`;
|
|
|
|
return await this.run(query, values);
|
|
}
|
|
|
|
updateColumnDefinition(df, columns, indexes) {
|
|
columns.push(
|
|
`${df.fieldname} ${this.typeMap[df.fieldtype]} ${
|
|
df.required && !df.default ? 'not null' : ''
|
|
} ${df.default ? `default '${df.default}'` : ''}`
|
|
);
|
|
}
|
|
|
|
async getTableColumns(doctype) {
|
|
return (await this.sql(`SHOW COLUMNS FROM ${doctype}`)).map((d) => d.Field);
|
|
}
|
|
|
|
async runAddColumnQuery(doctype, fields) {
|
|
await this.run(
|
|
`ALTER TABLE ${doctype} ADD COLUMN ${this.get_column_definition(doctype)}`
|
|
);
|
|
}
|
|
|
|
getOne(doctype, name, fields = '*') {
|
|
fields = this.prepareFields(fields);
|
|
|
|
return new Promise((resolve, reject) => {
|
|
this.conn.get(
|
|
`select ${fields} from ${doctype}
|
|
where name = ?`,
|
|
name,
|
|
(err, row) => {
|
|
resolve(row || {});
|
|
}
|
|
);
|
|
});
|
|
}
|
|
|
|
async insertOne(doctype, doc) {
|
|
let fields = this.get_keys(doctype);
|
|
let placeholders = fields.map((d) => '?').join(', ');
|
|
|
|
if (!doc.name) {
|
|
doc.name = frappe.getRandomString();
|
|
}
|
|
|
|
return await this.run(
|
|
`insert into ${doctype}
|
|
(${fields.map((field) => field.fieldname).join(', ')})
|
|
values (${placeholders})`,
|
|
this.getFormattedValues(fields, doc)
|
|
);
|
|
}
|
|
|
|
async updateOne(doctype, doc) {
|
|
let fields = this.getKeys(doctype);
|
|
let assigns = fields.map((field) => `${field.fieldname} = ?`);
|
|
let values = this.getFormattedValues(fields, doc);
|
|
|
|
// additional name for where clause
|
|
values.push(doc.name);
|
|
|
|
return await this.run(
|
|
`update ${doctype}
|
|
set ${assigns.join(', ')} where name=?`,
|
|
values
|
|
);
|
|
}
|
|
|
|
async runDeleteOtherChildren(field, added) {
|
|
await this.run(
|
|
`delete from ${field.childtype}
|
|
where
|
|
parent = ? and
|
|
name not in (${added
|
|
.slice(1)
|
|
.map((d) => '?')
|
|
.join(', ')})`,
|
|
added
|
|
);
|
|
}
|
|
|
|
async deleteOne(doctype, name) {
|
|
return await this.run(`delete from ${doctype} where name=?`, name);
|
|
}
|
|
|
|
async deleteChildren(parenttype, parent) {
|
|
await this.run(`delete from ${parent} where parent=?`, parent);
|
|
}
|
|
|
|
getAll({
|
|
doctype,
|
|
fields,
|
|
filters,
|
|
start,
|
|
limit,
|
|
order_by = 'modified',
|
|
order = 'desc',
|
|
} = {}) {
|
|
if (!fields) {
|
|
fields = frappe.getMeta(doctype).getKeywordFields();
|
|
}
|
|
return new Promise((resolve, reject) => {
|
|
let conditions = this.getFilterConditions(filters);
|
|
|
|
this.conn.all(
|
|
`select ${fields.join(', ')}
|
|
from ${doctype}
|
|
${conditions.conditions ? 'where' : ''} ${conditions.conditions}
|
|
${order_by ? 'order by ' + order_by : ''} ${
|
|
order_by ? order || 'asc' : ''
|
|
}
|
|
${limit ? 'limit ' + limit : ''} ${
|
|
start ? 'offset ' + start : ''
|
|
}`,
|
|
conditions.values,
|
|
(err, rows) => {
|
|
if (err) {
|
|
reject(err);
|
|
} else {
|
|
resolve(rows);
|
|
}
|
|
}
|
|
);
|
|
});
|
|
}
|
|
|
|
run(query, params) {
|
|
// TODO promisify
|
|
return new Promise((resolve, reject) => {
|
|
this.conn.query(query, params, (err) => {
|
|
if (err) {
|
|
if (debug) {
|
|
console.error(err);
|
|
}
|
|
reject(err);
|
|
} else {
|
|
resolve();
|
|
}
|
|
});
|
|
});
|
|
}
|
|
|
|
sql(query, params) {
|
|
return new Promise((resolve) => {
|
|
this.conn.query(query, params, (err, rows) => {
|
|
resolve(rows);
|
|
});
|
|
});
|
|
}
|
|
|
|
async commit() {
|
|
try {
|
|
await this.run('commit');
|
|
} catch (e) {
|
|
if (e.errno !== 1) {
|
|
throw e;
|
|
}
|
|
}
|
|
}
|
|
|
|
init_typeMap() {
|
|
this.typeMap = {
|
|
AutoComplete: 'VARCHAR(140)',
|
|
Currency: 'real',
|
|
Int: 'INT',
|
|
Float: 'decimal(18,6)',
|
|
Percent: 'real',
|
|
Check: 'INT(1)',
|
|
'Small Text': 'text',
|
|
'Long Text': 'text',
|
|
Code: 'text',
|
|
'Text Editor': 'text',
|
|
Date: 'DATE',
|
|
Datetime: 'DATETIME',
|
|
Time: 'TIME',
|
|
Text: 'text',
|
|
Data: 'VARCHAR(140)',
|
|
Link: ' varchar(140)',
|
|
DynamicLink: 'text',
|
|
Password: 'varchar(140)',
|
|
Select: 'VARCHAR(140)',
|
|
'Read Only': 'varchar(140)',
|
|
File: 'text',
|
|
Attach: 'text',
|
|
'Attach Image': 'text',
|
|
Signature: 'text',
|
|
Color: 'text',
|
|
Barcode: 'text',
|
|
Geolocation: 'text',
|
|
};
|
|
}
|
|
};
|